jinaga
Version:
Data management for web and mobile applications.
109 lines • 6.82 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildFeeds = void 0;
const specification_1 = require("./specification");
function buildFeeds(specification) {
const { specifications, unusedGivens } = addMatches(specification_1.emptySpecification, specification.given.map(g => g.label), specification.matches);
// The final feed represents the complete tuple.
// Build projections onto that one.
const finalFeed = specifications[specifications.length - 1];
if (specification.projection.type === "composite") {
const feedsWithProjections = addProjections(finalFeed, unusedGivens, specification.projection.components);
return [...specifications, ...feedsWithProjections].filter(specification_1.specificationIsNotDeterministic);
}
else {
return specifications.filter(specification_1.specificationIsNotDeterministic);
}
}
exports.buildFeeds = buildFeeds;
function addMatches(specification, unusedGivens, matches) {
const specifications = [];
for (const match of matches) {
specification = withMatch(specification, match);
for (const pathCondition of match.conditions.filter(specification_1.isPathCondition)) {
// If the right-hand side is a given, then add it to the feed parameters.
const reference = unusedGivens.find(given => given.name === pathCondition.labelRight);
if (reference) {
specification = withGiven(specification, reference);
unusedGivens = unusedGivens.filter(given => given.name !== reference.name);
}
}
for (const existentialCondition of match.conditions.filter(specification_1.isExistentialCondition)) {
if (existentialCondition.exists) {
// Include the matches of the existential condition into the current feed.
const { specifications: newSpecifications, unusedGivens: newUnusedGivens } = addMatches(specification, unusedGivens, existentialCondition.matches);
const last = newSpecifications.length - 1;
specifications.push(...newSpecifications.slice(0, last));
specification = newSpecifications[last];
unusedGivens = newUnusedGivens;
}
else {
// Branch from the current feed and follow the matches of the existential condition.
// This will produce tuples that prove the condition false.
const { specifications: negatingSpecifications } = addMatches(specification, unusedGivens, existentialCondition.matches);
specifications.push(...negatingSpecifications);
// Then apply the existential condition and continue with the tuple.
const { existentialCondition: newExistentialCondition, givens: newGivens, unusedGivens: newUnusedGivens } = buildExistentialCondition({
type: "existential",
exists: false,
matches: []
}, existentialCondition.matches, specification.given, unusedGivens);
specification = withCondition(specification, newGivens, newExistentialCondition);
unusedGivens = newUnusedGivens;
}
}
}
specifications.push(specification);
return { specifications, unusedGivens };
}
function buildExistentialCondition(existentialCondition, matches, givens, unusedGivens) {
for (const match of matches) {
existentialCondition = Object.assign(Object.assign({}, existentialCondition), { matches: [...existentialCondition.matches, Object.assign(Object.assign({}, match), { conditions: match.conditions.filter(specification_1.isPathCondition) })] });
for (const pathCondition of match.conditions.filter(specification_1.isPathCondition)) {
// If the right-hand side is a given, then add it to the feed parameters.
const reference = unusedGivens.find(given => given.name === pathCondition.labelRight);
if (reference) {
givens = [...givens, { label: reference, conditions: [] }];
unusedGivens = unusedGivens.filter(given => given.name !== reference.name);
}
}
for (const innerExistentialCondition of match.conditions.filter(specification_1.isExistentialCondition)) {
if (innerExistentialCondition.exists) {
// Include the matches of the existential condition into the current condition.
const { existentialCondition: newExistentialCondition, givens: newGivens, unusedGivens: newUnusedGivens } = buildExistentialCondition(innerExistentialCondition, innerExistentialCondition.matches, givens, unusedGivens);
existentialCondition = newExistentialCondition;
givens = newGivens;
unusedGivens = newUnusedGivens;
}
}
}
return { existentialCondition, givens, unusedGivens };
}
function addProjections(specification, unusedGivens, components) {
const specifications = [];
components.forEach(component => {
if (component.type === "specification") {
// Produce more facts in the tuple.
const { specifications: feedsWithMatches, unusedGivens: newUnusedGivens } = addMatches(specification, unusedGivens, component.matches);
specifications.push(...feedsWithMatches);
// Recursively build child projections.
const finalFeed = feedsWithMatches[feedsWithMatches.length - 1];
if (component.projection.type === "composite") {
const feedsWithProjections = addProjections(finalFeed, unusedGivens, component.projection.components);
specifications.push(...feedsWithProjections);
}
}
});
return specifications;
}
function withMatch(specification, match) {
const pathConditions = match.conditions.filter(specification_1.isPathCondition);
return Object.assign(Object.assign({}, specification), { matches: [...specification.matches, Object.assign(Object.assign({}, match), { conditions: pathConditions })] });
}
function withGiven(specification, label) {
return Object.assign(Object.assign({}, specification), { given: [...specification.given, { label, conditions: [] }] });
}
function withCondition(specification, newGivens, newExistentialCondition) {
return Object.assign(Object.assign({}, specification), { given: newGivens, matches: [...specification.matches.slice(0, specification.matches.length - 1), Object.assign(Object.assign({}, specification.matches[specification.matches.length - 1]), { conditions: [...specification.matches[specification.matches.length - 1].conditions, newExistentialCondition] })] });
}
//# sourceMappingURL=feed-builder.js.map