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/lib/engine.js
CHANGED
|
@@ -97,6 +97,7 @@ const {
|
|
|
97
97
|
getDataFactory,
|
|
98
98
|
internalTripleToRdfJsQuads,
|
|
99
99
|
normalizeParsedReasonerInputSync,
|
|
100
|
+
normalizeParsedReasonerInputAsync,
|
|
100
101
|
normalizeReasonerInputSync,
|
|
101
102
|
normalizeReasonerInputAsync,
|
|
102
103
|
} = require('./rdfjs');
|
|
@@ -105,6 +106,7 @@ const trace = require('./trace');
|
|
|
105
106
|
const { deterministicSkolemIdFromKey } = require('./skolem');
|
|
106
107
|
|
|
107
108
|
const deref = require('./deref');
|
|
109
|
+
const { createFactStore, collectStore, MemoryFactStore, PersistentFactStore, tripleToStoreKey } = require('./store');
|
|
108
110
|
|
|
109
111
|
const hasOwn = Object.prototype.hasOwnProperty;
|
|
110
112
|
|
|
@@ -3783,6 +3785,278 @@ function reasonStream(input, opts = {}) {
|
|
|
3783
3785
|
return __out;
|
|
3784
3786
|
}
|
|
3785
3787
|
|
|
3788
|
+
|
|
3789
|
+
async function __parseRunAsyncInput(input, opts) {
|
|
3790
|
+
const {
|
|
3791
|
+
baseIri = null,
|
|
3792
|
+
proof = false,
|
|
3793
|
+
rdf = false,
|
|
3794
|
+
sourceLabel = '<input>',
|
|
3795
|
+
} = opts || {};
|
|
3796
|
+
|
|
3797
|
+
const parsedSourceList = parseN3SourceList(input, { baseIri, rdf: !!rdf, sourceLocations: !!proof });
|
|
3798
|
+
if (parsedSourceList) return parsedSourceList;
|
|
3799
|
+
|
|
3800
|
+
const parsedObject = await normalizeParsedReasonerInputAsync(input);
|
|
3801
|
+
if (parsedObject) {
|
|
3802
|
+
if (baseIri && parsedObject.prefixes && typeof parsedObject.prefixes.setBase === 'function') parsedObject.prefixes.setBase(baseIri);
|
|
3803
|
+
return parsedObject;
|
|
3804
|
+
}
|
|
3805
|
+
|
|
3806
|
+
const n3Text = await normalizeReasonerInputAsync(input);
|
|
3807
|
+
return parseN3Text(n3Text, {
|
|
3808
|
+
baseIri: baseIri || '',
|
|
3809
|
+
label: sourceLabel || '<input>',
|
|
3810
|
+
keepSourceArtifacts: false,
|
|
3811
|
+
sourceLocations: !!proof,
|
|
3812
|
+
rdf: !!rdf,
|
|
3813
|
+
});
|
|
3814
|
+
}
|
|
3815
|
+
|
|
3816
|
+
function __storePatternTerm(t, subst) {
|
|
3817
|
+
const applied = applySubstTerm(t, subst || __emptySubst());
|
|
3818
|
+
return containsVarTerm(applied) ? null : applied;
|
|
3819
|
+
}
|
|
3820
|
+
|
|
3821
|
+
function __mergeStoreSubst(base, delta) {
|
|
3822
|
+
let out = base;
|
|
3823
|
+
for (const k of Object.keys(delta || {})) {
|
|
3824
|
+
const v = delta[k];
|
|
3825
|
+
if (Object.prototype.hasOwnProperty.call(out, k)) {
|
|
3826
|
+
if (!termsEqual(out[k], v)) return null;
|
|
3827
|
+
} else {
|
|
3828
|
+
if (out === base) out = __cloneSubst(base);
|
|
3829
|
+
out[k] = v;
|
|
3830
|
+
}
|
|
3831
|
+
}
|
|
3832
|
+
return out;
|
|
3833
|
+
}
|
|
3834
|
+
|
|
3835
|
+
async function __proveGoalsAgainstStore(goals, subst, store, backRules, localFacts, depth, varGen, opts = {}) {
|
|
3836
|
+
if (!Array.isArray(goals) || goals.length === 0) return [subst || __emptySubst()];
|
|
3837
|
+
if (depth > 64) return [];
|
|
3838
|
+
|
|
3839
|
+
const goal0 = applySubstTriple(goals[0], subst || __emptySubst());
|
|
3840
|
+
const rest = goals.slice(1);
|
|
3841
|
+
const out = [];
|
|
3842
|
+
|
|
3843
|
+
if (isBuiltinPred(goal0.p)) {
|
|
3844
|
+
const deltas = evalBuiltin(goal0, __emptySubst(), localFacts || [], backRules || [], depth, varGen, undefined);
|
|
3845
|
+
for (const delta of deltas) {
|
|
3846
|
+
const nextSubst = __mergeStoreSubst(subst || __emptySubst(), delta);
|
|
3847
|
+
if (nextSubst === null) continue;
|
|
3848
|
+
out.push(...await __proveGoalsAgainstStore(rest, nextSubst, store, backRules, localFacts, depth + 1, varGen, opts));
|
|
3849
|
+
if (opts.maxResults && out.length >= opts.maxResults) return out.slice(0, opts.maxResults);
|
|
3850
|
+
}
|
|
3851
|
+
return out;
|
|
3852
|
+
}
|
|
3853
|
+
|
|
3854
|
+
// Backward rules are kept in memory; they may call back into the persistent
|
|
3855
|
+
// fact store for their own premises.
|
|
3856
|
+
if (goal0.p instanceof Iri && Array.isArray(backRules) && backRules.length) {
|
|
3857
|
+
ensureBackRuleIndexes(backRules);
|
|
3858
|
+
const candRules = (backRules.__byHeadPred.get(goal0.p.__tid) || []).concat(backRules.__wildHeadPred || []);
|
|
3859
|
+
for (const r of candRules) {
|
|
3860
|
+
if (!r || !Array.isArray(r.conclusion) || r.conclusion.length !== 1) continue;
|
|
3861
|
+
const rStd = standardizeRule(r, varGen);
|
|
3862
|
+
const head = rStd.conclusion[0];
|
|
3863
|
+
const s2 = unifyTriple(head, goal0, subst || __emptySubst());
|
|
3864
|
+
if (s2 === null) continue;
|
|
3865
|
+
const newGoals = (rStd.premise || []).concat(rest);
|
|
3866
|
+
out.push(...await __proveGoalsAgainstStore(newGoals, s2, store, backRules, localFacts, depth + 1, varGen, opts));
|
|
3867
|
+
if (opts.maxResults && out.length >= opts.maxResults) return out.slice(0, opts.maxResults);
|
|
3868
|
+
}
|
|
3869
|
+
}
|
|
3870
|
+
|
|
3871
|
+
const sPat = __storePatternTerm(goal0.s, subst || __emptySubst());
|
|
3872
|
+
const pPat = __storePatternTerm(goal0.p, subst || __emptySubst());
|
|
3873
|
+
const oPat = __storePatternTerm(goal0.o, subst || __emptySubst());
|
|
3874
|
+
|
|
3875
|
+
for await (const fact of store.match(sPat, pPat, oPat)) {
|
|
3876
|
+
const s2 = unifyTriple(goal0, fact, subst || __emptySubst());
|
|
3877
|
+
if (s2 === null) continue;
|
|
3878
|
+
out.push(...await __proveGoalsAgainstStore(rest, s2, store, backRules, localFacts, depth + 1, varGen, opts));
|
|
3879
|
+
if (opts.maxResults && out.length >= opts.maxResults) return out.slice(0, opts.maxResults);
|
|
3880
|
+
}
|
|
3881
|
+
|
|
3882
|
+
return out;
|
|
3883
|
+
}
|
|
3884
|
+
|
|
3885
|
+
async function runStoreBacked(input, store, opts = {}) {
|
|
3886
|
+
const parsed = parseN3SourceList(input, {
|
|
3887
|
+
baseIri: opts.baseIri || null,
|
|
3888
|
+
rdf: !!opts.rdf,
|
|
3889
|
+
sourceLocations: !!opts.proof,
|
|
3890
|
+
}) || input;
|
|
3891
|
+
|
|
3892
|
+
const prefixes = parsed.prefixes;
|
|
3893
|
+
const triples = parsed.triples || [];
|
|
3894
|
+
const frules = parsed.frules || [];
|
|
3895
|
+
const brules = parsed.brules || [];
|
|
3896
|
+
const qrules = parsed.logQueryRules || [];
|
|
3897
|
+
|
|
3898
|
+
materializeRdfLists(triples, frules.concat(qrules || []), brules);
|
|
3899
|
+
await store.batchAdd(triples, 'explicit');
|
|
3900
|
+
|
|
3901
|
+
const derived = [];
|
|
3902
|
+
const derivedKeys = new Set();
|
|
3903
|
+
const varGen = [0];
|
|
3904
|
+
const maxIterations = Number.isInteger(opts.maxIterations) && opts.maxIterations > 0 ? opts.maxIterations : 1024;
|
|
3905
|
+
|
|
3906
|
+
for (let iteration = 0; iteration < maxIterations; iteration += 1) {
|
|
3907
|
+
let changed = false;
|
|
3908
|
+
for (let ruleIndex = 0; ruleIndex < frules.length; ruleIndex += 1) {
|
|
3909
|
+
const r = frules[ruleIndex];
|
|
3910
|
+
if (!r || r.isFuse || r.__dynamicConclusionTerm) continue;
|
|
3911
|
+
__prepareForwardRule(r);
|
|
3912
|
+
const solutions = await __proveGoalsAgainstStore(r.premise || [], __emptySubst(), store, brules, triples, 0, varGen, {});
|
|
3913
|
+
for (const subst of solutions) {
|
|
3914
|
+
for (const cpat of r.conclusion || []) {
|
|
3915
|
+
const fact = applySubstTriple(cpat, subst);
|
|
3916
|
+
if (!isGroundTriple(fact)) continue;
|
|
3917
|
+
if (await store.add(fact, 'inferred')) {
|
|
3918
|
+
const df = makeDerivedRecord(fact, r, (r.premise || []).map((p) => applySubstTriple(p, subst)), subst, false);
|
|
3919
|
+
const key = tripleToStoreKey(fact);
|
|
3920
|
+
if (!derivedKeys.has(key)) {
|
|
3921
|
+
derivedKeys.add(key);
|
|
3922
|
+
derived.push(df);
|
|
3923
|
+
}
|
|
3924
|
+
changed = true;
|
|
3925
|
+
}
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3928
|
+
}
|
|
3929
|
+
if (!changed) break;
|
|
3930
|
+
}
|
|
3931
|
+
|
|
3932
|
+
let queryTriples = [];
|
|
3933
|
+
const queryDerived = [];
|
|
3934
|
+
if (qrules.length) {
|
|
3935
|
+
for (const r of qrules) {
|
|
3936
|
+
const solutions = await __proveGoalsAgainstStore(r.premise || [], __emptySubst(), store, brules, triples, 0, varGen, {});
|
|
3937
|
+
for (const subst of solutions) {
|
|
3938
|
+
for (const cpat of r.conclusion || []) {
|
|
3939
|
+
const fact = applySubstTriple(cpat, subst);
|
|
3940
|
+
if (!isGroundTriple(fact)) continue;
|
|
3941
|
+
queryTriples.push(fact);
|
|
3942
|
+
queryDerived.push(makeDerivedRecord(fact, r, (r.premise || []).map((p) => applySubstTriple(p, subst)), subst, false));
|
|
3943
|
+
}
|
|
3944
|
+
}
|
|
3945
|
+
}
|
|
3946
|
+
}
|
|
3947
|
+
|
|
3948
|
+
if (queryTriples.length) {
|
|
3949
|
+
const seen = new Set();
|
|
3950
|
+
queryTriples = queryTriples.filter((tr) => {
|
|
3951
|
+
const key = tripleToStoreKey(tr);
|
|
3952
|
+
if (seen.has(key)) return false;
|
|
3953
|
+
seen.add(key);
|
|
3954
|
+
return true;
|
|
3955
|
+
});
|
|
3956
|
+
}
|
|
3957
|
+
|
|
3958
|
+
return {
|
|
3959
|
+
prefixes,
|
|
3960
|
+
facts: [],
|
|
3961
|
+
derived,
|
|
3962
|
+
queryMode: !!qrules.length,
|
|
3963
|
+
queryTriples,
|
|
3964
|
+
queryDerived,
|
|
3965
|
+
closureN3: qrules.length
|
|
3966
|
+
? prettyPrintQueryTriples(queryTriples, prefixes)
|
|
3967
|
+
: derived.map((df) => (opts.rdf ? tripleToRdfCompatible(df.fact, prefixes) : tripleToN3(df.fact, prefixes))).join('\n'),
|
|
3968
|
+
store,
|
|
3969
|
+
storeBacked: true,
|
|
3970
|
+
};
|
|
3971
|
+
}
|
|
3972
|
+
|
|
3973
|
+
|
|
3974
|
+
function __withoutStoreOptions(opts) {
|
|
3975
|
+
const out = { ...(opts || {}) };
|
|
3976
|
+
delete out.store;
|
|
3977
|
+
delete out.storePath;
|
|
3978
|
+
delete out.storeClear;
|
|
3979
|
+
return out;
|
|
3980
|
+
}
|
|
3981
|
+
|
|
3982
|
+
function __normalizeStoreOption(opts) {
|
|
3983
|
+
const cfg = opts && opts.store;
|
|
3984
|
+
if (!cfg) return null;
|
|
3985
|
+
if (typeof cfg === 'string') return { name: cfg, path: opts.storePath || undefined, clear: !!opts.storeClear };
|
|
3986
|
+
if (typeof cfg === 'object') {
|
|
3987
|
+
return {
|
|
3988
|
+
...cfg,
|
|
3989
|
+
path: cfg.path || opts.storePath || undefined,
|
|
3990
|
+
clear: !!(cfg.clear || opts.storeClear),
|
|
3991
|
+
};
|
|
3992
|
+
}
|
|
3993
|
+
throw new TypeError('runAsync option "store" must be a store name string or a store options object');
|
|
3994
|
+
}
|
|
3995
|
+
|
|
3996
|
+
async function runAsync(input, opts = {}) {
|
|
3997
|
+
const storeConfig = __normalizeStoreOption(opts);
|
|
3998
|
+
const runOpts = __withoutStoreOptions(opts);
|
|
3999
|
+
|
|
4000
|
+
// No store configured: keep ordinary in-memory behavior, but accept async RDF/JS
|
|
4001
|
+
// iterables by normalizing the input before calling the synchronous engine.
|
|
4002
|
+
if (!storeConfig) {
|
|
4003
|
+
const normalizedInput = parseN3SourceList(input, {
|
|
4004
|
+
baseIri: runOpts.baseIri || null,
|
|
4005
|
+
rdf: !!runOpts.rdf,
|
|
4006
|
+
sourceLocations: !!runOpts.proof,
|
|
4007
|
+
}) || (await normalizeReasonerInputAsync(input));
|
|
4008
|
+
return reasonStream(normalizedInput, runOpts);
|
|
4009
|
+
}
|
|
4010
|
+
|
|
4011
|
+
const store = await createFactStore(storeConfig);
|
|
4012
|
+
let closeStore = true;
|
|
4013
|
+
try {
|
|
4014
|
+
const parsed = await __parseRunAsyncInput(input, runOpts);
|
|
4015
|
+
|
|
4016
|
+
// Persist the newly supplied explicit facts first, then include all stored
|
|
4017
|
+
// facts as the starting closure for this run. This lets --store reuse facts
|
|
4018
|
+
// across runs while keeping the current in-memory prover semantics intact.
|
|
4019
|
+
await store.batchAdd(parsed.triples || [], 'explicit');
|
|
4020
|
+
const storedTriples = await collectStore(store);
|
|
4021
|
+
|
|
4022
|
+
const storedKeys = new Set();
|
|
4023
|
+
for (const tr of storedTriples) storedKeys.add(require('./store').tripleToStoreKey(tr));
|
|
4024
|
+
const mergedTriples = storedTriples.slice();
|
|
4025
|
+
for (const tr of parsed.triples || []) {
|
|
4026
|
+
const key = require('./store').tripleToStoreKey(tr);
|
|
4027
|
+
if (!storedKeys.has(key)) {
|
|
4028
|
+
storedKeys.add(key);
|
|
4029
|
+
mergedTriples.push(tr);
|
|
4030
|
+
}
|
|
4031
|
+
}
|
|
4032
|
+
|
|
4033
|
+
const result = reasonStream(
|
|
4034
|
+
{
|
|
4035
|
+
prefixes: parsed.prefixes,
|
|
4036
|
+
triples: mergedTriples,
|
|
4037
|
+
frules: parsed.frules,
|
|
4038
|
+
brules: parsed.brules,
|
|
4039
|
+
logQueryRules: parsed.logQueryRules,
|
|
4040
|
+
},
|
|
4041
|
+
runOpts,
|
|
4042
|
+
);
|
|
4043
|
+
|
|
4044
|
+
await store.batchAdd((result.derived || []).map((df) => df.fact), 'inferred');
|
|
4045
|
+
result.store = store;
|
|
4046
|
+
closeStore = false;
|
|
4047
|
+
return result;
|
|
4048
|
+
} catch (e) {
|
|
4049
|
+
await store.close();
|
|
4050
|
+
throw e;
|
|
4051
|
+
} finally {
|
|
4052
|
+
// Keep result.store usable for callers. On exceptional paths it is closed
|
|
4053
|
+
// above; on success callers may close it when they are done.
|
|
4054
|
+
if (closeStore) {
|
|
4055
|
+
try { await store.close(); } catch {}
|
|
4056
|
+
}
|
|
4057
|
+
}
|
|
4058
|
+
}
|
|
4059
|
+
|
|
3786
4060
|
function reasonRdfJs(input, opts = {}) {
|
|
3787
4061
|
const { dataFactory = null, skipUnsupportedRdfJs = false, ...restOpts } = opts || {};
|
|
3788
4062
|
const rdfFactory = getDataFactory(dataFactory);
|
|
@@ -3890,6 +4164,8 @@ function setTracePrefixes(v) {
|
|
|
3890
4164
|
|
|
3891
4165
|
module.exports = {
|
|
3892
4166
|
reasonStream,
|
|
4167
|
+
runAsync,
|
|
4168
|
+
runStoreBacked,
|
|
3893
4169
|
reasonRdfJs,
|
|
3894
4170
|
collectLogQueryConclusions,
|
|
3895
4171
|
forwardChainAndCollectLogQueryConclusions,
|
|
@@ -3926,4 +4202,7 @@ module.exports = {
|
|
|
3926
4202
|
loadBuiltinModule,
|
|
3927
4203
|
listBuiltinIris,
|
|
3928
4204
|
INFERENCE_FUSE_EXIT_CODE,
|
|
4205
|
+
createFactStore,
|
|
4206
|
+
MemoryFactStore,
|
|
4207
|
+
PersistentFactStore,
|
|
3929
4208
|
};
|
package/lib/entry.js
CHANGED
|
@@ -17,6 +17,7 @@ const { dataFactory } = require('./rdfjs');
|
|
|
17
17
|
module.exports = {
|
|
18
18
|
// public
|
|
19
19
|
reasonStream: engine.reasonStream,
|
|
20
|
+
runAsync: engine.runAsync,
|
|
20
21
|
reasonRdfJs: engine.reasonRdfJs,
|
|
21
22
|
rdfjs: dataFactory,
|
|
22
23
|
main: engine.main,
|
|
@@ -41,6 +42,9 @@ module.exports = {
|
|
|
41
42
|
registerBuiltinModule: engine.registerBuiltinModule,
|
|
42
43
|
loadBuiltinModule: engine.loadBuiltinModule,
|
|
43
44
|
listBuiltinIris: engine.listBuiltinIris,
|
|
45
|
+
createFactStore: engine.createFactStore,
|
|
46
|
+
MemoryFactStore: engine.MemoryFactStore,
|
|
47
|
+
PersistentFactStore: engine.PersistentFactStore,
|
|
44
48
|
getEnforceHttpsEnabled: engine.getEnforceHttpsEnabled,
|
|
45
49
|
setEnforceHttpsEnabled: engine.setEnforceHttpsEnabled,
|
|
46
50
|
getProofCommentsEnabled: engine.getProofCommentsEnabled,
|
package/lib/rdfjs.js
CHANGED
|
@@ -952,6 +952,7 @@ module.exports = {
|
|
|
952
952
|
internalTripleToRdfJsQuads,
|
|
953
953
|
internalTripleToRdfJsQuadInGraph,
|
|
954
954
|
normalizeParsedReasonerInputSync,
|
|
955
|
+
normalizeParsedReasonerInputAsync,
|
|
955
956
|
normalizeReasonerInputSync,
|
|
956
957
|
normalizeReasonerInputAsync,
|
|
957
958
|
hasEyelingObjectInput,
|