@hyperscale0/hsx 1.0.128 → 1.0.132
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/dist/src/cli.js +1 -1
- package/dist/src/cli.js.map +1 -1
- package/dist/src/compile.d.ts.map +1 -1
- package/dist/src/compile.js +173 -23
- package/dist/src/compile.js.map +1 -1
- package/dist/src/examples-bundle.js +6 -6
- package/dist/src/examples-bundle.js.map +1 -1
- package/dist/src/parse.js +4 -1
- package/dist/src/parse.js.map +1 -1
- package/dist/src/std-bundle.js +10 -10
- package/dist/src/std-bundle.js.map +1 -1
- package/docs/README.md +78 -27
- package/examples/cards.hsx +7 -1
- package/examples/collections.hsx +4 -0
- package/examples/cost-table.json +80 -56
- package/examples/insurance.hsx +2 -1
- package/examples/marketplace.hsx +3 -1
- package/examples/rental-deposit.hsx +2 -0
- package/examples/wallet.hsx +1 -1
- package/package.json +4 -4
- package/src/cli.ts +1 -1
- package/src/compile.ts +246 -23
- package/src/examples-bundle.ts +6 -6
- package/src/parse.ts +4 -1
- package/src/std-bundle.ts +10 -10
- package/std/booking.hsx +1 -1
- package/std/cards.hsx +20 -11
- package/std/escrow.hsx +45 -10
- package/std/financing.hsx +214 -62
- package/std/insurance.hsx +3 -3
- package/std/lending.hsx +16 -8
- package/std/marketplace.hsx +4 -3
- package/std/money.hsx +28 -14
- package/std/savings.hsx +3 -2
- package/std/wallet.hsx +13 -8
package/dist/src/cli.js
CHANGED
|
@@ -75,7 +75,7 @@ export async function runCli(argv, io) {
|
|
|
75
75
|
else {
|
|
76
76
|
const result = compile(source, { standardLibrary });
|
|
77
77
|
for (const d of result.diagnostics)
|
|
78
|
-
io.err(`${d.source && d.source !== "program" ? d.source : file}:${d.line}:${d.column}: ${d.code} ${d.message
|
|
78
|
+
io.err(`${d.source && d.source !== "program" ? d.source : file}:${d.line}:${d.column}: ${d.code} ${d.message.replace(/[^.?!]$/, "$&.")} ${d.fix}`);
|
|
79
79
|
if (!result.artifacts || result.verdict !== "valid")
|
|
80
80
|
return 1;
|
|
81
81
|
if (command === "check")
|
package/dist/src/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compile.ts"],"names":[],"mappings":"AAOA,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAgBL,KAAK,WAAW,EAQjB,MAAM,kBAAkB,CAAC;AAU1B,OAAO,EAIL,KAAK,UAAU,EAKf,KAAK,IAAI,EACV,MAAM,UAAU,CAAC;AAClB,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEhF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;CACpC;AACD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,IAAI,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,aAAa,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3E;AACD,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,MAAM,WAAW,cAAc;IAC7B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC;CAClE;AACD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,WAAW,EAAE,iBAAiB,EAAE,CAAC;IACjC,SAAS,CAAC,EAAE;QACV,QAAQ,EAAE,WAAW,CAAC;QACtB,YAAY,EAAE,eAAe,CAAC;QAC9B,SAAS,EAAE,qBAAqB,EAAE,CAAC;KACpC,CAAC;CACH;AAqTD,wBAAgB,OAAO,CACrB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,cAAmB,GAC3B,aAAa,
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compile.ts"],"names":[],"mappings":"AAOA,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAgBL,KAAK,WAAW,EAQjB,MAAM,kBAAkB,CAAC;AAU1B,OAAO,EAIL,KAAK,UAAU,EAKf,KAAK,IAAI,EACV,MAAM,UAAU,CAAC;AAClB,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEhF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;CACpC;AACD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,IAAI,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,aAAa,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3E;AACD,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,MAAM,WAAW,cAAc;IAC7B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC;CAClE;AACD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,WAAW,EAAE,iBAAiB,EAAE,CAAC;IACjC,SAAS,CAAC,EAAE;QACV,QAAQ,EAAE,WAAW,CAAC;QACtB,YAAY,EAAE,eAAe,CAAC;QAC9B,SAAS,EAAE,qBAAqB,EAAE,CAAC;KACpC,CAAC;CACH;AAqTD,wBAAgB,OAAO,CACrB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,cAAmB,GAC3B,aAAa,CAo5Hf"}
|
package/dist/src/compile.js
CHANGED
|
@@ -285,6 +285,9 @@ export function compile(source, options = {}) {
|
|
|
285
285
|
const declarationSources = new Map();
|
|
286
286
|
const standardOrigins = new Map();
|
|
287
287
|
const requirementOrigins = new Map();
|
|
288
|
+
// Instruments that lost a std action to an empty all() parent. Their
|
|
289
|
+
// lifecycles drop the states only that action reached.
|
|
290
|
+
const trimmed = new Set();
|
|
288
291
|
const used = new Set();
|
|
289
292
|
for (const use of program.decls.filter((d) => d.kind === "use")) {
|
|
290
293
|
if (used.has(use.name))
|
|
@@ -366,6 +369,11 @@ export function compile(source, options = {}) {
|
|
|
366
369
|
const assignments = new Map();
|
|
367
370
|
const attachmentSubjects = new Map();
|
|
368
371
|
const names = new Set();
|
|
372
|
+
// A record's create turns public only through a program-level expose,
|
|
373
|
+
// which applies after lowering, so creation input needs the list first.
|
|
374
|
+
const exposedCreates = new Set(program.decls.flatMap((decl) => decl.kind === "expose" && decl.target.endsWith(".create")
|
|
375
|
+
? [decl.target.split(".").slice(0, -1).join("_")]
|
|
376
|
+
: []));
|
|
369
377
|
for (const decl of program.decls) {
|
|
370
378
|
if (decl.kind === "expose" || decl.kind === "hide" || decl.kind === "use")
|
|
371
379
|
continue;
|
|
@@ -710,6 +718,21 @@ export function compile(source, options = {}) {
|
|
|
710
718
|
(!!attachmentInfo &&
|
|
711
719
|
subjectPartyRoles.includes(name));
|
|
712
720
|
const resolvedParties = new Set();
|
|
721
|
+
// A party of a sibling attachment this one references, such as the
|
|
722
|
+
// borrower of `self.plan`, binds here the way it binds there.
|
|
723
|
+
const reachedParty = (name) => {
|
|
724
|
+
if (!attachmentInfo)
|
|
725
|
+
return;
|
|
726
|
+
const targets = fields.flatMap((field) => field.type === "ref" && field.targetKind === "instrument"
|
|
727
|
+
? [field.target].flat()
|
|
728
|
+
: []);
|
|
729
|
+
const bindings = attachmentInfo.attachments.flatMap((attachment) => targets.some((target) => target === attachment.instrument ||
|
|
730
|
+
target.startsWith(`${attachment.instrument}_`)) && attachment.parties[name]
|
|
731
|
+
? [attachment.parties[name]]
|
|
732
|
+
: []);
|
|
733
|
+
const distinct = new Set(bindings.map((item) => JSON.stringify(item)));
|
|
734
|
+
return distinct.size === 1 ? bindings[0] : undefined;
|
|
735
|
+
};
|
|
713
736
|
const resolve = (expr, seen = new Set(), partyBinding = false) => {
|
|
714
737
|
if (expr.kind === "call" &&
|
|
715
738
|
["object", "all", "party"].includes(expr.name)) {
|
|
@@ -739,6 +762,15 @@ export function compile(source, options = {}) {
|
|
|
739
762
|
const local = (name) => attachmentSubjects.has(name)
|
|
740
763
|
? name.slice(attachmentInfo.subjectKindId.length + 1)
|
|
741
764
|
: `${name} (program)`;
|
|
765
|
+
const elsewhere = [...assignments.values()]
|
|
766
|
+
.filter((assignment) => assignment.target === type &&
|
|
767
|
+
attachmentSubjects.has(assignment.name) &&
|
|
768
|
+
attachmentSubjects.get(assignment.name) !==
|
|
769
|
+
attachmentInfo.subjectKindId)
|
|
770
|
+
.map((assignment) => {
|
|
771
|
+
const subject = attachmentSubjects.get(assignment.name);
|
|
772
|
+
return `\`${subject}.${assignment.name.slice(subject.length + 1)}\``;
|
|
773
|
+
});
|
|
742
774
|
const target = templates.get(type);
|
|
743
775
|
const required = target?.parameters
|
|
744
776
|
.filter((p) => p.value.kind !== "default" &&
|
|
@@ -748,7 +780,7 @@ export function compile(source, options = {}) {
|
|
|
748
780
|
? `No \`${type}\` attachment exists on \`${attachmentInfo.subjectKindId}\`.`
|
|
749
781
|
: `Several \`${type}\` attachments match on \`${attachmentInfo.subjectKindId}\`: ${matches.map(local).join(", ")}.`}`, matches.length
|
|
750
782
|
? `Bind \`${parameter}\` explicitly to one of: ${matches.map(local).join(", ")}.`
|
|
751
|
-
: `
|
|
783
|
+
: `Attach \`${type}\` to \`${attachmentInfo.subjectKindId}\` and bind \`${parameter}\` to that attachment's name. Choose ${required.map((name) => (name.startsWith("per_") ? `its ${name.slice(4).replaceAll("_", " ")} limit` : `\`${name}\``)).join(", ") || "its required bindings"} explicitly.${elsewhere.length ? ` ${elsewhere.join(", ")} ${elsewhere.length === 1 ? "is" : "are"} on another object, which this binding cannot reach.` : ""}`);
|
|
752
784
|
}
|
|
753
785
|
if (expr.name !== "all" && matches.length !== 1)
|
|
754
786
|
failWithCode(expr, partyBinding ? "subject_party_unbound" : "HSX1001", `${id} needs ${expr.name === "all" ? "at least one" : "exactly one"} ${type}`, "declare the required object or supply this tunable explicitly");
|
|
@@ -1059,6 +1091,19 @@ export function compile(source, options = {}) {
|
|
|
1059
1091
|
value: `${id}_${key}`,
|
|
1060
1092
|
span: origin,
|
|
1061
1093
|
});
|
|
1094
|
+
// A subject role only has money here when this attachment binds it.
|
|
1095
|
+
const moneyPath = (expr) => {
|
|
1096
|
+
const lowered = path(expr);
|
|
1097
|
+
const role = lowered.slice("party.".length);
|
|
1098
|
+
if (attachmentInfo &&
|
|
1099
|
+
lowered.startsWith("party.") &&
|
|
1100
|
+
subjectPartyRoles.includes(role) &&
|
|
1101
|
+
!Object.values(attachmentInfo.parties).some((binding) => "role" in binding && binding.role === role))
|
|
1102
|
+
failWithCode(expr, "subject_party_unbound", `\`${role}\` has no money account in \`${decl.name}\``, role === "operator"
|
|
1103
|
+
? "Use `programOperator` for the company's own account."
|
|
1104
|
+
: `Add a party parameter to \`${decl.name}\` and bind it to \`${role}\` where you attach it.`);
|
|
1105
|
+
return lowered;
|
|
1106
|
+
};
|
|
1062
1107
|
const fields = [];
|
|
1063
1108
|
const calculations = [];
|
|
1064
1109
|
let currentAction;
|
|
@@ -1780,9 +1825,17 @@ export function compile(source, options = {}) {
|
|
|
1780
1825
|
"pass_through",
|
|
1781
1826
|
].includes(purposeName))
|
|
1782
1827
|
fail(purpose, `unknown economic purpose ${purposeName}`, "choose a declared economic purpose");
|
|
1783
|
-
|
|
1828
|
+
let sourcePartyName = sourceParty
|
|
1784
1829
|
? String(data(sourceParty))
|
|
1785
1830
|
: undefined;
|
|
1831
|
+
const reached = sourcePartyName && !isParty(sourcePartyName)
|
|
1832
|
+
? reachedParty(sourcePartyName)
|
|
1833
|
+
: undefined;
|
|
1834
|
+
if (reached) {
|
|
1835
|
+
attachmentInfo.parties[sourcePartyName] = reached;
|
|
1836
|
+
sourcePartyName =
|
|
1837
|
+
"role" in reached ? reached.role : reached.party;
|
|
1838
|
+
}
|
|
1786
1839
|
if (sourcePartyName && !isParty(sourcePartyName))
|
|
1787
1840
|
fail(sourceParty, `unknown source party ${sourcePartyName}`, "bind an authored party");
|
|
1788
1841
|
return economicsParts
|
|
@@ -1869,7 +1922,7 @@ export function compile(source, options = {}) {
|
|
|
1869
1922
|
operation: "internal_transfer.create",
|
|
1870
1923
|
...(economics ? { economics } : {}),
|
|
1871
1924
|
amount: piece,
|
|
1872
|
-
from:
|
|
1925
|
+
from: moneyPath(from),
|
|
1873
1926
|
to: `party.${recipient.value}`,
|
|
1874
1927
|
});
|
|
1875
1928
|
}
|
|
@@ -1889,8 +1942,8 @@ export function compile(source, options = {}) {
|
|
|
1889
1942
|
? { capture: String(data(parts.get("capture"))) }
|
|
1890
1943
|
: {}),
|
|
1891
1944
|
amount: val(amount),
|
|
1892
|
-
from:
|
|
1893
|
-
to:
|
|
1945
|
+
from: moneyPath(from),
|
|
1946
|
+
to: moneyPath(to),
|
|
1894
1947
|
};
|
|
1895
1948
|
const fee = parts.get("fee");
|
|
1896
1949
|
if (!fee)
|
|
@@ -1974,6 +2027,14 @@ export function compile(source, options = {}) {
|
|
|
1974
2027
|
})
|
|
1975
2028
|
: undefined;
|
|
1976
2029
|
const charges = vat ? [charge, vat] : [charge];
|
|
2030
|
+
// A payer's limit reads this: a buyer pays the charges on
|
|
2031
|
+
// top, a seller pays them out of the amount.
|
|
2032
|
+
derived("debit", "Payer debit", {
|
|
2033
|
+
op: "sum",
|
|
2034
|
+
values: paidBy === "buyer"
|
|
2035
|
+
? [transfer.amount, ...charges]
|
|
2036
|
+
: [transfer.amount],
|
|
2037
|
+
});
|
|
1977
2038
|
const net = paidBy === "seller"
|
|
1978
2039
|
? derived("net", "Amount after fee", {
|
|
1979
2040
|
op: "subtract",
|
|
@@ -2040,7 +2101,7 @@ export function compile(source, options = {}) {
|
|
|
2040
2101
|
}
|
|
2041
2102
|
if (actionFeeCalculations.length)
|
|
2042
2103
|
a.calculate = [...(a.calculate ?? []), ...actionFeeCalculations];
|
|
2043
|
-
if (attachmentInfo
|
|
2104
|
+
if (attachmentInfo) {
|
|
2044
2105
|
if (attachmentInfo.exposed.has(name)) {
|
|
2045
2106
|
if (automatic(a.actor))
|
|
2046
2107
|
fail(row, `${name} runs on the clock or its parent, not a caller`, "expose only caller actions");
|
|
@@ -2094,6 +2155,26 @@ export function compile(source, options = {}) {
|
|
|
2094
2155
|
message: `${id}.${name}.subject.${requirement.field.name}`,
|
|
2095
2156
|
});
|
|
2096
2157
|
}
|
|
2158
|
+
// A parent list may name a list parameter such as `[parent, on]`.
|
|
2159
|
+
if (typeof a.actor === "object" &&
|
|
2160
|
+
"parent" in a.actor &&
|
|
2161
|
+
Array.isArray(a.actor.parent))
|
|
2162
|
+
a.actor.parent = a.actor.parent.flat();
|
|
2163
|
+
// A parent actor over an empty all() names no instrument that could
|
|
2164
|
+
// invoke the action. A std action then does not exist in this program;
|
|
2165
|
+
// in user code the all() is a mistake.
|
|
2166
|
+
if (typeof a.actor === "object" &&
|
|
2167
|
+
"parent" in a.actor &&
|
|
2168
|
+
Array.isArray(a.actor.parent) &&
|
|
2169
|
+
!a.actor.parent.length) {
|
|
2170
|
+
if ((declarationSources.get(decl) ?? "program") === "program") {
|
|
2171
|
+
const parent = entries(asBlock(slots.get("actor"))).get("parent");
|
|
2172
|
+
fail(parent ?? row, `${parent?.kind === "call" ? `${parent.name}(${text(parent.args[0])})` : `the parent actor of ${name}`} matches no instrument`, "name an instrument this program declares or attaches");
|
|
2173
|
+
}
|
|
2174
|
+
delete lifecycle.transitions[name];
|
|
2175
|
+
trimmed.add(id);
|
|
2176
|
+
continue;
|
|
2177
|
+
}
|
|
2097
2178
|
inst.actions[name] = a;
|
|
2098
2179
|
inst.actionOrder.push(name);
|
|
2099
2180
|
}
|
|
@@ -2304,8 +2385,7 @@ export function compile(source, options = {}) {
|
|
|
2304
2385
|
const attachedInst = document.instruments.find((i) => i.id === instId);
|
|
2305
2386
|
for (const createdInst of document.instruments
|
|
2306
2387
|
.slice(firstAttachedInstrument)
|
|
2307
|
-
.filter((instrument) => instrument.id === instId ||
|
|
2308
|
-
instrument.actions.create?.publicAction)) {
|
|
2388
|
+
.filter((instrument) => instrument.id === instId || exposedCreates.has(instrument.id))) {
|
|
2309
2389
|
if (!createdInst.actions.create)
|
|
2310
2390
|
continue;
|
|
2311
2391
|
const owned = new Set(createdInst.calculate.map((node) => node.target));
|
|
@@ -2318,8 +2398,14 @@ export function compile(source, options = {}) {
|
|
|
2318
2398
|
}
|
|
2319
2399
|
const create = createdInst.actions.create;
|
|
2320
2400
|
for (const field of createdInst.fields) {
|
|
2401
|
+
// The engine resolves a lone candidate itself; with several (a
|
|
2402
|
+
// plan's slices) the caller names one, as late_charge does.
|
|
2403
|
+
if (field.type === "ref" && field.targetKind === "instrument") {
|
|
2404
|
+
if (!create.input.some((input) => input.name === field.name))
|
|
2405
|
+
create.input.push({ ...field, optional: true });
|
|
2406
|
+
continue;
|
|
2407
|
+
}
|
|
2321
2408
|
if (field.type === "account" ||
|
|
2322
|
-
(field.type === "ref" && field.targetKind === "instrument") ||
|
|
2323
2409
|
(field.type === "list" &&
|
|
2324
2410
|
field.item === "ref" &&
|
|
2325
2411
|
field.targetKind === "instrument") ||
|
|
@@ -2328,18 +2414,22 @@ export function compile(source, options = {}) {
|
|
|
2328
2414
|
owned.has(field.name) ||
|
|
2329
2415
|
create.input.some((input) => input.name === field.name))
|
|
2330
2416
|
continue;
|
|
2331
|
-
create.subject
|
|
2332
|
-
const existing = create.subject.requirements.find((item) => item.field.name === field.name);
|
|
2417
|
+
const existing = create.subject?.requirements.find((item) => item.field.name === field.name);
|
|
2333
2418
|
if (existing) {
|
|
2334
2419
|
if (canonicalJson(existing.field) !== canonicalJson(field))
|
|
2335
2420
|
failWithCode(entry, "subject_field_conflict", `${createdInst.id}.create.subject.${field.name} conflicts with its instrument field`, "use the instrument field's type and constraints");
|
|
2336
2421
|
continue;
|
|
2337
2422
|
}
|
|
2423
|
+
// A creation value belongs to this agreement. Only a rename shares
|
|
2424
|
+
// it as object metadata; a matching authored field name does not,
|
|
2425
|
+
// so two agreements never read each other's amount.
|
|
2338
2426
|
const objectField = renames.get(field.name);
|
|
2339
|
-
|
|
2340
|
-
field
|
|
2341
|
-
|
|
2342
|
-
}
|
|
2427
|
+
if (!objectField) {
|
|
2428
|
+
create.input.push({ ...field });
|
|
2429
|
+
continue;
|
|
2430
|
+
}
|
|
2431
|
+
const requirement = { field, objectField };
|
|
2432
|
+
create.subject ??= { requirements: [], adapters: [] };
|
|
2343
2433
|
create.subject.requirements.push(requirement);
|
|
2344
2434
|
requirementOrigins.set(requirement, {
|
|
2345
2435
|
source: declarationSources.get(template) ?? "program",
|
|
@@ -2353,6 +2443,12 @@ export function compile(source, options = {}) {
|
|
|
2353
2443
|
Object.values(attachedInst.actions).some((action) => action.subject?.requirements.some((requirement) => requirement.field.name === oldName));
|
|
2354
2444
|
if (!found) {
|
|
2355
2445
|
const renameEntry = renameEntries.get(oldName) ?? entry;
|
|
2446
|
+
const record = document.instruments
|
|
2447
|
+
.slice(firstAttachedInstrument)
|
|
2448
|
+
.find((instrument) => instrument.id.startsWith(`${instId}_`) &&
|
|
2449
|
+
instrument.fields.some((field) => field.name === oldName));
|
|
2450
|
+
if (record)
|
|
2451
|
+
failWithCode(renameEntry, "subject_field_unknown", `rename source '${oldName}' belongs to the ${record.id.slice(instId.length + 1)} record of ${targetTemplate}; rename binds only fields of ${targetTemplate} itself`, `remove this rename; supply ${oldName} as input when the record is created, or set it as a tunable where the header offers one`);
|
|
2356
2452
|
const declared = attachedInst
|
|
2357
2453
|
? Object.values(attachedInst.actions).flatMap((action) => action.subject?.requirements.map((requirement) => requirement.field.name) ?? [])
|
|
2358
2454
|
: [];
|
|
@@ -2706,7 +2802,7 @@ export function compile(source, options = {}) {
|
|
|
2706
2802
|
// A family member drops an optional reference field its binding left
|
|
2707
2803
|
// unset (a borrower-funded plan has no `funds`), so it cannot match and
|
|
2708
2804
|
// leaves the selection. The header must still declare the field.
|
|
2709
|
-
const
|
|
2805
|
+
const declaredMembers = (selection) => {
|
|
2710
2806
|
const members = [selection.instrument].flat();
|
|
2711
2807
|
const header = selection.family
|
|
2712
2808
|
? templates.get(`${selection.family.module}.${selection.family.exportPath}`)
|
|
@@ -2716,12 +2812,43 @@ export function compile(source, options = {}) {
|
|
|
2716
2812
|
return members;
|
|
2717
2813
|
return members.filter((id) => resolveField(document, byId.get(id), `self.${selection.reference}`));
|
|
2718
2814
|
};
|
|
2719
|
-
// A
|
|
2815
|
+
// A member whose reference points at another attachment of the anchor's
|
|
2816
|
+
// own template (the plan funding another object's escrow) cannot match
|
|
2817
|
+
// either, so each object only selects what can reference it.
|
|
2818
|
+
const kin = (a, b) => {
|
|
2819
|
+
const left = byId.get(a);
|
|
2820
|
+
const right = byId.get(b);
|
|
2821
|
+
return (!!left && !!right && declarations.get(left) === declarations.get(right));
|
|
2822
|
+
};
|
|
2823
|
+
const matchable = (selection, inst, action) => declaredMembers(selection).filter((id) => {
|
|
2824
|
+
const member = byId.get(id);
|
|
2825
|
+
if (!member)
|
|
2826
|
+
return true;
|
|
2827
|
+
const anchor = resolveField(document, inst, selection.anchor, action?.input, action);
|
|
2828
|
+
const reference = resolveField(document, member, `self.${selection.reference}`);
|
|
2829
|
+
if (anchor?.type !== "ref" || reference?.type !== "ref")
|
|
2830
|
+
return true;
|
|
2831
|
+
const targets = [anchor.target].flat();
|
|
2832
|
+
const candidates = [reference.target].flat();
|
|
2833
|
+
return !candidates.every((candidate) => !targets.includes(candidate) &&
|
|
2834
|
+
targets.some((target) => kin(target, candidate)));
|
|
2835
|
+
});
|
|
2836
|
+
// A count over no matchable member is zero, in a requirement or a calculation.
|
|
2720
2837
|
for (const inst of document.instruments)
|
|
2721
|
-
for (const action of Object.values(inst.actions))
|
|
2838
|
+
for (const action of Object.values(inst.actions)) {
|
|
2839
|
+
if (action.calculate)
|
|
2840
|
+
action.calculate = action.calculate.map((calculation) => calculation.op === "aggregate" &&
|
|
2841
|
+
calculation.measure === "count" &&
|
|
2842
|
+
!matchable(calculation.selection, inst, action).length
|
|
2843
|
+
? {
|
|
2844
|
+
target: calculation.target,
|
|
2845
|
+
op: "sum",
|
|
2846
|
+
values: [{ literal: 0 }],
|
|
2847
|
+
}
|
|
2848
|
+
: calculation);
|
|
2722
2849
|
action.requires = action.requires.map((requirement) => requirement.kind === "aggregate" &&
|
|
2723
2850
|
requirement.measure === "count" &&
|
|
2724
|
-
!matchable(requirement.selection).length
|
|
2851
|
+
!matchable(requirement.selection, inst, action).length
|
|
2725
2852
|
? {
|
|
2726
2853
|
kind: "compare",
|
|
2727
2854
|
left: { literal: 0 },
|
|
@@ -2729,10 +2856,12 @@ export function compile(source, options = {}) {
|
|
|
2729
2856
|
right: requirement.value,
|
|
2730
2857
|
}
|
|
2731
2858
|
: requirement);
|
|
2859
|
+
}
|
|
2732
2860
|
const checkSelection = (selection, at, scope) => {
|
|
2861
|
+
walk(selection.overlaps, "overlaps", site(selection, "overlaps", at), scope);
|
|
2733
2862
|
walk(selection.anchor, "anchor", site(selection, "anchor", at), scope);
|
|
2734
2863
|
walk(selection.where, "where", site(selection, "where", at), scope);
|
|
2735
|
-
const members = matchable(selection);
|
|
2864
|
+
const members = matchable(selection, scope.inst, scope.action);
|
|
2736
2865
|
if (members.length &&
|
|
2737
2866
|
members.length < [selection.instrument].flat().length)
|
|
2738
2867
|
selection.instrument = members;
|
|
@@ -2744,6 +2873,9 @@ export function compile(source, options = {}) {
|
|
|
2744
2873
|
member(key, keySite(selection.where, key, at));
|
|
2745
2874
|
member(selection.reference, site(selection, "reference", at));
|
|
2746
2875
|
selection.order?.forEach((key, index) => member(key, site(selection.order, index, at)));
|
|
2876
|
+
if (selection.overlaps)
|
|
2877
|
+
for (const key of ["start", "end"])
|
|
2878
|
+
member(selection.overlaps[key], site(selection.overlaps, key, at));
|
|
2747
2879
|
if (selection.window)
|
|
2748
2880
|
member(selection.window.field, site(selection.window, "field", at));
|
|
2749
2881
|
}
|
|
@@ -2848,7 +2980,7 @@ export function compile(source, options = {}) {
|
|
|
2848
2980
|
(edge.to !== "preserve" &&
|
|
2849
2981
|
!inst.lifecycle.states.includes(edge.to))))
|
|
2850
2982
|
continue;
|
|
2851
|
-
let specialized =
|
|
2983
|
+
let specialized = trimmed.has(inst.id);
|
|
2852
2984
|
for (const [key, action] of Object.entries(inst.actions)) {
|
|
2853
2985
|
const constant = (value) => {
|
|
2854
2986
|
if ("literal" in value)
|
|
@@ -2934,6 +3066,22 @@ export function compile(source, options = {}) {
|
|
|
2934
3066
|
if (Object.values(instrument.actions).filter((action) => action.publicAction === decl.name).length > 1)
|
|
2935
3067
|
fail(decl, `public action ${decl.name} is used more than once on ${parts.join(".")}`, "give each exposed action a distinct public name");
|
|
2936
3068
|
}
|
|
3069
|
+
// A public action on a fresh attachment creates it first with no input
|
|
3070
|
+
// (in the engine executor), so creation that needs input must be public.
|
|
3071
|
+
for (const kind of document.objects)
|
|
3072
|
+
for (const attachment of kind.attachments) {
|
|
3073
|
+
if (attachment.parent)
|
|
3074
|
+
continue;
|
|
3075
|
+
const instrument = byId.get(attachment.instrument);
|
|
3076
|
+
const create = instrument.actions.create;
|
|
3077
|
+
const needed = create?.input.filter((field) => !field.optional) ?? [];
|
|
3078
|
+
const entry = Object.values(instrument.actions).find((action) => action.publicAction);
|
|
3079
|
+
if (!needed.length || create.publicAction || !entry)
|
|
3080
|
+
continue;
|
|
3081
|
+
fail(objects
|
|
3082
|
+
.get(kind.id)
|
|
3083
|
+
.body.entries.find((row) => new RegExp(`^attach\\s+${attachment.name}\\s*=`).test(row.key)) ?? objects.get(kind.id), `${attachment.name} starts from ${entry.publicAction}, but its create needs ${needed.map((field) => field.name).join(", ")} and is not exposed`, `expose create on ${attachment.name} so the caller supplies ${needed.length === 1 ? "it" : "them"}, or rename { ${needed[0].name}: ${needed[0].name} } to read object metadata`);
|
|
3084
|
+
}
|
|
2937
3085
|
for (const kind of document.objects) {
|
|
2938
3086
|
for (const name of kind.entryActions ?? []) {
|
|
2939
3087
|
const eligible = kind.attachments.some((attachment) => {
|
|
@@ -2969,12 +3117,14 @@ export function compile(source, options = {}) {
|
|
|
2969
3117
|
?.find((binding) => binding.defaultState === stranded.state &&
|
|
2970
3118
|
instrument.actions[binding.action]?.moves.some((move) => "amount" in move &&
|
|
2971
3119
|
stranded.accounts.some((account) => move.from === `self.${account}`)));
|
|
3120
|
+
const reaching = stranded.actions.at(-1);
|
|
3121
|
+
const drain = `move ${stranded.accounts.map((account) => `\`self.${account}.balance\``).join(" and ")} out in ${reaching ? `\`${reaching}\`` : "the action that reaches it"}, or add an action from \`${stranded.state}\` that does`;
|
|
2972
3122
|
return diagnostic({
|
|
2973
3123
|
code: i.code,
|
|
2974
3124
|
message: `\`${attachment?.name ?? instrument.id}\` can reach \`${stranded.state}\` with money in ${stranded.accounts.map((account) => `\`${account}\``).join(", ")}, but no action leaves that state and disposes of the balance.`,
|
|
2975
3125
|
fix: binding
|
|
2976
|
-
? `Restore \`${binding.parameter}: ${stranded.state}\`, or
|
|
2977
|
-
:
|
|
3126
|
+
? `Restore \`${binding.parameter}: ${stranded.state}\`, or ${drain}.`
|
|
3127
|
+
: `${drain[0].toUpperCase()}${drain.slice(1)}.`,
|
|
2978
3128
|
span: binding?.span ?? origin?.span ?? program.span,
|
|
2979
3129
|
related: stranded.accounts.map((account) => ({
|
|
2980
3130
|
source: "program",
|