UNPKG

jinaga

Version:

Data management for web and mobile applications.

109 lines 6.82 kB
"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