@lotics/cli 0.251.0 → 0.252.0
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 +414 -291
- package/docs/building_an_app.md +6 -1
- package/package.json +1 -1
package/dist/src/cli.js
CHANGED
|
@@ -52,7 +52,7 @@ var __toESM = (mod2, isNodeMode, target) => (target = mod2 != null ? __create(__
|
|
|
52
52
|
var define_LOTICS_KIT_VERSIONS_default;
|
|
53
53
|
var init_define_LOTICS_KIT_VERSIONS = __esm({
|
|
54
54
|
"<define:__LOTICS_KIT_VERSIONS__>"() {
|
|
55
|
-
define_LOTICS_KIT_VERSIONS_default = { runtime: "0.37.
|
|
55
|
+
define_LOTICS_KIT_VERSIONS_default = { runtime: "0.37.1" };
|
|
56
56
|
}
|
|
57
57
|
});
|
|
58
58
|
|
|
@@ -2547,20 +2547,20 @@ var require_compiler = __commonJS({
|
|
|
2547
2547
|
}
|
|
2548
2548
|
Compiler.prototype = {
|
|
2549
2549
|
compiler: Compiler,
|
|
2550
|
-
equals: function equals(
|
|
2550
|
+
equals: function equals(other2) {
|
|
2551
2551
|
var len = this.opcodes.length;
|
|
2552
|
-
if (
|
|
2552
|
+
if (other2.opcodes.length !== len) {
|
|
2553
2553
|
return false;
|
|
2554
2554
|
}
|
|
2555
2555
|
for (var i = 0; i < len; i++) {
|
|
2556
|
-
var opcode = this.opcodes[i], otherOpcode =
|
|
2556
|
+
var opcode = this.opcodes[i], otherOpcode = other2.opcodes[i];
|
|
2557
2557
|
if (opcode.opcode !== otherOpcode.opcode || !argEquals(opcode.args, otherOpcode.args)) {
|
|
2558
2558
|
return false;
|
|
2559
2559
|
}
|
|
2560
2560
|
}
|
|
2561
2561
|
len = this.children.length;
|
|
2562
2562
|
for (var i = 0; i < len; i++) {
|
|
2563
|
-
if (!this.children[i].equals(
|
|
2563
|
+
if (!this.children[i].equals(other2.children[i])) {
|
|
2564
2564
|
return false;
|
|
2565
2565
|
}
|
|
2566
2566
|
}
|
|
@@ -44847,8 +44847,8 @@ var ZodObject = /* @__PURE__ */ $constructor("ZodObject", (inst, def) => {
|
|
|
44847
44847
|
safeExtend(incoming) {
|
|
44848
44848
|
return util_exports.safeExtend(this, incoming);
|
|
44849
44849
|
},
|
|
44850
|
-
merge(
|
|
44851
|
-
return util_exports.merge(this,
|
|
44850
|
+
merge(other2) {
|
|
44851
|
+
return util_exports.merge(this, other2);
|
|
44852
44852
|
},
|
|
44853
44853
|
pick(mask) {
|
|
44854
44854
|
return util_exports.pick(this, mask);
|
|
@@ -51975,6 +51975,13 @@ function generatePrefixedId(prefix) {
|
|
|
51975
51975
|
}
|
|
51976
51976
|
var RECORD_ID_PATTERN = new RegExp(`^rec_[${ID_ALPHABET}]{${ID_LENGTH}}$`);
|
|
51977
51977
|
var FILE_ID_PATTERN = new RegExp(`^fil_[${ID_ALPHABET}]{${ID_LENGTH}}$`);
|
|
51978
|
+
var TABLE_ID_PATTERN = new RegExp(
|
|
51979
|
+
`^tbl_[${ID_ALPHABET}]+$|^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`,
|
|
51980
|
+
"i"
|
|
51981
|
+
);
|
|
51982
|
+
function isTableId(value) {
|
|
51983
|
+
return TABLE_ID_PATTERN.test(value);
|
|
51984
|
+
}
|
|
51978
51985
|
function generateWorkspaceId() {
|
|
51979
51986
|
return generatePrefixedId("wsp");
|
|
51980
51987
|
}
|
|
@@ -52000,6 +52007,10 @@ var FIELD_KEY_PREFIX = "fld_";
|
|
|
52000
52007
|
function generateFieldKey() {
|
|
52001
52008
|
return `${FIELD_KEY_PREFIX}${nanoid4()}`;
|
|
52002
52009
|
}
|
|
52010
|
+
var STORED_KEY_PATTERN = /^[A-Za-z0-9_]+$/;
|
|
52011
|
+
function isStoredKey(value) {
|
|
52012
|
+
return STORED_KEY_PATTERN.test(value);
|
|
52013
|
+
}
|
|
52003
52014
|
function generateOptionKey() {
|
|
52004
52015
|
return `opt_${nanoid4()}`;
|
|
52005
52016
|
}
|
|
@@ -52726,9 +52737,9 @@ function unpairableAdoptedLinks(entities, live) {
|
|
|
52726
52737
|
for (const field2 of entity.fields) {
|
|
52727
52738
|
if (field2.type !== "select_record_link") continue;
|
|
52728
52739
|
if (field2.paired_field_alias === void 0 && field2.sync_both_ways !== true) continue;
|
|
52729
|
-
const
|
|
52730
|
-
if (
|
|
52731
|
-
if (
|
|
52740
|
+
const held2 = live.link(entity.alias, field2.alias);
|
|
52741
|
+
if (held2 === void 0 || held2.paired) continue;
|
|
52742
|
+
if (held2.target_table !== live.table(field2.target_entity)) continue;
|
|
52732
52743
|
found.push({ entity: entity.alias, field: field2.alias });
|
|
52733
52744
|
}
|
|
52734
52745
|
}
|
|
@@ -52829,15 +52840,15 @@ function selectWordRefusals(entityAlias, expression, fieldByEntity, path39) {
|
|
|
52829
52840
|
return parseFieldRefTokens(expression).flatMap((token2) => {
|
|
52830
52841
|
if (contractOptionRef(token2) !== void 0) return [];
|
|
52831
52842
|
const field2 = fieldByEntity.get(entityAlias)?.get(token2);
|
|
52832
|
-
const
|
|
52833
|
-
const spelled =
|
|
52834
|
-
if (
|
|
52843
|
+
const held2 = field2 === void 0 ? void 0 : formulaSelectOptions(entityAlias, field2, fieldByEntity);
|
|
52844
|
+
const spelled = held2?.options.find((option) => words.has(option.label) || words.has(option.alias));
|
|
52845
|
+
if (held2 === void 0 || spelled === void 0) return [];
|
|
52835
52846
|
const word = words.has(spelled.label) ? spelled.label : spelled.alias;
|
|
52836
52847
|
return [
|
|
52837
52848
|
{
|
|
52838
52849
|
severity: "error",
|
|
52839
52850
|
path: path39,
|
|
52840
|
-
message:
|
|
52851
|
+
message: held2.own ? `compares {${token2}} to "${word}", and a select reaches a formula as the KEYS of its options, never their words \u2014 name the option {${token2}:${spelled.alias}}: includes({${token2}}, {${token2}:${spelled.alias}})` : `compares {${token2}} to "${word}", and a looked-up select reaches a formula as the KEYS of its options, never their words \u2014 test it on "${held2.entity}", where the select lives ({field:option} names one there), and look that result up`
|
|
52841
52852
|
}
|
|
52842
52853
|
];
|
|
52843
52854
|
});
|
|
@@ -54151,17 +54162,17 @@ function contactHref(text) {
|
|
|
54151
54162
|
function navigatesSections(drawn) {
|
|
54152
54163
|
return drawn >= 3;
|
|
54153
54164
|
}
|
|
54154
|
-
function offeredTogether(one,
|
|
54155
|
-
const theirs =
|
|
54165
|
+
function offeredTogether(one, other2) {
|
|
54166
|
+
const theirs = other2.when;
|
|
54156
54167
|
if (one.when === void 0 || theirs === void 0) return false;
|
|
54157
|
-
const shared = one.when.flatMap((
|
|
54158
|
-
const match2 = theirs.find((candidate) => candidate.field ===
|
|
54159
|
-
return match2 === void 0 ? [] : [
|
|
54168
|
+
const shared = one.when.flatMap((held2) => {
|
|
54169
|
+
const match2 = theirs.find((candidate) => candidate.field === held2.field);
|
|
54170
|
+
return match2 === void 0 ? [] : [held2.options.some((option) => match2.options.includes(option))];
|
|
54160
54171
|
});
|
|
54161
54172
|
return shared.length > 0 && shared.every(Boolean);
|
|
54162
54173
|
}
|
|
54163
54174
|
function isOutcome(act, acts) {
|
|
54164
|
-
return act.to !== void 0 && acts.some((
|
|
54175
|
+
return act.to !== void 0 && acts.some((other2) => other2.alias !== act.alias && other2.to !== void 0 && other2.of === act.of && offeredTogether(act, other2));
|
|
54165
54176
|
}
|
|
54166
54177
|
function isCorrection(act, acts) {
|
|
54167
54178
|
return act.danger === true && !isOutcome(act, acts);
|
|
@@ -54267,11 +54278,11 @@ function actHome(model, app, act) {
|
|
|
54267
54278
|
const order = field2?.type === "select" ? (field2.options ?? []).map((option) => option.alias) : [];
|
|
54268
54279
|
if (typeof moved !== "string" || !order.includes(moved)) return void 0;
|
|
54269
54280
|
const sections = app.record?.sections ?? [];
|
|
54270
|
-
const
|
|
54271
|
-
const own =
|
|
54281
|
+
const held2 = act.when?.[status];
|
|
54282
|
+
const own = held2 === void 0 ? -1 : sections.findIndex((section) => held2.every((option) => section.at?.includes(option) === true));
|
|
54272
54283
|
const into = sections.findIndex((section) => section.at?.includes(moved) === true);
|
|
54273
54284
|
const earlier = (from, to) => order.indexOf(from) < order.indexOf(to);
|
|
54274
|
-
const forward =
|
|
54285
|
+
const forward = held2 !== void 0 && held2.some((option) => earlier(option, moved));
|
|
54275
54286
|
const passed = (stage) => stage.includes(order[0] ?? "") || actsOver(model, app.entity).some((one) => {
|
|
54276
54287
|
const to = one.set?.[status];
|
|
54277
54288
|
return typeof to === "string" && stage.includes(to) && (one.when?.[status] ?? []).some((from) => earlier(from, to));
|
|
@@ -54378,8 +54389,8 @@ function withEntityLocks(model, app) {
|
|
|
54378
54389
|
const merged = /* @__PURE__ */ new Map();
|
|
54379
54390
|
for (const check2 of [...app.checks ?? [], ...gathered]) {
|
|
54380
54391
|
const key = `${check2.of ?? ""}|${check2.field}`;
|
|
54381
|
-
const
|
|
54382
|
-
merged.set(key,
|
|
54392
|
+
const held2 = merged.get(key);
|
|
54393
|
+
merged.set(key, held2 === void 0 ? check2 : { ...held2, ...unionBlocks(held2.blocks, check2.blocks) });
|
|
54383
54394
|
}
|
|
54384
54395
|
return [...merged.values()];
|
|
54385
54396
|
}
|
|
@@ -54436,8 +54447,8 @@ function historyShape(model, parent) {
|
|
|
54436
54447
|
}
|
|
54437
54448
|
const parentStatus = entityOf(model, parent)?.fields.find((field2) => field2.alias === status.field);
|
|
54438
54449
|
if (statusField.type === "select" && parentStatus?.type === "select") {
|
|
54439
|
-
const
|
|
54440
|
-
const missing = parentStatus.options.filter((option) => !
|
|
54450
|
+
const held2 = new Set(statusField.options.map((option) => option.alias));
|
|
54451
|
+
const missing = parentStatus.options.filter((option) => !held2.has(option.alias)).map((option) => option.alias);
|
|
54441
54452
|
if (missing.length > 0) {
|
|
54442
54453
|
return { refused: `names history "${history.alias}", whose "${statusField.alias}" lacks the options ${missing.join(", ")} \u2014 a history writes the option the status moved to` };
|
|
54443
54454
|
}
|
|
@@ -54606,11 +54617,11 @@ function checkReading(model, reading, at2) {
|
|
|
54606
54617
|
const over = own(reading.over, `${at2}.over`);
|
|
54607
54618
|
if (over !== void 0 && over.type !== "date") findings.push(error51(`${at2}.over`, `"${reading.over}" is a ${over.type} field \u2014 a reading places its rows in time by a stored date`));
|
|
54608
54619
|
}
|
|
54609
|
-
for (const [name,
|
|
54620
|
+
for (const [name, held2] of Object.entries(reading.where ?? {})) {
|
|
54610
54621
|
const path39 = `${at2}.where.${name}`;
|
|
54611
54622
|
const field2 = own(name, path39);
|
|
54612
54623
|
if (field2 === void 0) continue;
|
|
54613
|
-
if (typeof
|
|
54624
|
+
if (typeof held2 === "boolean") {
|
|
54614
54625
|
if (field2.type !== "boolean") findings.push(error51(path39, `"${name}" is a ${field2.type} field \u2014 true or false keeps rows by a yes/no`));
|
|
54615
54626
|
continue;
|
|
54616
54627
|
}
|
|
@@ -54619,7 +54630,7 @@ function checkReading(model, reading, at2) {
|
|
|
54619
54630
|
continue;
|
|
54620
54631
|
}
|
|
54621
54632
|
const declared = new Set(field2.options.map((option) => option.alias));
|
|
54622
|
-
for (const [index, option] of
|
|
54633
|
+
for (const [index, option] of held2.entries()) {
|
|
54623
54634
|
if (!declared.has(option)) findings.push(error51(`${path39}.${index}`, `names "${option}", which is not an option of "${name}"`));
|
|
54624
54635
|
}
|
|
54625
54636
|
}
|
|
@@ -54909,9 +54920,9 @@ function checkInputDefault(model, entity, ask, at2) {
|
|
|
54909
54920
|
})();
|
|
54910
54921
|
return holds ? [] : [error51(at2, `"${name}" is a ${type} field and "${ask.input}" asks a ${ask.type} \u2014 an input starts from a field holding what it states`)];
|
|
54911
54922
|
}
|
|
54912
|
-
function offeredTogether2(one,
|
|
54923
|
+
function offeredTogether2(one, other2) {
|
|
54913
54924
|
return Object.entries(one.when ?? {}).every(([field2, options]) => {
|
|
54914
|
-
const theirs =
|
|
54925
|
+
const theirs = other2.when?.[field2];
|
|
54915
54926
|
return theirs === void 0 || options.some((option) => theirs.includes(option));
|
|
54916
54927
|
});
|
|
54917
54928
|
}
|
|
@@ -54988,7 +54999,7 @@ function templateFields(content) {
|
|
|
54988
54999
|
// ../shared/src/schemas/app_model_resolve_readings.ts
|
|
54989
55000
|
init_define_LOTICS_KIT_VERSIONS();
|
|
54990
55001
|
function whereOf(stated2) {
|
|
54991
|
-
return Object.entries(stated2 ?? {}).map(([field2,
|
|
55002
|
+
return Object.entries(stated2 ?? {}).map(([field2, held2]) => typeof held2 === "boolean" ? { field: field2, value: held2 } : { field: field2, options: held2 });
|
|
54992
55003
|
}
|
|
54993
55004
|
function resolveReading(model, reading, at2) {
|
|
54994
55005
|
if ("list" in reading) {
|
|
@@ -55442,8 +55453,8 @@ function resolveBlock(model, parent, block2, at2) {
|
|
|
55442
55453
|
const where = whenOf(block2.where);
|
|
55443
55454
|
const stating = Array.isArray(stated2) ? stated2 : stated2 === false || !peopleWrite(child) ? [] : defaultCreate(model, child, [link.link]);
|
|
55444
55455
|
if (stated2 === void 0 && stating.length > 0) defaulted.push(`${at2}.create`);
|
|
55445
|
-
const
|
|
55446
|
-
const create2 = stating.length === 0 ? [] : block2.expect === void 0 ? unique([...
|
|
55456
|
+
const held2 = where.map((one) => one.field);
|
|
55457
|
+
const create2 = stating.length === 0 ? [] : block2.expect === void 0 ? unique([...held2, ...stating]) : unique([block2.expect, ...held2, ...stating, ...expectedColumns(model, child, block2.columns ?? [])]);
|
|
55447
55458
|
return {
|
|
55448
55459
|
block: {
|
|
55449
55460
|
kind: "rows",
|
|
@@ -55495,19 +55506,19 @@ function blockHeld(model, entity, blocks) {
|
|
|
55495
55506
|
(block2) => block2.kind === "rows" || block2.kind === "timeline" ? entity.fields.flatMap((field2) => field2.type === "select_record_link" && field2.target_entity === block2.entity && field2.paired_field_alias === block2.via ? [field2.alias] : []) : []
|
|
55496
55507
|
)
|
|
55497
55508
|
);
|
|
55498
|
-
const
|
|
55509
|
+
const held2 = /* @__PURE__ */ new Set([...own, ...links]);
|
|
55499
55510
|
for (let grew = true; grew; ) {
|
|
55500
55511
|
grew = false;
|
|
55501
55512
|
for (const field2 of entity.fields) {
|
|
55502
|
-
if (
|
|
55513
|
+
if (held2.has(field2.alias)) continue;
|
|
55503
55514
|
const reads = field2.type === "rollup" || field2.type === "lookup" ? [field2.source_field_alias] : field2.type === "formula" ? contractFormulaFieldRefs(field2.formula.expression) : [];
|
|
55504
|
-
if (reads.some((alias2) =>
|
|
55505
|
-
|
|
55515
|
+
if (reads.some((alias2) => held2.has(alias2))) {
|
|
55516
|
+
held2.add(field2.alias);
|
|
55506
55517
|
grew = true;
|
|
55507
55518
|
}
|
|
55508
55519
|
}
|
|
55509
55520
|
}
|
|
55510
|
-
return
|
|
55521
|
+
return held2;
|
|
55511
55522
|
}
|
|
55512
55523
|
function printed(model, template) {
|
|
55513
55524
|
const content = model.templates?.find((one) => one.alias === template)?.content;
|
|
@@ -55515,13 +55526,13 @@ function printed(model, template) {
|
|
|
55515
55526
|
}
|
|
55516
55527
|
function actsReadBlocks(model, entity, section, acts) {
|
|
55517
55528
|
if (section.blocks.length === 0) return false;
|
|
55518
|
-
const
|
|
55529
|
+
const held2 = blockHeld(model, entity, section.blocks);
|
|
55519
55530
|
return section.acts.some((alias2) => {
|
|
55520
55531
|
const act = acts.find((one) => one.alias === alias2);
|
|
55521
55532
|
if (act === void 0) return false;
|
|
55522
55533
|
const asked = act.asks.flatMap((ask) => typeof ask === "string" ? [ask] : []);
|
|
55523
55534
|
const reads = [...act.requires, ...act.recommends, ...asked, ...printed(model, act.template)];
|
|
55524
|
-
return reads.some((field2) =>
|
|
55535
|
+
return reads.some((field2) => held2.has(field2)) || !reads.some((field2) => section.fields.includes(field2));
|
|
55525
55536
|
});
|
|
55526
55537
|
}
|
|
55527
55538
|
function resolveAct(model, app, act, checks) {
|
|
@@ -55539,7 +55550,7 @@ function resolveAct(model, app, act, checks) {
|
|
|
55539
55550
|
);
|
|
55540
55551
|
const feeds = (name) => Object.entries(set2).filter(([, value]) => value.kind === "input" && value.name === name).map(([field2]) => field2);
|
|
55541
55552
|
const sharedBy = (field2) => (app.acts ?? []).some(
|
|
55542
|
-
(
|
|
55553
|
+
(other2) => other2 !== act && ((other2.asks ?? []).includes(field2) || Object.entries(other2.set ?? {}).some(([written2, value]) => written2 === field2 && typeof value === "string" && value.startsWith(SET_INPUT)))
|
|
55543
55554
|
);
|
|
55544
55555
|
const asField = new Map(
|
|
55545
55556
|
act.workflow !== void 0 || act.template !== void 0 ? [] : inputs.flatMap((input) => {
|
|
@@ -55937,8 +55948,8 @@ function checkApp(model, app, at2) {
|
|
|
55937
55948
|
}
|
|
55938
55949
|
function hiddenWhenOffered(shown, offered) {
|
|
55939
55950
|
return Object.entries(shown ?? {}).some(([field2, options]) => {
|
|
55940
|
-
const
|
|
55941
|
-
return
|
|
55951
|
+
const held2 = offered?.[field2];
|
|
55952
|
+
return held2 !== void 0 && !held2.some((option) => options.includes(option));
|
|
55942
55953
|
});
|
|
55943
55954
|
}
|
|
55944
55955
|
function misplacedMove(act, title, entry) {
|
|
@@ -56020,11 +56031,11 @@ function checkStagedAct(display, section, act, path39) {
|
|
|
56020
56031
|
}
|
|
56021
56032
|
const field2 = status.field;
|
|
56022
56033
|
if (field2 === void 0) return [];
|
|
56023
|
-
const
|
|
56024
|
-
if (
|
|
56034
|
+
const held2 = act.when?.[field2];
|
|
56035
|
+
if (held2 === void 0) {
|
|
56025
56036
|
return [error51(path39, `"${act.alias}" is offered whatever "${field2}" holds, and "${section.title}" is the work only while it is ${at2.join(" or ")} \u2014 narrow its \`when\` to that, or ${elsewhere}`)];
|
|
56026
56037
|
}
|
|
56027
|
-
const outside =
|
|
56038
|
+
const outside = held2.filter((option) => !at2.includes(option));
|
|
56028
56039
|
return outside.length === 0 ? [] : [error51(path39, `"${act.alias}" is offered while "${field2}" is ${outside.join(" or ")}, when "${section.title}" is not the work \u2014 ${elsewhere}`)];
|
|
56029
56040
|
}
|
|
56030
56041
|
function blockIdentity(block2) {
|
|
@@ -56048,8 +56059,8 @@ function checkWhere(child, block2, at2) {
|
|
|
56048
56059
|
if (field2.required !== true) {
|
|
56049
56060
|
return [error51(path39, `"${name}" is optional on "${child.alias}" \u2014 a row holding none would stand in no block while every unnarrowed total counts it; make it required`)];
|
|
56050
56061
|
}
|
|
56051
|
-
const
|
|
56052
|
-
const stray = options.filter((option) => !
|
|
56062
|
+
const held2 = new Set((field2.options ?? []).map((option) => option.alias));
|
|
56063
|
+
const stray = options.filter((option) => !held2.has(option));
|
|
56053
56064
|
return [
|
|
56054
56065
|
...stray.length === 0 ? [] : [error51(path39, `names ${stray.map((one) => `"${one}"`).join(", ")}, which "${name}" has no option of`)],
|
|
56055
56066
|
...options.length === 1 && (block2.columns ?? []).includes(name) ? [error51(path39, `holds every row at "${options[0] ?? ""}", so its column says one thing on every row \u2014 drop the column`)] : []
|
|
@@ -56866,9 +56877,9 @@ var HISTORY_WORDS = {
|
|
|
56866
56877
|
}
|
|
56867
56878
|
};
|
|
56868
56879
|
function derivedLabelClash(entity, stage, table, backLink, derivesBackLink, tables) {
|
|
56869
|
-
const
|
|
56870
|
-
if (
|
|
56871
|
-
return `derives a table labelled "${table.label}" from the status "${stage.label}", and "${
|
|
56880
|
+
const other2 = tables.get(table.label);
|
|
56881
|
+
if (other2 !== void 0) {
|
|
56882
|
+
return `derives a table labelled "${table.label}" from the status "${stage.label}", and "${other2}" is already labelled so \u2014 rename the status field, which the table is named after`;
|
|
56872
56883
|
}
|
|
56873
56884
|
if (derivesBackLink && entity.fields.some((field2) => field2.label === backLink.label)) {
|
|
56874
56885
|
return `derives a "${backLink.label}" link on "${entity.alias}", which already has a field labelled so \u2014 rename that field, or the status "${stage.label}" the link is named after`;
|
|
@@ -57321,7 +57332,7 @@ function resultSideEffects(result) {
|
|
|
57321
57332
|
|
|
57322
57333
|
// src/version.ts
|
|
57323
57334
|
init_define_LOTICS_KIT_VERSIONS();
|
|
57324
|
-
var VERSION = "0.
|
|
57335
|
+
var VERSION = "0.252.0";
|
|
57325
57336
|
|
|
57326
57337
|
// src/timezone.ts
|
|
57327
57338
|
init_define_LOTICS_KIT_VERSIONS();
|
|
@@ -59180,7 +59191,8 @@ function describeApp(model, app) {
|
|
|
59180
59191
|
});
|
|
59181
59192
|
lines.push(...block("checks", checks));
|
|
59182
59193
|
const menu = app.acts.filter((act) => act.on === "record" && act.of === void 0 && !app.record.sections.some((section) => [...section.entry, ...section.acts].includes(act.alias)));
|
|
59183
|
-
|
|
59194
|
+
const removes = appWritePlan(model, app).get(app.entity)?.remove === true;
|
|
59195
|
+
lines.push(` header \u22EF ${[...menu.map((act) => act.label), ...removes ? ["Delete"] : []].join(", ") || "\u2014"}`);
|
|
59184
59196
|
if (stages !== void 0) {
|
|
59185
59197
|
lines.push(
|
|
59186
59198
|
...block(
|
|
@@ -59819,14 +59831,14 @@ function uniqueDifferences(entity, here, fields) {
|
|
|
59819
59831
|
return found?.how === "id" || found?.how === "label" ? found.live.alias : void 0;
|
|
59820
59832
|
};
|
|
59821
59833
|
const named = (among, tuple2) => tuple2.map((alias2) => among.fields.find((field2) => field2.alias === alias2)?.label ?? alias2).join(" + ");
|
|
59822
|
-
const
|
|
59834
|
+
const held2 = new Set((here.unique ?? []).map(signature));
|
|
59823
59835
|
const stated2 = /* @__PURE__ */ new Set();
|
|
59824
59836
|
const lines = [];
|
|
59825
59837
|
for (const tuple2 of entity.unique ?? []) {
|
|
59826
59838
|
const live = tuple2.flatMap((alias2) => liveAlias(alias2) ?? []);
|
|
59827
59839
|
const whole = live.length === tuple2.length ? signature(live) : void 0;
|
|
59828
59840
|
if (whole !== void 0) stated2.add(whole);
|
|
59829
|
-
if (whole !== void 0 &&
|
|
59841
|
+
if (whole !== void 0 && held2.has(whole)) continue;
|
|
59830
59842
|
lines.push({ side: "create", line: ` ${entity.label}: workspace lacks the unique set ${named(entity, tuple2)}` });
|
|
59831
59843
|
}
|
|
59832
59844
|
for (const tuple2 of here.unique ?? []) {
|
|
@@ -60109,10 +60121,9 @@ function aggregateRows(rows, aggregate) {
|
|
|
60109
60121
|
|
|
60110
60122
|
// ../shared/src/schemas/app_spec.ts
|
|
60111
60123
|
var APP_SPEC_VERSION = 3;
|
|
60112
|
-
var
|
|
60113
|
-
var
|
|
60114
|
-
var
|
|
60115
|
-
var specOptionIdSchema = liveId("opt", "an option");
|
|
60124
|
+
var specTableIdSchema = zod_default.string().refine(isTableId, "a table must be a live table id (`tbl_\u2026`, or an older table's UUID), not a model alias");
|
|
60125
|
+
var specFieldIdSchema = zod_default.string().refine(isStoredKey, "a field must be a live field key, not a label");
|
|
60126
|
+
var specOptionIdSchema = zod_default.string().refine((id) => id.startsWith("opt_") && isStoredKey(id), "an option must be a live `opt_` key, not a model alias");
|
|
60116
60127
|
var specColumnAliasSchema = zod_default.string().min(1);
|
|
60117
60128
|
var specReadSchema = zod_default.object({
|
|
60118
60129
|
query: zod_default.string().min(1),
|
|
@@ -63945,16 +63956,16 @@ function kitCheckouts(given) {
|
|
|
63945
63956
|
const name = fs13.existsSync(own) ? manifestSchema.parse(JSON.parse(fs13.readFileSync(own, "utf-8"))).name : void 0;
|
|
63946
63957
|
if (name !== void 0 && CHECKOUT_PACKAGES.includes(name)) return [given];
|
|
63947
63958
|
const root = path14.join(given, "packages");
|
|
63948
|
-
const
|
|
63959
|
+
const held2 = fs13.existsSync(root) ? fs13.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => path14.join(root, entry.name)).filter((dir) => {
|
|
63949
63960
|
const manifest = path14.join(dir, "package.json");
|
|
63950
63961
|
if (!fs13.existsSync(manifest)) return false;
|
|
63951
63962
|
const named = manifestSchema.parse(JSON.parse(fs13.readFileSync(manifest, "utf-8"))).name;
|
|
63952
63963
|
return named !== void 0 && CHECKOUT_PACKAGES.includes(named);
|
|
63953
63964
|
}) : [];
|
|
63954
|
-
if (
|
|
63965
|
+
if (held2.length === 0) {
|
|
63955
63966
|
fail(`${given} is neither ${CHECKOUT_PACKAGES.join(" nor ")} nor a checkout holding them under packages/ \u2014 name one of those.`);
|
|
63956
63967
|
}
|
|
63957
|
-
return
|
|
63968
|
+
return held2;
|
|
63958
63969
|
}
|
|
63959
63970
|
function npmOutput(args, cwd) {
|
|
63960
63971
|
return new Promise((resolve4, reject) => {
|
|
@@ -63979,19 +63990,19 @@ function proveKitInstall(projectDir, packed) {
|
|
|
63979
63990
|
}
|
|
63980
63991
|
async function packDependencies(kits, kitDir) {
|
|
63981
63992
|
const packed = [];
|
|
63982
|
-
const
|
|
63993
|
+
const held2 = new Set(kits.map((kit) => kit.name));
|
|
63983
63994
|
const queue = [...kits];
|
|
63984
63995
|
for (let kit = queue.shift(); kit !== void 0; kit = queue.shift()) {
|
|
63985
63996
|
const manifest = manifestSchema.parse(JSON.parse(fs13.readFileSync(path14.join(kit.source, "package.json"), "utf-8")));
|
|
63986
63997
|
const wanted2 = Object.entries({ ...manifest.dependencies, ...manifest.peerDependencies }).filter(([name]) => name.startsWith("@lotics/"));
|
|
63987
63998
|
for (const [name, range2] of wanted2) {
|
|
63988
|
-
if (
|
|
63999
|
+
if (held2.has(name)) continue;
|
|
63989
64000
|
const floor2 = range2.replace(/^[\^~]/, "");
|
|
63990
64001
|
const latest = await fetchLatestNpmVersion(name);
|
|
63991
64002
|
if (latest !== null && compareReleases(latest, floor2) >= 0) continue;
|
|
63992
64003
|
const sibling = siblingPackage(kit.source, name);
|
|
63993
64004
|
if (sibling === void 0) continue;
|
|
63994
|
-
|
|
64005
|
+
held2.add(name);
|
|
63995
64006
|
const one = await packCheckout(sibling, kitDir, null);
|
|
63996
64007
|
packed.push(one);
|
|
63997
64008
|
queue.push(one);
|
|
@@ -64012,9 +64023,9 @@ function caretRange(range2) {
|
|
|
64012
64023
|
const floor2 = [Number(match2[1]), Number(match2[2]), Number(match2[3])];
|
|
64013
64024
|
return { line: releaseLine(range2.slice(1)), floor: floor2 };
|
|
64014
64025
|
}
|
|
64015
|
-
function accepts(
|
|
64016
|
-
if (
|
|
64017
|
-
const have = caretRange(
|
|
64026
|
+
function accepts(held2, wanted2) {
|
|
64027
|
+
if (held2 === wanted2) return true;
|
|
64028
|
+
const have = caretRange(held2);
|
|
64018
64029
|
const want = caretRange(wanted2);
|
|
64019
64030
|
if (have === null || want === null || have.line !== want.line) return false;
|
|
64020
64031
|
const differs = have.floor.findIndex((part, at2) => part !== want.floor[at2]);
|
|
@@ -74004,13 +74015,13 @@ function entitiesToBind(model, set2) {
|
|
|
74004
74015
|
const link = rule.default_from?.split(".")[0];
|
|
74005
74016
|
if (link !== void 0) add(linkTarget(entity, model.entities, link)?.alias);
|
|
74006
74017
|
}
|
|
74007
|
-
for (const [
|
|
74008
|
-
const from = model.entities.find((one) => one.alias ===
|
|
74018
|
+
for (const [other2, rules] of Object.entries(model.write_rules ?? {})) {
|
|
74019
|
+
const from = model.entities.find((one) => one.alias === other2);
|
|
74009
74020
|
if (from === void 0) continue;
|
|
74010
74021
|
for (const [alias2, rule] of Object.entries(rules.fields ?? {})) {
|
|
74011
74022
|
const bounds = [rule.min, rule.max].flatMap((bound) => typeof bound === "string" && bound.includes(".") ? [bound.split(".")[0]] : []);
|
|
74012
74023
|
const links = [...bounds, ...rule.same === void 0 ? [] : [alias2]];
|
|
74013
|
-
if (links.some((link) => linkTarget(from, model.entities, link)?.alias === entity.alias)) add(
|
|
74024
|
+
if (links.some((link) => linkTarget(from, model.entities, link)?.alias === entity.alias)) add(other2);
|
|
74014
74025
|
}
|
|
74015
74026
|
}
|
|
74016
74027
|
}
|
|
@@ -74040,7 +74051,7 @@ function bindModel(model, wanted2, live) {
|
|
|
74040
74051
|
const columns = /* @__PURE__ */ new Map();
|
|
74041
74052
|
for (const [alias2, { entity, table }] of found) {
|
|
74042
74053
|
const index = liveIndex(table.fields, { id: (field2) => field2.id, label: (field2) => field2.name });
|
|
74043
|
-
const
|
|
74054
|
+
const held2 = /* @__PURE__ */ new Map();
|
|
74044
74055
|
for (const field2 of entity.fields) {
|
|
74045
74056
|
const key = fieldKeyName(alias2, field2.alias);
|
|
74046
74057
|
const column = bindAlias(live.binding?.entities[alias2]?.fields[field2.alias]?.id, field2.label, index);
|
|
@@ -74060,33 +74071,33 @@ function bindModel(model, wanted2, live) {
|
|
|
74060
74071
|
problems.set(key, `field "${field2.label}" holds ${multi ? "several values" : "one value"} in this workspace and ${multi ? "one" : "several"} in the model`);
|
|
74061
74072
|
continue;
|
|
74062
74073
|
}
|
|
74063
|
-
|
|
74074
|
+
held2.set(field2.alias, { field: field2, live: column.live });
|
|
74064
74075
|
}
|
|
74065
|
-
columns.set(alias2,
|
|
74076
|
+
columns.set(alias2, held2);
|
|
74066
74077
|
}
|
|
74067
74078
|
const optionsOf2 = (entityAlias, fieldAlias2, hops = 0) => {
|
|
74068
|
-
const
|
|
74079
|
+
const held2 = columns.get(entityAlias)?.get(fieldAlias2);
|
|
74069
74080
|
const entity = found.get(entityAlias)?.entity;
|
|
74070
|
-
if (
|
|
74071
|
-
if (
|
|
74072
|
-
const target = linkTarget(entity, model.entities,
|
|
74073
|
-
return target === void 0 ? void 0 : optionsOf2(target.alias,
|
|
74081
|
+
if (held2 === void 0 || entity === void 0 || hops > 8) return void 0;
|
|
74082
|
+
if (held2.field.type === "lookup") {
|
|
74083
|
+
const target = linkTarget(entity, model.entities, held2.field.source_field_alias);
|
|
74084
|
+
return target === void 0 ? void 0 : optionsOf2(target.alias, held2.field.lookup_field_alias, hops + 1);
|
|
74074
74085
|
}
|
|
74075
|
-
if (
|
|
74076
|
-
const index = liveIndex(
|
|
74086
|
+
if (held2.field.type !== "select") return void 0;
|
|
74087
|
+
const index = liveIndex(held2.live.options ?? [], { id: (option) => option.id, label: (option) => option.label });
|
|
74077
74088
|
const recorded = live.binding?.entities[entityAlias]?.fields[fieldAlias2]?.options;
|
|
74078
74089
|
const options = /* @__PURE__ */ new Map();
|
|
74079
|
-
for (const option of
|
|
74090
|
+
for (const option of held2.field.options) {
|
|
74080
74091
|
const bound = bindAlias(recorded?.[option.alias]?.id, option.label, index);
|
|
74081
74092
|
if (bound.how === "id" || bound.how === "label") options.set(option.alias, bound.live.id);
|
|
74082
|
-
else problems.set(`${fieldKeyName(entityAlias, fieldAlias2)}:${option.alias}`, `option "${option.label}" of "${
|
|
74093
|
+
else problems.set(`${fieldKeyName(entityAlias, fieldAlias2)}:${option.alias}`, `option "${option.label}" of "${held2.field.label}" is not in this workspace`);
|
|
74083
74094
|
}
|
|
74084
74095
|
return options;
|
|
74085
74096
|
};
|
|
74086
74097
|
const boundFields = /* @__PURE__ */ new Map();
|
|
74087
|
-
for (const [alias2,
|
|
74098
|
+
for (const [alias2, held2] of columns) {
|
|
74088
74099
|
const fields = /* @__PURE__ */ new Map();
|
|
74089
|
-
for (const [fieldAlias2, { field: field2, live: column }] of
|
|
74100
|
+
for (const [fieldAlias2, { field: field2, live: column }] of held2) {
|
|
74090
74101
|
const options = optionsOf2(alias2, fieldAlias2);
|
|
74091
74102
|
fields.set(fieldAlias2, { alias: fieldAlias2, id: column.id, field: field2, ...options === void 0 ? {} : { options } });
|
|
74092
74103
|
}
|
|
@@ -74258,6 +74269,21 @@ function heldEmpty(field2, value) {
|
|
|
74258
74269
|
function callerValue(field2) {
|
|
74259
74270
|
return field2.field.type === "select_member" && field2.field.multi === true ? `isNull(${CALLER}) ? null : [${CALLER}]` : CALLER;
|
|
74260
74271
|
}
|
|
74272
|
+
function sends(s, field2) {
|
|
74273
|
+
if (!s.carries.has(field2.alias)) return void 0;
|
|
74274
|
+
return s.row === void 0 ? `!isNull(${s.from}.${field2.alias})` : `includes(keys(${s.from}), ${str(field2.alias)})`;
|
|
74275
|
+
}
|
|
74276
|
+
function leftBy(s, field2) {
|
|
74277
|
+
const held2 = s.row === void 0 ? "null" : `${s.row}.data[${str(field2.id)}]`;
|
|
74278
|
+
if (!s.carries.has(field2.alias)) return held2;
|
|
74279
|
+
return s.row === void 0 ? `${s.from}.${field2.alias}` : `(${sends(s, field2)} ? ${s.from}.${field2.alias} : ${held2})`;
|
|
74280
|
+
}
|
|
74281
|
+
function landsOn(s, field2) {
|
|
74282
|
+
return s.inputs.has(field2.alias) ? field2.alias : field2.id;
|
|
74283
|
+
}
|
|
74284
|
+
function other(rows, record2) {
|
|
74285
|
+
return record2 === void 0 ? `first(${rows})` : `first(filter(${rows}, (one) => one.id != ${record2}))`;
|
|
74286
|
+
}
|
|
74261
74287
|
function scopeCell(clause, local) {
|
|
74262
74288
|
const row = (clause.through ?? []).reduce((at2, hop) => `linked(${at2}[${str(hop.id)}])[0]`, `${local}.data`);
|
|
74263
74289
|
return clause.through === void 0 ? `${row}[${str(clause.field.id)}]` : `${row}?.[${str(clause.field.id)}]`;
|
|
@@ -74273,6 +74299,13 @@ function scopePasses(rule, local) {
|
|
|
74273
74299
|
function scopeReadsRow(rule) {
|
|
74274
74300
|
return rule !== void 0 && rule.clauses.some((clause) => clause.kind !== "member_of");
|
|
74275
74301
|
}
|
|
74302
|
+
function held(condition, at2) {
|
|
74303
|
+
const values2 = Array.isArray(condition.value) ? condition.value : [condition.value];
|
|
74304
|
+
if (condition.field.field.type === "select" && condition.field.field.multi === true) {
|
|
74305
|
+
return `(${values2.map((value) => `includes(${at2}, ${JSON.stringify(value)})`).join(" || ")})`;
|
|
74306
|
+
}
|
|
74307
|
+
return `includes(${JSON.stringify(values2)}, ${at2})`;
|
|
74308
|
+
}
|
|
74276
74309
|
function whereCheck(local, condition) {
|
|
74277
74310
|
const at2 = `${local}.data[${str(condition.field.id)}]`;
|
|
74278
74311
|
const value = JSON.stringify(condition.value);
|
|
@@ -74290,9 +74323,9 @@ function whereCheck(local, condition) {
|
|
|
74290
74323
|
case "less_than_or_equal_to":
|
|
74291
74324
|
return `${at2} <= ${value}`;
|
|
74292
74325
|
case "has_any_of":
|
|
74293
|
-
return
|
|
74326
|
+
return held(condition, at2);
|
|
74294
74327
|
case "has_none_of":
|
|
74295
|
-
return
|
|
74328
|
+
return `!${held(condition, at2)}`;
|
|
74296
74329
|
default:
|
|
74297
74330
|
return "false";
|
|
74298
74331
|
}
|
|
@@ -74320,7 +74353,8 @@ function checksOn(checks, cellOf) {
|
|
|
74320
74353
|
return validateBlock(
|
|
74321
74354
|
checks.map((check2) => {
|
|
74322
74355
|
const cell = cellOf(str(check2.field.id));
|
|
74323
|
-
|
|
74356
|
+
const text = `trim(coalesce(${cell}, ""))`;
|
|
74357
|
+
return check2.text ? checkLine(`!isEmpty(${text})`, void 0, text) : checkLine(`${cell} == true`, void 0, str(check2.label));
|
|
74324
74358
|
})
|
|
74325
74359
|
);
|
|
74326
74360
|
}
|
|
@@ -74336,60 +74370,73 @@ function locksGuard(locks, local, words) {
|
|
|
74336
74370
|
];
|
|
74337
74371
|
});
|
|
74338
74372
|
}
|
|
74339
|
-
function valueChecks(fields, words,
|
|
74373
|
+
function valueChecks(fields, words, s) {
|
|
74340
74374
|
return fields.flatMap((one) => {
|
|
74341
74375
|
const name = one.field.alias;
|
|
74342
|
-
const
|
|
74376
|
+
const sent = sends(s, one.field);
|
|
74377
|
+
if (sent === void 0) return [];
|
|
74378
|
+
const value = `${s.from}.${name}`;
|
|
74379
|
+
const given = s.row === void 0 ? sent : `${sent} && !isNull(${value})`;
|
|
74380
|
+
const at2 = landsOn(s, one.field);
|
|
74343
74381
|
return [
|
|
74344
|
-
...one.min?.kind !== "value" ? [] : [checkLine(`${given} && ${
|
|
74345
|
-
...one.max?.kind !== "value" ? [] : [checkLine(`${given} && ${
|
|
74382
|
+
...one.min?.kind !== "value" ? [] : [checkLine(`${given} && ${value} < ${one.min.value}`, at2, str(words.refusals.below(one.label, String(one.min.value))))],
|
|
74383
|
+
...one.max?.kind !== "value" ? [] : [checkLine(`${given} && ${value} > ${one.max.value}`, at2, str(words.refusals.above(one.label, String(one.max.value))))]
|
|
74346
74384
|
];
|
|
74347
74385
|
});
|
|
74348
74386
|
}
|
|
74349
74387
|
function boundsByField(fields) {
|
|
74350
74388
|
return fields.some((one) => [one.min, one.max].some((bound) => bound !== void 0 && bound.kind !== "value"));
|
|
74351
74389
|
}
|
|
74352
|
-
function fieldBoundChecks(fields, words,
|
|
74353
|
-
const sent = (name) => row === void 0 ? `!isNull(${from}.${name})` : `includes(keys(${from}), ${str(name)})`;
|
|
74354
|
-
const now = (field2) => row === void 0 ? `${from}.${field2.alias}` : `(${sent(field2.alias)} ? ${from}.${field2.alias} : ${row}.data[${str(field2.id)}])`;
|
|
74355
|
-
const fetched = /* @__PURE__ */ new Set();
|
|
74390
|
+
function fieldBoundChecks(fields, words, s) {
|
|
74356
74391
|
const lines = [];
|
|
74392
|
+
const bound = /* @__PURE__ */ new Set();
|
|
74393
|
+
const local = (name, value) => {
|
|
74394
|
+
if (!bound.has(name)) {
|
|
74395
|
+
bound.add(name);
|
|
74396
|
+
lines.push(`const ${name} = ${value};`);
|
|
74397
|
+
}
|
|
74398
|
+
return name;
|
|
74399
|
+
};
|
|
74400
|
+
const leftOf = (field2) => local(`${camel(field2.alias)}Left`, leftBy(s, field2));
|
|
74357
74401
|
const checks = [];
|
|
74358
74402
|
for (const one of fields) {
|
|
74359
|
-
for (const [side,
|
|
74360
|
-
if (
|
|
74361
|
-
|
|
74403
|
+
for (const [side, limitBy] of [["min", one.min], ["max", one.max]]) {
|
|
74404
|
+
if (limitBy === void 0 || limitBy.kind === "value") continue;
|
|
74405
|
+
if (limitBy.kind === "field" && s.row === void 0 && !s.carries.has(limitBy.field.alias)) continue;
|
|
74406
|
+
const moved = [sends(s, one.field), sends(s, limitBy.kind === "field" ? limitBy.field : limitBy.link)].filter((sent) => sent !== void 0);
|
|
74407
|
+
if (moved.length === 0) continue;
|
|
74362
74408
|
let limit;
|
|
74363
|
-
|
|
74364
|
-
|
|
74365
|
-
if (row === void 0 && !fields.some((other) => other.field.id === bound.field.id)) continue;
|
|
74366
|
-
limit = now(bound.field);
|
|
74367
|
-
moved = `(${sent(one.field.alias)} || ${sent(bound.field.alias)})`;
|
|
74409
|
+
if (limitBy.kind === "field") {
|
|
74410
|
+
limit = leftOf(limitBy.field);
|
|
74368
74411
|
} else {
|
|
74369
|
-
const
|
|
74370
|
-
if (!
|
|
74371
|
-
|
|
74412
|
+
const linked = `${camel(limitBy.link.alias)}Bound`;
|
|
74413
|
+
if (!bound.has(linked)) {
|
|
74414
|
+
bound.add(linked);
|
|
74415
|
+
const sent = sends(s, limitBy.link);
|
|
74372
74416
|
lines.push(
|
|
74373
|
-
`let ${
|
|
74374
|
-
|
|
74375
|
-
|
|
74376
|
-
|
|
74377
|
-
|
|
74417
|
+
`let ${linked} = ${s.row === void 0 ? "null" : `linked(${s.row}.data[${str(limitBy.link.id)}])[0]`};`,
|
|
74418
|
+
...sent === void 0 ? [] : [
|
|
74419
|
+
`if (${sent} && !isNull(${s.from}.${limitBy.link.alias})) {`,
|
|
74420
|
+
` const ${linked}Row = await get_record({ table_id: ${str(limitBy.table)}, record_id: ${s.from}.${limitBy.link.alias} });`,
|
|
74421
|
+
` ${linked} = ${linked}Row.data;`,
|
|
74422
|
+
`}`
|
|
74423
|
+
]
|
|
74378
74424
|
);
|
|
74379
74425
|
}
|
|
74380
|
-
limit = `
|
|
74381
|
-
moved = `(${sent(one.field.alias)} || ${sent(bound.link.alias)})`;
|
|
74426
|
+
limit = local(`${camel(`${limitBy.link.alias}_${limitBy.field.alias}`)}Limit`, `isNull(${linked}) ? null : ${linked}[${str(limitBy.field.id)}]`);
|
|
74382
74427
|
}
|
|
74428
|
+
const value = leftOf(one.field);
|
|
74383
74429
|
const dated = one.field.field.type === "date";
|
|
74384
74430
|
const fails = side === "min" ? dated ? `isBefore(${value}, ${limit})` : `${value} < ${limit}` : dated ? `isAfter(${value}, ${limit})` : `${value} > ${limit}`;
|
|
74385
|
-
const said = side === "min" ? words.refusals.below(one.label,
|
|
74386
|
-
checks.push(checkLine(`${moved} && !isNull(${value}) && !isNull(${limit}) && ${fails}`, one.field
|
|
74431
|
+
const said = side === "min" ? words.refusals.below(one.label, limitBy.label) : words.refusals.above(one.label, limitBy.label);
|
|
74432
|
+
checks.push(checkLine(`${moved.length === 1 ? moved[0] : `(${moved.join(" || ")})`} && !isNull(${value}) && !isNull(${limit}) && ${fails}`, landsOn(s, one.field), str(said)));
|
|
74387
74433
|
}
|
|
74388
74434
|
}
|
|
74389
74435
|
return [...lines, ...validateBlock(checks)];
|
|
74390
74436
|
}
|
|
74391
|
-
function heldGuards(
|
|
74392
|
-
|
|
74437
|
+
function heldGuards(held2, record2, words, s) {
|
|
74438
|
+
const from = s.from;
|
|
74439
|
+
return held2.flatMap((one, at2) => {
|
|
74393
74440
|
const local = `outside${at2 + 1}`;
|
|
74394
74441
|
const dated = one.child.bounded.field.type === "date";
|
|
74395
74442
|
const operator = one.side === "min" ? dated ? "before" : "less_than" : dated ? "after" : "greater_than";
|
|
@@ -74404,18 +74451,19 @@ function heldGuards(held, record2, words, from = "i") {
|
|
|
74404
74451
|
` });`,
|
|
74405
74452
|
` ${local} = first(${local}Rows.records);`,
|
|
74406
74453
|
`}`,
|
|
74407
|
-
...validateBlock([checkLine(`!isNull(${local})`, one.field
|
|
74454
|
+
...validateBlock([checkLine(`!isNull(${local})`, landsOn(s, one.field), str(words.refusals.strands(one.child.label, one.field.field.label)))])
|
|
74408
74455
|
];
|
|
74409
74456
|
});
|
|
74410
74457
|
}
|
|
74411
|
-
function overlapGuard(overlap, table, words,
|
|
74412
|
-
if (
|
|
74413
|
-
const
|
|
74414
|
-
const now = (field2) => at2 === void 0 ? `${from}.${field2.alias}` : `(${sent(field2)} ? ${from}.${field2.alias} : ${at2.row}.data[${str(field2.id)}])`;
|
|
74458
|
+
function overlapGuard(overlap, table, words, s, record2) {
|
|
74459
|
+
if (s.row === void 0 && ![overlap.from, overlap.to, ...overlap.by].every((field2) => s.carries.has(field2.alias))) return [];
|
|
74460
|
+
const now = (field2) => leftBy(s, field2);
|
|
74415
74461
|
const shared = (field2) => {
|
|
74416
74462
|
const type = field2.field.type;
|
|
74417
74463
|
if (type === "select_record_link") {
|
|
74418
|
-
const
|
|
74464
|
+
const sent2 = sends(s, field2);
|
|
74465
|
+
const own = `[${s.from}.${field2.alias}]`;
|
|
74466
|
+
const ids = sent2 === void 0 ? `${s.row}.data[${str(field2.id)}]` : s.row === void 0 ? own : `(${sent2} ? ${own} : ${s.row}.data[${str(field2.id)}])`;
|
|
74419
74467
|
return `{ node_type: "condition", field_key: ${str(field2.id)}, operator: "has_any_of", value: ${ids} }`;
|
|
74420
74468
|
}
|
|
74421
74469
|
if (type === "select_member" || type === "select") {
|
|
@@ -74428,52 +74476,61 @@ function overlapGuard(overlap, table, words, at2, asked, from = "i") {
|
|
|
74428
74476
|
...overlap.by.map(shared),
|
|
74429
74477
|
`{ node_type: "condition", field_key: ${str(overlap.from.id)}, operator: "on_or_before", value: ${day(overlap.to)} }`,
|
|
74430
74478
|
`{ node_type: "condition", field_key: ${str(overlap.to.id)}, operator: "on_or_after", value: ${day(overlap.from)} }`,
|
|
74431
|
-
...overlap.holds.map((hold) => `{ node_type: "condition", field_key: ${str(hold.field.id)}, operator: "has_any_of", value: [${hold.options.map(str).join(", ")}] }`)
|
|
74432
|
-
...at2 === void 0 ? [] : [`{ node_type: "condition", type: "record_id", operator: "is_none_of", value: [${at2.record}] }`]
|
|
74479
|
+
...overlap.holds.map((hold) => `{ node_type: "condition", field_key: ${str(hold.field.id)}, operator: "has_any_of", value: [${hold.options.map(str).join(", ")}] }`)
|
|
74433
74480
|
];
|
|
74434
|
-
const counted = overlap.holds.filter((hold) =>
|
|
74481
|
+
const counted = overlap.holds.filter((hold) => s.row !== void 0 || s.carries.has(hold.field.alias));
|
|
74435
74482
|
const holds = [`!isNull(${now(overlap.from)})`, `!isNull(${now(overlap.to)})`, ...counted.map((hold) => `includes([${hold.options.map(str).join(", ")}], ${now(hold.field)})`)];
|
|
74436
|
-
const
|
|
74483
|
+
const sent = [overlap.from, overlap.to, ...overlap.by, ...overlap.holds.map((hold) => hold.field)].flatMap((field2) => sends(s, field2) ?? []);
|
|
74484
|
+
if (s.row !== void 0 && sent.length === 0) return [];
|
|
74485
|
+
const moved = s.row === void 0 ? [] : [`(${sent.join(" || ")})`];
|
|
74437
74486
|
const when = [...moved, ...holds].join(" && ");
|
|
74438
74487
|
return [
|
|
74439
74488
|
`let covered = null;`,
|
|
74440
74489
|
`if (${when}) {`,
|
|
74441
74490
|
` const covering = await query_records({`,
|
|
74442
74491
|
` table_id: ${str(table.id)},`,
|
|
74492
|
+
// The row itself, and one other if any holds the span.
|
|
74493
|
+
` limit: ${record2 === void 0 ? 1 : 2},`,
|
|
74443
74494
|
` filters: { node_type: "group", logic: "and", children: [${conditions.join(", ")}] },`,
|
|
74444
74495
|
` });`,
|
|
74445
|
-
` covered =
|
|
74496
|
+
` covered = ${other("covering.records", record2)};`,
|
|
74446
74497
|
`}`,
|
|
74447
|
-
...validateBlock([checkLine(`!isNull(covered)`, overlap.from
|
|
74498
|
+
...validateBlock([checkLine(`!isNull(covered)`, landsOn(s, overlap.from), str(words.refusals.overlaps(overlap.label)))])
|
|
74448
74499
|
];
|
|
74449
74500
|
}
|
|
74450
|
-
function expectGuard(expect, table, words,
|
|
74501
|
+
function expectGuard(expect, table, words, s, record2) {
|
|
74451
74502
|
const { via, key } = expect;
|
|
74452
|
-
if (
|
|
74453
|
-
const
|
|
74454
|
-
|
|
74455
|
-
|
|
74503
|
+
if (s.row === void 0 && !(s.carries.has(via.alias) && s.carries.has(key.alias))) return [];
|
|
74504
|
+
const held2 = (field2) => {
|
|
74505
|
+
const sent2 = sends(s, field2);
|
|
74506
|
+
const own = `[${s.from}.${field2.alias}]`;
|
|
74507
|
+
const stored = field2.field.type === "select_record_link" ? `${s.row}.data[${str(field2.id)}]` : `[${s.row}.data[${str(field2.id)}]]`;
|
|
74508
|
+
return sent2 === void 0 ? stored : s.row === void 0 ? own : `(${sent2} ? ${own} : ${stored})`;
|
|
74509
|
+
};
|
|
74510
|
+
const holds = (field2) => s.row === void 0 ? `!isNull(${s.from}.${field2.alias})` : field2.field.type === "select_record_link" ? `!isEmpty(${held2(field2)})` : `!isNull(first(${held2(field2)}))`;
|
|
74456
74511
|
const local = `${camel(key.alias)}Held`;
|
|
74457
74512
|
const among = expect.among.map(
|
|
74458
|
-
(field2) => `(isNull(first(${
|
|
74513
|
+
(field2) => `(isNull(first(${held2(field2)})) ? { node_type: "condition", field_key: ${str(field2.id)}, operator: "is_empty" } : { node_type: "condition", field_key: ${str(field2.id)}, operator: "has_any_of", value: ${held2(field2)} })`
|
|
74459
74514
|
);
|
|
74460
74515
|
const conditions = [
|
|
74461
|
-
`{ node_type: "condition", field_key: ${str(via.id)}, operator: "has_any_of", value: ${
|
|
74462
|
-
`{ node_type: "condition", field_key: ${str(key.id)}, operator: "has_any_of", value: ${
|
|
74463
|
-
...among
|
|
74464
|
-
...at2 === void 0 ? [] : [`{ node_type: "condition", type: "record_id", operator: "is_none_of", value: [${at2.record}] }`]
|
|
74516
|
+
`{ node_type: "condition", field_key: ${str(via.id)}, operator: "has_any_of", value: ${held2(via)} }`,
|
|
74517
|
+
`{ node_type: "condition", field_key: ${str(key.id)}, operator: "has_any_of", value: ${held2(key)} }`,
|
|
74518
|
+
...among
|
|
74465
74519
|
];
|
|
74466
|
-
const
|
|
74520
|
+
const sent = [via, key, ...expect.among].flatMap((field2) => sends(s, field2) ?? []);
|
|
74521
|
+
if (s.row !== void 0 && sent.length === 0) return [];
|
|
74522
|
+
const when = [...s.row === void 0 ? [] : [`(${sent.join(" || ")})`], holds(via), holds(key)].join(" && ");
|
|
74467
74523
|
return [
|
|
74468
74524
|
`let ${local} = null;`,
|
|
74469
74525
|
`if (${when}) {`,
|
|
74470
74526
|
` const holding = await query_records({`,
|
|
74471
74527
|
` table_id: ${str(table.id)},`,
|
|
74528
|
+
` limit: ${record2 === void 0 ? 1 : 2},`,
|
|
74472
74529
|
` filters: { node_type: "group", logic: "and", children: [${conditions.join(", ")}] },`,
|
|
74473
74530
|
` });`,
|
|
74474
|
-
` ${local} =
|
|
74531
|
+
` ${local} = ${other("holding.records", record2)};`,
|
|
74475
74532
|
`}`,
|
|
74476
|
-
...validateBlock([checkLine(`!isNull(${local})`, key
|
|
74533
|
+
...validateBlock([checkLine(`!isNull(${local})`, landsOn(s, key), str(words.refusals.expected(expect.label, expect.record)))])
|
|
74477
74534
|
];
|
|
74478
74535
|
}
|
|
74479
74536
|
function admitsReadsRow(link) {
|
|
@@ -74491,7 +74548,8 @@ function linkChecks(fields, words, own) {
|
|
|
74491
74548
|
return editedByDelta(one.field.field) ? [`for (const picked of i.${name} ?? []) {`, ...indent([...fetch2("picked"), ...refusal]), `}`] : [`if (!isNull(i.${name})) {`, ...indent([...fetch2(`i.${name}`), ...refusal]), `}`];
|
|
74492
74549
|
});
|
|
74493
74550
|
}
|
|
74494
|
-
function keptGuards(kept, written, words,
|
|
74551
|
+
function keptGuards(kept, written, words, s) {
|
|
74552
|
+
const from = s.from;
|
|
74495
74553
|
const sent = (name) => `includes(keys(${from}), ${str(name)})`;
|
|
74496
74554
|
const writes = new Set(written.map((one) => one.field.alias));
|
|
74497
74555
|
const own = (field2) => writes.has(field2.alias) ? `(${sent(field2.alias)} ? ${from}.${field2.alias} : first(row.data[${str(field2.id)}]))` : `first(row.data[${str(field2.id)}])`;
|
|
@@ -74503,7 +74561,7 @@ function keptGuards(kept, written, words, from) {
|
|
|
74503
74561
|
const passes = link.same.map((pair) => `includes(coalesce(${local}.data[${str(pair.theirs.id)}], []), ${own(pair.own)})`).join(" && ");
|
|
74504
74562
|
const check2 = (id) => [
|
|
74505
74563
|
`const ${local} = await get_record({ table_id: ${str(link.target.id)}, record_id: ${id} });`,
|
|
74506
|
-
...validateBlock([checkLine(`!(${passes})`, moved[0].own
|
|
74564
|
+
...validateBlock([checkLine(`!(${passes})`, landsOn(s, moved[0].own), str(words.refusals.mismatched(link.target.label, moved[0].own.field.label)))])
|
|
74507
74565
|
];
|
|
74508
74566
|
const when = moved.map((pair) => sent(pair.own.alias)).join(" || ");
|
|
74509
74567
|
if (editedByDelta(one.field.field)) {
|
|
@@ -74511,17 +74569,18 @@ function keptGuards(kept, written, words, from) {
|
|
|
74511
74569
|
const keeps2 = writes.has(one.field.alias) ? [`if (!includes(coalesce(i.${removed}, []), kept)) {`, ...indent(check2("kept")), `}`] : check2("kept");
|
|
74512
74570
|
return [`if (${when}) {`, ` for (const kept of coalesce(row.data[${str(one.field.id)}], [])) {`, ...indent(keeps2, " "), ` }`, `}`];
|
|
74513
74571
|
}
|
|
74514
|
-
const
|
|
74572
|
+
const held2 = `${camel(one.field.alias)}Kept`;
|
|
74515
74573
|
const keeps = writes.has(one.field.alias) ? `(${when}) && !${sent(one.field.alias)}` : when;
|
|
74516
|
-
return [`if (${keeps}) {`, ` const ${
|
|
74574
|
+
return [`if (${keeps}) {`, ` const ${held2} = first(row.data[${str(one.field.id)}]);`, ` if (!isNull(${held2})) {`, ...indent(check2(held2), " "), ` }`, `}`];
|
|
74517
74575
|
});
|
|
74518
74576
|
}
|
|
74519
|
-
function strayGuards(strays, record2, words,
|
|
74577
|
+
function strayGuards(strays, record2, words, s) {
|
|
74578
|
+
const from = s.from;
|
|
74520
74579
|
return strays.flatMap((one, at2) => {
|
|
74521
74580
|
const local = `stray${at2 + 1}`;
|
|
74522
74581
|
const sent = `includes(keys(${from}), ${str(one.field.alias)})`;
|
|
74523
74582
|
const pointing = `{ node_type: "condition", field_key: ${str(one.child.link.id)}, operator: "has_any_of", value: [${record2}] }`;
|
|
74524
|
-
const
|
|
74583
|
+
const other2 = `{ node_type: "condition", field_key: ${str(one.child.compared.id)}, operator: "has_none_of", value: [${from}.${one.field.alias}] }`;
|
|
74525
74584
|
const read2 = (when, children) => [
|
|
74526
74585
|
`if (${when}) {`,
|
|
74527
74586
|
` const ${local}Rows = await query_records({`,
|
|
@@ -74534,10 +74593,10 @@ function strayGuards(strays, record2, words, from) {
|
|
|
74534
74593
|
];
|
|
74535
74594
|
return [
|
|
74536
74595
|
`let ${local} = null;`,
|
|
74537
|
-
...read2(`${sent} && !isNull(${from}.${one.field.alias})`, [pointing,
|
|
74596
|
+
...read2(`${sent} && !isNull(${from}.${one.field.alias})`, [pointing, other2]),
|
|
74538
74597
|
// A required field is never emptied, so only an optional one asks for any row at all.
|
|
74539
74598
|
...one.field.field.required === true ? [] : read2(`${sent} && isNull(${from}.${one.field.alias})`, [pointing]),
|
|
74540
|
-
...validateBlock([checkLine(`!isNull(${local})`, one.field
|
|
74599
|
+
...validateBlock([checkLine(`!isNull(${local})`, landsOn(s, one.field), str(words.refusals.mismatched(one.child.label, one.field.field.label)))])
|
|
74541
74600
|
];
|
|
74542
74601
|
});
|
|
74543
74602
|
}
|
|
@@ -74560,7 +74619,7 @@ function appendHistory(history, record2, moved, copies = []) {
|
|
|
74560
74619
|
`});`
|
|
74561
74620
|
];
|
|
74562
74621
|
}
|
|
74563
|
-
function milestoneOrder(stages, touches, left, words) {
|
|
74622
|
+
function milestoneOrder(stages, touches, left, words, landing) {
|
|
74564
74623
|
const applies = (stage) => stage.when.map((gate) => `includes([${gate.options.map(str).join(", ")}], ${left(gate.field)})`);
|
|
74565
74624
|
const dated = (stage) => left(stage.field) === "now()" ? "true" : `!(${heldEmpty(stage.field, left(stage.field))})`;
|
|
74566
74625
|
return validateBlock(
|
|
@@ -74571,10 +74630,11 @@ function milestoneOrder(stages, touches, left, words) {
|
|
|
74571
74630
|
const written = touched.includes("true") ? [] : [touched.length === 1 ? touched[0] ?? "" : `(${touched.join(" || ")})`];
|
|
74572
74631
|
const standing = [...written, dated(stage), ...applies(before)];
|
|
74573
74632
|
return [
|
|
74574
|
-
checkLine([...standing, heldEmpty(before.field, left(before.field))].filter((part) => part !== "true").join(" && "), stage.field
|
|
74633
|
+
checkLine([...standing, heldEmpty(before.field, left(before.field))].filter((part) => part !== "true").join(" && "), landing(stage.field), str(words.refusals.milestoneOrder(stage.label, before.label))),
|
|
74575
74634
|
checkLine(
|
|
74576
|
-
|
|
74577
|
-
stage.field.
|
|
74635
|
+
// No difference where either day is missing, which the tests before it already rule out.
|
|
74636
|
+
[...standing, dated(before), `coalesce(differenceInCalendarDays(${left(stage.field)}, ${left(before.field)}), 0) < 0`].filter((part) => part !== "true").join(" && "),
|
|
74637
|
+
landing(stage.field),
|
|
74578
74638
|
str(words.refusals.milestoneBefore(stage.label, before.label))
|
|
74579
74639
|
)
|
|
74580
74640
|
];
|
|
@@ -74582,12 +74642,17 @@ function milestoneOrder(stages, touches, left, words) {
|
|
|
74582
74642
|
)
|
|
74583
74643
|
);
|
|
74584
74644
|
}
|
|
74585
|
-
function milestoneClears(stages, table, record2,
|
|
74586
|
-
return stages.slice(0, -1).flatMap((stage, at2) =>
|
|
74587
|
-
|
|
74588
|
-
|
|
74589
|
-
|
|
74590
|
-
|
|
74645
|
+
function milestoneClears(stages, table, record2, s) {
|
|
74646
|
+
return stages.slice(0, -1).flatMap((stage, at2) => {
|
|
74647
|
+
const sent = sends(s, stage.field);
|
|
74648
|
+
if (sent === void 0) return [];
|
|
74649
|
+
const later = stages.slice(at2 + 1).map((one) => `${str(one.field.id)}: null`);
|
|
74650
|
+
return [
|
|
74651
|
+
`if (${sent} && isNull(${s.from}.${stage.field.alias})) {`,
|
|
74652
|
+
` await update_records({ table_id: ${str(table)}, record_ids: [${record2}], set: { ${later.join(", ")} } });`,
|
|
74653
|
+
`}`
|
|
74654
|
+
];
|
|
74655
|
+
});
|
|
74591
74656
|
}
|
|
74592
74657
|
function picksGuard(picks, words) {
|
|
74593
74658
|
return picks.flatMap((pick3) => {
|
|
@@ -74618,21 +74683,45 @@ function makeDocument(template, row) {
|
|
|
74618
74683
|
`});`
|
|
74619
74684
|
];
|
|
74620
74685
|
}
|
|
74621
|
-
function done(message2,
|
|
74622
|
-
|
|
74686
|
+
function done(message2, handed = {}) {
|
|
74687
|
+
const keys2 = Object.keys(handed);
|
|
74688
|
+
const data = keys2.length === 0 ? "" : `, data: { ${keys2.map((key) => `${key}: ${handed[key].value}`).join(", ")} }`;
|
|
74689
|
+
return `return({ status: "success", message: ${str(message2)}${data} });`;
|
|
74690
|
+
}
|
|
74691
|
+
function handedOutputs(handed) {
|
|
74692
|
+
return Object.fromEntries(Object.entries(handed).map(([key, one]) => [key, one.output]));
|
|
74623
74693
|
}
|
|
74694
|
+
function handedRow(value, table) {
|
|
74695
|
+
return { value, output: { type: "record_link", table_id: table } };
|
|
74696
|
+
}
|
|
74697
|
+
var HANDED_PAPER = {
|
|
74698
|
+
file_id: { value: "paper.file_id", output: { type: "text" } },
|
|
74699
|
+
url: { value: "paper.url", output: { type: "text" } },
|
|
74700
|
+
filename: { value: "paper.filename", output: { type: "text" } }
|
|
74701
|
+
};
|
|
74624
74702
|
|
|
74625
74703
|
// src/app_body_act.ts
|
|
74626
74704
|
var MOVED_TO = "statusMovedTo";
|
|
74705
|
+
function actSending(plan) {
|
|
74706
|
+
return {
|
|
74707
|
+
from: "leaves",
|
|
74708
|
+
carries: /* @__PURE__ */ new Set([...plan.set.map((one) => one.field.alias), ...plan.asks.filter((one) => !editedByDelta(one.field.field)).map((one) => one.field.alias)]),
|
|
74709
|
+
inputs: /* @__PURE__ */ new Set([
|
|
74710
|
+
...plan.asks.flatMap((one) => editedByDelta(one.field.field) ? [deltaOf(one.field).added, deltaOf(one.field).removed] : [one.field.alias]),
|
|
74711
|
+
...plan.inputs.map((input) => input.name)
|
|
74712
|
+
]),
|
|
74713
|
+
row: "row"
|
|
74714
|
+
};
|
|
74715
|
+
}
|
|
74627
74716
|
function actGates(plan) {
|
|
74628
74717
|
const { words } = plan;
|
|
74629
74718
|
const asked = new Set(plan.asks.map((one) => one.field.alias));
|
|
74630
74719
|
const lacks = (need) => {
|
|
74631
|
-
const
|
|
74632
|
-
if (!asked.has(need.field.alias)) return heldEmpty(need.field,
|
|
74633
|
-
if (!editedByDelta(need.field.field)) return heldEmpty(need.field, `(includes(keys(i), ${str(need.field.alias)}) ? i.${need.field.alias} : ${
|
|
74720
|
+
const held2 = `row.data[${str(need.field.id)}]`;
|
|
74721
|
+
if (!asked.has(need.field.alias)) return heldEmpty(need.field, held2);
|
|
74722
|
+
if (!editedByDelta(need.field.field)) return heldEmpty(need.field, `(includes(keys(i), ${str(need.field.alias)}) ? i.${need.field.alias} : ${held2})`);
|
|
74634
74723
|
const { added, removed } = deltaOf(need.field);
|
|
74635
|
-
return `isEmpty(i.${added}) && size(i.${removed} ?? []) >= size(${
|
|
74724
|
+
return `isEmpty(i.${added}) && size(i.${removed} ?? []) >= size(${held2} ?? [])`;
|
|
74636
74725
|
};
|
|
74637
74726
|
const set2 = new Map(plan.set.map((one) => [one.field.id, one.value]));
|
|
74638
74727
|
return [
|
|
@@ -74655,7 +74744,8 @@ function actGates(plan) {
|
|
|
74655
74744
|
// What the act sets it always writes; what it asks, where the ask is answered.
|
|
74656
74745
|
(field2) => set2.has(field2.id) ? "true" : asked.has(field2.alias) ? `includes(keys(i), ${str(field2.alias)})` : void 0,
|
|
74657
74746
|
(field2) => set2.get(field2.id) ?? (asked.has(field2.alias) ? `(includes(keys(i), ${str(field2.alias)}) ? i.${field2.alias} : row.data[${str(field2.id)}])` : `row.data[${str(field2.id)}]`),
|
|
74658
|
-
words
|
|
74747
|
+
words,
|
|
74748
|
+
(field2) => landsOn(actSending(plan), field2)
|
|
74659
74749
|
)
|
|
74660
74750
|
];
|
|
74661
74751
|
}
|
|
@@ -74674,7 +74764,7 @@ function actWrite(plan, record2) {
|
|
|
74674
74764
|
const name = deltaOf(one.field).removed;
|
|
74675
74765
|
return [
|
|
74676
74766
|
`if (!isEmpty(i.${name})) {`,
|
|
74677
|
-
` await update_records({ table_id: ${str(plan.table.id)}, record_ids: [${record2}], remove_from: { ${str(one.field.id)}: i.${name} } });`,
|
|
74767
|
+
` await update_records({ table_id: ${str(plan.table.id)}, record_ids: [${record2}], remove_from: { ${str(one.field.id)}: i.${name} ?? [] } });`,
|
|
74678
74768
|
`}`
|
|
74679
74769
|
];
|
|
74680
74770
|
});
|
|
@@ -74717,22 +74807,27 @@ function actLeaves(plan) {
|
|
|
74717
74807
|
}
|
|
74718
74808
|
function actRules(plan, record2) {
|
|
74719
74809
|
const { rules, words } = plan;
|
|
74810
|
+
const sending = actSending(plan);
|
|
74720
74811
|
return [
|
|
74721
|
-
...fieldBoundChecks(rules.bounded, words,
|
|
74722
|
-
...heldGuards(rules.held, record2, words,
|
|
74723
|
-
...keptGuards(rules.kept, rules.written, words,
|
|
74724
|
-
...strayGuards(rules.strays, record2, words,
|
|
74725
|
-
...rules.overlap === void 0 ? [] : overlapGuard(rules.overlap, plan.table, words,
|
|
74812
|
+
...fieldBoundChecks(rules.bounded, words, sending),
|
|
74813
|
+
...heldGuards(rules.held, record2, words, sending),
|
|
74814
|
+
...keptGuards(rules.kept, rules.written, words, sending),
|
|
74815
|
+
...strayGuards(rules.strays, record2, words, sending),
|
|
74816
|
+
...rules.overlap === void 0 ? [] : overlapGuard(rules.overlap, plan.table, words, sending, record2)
|
|
74726
74817
|
];
|
|
74727
74818
|
}
|
|
74819
|
+
function inputEmpty(type, value) {
|
|
74820
|
+
if (type === "text" || type === "long_text") return `isEmpty(trim(coalesce(${value}, "")))`;
|
|
74821
|
+
return type === "number" ? `isNull(${value})` : `isEmpty(${value})`;
|
|
74822
|
+
}
|
|
74728
74823
|
function actInputChecks(plan) {
|
|
74729
74824
|
const { words } = plan;
|
|
74730
74825
|
return validateBlock([
|
|
74731
|
-
...plan.inputs.flatMap((input) => input.required ? [checkLine(`
|
|
74826
|
+
...plan.inputs.flatMap((input) => input.required ? [checkLine(inputEmpty(input.type, `i.${input.name}`), input.name, str(words.refusals.required(input.label)))] : []),
|
|
74732
74827
|
...plan.inputs.flatMap(
|
|
74733
74828
|
(input) => input.options === void 0 ? [] : [checkLine(`!isNull(i.${input.name}) && !includes([${input.options.map(str).join(", ")}], i.${input.name})`, input.name, str(words.refusals.choice(input.label)))]
|
|
74734
74829
|
),
|
|
74735
|
-
...actRuled(plan) ? valueChecks(plan.rules.written, words,
|
|
74830
|
+
...actRuled(plan) ? valueChecks(plan.rules.written, words, actSending(plan)) : []
|
|
74736
74831
|
]);
|
|
74737
74832
|
}
|
|
74738
74833
|
function actDocument(plan, record2) {
|
|
@@ -74789,9 +74884,9 @@ function actRegion(plan, authored = false) {
|
|
|
74789
74884
|
];
|
|
74790
74885
|
}
|
|
74791
74886
|
function actSource(plan) {
|
|
74792
|
-
const handed = plan.template === void 0 ?
|
|
74793
|
-
return `${[...actRegion(plan), done(plan.words.done.acted(plan.label), handed)].join("\n")}
|
|
74794
|
-
|
|
74887
|
+
const handed = plan.template === void 0 ? {} : plan.on === "record" ? { record_id: handedRow(`i.${plan.param}`, plan.table.id), ...HANDED_PAPER } : HANDED_PAPER;
|
|
74888
|
+
return { source: `${[...actRegion(plan), done(plan.words.done.acted(plan.label), handed)].join("\n")}
|
|
74889
|
+
`, outputs: handedOutputs(handed) };
|
|
74795
74890
|
}
|
|
74796
74891
|
function exportSource(plan) {
|
|
74797
74892
|
const lines = [
|
|
@@ -74807,10 +74902,10 @@ function exportSource(plan) {
|
|
|
74807
74902
|
]),
|
|
74808
74903
|
`}`,
|
|
74809
74904
|
...makeDocument(plan.template, "row"),
|
|
74810
|
-
done(plan.words.done.made(plan.template.label),
|
|
74905
|
+
done(plan.words.done.made(plan.template.label), HANDED_PAPER)
|
|
74811
74906
|
];
|
|
74812
|
-
return `${lines.join("\n")}
|
|
74813
|
-
|
|
74907
|
+
return { source: `${lines.join("\n")}
|
|
74908
|
+
`, outputs: handedOutputs(HANDED_PAPER) };
|
|
74814
74909
|
}
|
|
74815
74910
|
var GUARDS_START = "// <lotics:guards> Generated from the model by `lotics app regenerate` \u2014 edits between these lines are replaced.";
|
|
74816
74911
|
var GUARDS_END = "// </lotics:guards> Your code follows.";
|
|
@@ -74845,13 +74940,19 @@ function createValue(field2) {
|
|
|
74845
74940
|
}
|
|
74846
74941
|
function createSource(plan) {
|
|
74847
74942
|
const { words } = plan;
|
|
74943
|
+
const handedFields = [...plan.fields.map((one) => one.field), ...plan.parent === void 0 ? [] : [plan.parent.field]];
|
|
74944
|
+
const sending = {
|
|
74945
|
+
from: "i",
|
|
74946
|
+
carries: new Set(handedFields.filter((field2) => !editedByDelta(field2.field)).map((field2) => field2.alias)),
|
|
74947
|
+
inputs: new Set(handedFields.map((field2) => editedByDelta(field2.field) ? deltaOf(field2).added : field2.alias))
|
|
74948
|
+
};
|
|
74848
74949
|
const lines = [`const i = trigger.app_workflow.inputs;`];
|
|
74849
74950
|
lines.push(
|
|
74850
74951
|
...validateBlock([
|
|
74851
74952
|
...plan.fields.flatMap(
|
|
74852
74953
|
(one) => one.required ? [checkLine(heldEmpty(one.field, createdInput(one.field)), one.field.alias, str(words.refusals.required(one.label)))] : []
|
|
74853
74954
|
),
|
|
74854
|
-
...valueChecks(plan.fields, words)
|
|
74955
|
+
...valueChecks(plan.fields, words, sending)
|
|
74855
74956
|
])
|
|
74856
74957
|
);
|
|
74857
74958
|
if (plan.parent !== void 0 && (plan.parent.table.scope !== void 0 || plan.parent.checks.length > 0)) {
|
|
@@ -74870,14 +74971,14 @@ function createSource(plan) {
|
|
|
74870
74971
|
plan.milestones,
|
|
74871
74972
|
(field2) => dates(field2) ? "true" : void 0,
|
|
74872
74973
|
(field2) => asked.has(field2.id) ? createdInput(field2) : stamped.get(field2.id) === "now" ? "now()" : createdDefault(field2),
|
|
74873
|
-
words
|
|
74974
|
+
words,
|
|
74975
|
+
(field2) => landsOn(sending, field2)
|
|
74874
74976
|
)
|
|
74875
74977
|
);
|
|
74876
74978
|
}
|
|
74877
|
-
lines.push(...fieldBoundChecks(plan.fields, words,
|
|
74878
|
-
if (plan.overlap !== void 0) lines.push(...overlapGuard(plan.overlap, plan.table, words,
|
|
74879
|
-
const
|
|
74880
|
-
for (const expect of plan.expects) lines.push(...expectGuard(expect, plan.table, words, void 0, handed));
|
|
74979
|
+
lines.push(...fieldBoundChecks(plan.fields, words, sending));
|
|
74980
|
+
if (plan.overlap !== void 0) lines.push(...overlapGuard(plan.overlap, plan.table, words, sending));
|
|
74981
|
+
for (const expect of plan.expects) lines.push(...expectGuard(expect, plan.table, words, sending));
|
|
74881
74982
|
for (const field2 of plan.unique) {
|
|
74882
74983
|
const local = `${camel(field2.alias)}Taken`;
|
|
74883
74984
|
lines.push(
|
|
@@ -74915,7 +75016,7 @@ function createSource(plan) {
|
|
|
74915
75016
|
` },`,
|
|
74916
75017
|
` ],`,
|
|
74917
75018
|
`});`,
|
|
74918
|
-
`opened = made.record_ids[0];`,
|
|
75019
|
+
`const opened = made.record_ids[0];`,
|
|
74919
75020
|
...plan.history === void 0 ? [] : [
|
|
74920
75021
|
`const openedRow = await get_record({ table_id: ${str(plan.table.id)}, record_id: opened });`,
|
|
74921
75022
|
`if (!isNull(openedRow.data[${str(plan.history.source.id)}])) {`,
|
|
@@ -74923,10 +75024,13 @@ function createSource(plan) {
|
|
|
74923
75024
|
`}`
|
|
74924
75025
|
]
|
|
74925
75026
|
];
|
|
75027
|
+
const handing = (row, reused) => ({ record_id: handedRow(row, plan.table.id), reused: { value: String(reused), output: { type: "boolean" } } });
|
|
75028
|
+
const outputs = handedOutputs(handing("opened", false));
|
|
75029
|
+
const returned = done(words.done.opened(plan.table.label), handing("opened", false));
|
|
74926
75030
|
if (plan.naturalKey.length === 0) {
|
|
74927
|
-
lines.push(
|
|
74928
|
-
return `${lines.join("\n")}
|
|
74929
|
-
|
|
75031
|
+
lines.push(...opening, returned);
|
|
75032
|
+
return { source: `${lines.join("\n")}
|
|
75033
|
+
`, outputs };
|
|
74930
75034
|
}
|
|
74931
75035
|
const conditions = plan.naturalKey.map(
|
|
74932
75036
|
(field2) => field2.field.type === "select_record_link" ? `{ node_type: "condition", field_key: ${str(field2.id)}, operator: "has_any_of", value: [i.${field2.alias}] }` : `{ node_type: "condition", field_key: ${str(field2.id)}, operator: "equals", value: ${field2.field.type === "text" ? `trim(coalesce(i.${field2.alias}, ""))` : `i.${field2.alias}`} }`
|
|
@@ -74939,21 +75043,14 @@ function createSource(plan) {
|
|
|
74939
75043
|
`});`,
|
|
74940
75044
|
`const found = first(known.records);`,
|
|
74941
75045
|
...plan.table.scope === void 0 ? [] : validateBlock([checkLine(`!isNull(found) && !(${scopePasses(plan.table.scope, "found")})`, first2?.alias, str(words.refusals.taken(first2?.field.label ?? "")))]),
|
|
74942
|
-
`let opened = null;`,
|
|
74943
|
-
`if (isNull(found)) {`,
|
|
74944
|
-
...indent(opening),
|
|
74945
|
-
`}`,
|
|
74946
75046
|
`if (!isNull(found)) {`,
|
|
74947
|
-
`
|
|
75047
|
+
` ${done(words.done.reused(plan.table.label), handing("found.id", true))}`,
|
|
74948
75048
|
`}`,
|
|
74949
|
-
|
|
74950
|
-
|
|
74951
|
-
` message: isNull(found) ? ${str(words.done.opened(plan.table.label))} : ${str(words.done.reused(plan.table.label))},`,
|
|
74952
|
-
` data: { record_id: opened, reused: !isNull(found) },`,
|
|
74953
|
-
`});`
|
|
75049
|
+
...opening,
|
|
75050
|
+
returned
|
|
74954
75051
|
);
|
|
74955
|
-
return `${lines.join("\n")}
|
|
74956
|
-
|
|
75052
|
+
return { source: `${lines.join("\n")}
|
|
75053
|
+
`, outputs };
|
|
74957
75054
|
}
|
|
74958
75055
|
|
|
74959
75056
|
// src/app_body_update.ts
|
|
@@ -74961,15 +75058,22 @@ init_define_LOTICS_KIT_VERSIONS();
|
|
|
74961
75058
|
function updateSource(plan) {
|
|
74962
75059
|
const { words } = plan;
|
|
74963
75060
|
const record2 = `i.${plan.param}`;
|
|
75061
|
+
const handed = { record_id: handedRow(record2, plan.table.id) };
|
|
74964
75062
|
const sent = (name) => `includes(keys(i), ${str(name)})`;
|
|
75063
|
+
const sending = {
|
|
75064
|
+
from: "i",
|
|
75065
|
+
carries: new Set(plan.fields.filter((one) => !editedByDelta(one.field.field)).map((one) => one.field.alias)),
|
|
75066
|
+
inputs: new Set(plan.fields.flatMap((one) => editedByDelta(one.field.field) ? [deltaOf(one.field).added, deltaOf(one.field).removed] : [one.field.alias])),
|
|
75067
|
+
row: "row"
|
|
75068
|
+
};
|
|
74965
75069
|
const locked = plan.locks.some((lock) => lock.checks.length > 0);
|
|
74966
75070
|
const readsRow = scopeReadsRow(plan.table.scope) || plan.checks.length > 0 || locked || plan.history !== void 0 || boundsByField(plan.bounded) || plan.overlap !== void 0 || plan.expects.length > 0 || plan.milestones.length > 0 || plan.kept.length > 0 || sameReadsRow(plan.fields);
|
|
74967
75071
|
const saved = new Set(plan.fields.map((one) => one.field.id));
|
|
74968
75072
|
const left = (field2) => {
|
|
74969
|
-
const
|
|
75073
|
+
const held2 = leftBy(sending, field2);
|
|
74970
75074
|
const at2 = plan.milestones.findIndex((stage) => stage.field.id === field2.id);
|
|
74971
75075
|
const clears = plan.milestones.slice(0, Math.max(at2, 0)).filter((stage) => saved.has(stage.field.id)).map((stage) => `(${sent(stage.field.alias)} && isNull(i.${stage.field.alias}))`);
|
|
74972
|
-
return clears.length === 0 ?
|
|
75076
|
+
return clears.length === 0 ? held2 : `(${clears.join(" || ")} ? null : ${held2})`;
|
|
74973
75077
|
};
|
|
74974
75078
|
const write = (op, name) => [
|
|
74975
75079
|
`if (${sent(name)}) {`,
|
|
@@ -74994,32 +75098,35 @@ function updateSource(plan) {
|
|
|
74994
75098
|
...plan.fields.flatMap(
|
|
74995
75099
|
(one) => !one.required || editedByDelta(one.field.field) ? [] : [checkLine(`${sent(one.field.alias)} && ${heldEmpty(one.field, `i.${one.field.alias}`)}`, one.field.alias, str(words.refusals.required(one.label)))]
|
|
74996
75100
|
),
|
|
74997
|
-
...valueChecks(plan.fields, words,
|
|
75101
|
+
...valueChecks(plan.fields, words, sending)
|
|
74998
75102
|
]),
|
|
74999
75103
|
...readsRow ? [`const row = await get_record({ table_id: ${str(plan.table.id)}, record_id: ${record2} });`] : [],
|
|
75000
75104
|
...scopeGuard(plan.table, "row", words),
|
|
75001
75105
|
...checksGuard(plan.checks, "row"),
|
|
75002
75106
|
...locksGuard(plan.locks, "row", words),
|
|
75003
|
-
...fieldBoundChecks(plan.bounded, words,
|
|
75004
|
-
...heldGuards(plan.held, record2, words),
|
|
75005
|
-
...plan.overlap === void 0 ? [] : overlapGuard(plan.overlap, plan.table, words,
|
|
75006
|
-
...plan.expects.flatMap((expect) => expectGuard(expect, plan.table, words,
|
|
75107
|
+
...fieldBoundChecks(plan.bounded, words, sending),
|
|
75108
|
+
...heldGuards(plan.held, record2, words, sending),
|
|
75109
|
+
...plan.overlap === void 0 ? [] : overlapGuard(plan.overlap, plan.table, words, sending, record2),
|
|
75110
|
+
...plan.expects.flatMap((expect) => expectGuard(expect, plan.table, words, sending, record2)),
|
|
75007
75111
|
// A `same` link compares with what the row names once the save lands: the value sent, else the one held.
|
|
75008
|
-
...linkChecks(plan.fields, words, (field2) =>
|
|
75009
|
-
|
|
75010
|
-
|
|
75011
|
-
|
|
75112
|
+
...linkChecks(plan.fields, words, (field2) => {
|
|
75113
|
+
const moved = sends(sending, field2);
|
|
75114
|
+
return moved === void 0 ? `first(row.data[${str(field2.id)}])` : `(${moved} ? i.${field2.alias} : first(row.data[${str(field2.id)}]))`;
|
|
75115
|
+
}),
|
|
75116
|
+
...keptGuards(plan.kept, plan.fields, words, sending),
|
|
75117
|
+
...strayGuards(plan.strays, record2, words, sending),
|
|
75118
|
+
...milestoneOrder(plan.milestones, (field2) => saved.has(field2.id) ? sent(field2.alias) : void 0, left, words, (field2) => landsOn(sending, field2)),
|
|
75012
75119
|
...writes,
|
|
75013
|
-
...milestoneClears(plan.milestones, plan.table.id, record2,
|
|
75120
|
+
...milestoneClears(plan.milestones, plan.table.id, record2, sending),
|
|
75014
75121
|
...history === void 0 ? [] : [
|
|
75015
75122
|
`if (${sent(history.source.alias)} && i.${history.source.alias} != row.data[${str(history.source.id)}] && !isNull(i.${history.source.alias})) {`,
|
|
75016
75123
|
...indent(appendHistory(history, record2, `i.${history.source.alias}`)),
|
|
75017
75124
|
`}`
|
|
75018
75125
|
],
|
|
75019
|
-
done(words.done.updated(plan.table.label),
|
|
75126
|
+
done(words.done.updated(plan.table.label), handed)
|
|
75020
75127
|
];
|
|
75021
|
-
return `${lines.join("\n")}
|
|
75022
|
-
|
|
75128
|
+
return { source: `${lines.join("\n")}
|
|
75129
|
+
`, outputs: handedOutputs(handed) };
|
|
75023
75130
|
}
|
|
75024
75131
|
function removeSource(plan) {
|
|
75025
75132
|
const record2 = `i.${plan.param}`;
|
|
@@ -75033,8 +75140,8 @@ function removeSource(plan) {
|
|
|
75033
75140
|
`await delete_records({ table_id: ${str(plan.table.id)}, record_ids: [${record2}] });`,
|
|
75034
75141
|
done(plan.words.done.removed(plan.table.label))
|
|
75035
75142
|
];
|
|
75036
|
-
return `${lines.join("\n")}
|
|
75037
|
-
|
|
75143
|
+
return { source: `${lines.join("\n")}
|
|
75144
|
+
`, outputs: {} };
|
|
75038
75145
|
}
|
|
75039
75146
|
|
|
75040
75147
|
// src/app_compile_context.ts
|
|
@@ -75660,10 +75767,10 @@ function historyCopies(ctx, act, entity, history) {
|
|
|
75660
75767
|
const shape = historyShape(ctx.model, entity);
|
|
75661
75768
|
if (shape === void 0 || "refused" in shape) return [];
|
|
75662
75769
|
const taken = /* @__PURE__ */ new Set([shape.link, shape.status.field, shape.at.field, ...shape.by === void 0 ? [] : [shape.by]]);
|
|
75663
|
-
const
|
|
75770
|
+
const held2 = ctx.bound.entities.get(shape.entity)?.fields;
|
|
75664
75771
|
return act.asks.flatMap((ask) => {
|
|
75665
75772
|
const name = typeof ask === "string" ? ask : ask.input;
|
|
75666
|
-
const into =
|
|
75773
|
+
const into = held2?.get(name);
|
|
75667
75774
|
if (into === void 0 || taken.has(name) || editedByDelta(into.field)) return [];
|
|
75668
75775
|
if (typeof ask !== "string") return [{ into, value: inputInto(into, `i.${name}`) }];
|
|
75669
75776
|
const from = fieldOf2(ctx, entity, name);
|
|
@@ -75730,7 +75837,7 @@ function actPlan(ctx, act) {
|
|
|
75730
75837
|
requires: act.requires.map((name) => ({ field: fieldOf2(ctx, entity, name), label: label2(name) })),
|
|
75731
75838
|
asks,
|
|
75732
75839
|
inputs: act.asks.flatMap(
|
|
75733
|
-
(ask) => typeof ask === "string" ? [] : [{ name: ask.input, label: ask.label, required: ask.required === true, ...ask.options === void 0 ? {} : { options: ask.options.map((option) => option.alias) } }]
|
|
75840
|
+
(ask) => typeof ask === "string" ? [] : [{ name: ask.input, label: ask.label, type: ask.type, required: ask.required === true, ...ask.options === void 0 ? {} : { options: ask.options.map((option) => option.alias) } }]
|
|
75734
75841
|
),
|
|
75735
75842
|
set: Object.entries(act.set).map(([name, value]) => {
|
|
75736
75843
|
const bf = fieldOf2(ctx, entity, name);
|
|
@@ -75784,7 +75891,8 @@ function createInputs(ctx, alias2, writes) {
|
|
|
75784
75891
|
const inputs = {};
|
|
75785
75892
|
if (writes.parent !== void 0) {
|
|
75786
75893
|
const via = fieldOf2(ctx, alias2, writes.parent);
|
|
75787
|
-
|
|
75894
|
+
if (via.field.type !== "select_record_link") fail(`"${alias2}.${via.alias}" files a row under its record, so it must be a link`);
|
|
75895
|
+
inputs[via.alias] = { type: "record_link", table_id: entityOf3(ctx, via.field.target_entity).table, required: true };
|
|
75788
75896
|
}
|
|
75789
75897
|
for (const name of writes.create ?? []) {
|
|
75790
75898
|
const bf = fieldOf2(ctx, alias2, name);
|
|
@@ -76266,9 +76374,9 @@ function compileApp(model, app, bound, tables) {
|
|
|
76266
76374
|
const written = /* @__PURE__ */ new Map();
|
|
76267
76375
|
const deletes = /* @__PURE__ */ new Set();
|
|
76268
76376
|
const wrote = (table, fields) => {
|
|
76269
|
-
const
|
|
76270
|
-
for (const field2 of fields)
|
|
76271
|
-
written.set(table,
|
|
76377
|
+
const held2 = written.get(table) ?? /* @__PURE__ */ new Set();
|
|
76378
|
+
for (const field2 of fields) held2.add(field2.id);
|
|
76379
|
+
written.set(table, held2);
|
|
76272
76380
|
};
|
|
76273
76381
|
const entities = {};
|
|
76274
76382
|
for (const alias2 of drawn.keys()) {
|
|
@@ -76282,8 +76390,9 @@ function compileApp(model, app, bound, tables) {
|
|
|
76282
76390
|
if (writes?.create !== void 0) {
|
|
76283
76391
|
const workflow = createAlias(alias2);
|
|
76284
76392
|
const create = createPlan(ctx, alias2, writes);
|
|
76285
|
-
|
|
76286
|
-
|
|
76393
|
+
const body = createSource(create);
|
|
76394
|
+
bodies[workflow] = body.source;
|
|
76395
|
+
workflows[workflow] = { inputs: createInputs(ctx, alias2, writes), outputs: body.outputs, description: described(words.workflows.create(bent.entity.label), bent.entity) };
|
|
76287
76396
|
wrote(bent.table, [
|
|
76288
76397
|
...create.fields.map((one) => one.field),
|
|
76289
76398
|
...create.parent === void 0 ? [] : [create.parent.field],
|
|
@@ -76301,7 +76410,7 @@ function compileApp(model, app, bound, tables) {
|
|
|
76301
76410
|
const overlap = bodyOverlap(ctx, alias2);
|
|
76302
76411
|
const stages = bodyMilestones(ctx, alias2);
|
|
76303
76412
|
const milestones = touchesMilestones(stages, new Set(fields.map((one) => one.field.alias))) ? stages : [];
|
|
76304
|
-
|
|
76413
|
+
const body = updateSource({
|
|
76305
76414
|
table,
|
|
76306
76415
|
param: RECORD_INPUT,
|
|
76307
76416
|
fields,
|
|
@@ -76317,15 +76426,21 @@ function compileApp(model, app, bound, tables) {
|
|
|
76317
76426
|
milestones,
|
|
76318
76427
|
words
|
|
76319
76428
|
});
|
|
76320
|
-
|
|
76429
|
+
bodies[workflow] = body.source;
|
|
76430
|
+
workflows[workflow] = { inputs: updateInputs(ctx, alias2, fields), outputs: body.outputs, description: described(words.workflows.update(bent.entity.label), bent.entity) };
|
|
76321
76431
|
wrote(bent.table, [...fields.map((one) => one.field), ...milestones.map((stage) => stage.field)]);
|
|
76322
76432
|
if (moves !== void 0) wrote(moves.table, historyFields(moves));
|
|
76323
76433
|
spec2.update = { workflow };
|
|
76324
76434
|
}
|
|
76325
76435
|
if (writes?.remove === true) {
|
|
76326
76436
|
const workflow = removeAlias(alias2);
|
|
76327
|
-
|
|
76328
|
-
|
|
76437
|
+
const body = removeSource({ table, param: RECORD_INPUT, checks: bodyChecks(ctx, "delete", alias2), locks: parentLocks(ctx, alias2), words });
|
|
76438
|
+
bodies[workflow] = body.source;
|
|
76439
|
+
workflows[workflow] = {
|
|
76440
|
+
inputs: { [RECORD_INPUT]: { type: "record_link", table_id: bent.table, required: true } },
|
|
76441
|
+
outputs: body.outputs,
|
|
76442
|
+
description: described(words.workflows.remove(bent.entity.label), bent.entity)
|
|
76443
|
+
};
|
|
76329
76444
|
deletes.add(bent.table);
|
|
76330
76445
|
spec2.remove = { workflow };
|
|
76331
76446
|
}
|
|
@@ -76334,11 +76449,13 @@ function compileApp(model, app, bound, tables) {
|
|
|
76334
76449
|
const acts = app.acts.map((act) => {
|
|
76335
76450
|
const body = actPlan(ctx, act);
|
|
76336
76451
|
const workflow = act.workflow ?? actAlias(act.alias);
|
|
76337
|
-
|
|
76338
|
-
|
|
76452
|
+
const generated = act.workflow === void 0 ? actSource(body) : void 0;
|
|
76453
|
+
if (generated === void 0) authored[workflow] = body;
|
|
76454
|
+
else bodies[workflow] = generated.source;
|
|
76339
76455
|
const on = entityOf3(ctx, actEntity(ctx.app, act)).entity;
|
|
76340
76456
|
workflows[workflow] = {
|
|
76341
76457
|
inputs: actInputs(ctx, act),
|
|
76458
|
+
...generated === void 0 ? {} : { outputs: generated.outputs },
|
|
76342
76459
|
description: described(act.on === "record" ? words.workflows.act(act.label, on.label) : words.workflows.actOnRows(act.label, on.label), on)
|
|
76343
76460
|
};
|
|
76344
76461
|
wrote(body.table.id, [...body.set.map((one) => one.field), ...body.asks.map((one) => one.field), ...body.template?.into === void 0 ? [] : [body.template.into]]);
|
|
@@ -76350,10 +76467,12 @@ function compileApp(model, app, bound, tables) {
|
|
|
76350
76467
|
if (exported !== void 0 && exported !== true) {
|
|
76351
76468
|
const workflow = exportAlias(app.entity);
|
|
76352
76469
|
const body = exportPlan(ctx, exported.template);
|
|
76353
|
-
|
|
76470
|
+
const generated = exportSource(body);
|
|
76471
|
+
bodies[workflow] = generated.source;
|
|
76354
76472
|
const own = entityOf3(ctx, app.entity).entity;
|
|
76355
76473
|
workflows[workflow] = {
|
|
76356
76474
|
inputs: { [RECORDS_INPUT]: { type: "record_link", table_id: body.table.id, multi: true, max: RECORDS_INPUT_MAX, required: true } },
|
|
76475
|
+
outputs: generated.outputs,
|
|
76357
76476
|
description: described(words.workflows.export(body.template.label, own.label), own)
|
|
76358
76477
|
};
|
|
76359
76478
|
exportSpec = { workflow };
|
|
@@ -76512,8 +76631,8 @@ function writesDeclaration(queries, tables, written) {
|
|
|
76512
76631
|
const aliased = codegenAliases(queries, tables);
|
|
76513
76632
|
const out = {};
|
|
76514
76633
|
for (const [table, fields] of written) {
|
|
76515
|
-
const
|
|
76516
|
-
out[
|
|
76634
|
+
const held2 = aliased.find((one) => one.table.id === table);
|
|
76635
|
+
out[held2?.alias ?? table] = [...fields].map((id) => held2?.fields.find((one) => one.field.id === id)?.alias ?? id).sort();
|
|
76517
76636
|
}
|
|
76518
76637
|
return out;
|
|
76519
76638
|
}
|
|
@@ -76593,15 +76712,16 @@ var projectionSchema = zod_default.object({
|
|
|
76593
76712
|
function projectionOf(declaration) {
|
|
76594
76713
|
const read2 = projectionSchema.safeParse(declaration?.ast);
|
|
76595
76714
|
if (!read2.success) return void 0;
|
|
76715
|
+
const columns = read2.data.columns.flatMap((column) => {
|
|
76716
|
+
if (typeof column === "string") return [{ output: column, key: column }];
|
|
76717
|
+
const key = typeof column.source === "string" ? column.source : void 0;
|
|
76718
|
+
const output = column.output ?? key;
|
|
76719
|
+
return output === void 0 ? [] : [{ output, ...key === void 0 ? {} : { key } }];
|
|
76720
|
+
});
|
|
76596
76721
|
return {
|
|
76597
76722
|
table: read2.data.from.table_id,
|
|
76598
|
-
outputs: new Set(
|
|
76599
|
-
|
|
76600
|
-
if (typeof column === "string") return [column];
|
|
76601
|
-
if (column.output !== void 0) return [column.output];
|
|
76602
|
-
return typeof column.source === "string" ? [column.source] : [];
|
|
76603
|
-
})
|
|
76604
|
-
)
|
|
76723
|
+
outputs: new Set(columns.map((column) => column.output)),
|
|
76724
|
+
keys: new Map(columns.flatMap((column) => column.key === void 0 ? [] : [[column.output, column.key]]))
|
|
76605
76725
|
};
|
|
76606
76726
|
}
|
|
76607
76727
|
var paramsOf = (manifest, alias2) => new Set(Object.keys(manifest.queries?.[alias2]?.params ?? {}));
|
|
@@ -76635,6 +76755,8 @@ function checkRead(at2, read2, entity, manifest) {
|
|
|
76635
76755
|
if (projection2.table !== entity.table) findings.push({ at: at2, message: `reads ${entity.label} (${entity.table}) through "${read2.query}", which reads ${projection2.table}` });
|
|
76636
76756
|
for (const field2 of Object.values(entity.fields)) {
|
|
76637
76757
|
if (!projection2.outputs.has(field2.alias)) findings.push({ at: at2, message: `draws "${field2.alias}" (${field2.label}), which "${read2.query}" does not project` });
|
|
76758
|
+
const key = projection2.keys.get(field2.alias);
|
|
76759
|
+
if (key !== void 0 && key !== field2.id) findings.push({ at: at2, message: `reads "${field2.alias}" as field \`${field2.id}\`, and "${read2.query}" projects it from \`${key}\`` });
|
|
76638
76760
|
for (const [linked, column] of Object.entries(field2.face ?? {})) {
|
|
76639
76761
|
if (!projection2.outputs.has(column)) findings.push({ at: at2, message: `draws the "${linked}" of the row "${field2.alias}" names under "${column}", which "${read2.query}" does not project` });
|
|
76640
76762
|
}
|
|
@@ -76861,8 +76983,8 @@ export const components: RuntimeComponents = {};
|
|
|
76861
76983
|
function buildAppFiles(app, compiled, existing) {
|
|
76862
76984
|
const generated = Object.entries(compiled.bodies).map(([alias2, body]) => ({ path: workflowPath(alias2), content: body }));
|
|
76863
76985
|
const authored = Object.entries(compiled.authored).map(([alias2, plan]) => {
|
|
76864
|
-
const
|
|
76865
|
-
return { path: workflowPath(alias2), content: injectGuards(
|
|
76986
|
+
const held2 = existing(workflowPath(alias2));
|
|
76987
|
+
return { path: workflowPath(alias2), content: injectGuards(held2 === null ? null : stripWorkflowHeader(held2), plan) };
|
|
76866
76988
|
});
|
|
76867
76989
|
return [
|
|
76868
76990
|
{ path: APP_SPEC_PATH, content: `${JSON.stringify(compiled.spec, null, 2)}
|
|
@@ -79578,8 +79700,8 @@ function planFilterTraversal(filter2, aggregatedTableId, aggregatedFields, linke
|
|
|
79578
79700
|
}
|
|
79579
79701
|
const fieldMaps = /* @__PURE__ */ new Map();
|
|
79580
79702
|
const fieldMapOf = (tableId2, fields) => {
|
|
79581
|
-
const
|
|
79582
|
-
if (
|
|
79703
|
+
const held2 = fieldMaps.get(tableId2);
|
|
79704
|
+
if (held2) return held2;
|
|
79583
79705
|
const byKey = {};
|
|
79584
79706
|
for (const f of fields) byKey[f.key] = f;
|
|
79585
79707
|
fieldMaps.set(tableId2, byKey);
|
|
@@ -80052,9 +80174,9 @@ function idsOf(cell) {
|
|
|
80052
80174
|
});
|
|
80053
80175
|
}
|
|
80054
80176
|
function heldBy(records, tableId2) {
|
|
80055
|
-
const
|
|
80056
|
-
if (
|
|
80057
|
-
return
|
|
80177
|
+
const held2 = records.get(tableId2);
|
|
80178
|
+
if (held2 === void 0) throw new Error(`this model's tables do not include ${tableId2}`);
|
|
80179
|
+
return held2;
|
|
80058
80180
|
}
|
|
80059
80181
|
function fieldsOf(fieldsByTable, tableId2) {
|
|
80060
80182
|
const fields = fieldsByTable.get(tableId2);
|
|
@@ -80289,9 +80411,9 @@ function pairBack(field2, value, from, byRef, entityByAlias, tableByAlias, field
|
|
|
80289
80411
|
if (typeof ref !== "string") continue;
|
|
80290
80412
|
const linked = byRef.get(ref);
|
|
80291
80413
|
if (linked === void 0) continue;
|
|
80292
|
-
const
|
|
80293
|
-
if (
|
|
80294
|
-
linked.cells.set(partnerKey, [...
|
|
80414
|
+
const held2 = readLinkCell(linked.cells.get(partnerKey));
|
|
80415
|
+
if (held2.some((one) => one.id === from.id)) continue;
|
|
80416
|
+
linked.cells.set(partnerKey, [...held2, { id: from.id, display: "" }]);
|
|
80295
80417
|
}
|
|
80296
80418
|
}
|
|
80297
80419
|
function readLinkCell(cell) {
|
|
@@ -80360,20 +80482,20 @@ function buildDisplays(entities, display, records, tableByAlias, fieldsByTable)
|
|
|
80360
80482
|
heldBy(records, table.id).forEach((record2, r) => cellOf.set(record2.id, { entity, record: record2, r, key: at2 === -1 ? void 0 : fields[at2]?.key, link }));
|
|
80361
80483
|
}
|
|
80362
80484
|
const nameOf2 = (id, seen) => {
|
|
80363
|
-
const
|
|
80364
|
-
if (
|
|
80365
|
-
const stated2 =
|
|
80366
|
-
if (
|
|
80485
|
+
const held2 = cellOf.get(id);
|
|
80486
|
+
if (held2 === void 0 || seen.has(id)) return void 0;
|
|
80487
|
+
const stated2 = held2.key === void 0 ? void 0 : held2.record.cells.get(held2.key);
|
|
80488
|
+
if (held2.link) {
|
|
80367
80489
|
const through = readLinkCell(stated2)[0];
|
|
80368
80490
|
const name = through === void 0 ? void 0 : nameOf2(through.id, /* @__PURE__ */ new Set([...seen, id]));
|
|
80369
80491
|
if (name !== void 0) return name;
|
|
80370
80492
|
} else if (typeof stated2 === "string" && stated2 !== "") return stated2;
|
|
80371
|
-
return `${
|
|
80493
|
+
return `${held2.entity.singular ?? held2.entity.label} ${held2.r + 1}`;
|
|
80372
80494
|
};
|
|
80373
80495
|
return new Map([...cellOf.keys()].map((id) => [id, nameOf2(id, /* @__PURE__ */ new Set()) ?? id]));
|
|
80374
80496
|
}
|
|
80375
80497
|
function fillLinkDisplays(records, displays, fieldsByTable) {
|
|
80376
|
-
for (const [tableId2,
|
|
80498
|
+
for (const [tableId2, held2] of records) {
|
|
80377
80499
|
const linking = new Set(
|
|
80378
80500
|
(fieldsByTable.get(tableId2) ?? []).filter((field2) => field2.type === "select_record_link" || field2.type === "lookup" && field2.lookup_field_type === "select_record_link").map((field2) => field2.key)
|
|
80379
80501
|
);
|
|
@@ -80382,14 +80504,14 @@ function fillLinkDisplays(records, displays, fieldsByTable) {
|
|
|
80382
80504
|
const links = readLinkCell(cell);
|
|
80383
80505
|
return links.length === 0 ? cell : links.map((link) => ({ id: link.id, display: displays.get(link.id) ?? link.id }));
|
|
80384
80506
|
};
|
|
80385
|
-
for (const record2 of
|
|
80507
|
+
for (const record2 of held2) {
|
|
80386
80508
|
for (const [key, cell] of record2.cells) {
|
|
80387
80509
|
if (linking.has(key)) record2.cells.set(key, named(cell));
|
|
80388
80510
|
}
|
|
80389
80511
|
}
|
|
80390
80512
|
}
|
|
80391
80513
|
}
|
|
80392
|
-
function narrowings(filter2,
|
|
80514
|
+
function narrowings(filter2, held2) {
|
|
80393
80515
|
const found = {};
|
|
80394
80516
|
const visit2 = (node) => {
|
|
80395
80517
|
if (node === null || typeof node !== "object") return;
|
|
@@ -80405,12 +80527,12 @@ function narrowings(filter2, held) {
|
|
|
80405
80527
|
const operator = Reflect.get(node, "operator");
|
|
80406
80528
|
const days = (side) => {
|
|
80407
80529
|
if (typeof fieldKey !== "string") return void 0;
|
|
80408
|
-
return { side, day: Object.fromEntries(
|
|
80530
|
+
return { side, day: Object.fromEntries(held2.flatMap((record2) => {
|
|
80409
80531
|
const day = dayOf2(record2.cells.get(fieldKey));
|
|
80410
80532
|
return day === null ? [] : [[record2.id, day]];
|
|
80411
80533
|
})) };
|
|
80412
80534
|
};
|
|
80413
|
-
const by = type === "record_id" ? { own: operator === "is_none_of" ? "not" : "is" } : operator === "on_or_after" ? days("from") : operator === "on_or_before" ? days("to") : typeof fieldKey === "string" ? { holds: Object.fromEntries(
|
|
80535
|
+
const by = type === "record_id" ? { own: operator === "is_none_of" ? "not" : "is" } : operator === "on_or_after" ? days("from") : operator === "on_or_before" ? days("to") : typeof fieldKey === "string" ? { holds: Object.fromEntries(held2.map((record2) => [record2.id, idsOf(record2.cells.get(fieldKey))])) } : void 0;
|
|
80414
80536
|
if (by === void 0) return;
|
|
80415
80537
|
for (const token2 of tokens) found[token2] = [...found[token2] ?? [], by];
|
|
80416
80538
|
};
|
|
@@ -80448,12 +80570,12 @@ function census(entities, tableByAlias, records, fieldsByTable) {
|
|
|
80448
80570
|
for (const entity of entities) {
|
|
80449
80571
|
const table = tableByAlias.get(entity.alias);
|
|
80450
80572
|
if (table === void 0) continue;
|
|
80451
|
-
const
|
|
80452
|
-
if (
|
|
80573
|
+
const held2 = heldBy(records, table.id);
|
|
80574
|
+
if (held2.length === 0) continue;
|
|
80453
80575
|
const fields = fieldsOf(fieldsByTable, table.id);
|
|
80454
80576
|
entity.fields.forEach((field2, f) => {
|
|
80455
80577
|
if (!COMPUTED.has(field2.type)) return;
|
|
80456
|
-
const cells =
|
|
80578
|
+
const cells = held2.map((record2) => record2.cells.get(fields[f].key));
|
|
80457
80579
|
const named = `${entity.alias}.${field2.alias} (${field2.type})`;
|
|
80458
80580
|
if (cells.some(holdsFormulaError)) errored.push(named);
|
|
80459
80581
|
else if (cells.every(isEmptyFieldValue)) unfilled.push(named);
|
|
@@ -80522,10 +80644,10 @@ function computeDerived(order, tableByAlias, records, fieldsByTable) {
|
|
|
80522
80644
|
contexts.set(table.id, context);
|
|
80523
80645
|
}
|
|
80524
80646
|
const linkedRecords = new Map(
|
|
80525
|
-
[...records].map(([id,
|
|
80647
|
+
[...records].map(([id, held3]) => [id, held3.map(asTableRecord)])
|
|
80526
80648
|
);
|
|
80527
|
-
const
|
|
80528
|
-
const computed =
|
|
80649
|
+
const held2 = heldBy(records, table.id);
|
|
80650
|
+
const computed = held2.map(
|
|
80529
80651
|
(record2) => computeFormulaFieldsWithContext(
|
|
80530
80652
|
Object.fromEntries(record2.cells),
|
|
80531
80653
|
fields,
|
|
@@ -80537,7 +80659,7 @@ function computeDerived(order, tableByAlias, records, fieldsByTable) {
|
|
|
80537
80659
|
linkExpanded
|
|
80538
80660
|
)[key]
|
|
80539
80661
|
);
|
|
80540
|
-
|
|
80662
|
+
held2.forEach((record2, r) => {
|
|
80541
80663
|
const value = computed[r];
|
|
80542
80664
|
if (value === void 0) record2.cells.delete(key);
|
|
80543
80665
|
else record2.cells.set(key, value);
|
|
@@ -82796,8 +82918,8 @@ function reusesInstall(project2) {
|
|
|
82796
82918
|
const stamp = `${project2.dir}.json`;
|
|
82797
82919
|
if (!fs23.existsSync(path24.join(project2.dir, "node_modules", "vite", "bin", "vite.js"))) return false;
|
|
82798
82920
|
if (!fs23.existsSync(stamp)) return false;
|
|
82799
|
-
const
|
|
82800
|
-
return
|
|
82921
|
+
const held2 = stampSchema.safeParse(parseJson2(fs23.readFileSync(stamp, "utf8")));
|
|
82922
|
+
return held2.success && JSON.stringify(sortedStamp(held2.data)) === JSON.stringify(sortedStamp(project2.stamp));
|
|
82801
82923
|
}
|
|
82802
82924
|
function sortedStamp(stamp) {
|
|
82803
82925
|
return { key: stamp.key, tarballs: sorted(stamp.tarballs) };
|
|
@@ -83116,8 +83238,8 @@ async function appPreview(args) {
|
|
|
83116
83238
|
rmSync2(staging, { recursive: true, force: true });
|
|
83117
83239
|
}
|
|
83118
83240
|
}
|
|
83119
|
-
async function previewIn(args,
|
|
83120
|
-
const { plan, project: project2, widths, timed, phases, specs, kits } =
|
|
83241
|
+
async function previewIn(args, held2) {
|
|
83242
|
+
const { plan, project: project2, widths, timed, phases, specs, kits } = held2;
|
|
83121
83243
|
const projectDir = project2.dir;
|
|
83122
83244
|
const bundle = probeBundle();
|
|
83123
83245
|
if (args.shots !== void 0) mkdirSync2(args.shots, { recursive: true });
|
|
@@ -83144,7 +83266,7 @@ async function previewIn(args, held) {
|
|
|
83144
83266
|
screens: args.screens,
|
|
83145
83267
|
shots: args.shots,
|
|
83146
83268
|
sleep: sleep5,
|
|
83147
|
-
...
|
|
83269
|
+
...held2.record === void 0 ? {} : { record: held2.record }
|
|
83148
83270
|
});
|
|
83149
83271
|
} finally {
|
|
83150
83272
|
await dev.stop();
|
|
@@ -85062,8 +85184,8 @@ function planGeneration(projectDir, generated, retiredWorkflows) {
|
|
|
85062
85184
|
}
|
|
85063
85185
|
for (const alias2 of retiredWorkflows) {
|
|
85064
85186
|
const relative3 = `${WORKFLOW_DIR}${alias2}${WORKFLOW_SUFFIX}`;
|
|
85065
|
-
const
|
|
85066
|
-
if (
|
|
85187
|
+
const held2 = read(projectDir, relative3);
|
|
85188
|
+
if (held2 === null || held2.includes(GUARDS_START)) continue;
|
|
85067
85189
|
deletes.push(relative3);
|
|
85068
85190
|
outcomes.push({ path: relative3, kind: "deleted" });
|
|
85069
85191
|
}
|
|
@@ -85141,12 +85263,12 @@ function plannedWorkflowBodies(projectDir, plan, declared) {
|
|
|
85141
85263
|
const alias2 = workflowAlias(write.path);
|
|
85142
85264
|
if (alias2 !== null) sources.set(alias2, write.content);
|
|
85143
85265
|
}
|
|
85144
|
-
const
|
|
85266
|
+
const held2 = [...sources].map(([alias2, source]) => ({
|
|
85145
85267
|
alias: alias2,
|
|
85146
85268
|
source: stripWorkflowHeader(source)
|
|
85147
85269
|
}));
|
|
85148
85270
|
const missing = declared.filter((alias2) => !sources.has(alias2)).map((alias2) => ({ alias: alias2, source: null }));
|
|
85149
|
-
return [...
|
|
85271
|
+
return [...held2, ...missing].sort((a, b) => a.alias < b.alias ? -1 : a.alias > b.alias ? 1 : 0);
|
|
85150
85272
|
}
|
|
85151
85273
|
function brandingDrift(app, live) {
|
|
85152
85274
|
const color = app.theme?.color ?? null;
|
|
@@ -85246,13 +85368,14 @@ async function foldRegeneration(client, args = {}) {
|
|
|
85246
85368
|
// business reissuing it, and dropping it makes the next push read as a
|
|
85247
85369
|
// new bind.
|
|
85248
85370
|
...previous.workflow_id === void 0 ? {} : { workflow_id: previous.workflow_id },
|
|
85249
|
-
//
|
|
85250
|
-
//
|
|
85251
|
-
//
|
|
85252
|
-
// declaration disagreeing with the live
|
|
85253
|
-
// changed, which re-reported and re-pushed
|
|
85254
|
-
// body this run DOES rewrite loses
|
|
85255
|
-
// body it was derived from, and the next push
|
|
85371
|
+
// A generated body's `outputs` are the generator's, declared as its
|
|
85372
|
+
// return hands them. An AUTHORED act's are the ones the server DERIVED
|
|
85373
|
+
// from its body, which `workflow set` writes back into the manifest — and
|
|
85374
|
+
// a run that dropped them left the declaration disagreeing with the live
|
|
85375
|
+
// binding over a schema nobody changed, which re-reported and re-pushed
|
|
85376
|
+
// the same alias for ever. A body this run DOES rewrite loses them: the
|
|
85377
|
+
// derivation belonged to the body it was derived from, and the next push
|
|
85378
|
+
// re-derives it.
|
|
85256
85379
|
...next.outputs === void 0 && previous.outputs !== void 0 && !rewrittenBodies.has(alias2) ? { outputs: previous.outputs } : {}
|
|
85257
85380
|
};
|
|
85258
85381
|
}
|