@balena/contrato
Advanced tools
Comparing version 0.11.0-build-cleanup-interfaces-b2e71c992182a8cf3bd9e0d3c1bfa3025e63b604-1 to 0.11.0-build-universe-20c9f26832f3cfafd44699e733b8fb4297bf2a35-1
import Contract from './contract'; | ||
import type { BlueprintLayout } from './types'; | ||
import type { BlueprintLayout } from './types/types'; | ||
export default class Blueprint extends Contract { | ||
constructor(layout: BlueprintLayout, skeleton?: any); | ||
reproduce(contract: Contract): IterableIterator<Contract>; | ||
sequence(contract: Contract, options?: { | ||
allowRequirements: boolean; | ||
}): Contract[]; | ||
reproduce(contract: Contract, asIterable?: false): Contract[]; | ||
reproduce(contract: Contract, asIterable: true): IterableIterator<Contract>; | ||
reproduce(contract: Contract, asIterable?: boolean): IterableIterator<Contract> | Contract[]; | ||
} |
@@ -6,8 +6,18 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const clone_1 = __importDefault(require("lodash/clone")); | ||
const concat_1 = __importDefault(require("lodash/concat")); | ||
const fill_1 = __importDefault(require("lodash/fill")); | ||
const filter_1 = __importDefault(require("lodash/filter")); | ||
const flatMap_1 = __importDefault(require("lodash/flatMap")); | ||
const flatten_1 = __importDefault(require("lodash/flatten")); | ||
const forEach_1 = __importDefault(require("lodash/forEach")); | ||
const includes_1 = __importDefault(require("lodash/includes")); | ||
const isEmpty_1 = __importDefault(require("lodash/isEmpty")); | ||
const isEqual_1 = __importDefault(require("lodash/isEqual")); | ||
const reduce_1 = __importDefault(require("lodash/reduce")); | ||
const uniqWith_1 = __importDefault(require("lodash/uniqWith")); | ||
const semver_1 = require("semver"); | ||
const contract_1 = __importDefault(require("./contract")); | ||
const cardinality_1 = require("./cardinality"); | ||
const types_1 = require("./types"); | ||
const types_1 = require("./types/types"); | ||
const utils_1 = require("./utils"); | ||
@@ -46,3 +56,5 @@ class Blueprint extends contract_1.default { | ||
} | ||
reproduce(contract) { | ||
sequence(contract, options = { | ||
allowRequirements: true, | ||
}) { | ||
const layout = this.metadata.layout; | ||
@@ -52,2 +64,149 @@ const combinations = (0, reduce_1.default)(layout.finite.selectors, (accumulator, value) => { | ||
(0, forEach_1.default)(value, (option) => { | ||
const combi = (0, uniqWith_1.default)(contract.getChildrenCombinations(option), (left, right) => { | ||
return (0, isEqual_1.default)(left[0].raw, right[0].raw); | ||
}); | ||
internalAccumulator = internalAccumulator.concat([combi]); | ||
}); | ||
return internalAccumulator; | ||
}, []); | ||
(0, forEach_1.default)(combinations, (dimension) => { | ||
dimension.sort((left, right) => { | ||
return (0, semver_1.compare)(left[0].raw.version, right[0].raw.version); | ||
}); | ||
}); | ||
const currentPointer = new Array(combinations.length); | ||
(0, fill_1.default)(currentPointer, 0); | ||
const bestPointer = new Array(combinations.length); | ||
for (let idx = 0; idx < combinations.length; idx++) { | ||
bestPointer[idx] = combinations[idx].length - 1; | ||
} | ||
const buildContextFromPointer = (pointer) => { | ||
const context = new contract_1.default(this.raw.skeleton, { | ||
hash: false, | ||
}); | ||
const combination = []; | ||
for (let idx = 0; idx < combinations.length; idx++) { | ||
combination.push(combinations[idx][pointer[idx]]); | ||
} | ||
context.addChildren((0, flatten_1.default)(combination), { | ||
rehash: true, | ||
}); | ||
const references = context.getChildrenCrossReferencedContracts({ | ||
from: contract, | ||
types: layout.infinite.types, | ||
}); | ||
const contracts = references.length === 0 | ||
? contract.getChildren({ | ||
types: layout.infinite.types, | ||
}) | ||
: references; | ||
context.addChildren(contracts, { | ||
rehash: false, | ||
}); | ||
for (const reference of contracts) { | ||
if (!context.satisfiesChildContract(reference, { | ||
types: layout.types, | ||
})) { | ||
context.removeChild(reference, { | ||
rehash: false, | ||
}); | ||
} | ||
} | ||
context.interpolate(); | ||
const requirements = context.getAllNotSatisfiedChildRequirements(); | ||
const newRequirements = (0, uniqWith_1.default)((0, filter_1.default)((0, concat_1.default)(context.raw.requires, requirements)), isEqual_1.default); | ||
if (newRequirements && !(0, isEmpty_1.default)(newRequirements)) { | ||
if (!options.allowRequirements) { | ||
return null; | ||
} | ||
context.raw.requires = newRequirements; | ||
context.interpolate(); | ||
} | ||
const childCapabilities = (0, filter_1.default)((0, uniqWith_1.default)((0, flatMap_1.default)(context.getChildren(), (v) => v.raw.capabilities), isEqual_1.default)); | ||
if (childCapabilities && !(0, isEmpty_1.default)(childCapabilities)) { | ||
context.raw.capabilities = childCapabilities; | ||
context.interpolate(); | ||
} | ||
return context; | ||
}; | ||
const checkSolutions = (pointer) => { | ||
const context = buildContextFromPointer(pointer); | ||
return !context | ||
? false | ||
: context.areChildrenSatisfied({ | ||
types: layout.types, | ||
}); | ||
}; | ||
const checked = []; | ||
const pointerValue = (pointer) => (0, reduce_1.default)(pointer, (sum, value) => sum + value, 0); | ||
let currentBestPointer = new Array(combinations.length); | ||
(0, fill_1.default)(currentBestPointer, 0); | ||
const currentBestPointerValue = pointerValue(currentBestPointer); | ||
let currentBestPath = []; | ||
const isValidPointer = (pointer) => { | ||
if ((0, includes_1.default)(checked, pointer)) { | ||
return false; | ||
} | ||
for (let idx = 0; idx < combinations.length; idx++) { | ||
if (pointer[idx] > bestPointer[idx]) { | ||
return false; | ||
} | ||
} | ||
if (!checkSolutions(pointer)) { | ||
return false; | ||
} | ||
return true; | ||
}; | ||
const search = (combos, pointer, path) => { | ||
checked.push(pointer); | ||
for (let idx = 0; idx < combos.length; idx++) { | ||
const possiblePointer = (0, clone_1.default)(pointer); | ||
possiblePointer[idx] += 1; | ||
if (isValidPointer(possiblePointer)) { | ||
const currentPath = (0, clone_1.default)(path); | ||
currentPath.push(possiblePointer); | ||
if ((0, isEqual_1.default)(possiblePointer, bestPointer)) { | ||
currentBestPath = currentPath; | ||
return true; | ||
} | ||
const solutionValue = pointerValue(possiblePointer); | ||
if (solutionValue > currentBestPointerValue) { | ||
currentBestPointer = possiblePointer; | ||
currentBestPath = currentPath; | ||
} | ||
if (search(combos, possiblePointer, currentPath)) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
} | ||
return false; | ||
}; | ||
if (isValidPointer(currentPointer)) { | ||
currentBestPointer = currentPointer; | ||
currentBestPath = [currentPointer]; | ||
search(combinations, currentPointer, [currentPointer]); | ||
} | ||
return (0, reduce_1.default)(currentBestPath, (seq, pointer) => { | ||
const context = buildContextFromPointer(pointer); | ||
if (context) { | ||
if (!context.areChildrenSatisfied({ | ||
types: layout.infinite.types, | ||
})) { | ||
return seq; | ||
} | ||
context.interpolate(); | ||
seq.push(context); | ||
} | ||
return seq; | ||
}, []); | ||
} | ||
reproduce(contract, asIterable = false) { | ||
if (!asIterable) { | ||
return [...this.reproduce(contract, true)]; | ||
} | ||
const layout = this.metadata.layout; | ||
const combinations = (0, reduce_1.default)(layout.finite.selectors, (accumulator, value) => { | ||
let internalAccumulator = accumulator; | ||
(0, forEach_1.default)(value, (option) => { | ||
internalAccumulator = internalAccumulator.concat([ | ||
@@ -54,0 +213,0 @@ contract.getChildrenCombinations(option), |
@@ -1,2 +0,2 @@ | ||
import type { ContractObject } from './types'; | ||
import type { ContractObject } from './types/types'; | ||
export default class Contract { | ||
@@ -42,3 +42,2 @@ metadata: any; | ||
}): Contract[]; | ||
private isRequirementSatisfied; | ||
getNotSatisfiedChildRequirements(contract: Contract, options?: { | ||
@@ -45,0 +44,0 @@ types: Set<string>; |
@@ -28,3 +28,3 @@ "use strict"; | ||
const hash_1 = require("./hash"); | ||
const types_1 = require("./types"); | ||
const types_1 = require("./types/types"); | ||
const template_1 = require("./template"); | ||
@@ -385,3 +385,3 @@ const variants_1 = require("./variants"); | ||
return (0, flatMap_1.default)(rang, (tcardinality) => { | ||
return new js_combinatorics_1.Combination(contracts, tcardinality).toArray(); | ||
return (0, js_combinatorics_1.bigCombination)(contracts, tcardinality).toArray(); | ||
}); | ||
@@ -426,32 +426,2 @@ } | ||
} | ||
isRequirementSatisfied(requirement, options = {}) { | ||
const shouldEvaluateType = (type) => options.types ? options.types.has(type) : true; | ||
const hasMatch = (matcher) => { | ||
return (this.findChildren(matcher).length > 0 || | ||
this.findChildrenWithCapabilities(matcher).length > 0); | ||
}; | ||
if (requirement.raw.operation === 'or') { | ||
const disjuncts = (0, filter_1.default)(requirement.raw.data.getAll(), (disjunct) => { | ||
return shouldEvaluateType(disjunct.raw.data.type); | ||
}); | ||
if (disjuncts.length === 0 || (0, some_1.default)((0, map_1.default)(disjuncts, hasMatch))) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
else if (requirement.raw.operation === 'not') { | ||
const disjuncts = (0, filter_1.default)(requirement.raw.data.getAll(), (disjunct) => { | ||
return shouldEvaluateType(disjunct.raw.data.type); | ||
}); | ||
if (disjuncts.length > 0 && (0, some_1.default)((0, map_1.default)(disjuncts, hasMatch))) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
if (shouldEvaluateType(requirement.raw.data.type) && | ||
!hasMatch(requirement)) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
getNotSatisfiedChildRequirements(contract, options = { types: new Set() }) { | ||
@@ -464,7 +434,24 @@ const conjuncts = (0, reduce_1.default)(contract.getChildren(), (accumulator, child) => { | ||
} | ||
const shouldEvaluateType = (type) => options.types ? options.types.has(type) : true; | ||
const requirements = []; | ||
const hasMatch = (matcher) => { | ||
return (this.findChildren(matcher).length > 0 || | ||
this.findChildrenWithCapabilities(matcher).length > 0); | ||
}; | ||
for (const conjunct of conjuncts) { | ||
if (!this.isRequirementSatisfied(conjunct, options)) { | ||
if (conjunct.raw.operation === 'or') { | ||
const disjuncts = (0, filter_1.default)(conjunct.raw.data.getAll(), (disjunct) => { | ||
return shouldEvaluateType(disjunct.raw.data.type); | ||
}); | ||
if (disjuncts.length === 0 || (0, some_1.default)((0, map_1.default)(disjuncts, hasMatch))) { | ||
continue; | ||
} | ||
requirements.push(conjunct.raw.data); | ||
} | ||
if (shouldEvaluateType(conjunct.raw.data.type) && !hasMatch(conjunct)) { | ||
requirements.push(conjunct.raw.data); | ||
} | ||
else if (!shouldEvaluateType(conjunct.raw.data.type)) { | ||
requirements.push(conjunct.raw.data); | ||
} | ||
} | ||
@@ -480,6 +467,26 @@ return requirements; | ||
} | ||
const shouldEvaluateType = (type) => options.types ? options.types.has(type) : true; | ||
const hasMatch = (matcher) => this.findChildren(matcher).length > 0; | ||
for (const conjunct of conjuncts) { | ||
if (!this.isRequirementSatisfied(conjunct, options)) { | ||
if (conjunct.raw.operation === 'or') { | ||
const disjuncts = (0, filter_1.default)(conjunct.raw.data.getAll(), (disjunct) => { | ||
return shouldEvaluateType(disjunct.raw.data.type); | ||
}); | ||
if (disjuncts.length === 0 || (0, some_1.default)((0, map_1.default)(disjuncts, hasMatch))) { | ||
continue; | ||
} | ||
return false; | ||
} | ||
else if (conjunct.raw.operation === 'not') { | ||
const disjuncts = (0, filter_1.default)(conjunct.raw.data.getAll(), (disjunct) => { | ||
return shouldEvaluateType(disjunct.raw.data.type); | ||
}); | ||
if (disjuncts.length > 0 && (0, some_1.default)((0, map_1.default)(disjuncts, hasMatch))) { | ||
return false; | ||
} | ||
continue; | ||
} | ||
if (shouldEvaluateType(conjunct.raw.data.type) && !hasMatch(conjunct)) { | ||
return false; | ||
} | ||
} | ||
@@ -486,0 +493,0 @@ return true; |
@@ -1,6 +0,10 @@ | ||
import { BlueprintLayout, BlueprintObject, ContractObject } from './types'; | ||
import { BlueprintLayout, BlueprintObject, ContractObject } from './types/types'; | ||
import Contract from './contract'; | ||
import Blueprint from './blueprint'; | ||
import Universe from './universe'; | ||
import { buildTemplate } from './partials'; | ||
export { BlueprintLayout, ContractObject, BlueprintObject, Contract, Blueprint, buildTemplate, }; | ||
export declare function query(universe: Contract, layout: BlueprintLayout, skeleton: object): IterableIterator<Contract>; | ||
import { parse as parseCardinality } from './cardinality'; | ||
export { BlueprintLayout, ContractObject, BlueprintObject, Contract, Blueprint, Universe, buildTemplate, parseCardinality, }; | ||
export declare function query(universe: Contract, layout: BlueprintLayout, skeleton: object, asIterable: true): IterableIterator<Contract>; | ||
export declare function query(universe: Contract, layout: BlueprintLayout, skeleton: object, asIterable?: false): Contract[]; | ||
export declare const sequence: (universe: Contract, layout: BlueprintLayout, skeleton: object) => Contract[]; |
@@ -6,3 +6,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.buildTemplate = exports.Blueprint = exports.Contract = void 0; | ||
exports.sequence = exports.parseCardinality = exports.buildTemplate = exports.Universe = exports.Blueprint = exports.Contract = void 0; | ||
exports.query = query; | ||
@@ -13,7 +13,13 @@ const contract_1 = __importDefault(require("./contract")); | ||
exports.Blueprint = blueprint_1.default; | ||
const universe_1 = __importDefault(require("./universe")); | ||
exports.Universe = universe_1.default; | ||
const partials_1 = require("./partials"); | ||
Object.defineProperty(exports, "buildTemplate", { enumerable: true, get: function () { return partials_1.buildTemplate; } }); | ||
function query(universe, layout, skeleton) { | ||
return new blueprint_1.default(layout, skeleton).reproduce(universe); | ||
const cardinality_1 = require("./cardinality"); | ||
Object.defineProperty(exports, "parseCardinality", { enumerable: true, get: function () { return cardinality_1.parse; } }); | ||
function query(universe, layout, skeleton, asIterable = false) { | ||
return new blueprint_1.default(layout, skeleton).reproduce(universe, asIterable); | ||
} | ||
const sequence = (universe, layout, skeleton) => new blueprint_1.default(layout, skeleton).sequence(universe); | ||
exports.sequence = sequence; | ||
//# sourceMappingURL=index.js.map |
@@ -10,3 +10,3 @@ import type Contract from './contract'; | ||
resetType(type: string): void; | ||
merge(cache: MatcherCache): this; | ||
merge(cache: MatcherCache): MatcherCache; | ||
} |
import Contract from './contract'; | ||
import type { ContractObject } from './types'; | ||
import type { ContractObject } from './types/types'; | ||
export declare const findPartial: (name: string, context: Contract, options: { | ||
@@ -4,0 +4,0 @@ baseDirectory: string; |
@@ -114,3 +114,3 @@ "use strict"; | ||
const safeContent = new hb.SafeString(partialContent.slice(0, partialContent.length - 1)); | ||
const builtContent = await Promise.resolve(hb.compile(safeContent.toString())(options.data.root)); | ||
const builtContent = await hb.compile(safeContent.toString())(options.data.root); | ||
return new hb.SafeString(builtContent); | ||
@@ -145,5 +145,5 @@ } | ||
}, context.toJSON().children); | ||
return (0, utils_1.stripExtraBlankLines)(await Promise.resolve(hb.compile(template)(data))); | ||
return (0, utils_1.stripExtraBlankLines)(await hb.compile(template)(data)); | ||
}; | ||
exports.buildTemplate = buildTemplate; | ||
//# sourceMappingURL=partials.js.map |
@@ -1,2 +0,2 @@ | ||
import type { ContractObject } from './types'; | ||
import type { ContractObject } from './types/types'; | ||
export declare const compileContract: (contract: ContractObject, options?: { | ||
@@ -3,0 +3,0 @@ blacklist?: Set<string>; |
@@ -1,2 +0,2 @@ | ||
import type { ContractObject } from './types'; | ||
import type { ContractObject } from './types/types'; | ||
export declare const build: (contract: ContractObject) => ContractObject[]; |
{ | ||
"name": "@balena/contrato", | ||
"version": "0.11.0-build-cleanup-interfaces-b2e71c992182a8cf3bd9e0d3c1bfa3025e63b604-1", | ||
"version": "0.11.0-build-universe-20c9f26832f3cfafd44699e733b8fb4297bf2a35-1", | ||
"description": "The official contract implementation", | ||
@@ -26,6 +26,7 @@ "homepage": "https://github.com/product-os/contrato", | ||
"clean": "rimraf build", | ||
"build": "npm run clean && tsc", | ||
"build": "npm run clean && npm run buildtypes && tsc", | ||
"buildtypes": "ts-node --transpile-only ./scripts/build-types.ts && balena-lint --typescript --fix lib/types", | ||
"doc": "typedoc --options ./typedoc.json", | ||
"lint": "balena-lint -t tsconfig.dev.json --typescript lib tests", | ||
"lint-fix": "balena-lint -t tsconfig.dev.json --typescript --fix lib tests", | ||
"lint": "balena-lint -t tsconfig.dev.json --typescript lib tests scripts", | ||
"lint-fix": "balena-lint -t tsconfig.dev.json --typescript --fix lib tests scripts", | ||
"test:node": "mocha -r ts-node/register/transpile-only --reporter spec \"tests/**/*.spec.ts\"", | ||
@@ -41,11 +42,12 @@ "test": "npm run build && npm run lint && npm run test:node", | ||
"handlebars": "^4.7.8", | ||
"js-combinatorics": "^2.1.2", | ||
"js-combinatorics": "^0.5.5", | ||
"json-schema": "^0.4.0", | ||
"lodash": "^4.17.19", | ||
"object-hash": "^3.0.0", | ||
"object-hash": "^1.3.1", | ||
"p-map": "^7.0.3", | ||
"promised-handlebars": "^2.0.1", | ||
"semver": "^7.6.3" | ||
"semver": "^5.7.1" | ||
}, | ||
"devDependencies": { | ||
"@balena/lint": "^9.1.3", | ||
"@balena/lint": "^8.2.8", | ||
"@types/chai": "^4.2.11", | ||
@@ -63,5 +65,7 @@ "@types/chai-as-promised": "^7.1.2", | ||
"chai-as-promised": "^7.1.1", | ||
"cuelang-js": "^1.1.1", | ||
"husky": "^4.2.5", | ||
"lint-staged": "^10.1.7", | ||
"mocha": "^10.4.0", | ||
"openapi-typescript": "^3.2.4", | ||
"rimraf": "^3.0.2", | ||
@@ -77,4 +81,4 @@ "ts-node": "^8.10.1", | ||
"versionist": { | ||
"publishedAt": "2024-12-31T20:35:19.334Z" | ||
"publishedAt": "2025-01-10T16:21:07.516Z" | ||
} | ||
} |
@@ -1,8 +0,10 @@ | ||
# Contrato | ||
Contrato | ||
======== | ||
> The official contracts implementation | ||
[![Documentation](https://github.com/product-os/contrato/actions/workflows/docs.yml/badge.svg)](https://balena-io.github.io/contrato/modules/contrato.html) | ||
[![Documentation](https://github.com/product-os/contrato/actions/workflows/docs.yml/badge.svg)](https://product-os.github.io/contrato/modules/contrato.html) | ||
## Tests | ||
Tests | ||
----- | ||
@@ -15,6 +17,7 @@ Run the `test` npm script: | ||
## Contribute | ||
Contribute | ||
---------- | ||
- Issue Tracker: [github.com/product-os/contrato/issues](https://github.com/balena-io/contrato/issues) | ||
- Source Code: [github.com/product-os/contrato](https://github.com/balena-io/contrato) | ||
- Issue Tracker: [github.com/product-os/contrato/issues](https://github.com/product-os/contrato/issues) | ||
- Source Code: [github.com/product-os/contrato](https://github.com/product-os/contrato) | ||
@@ -28,9 +31,11 @@ Before submitting a PR, please make sure that you include tests, and that the | ||
## Support | ||
Support | ||
------- | ||
If you're having any problem, please [raise an | ||
issue](https://github.com/balena-io/contrato/issues/new) on GitHub. | ||
issue](https://github.com/product-os/contrato/issues/new) on GitHub. | ||
## License | ||
License | ||
------- | ||
The project is licensed under the Apache 2.0 license. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
143601
51
1905
40
11
22
2
+ Addedp-map@^7.0.3
+ Addedjs-combinatorics@0.5.5(transitive)
+ Addedobject-hash@1.3.1(transitive)
+ Addedp-map@7.0.3(transitive)
+ Addedsemver@5.7.2(transitive)
- Removedjs-combinatorics@2.1.2(transitive)
- Removedobject-hash@3.0.0(transitive)
- Removedsemver@7.6.3(transitive)
Updatedjs-combinatorics@^0.5.5
Updatedobject-hash@^1.3.1
Updatedsemver@^5.7.1