@ai-matrx/records 0.82.1 → 0.83.1
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/CHANGELOG.md +18 -1
- package/dist/memory/index.cjs +2 -0
- package/dist/memory/index.cjs.map +1 -1
- package/dist/memory/index.js +2 -0
- package/dist/memory/index.js.map +1 -1
- package/dist/templates/index.cjs +33 -136
- package/dist/templates/index.cjs.map +1 -1
- package/dist/templates/index.d.cts +9 -5
- package/dist/templates/index.d.ts +9 -5
- package/dist/templates/index.js +33 -136
- package/dist/templates/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -53,8 +53,12 @@ type AggregateOutcome = {
|
|
|
53
53
|
* is not a number is a refusal; no values at all is NULL, not 0); filled/empty/unique by
|
|
54
54
|
* `nullif(text,'')`; percent_empty/percent_filled as 100 x share of the rows (NULL over none). Exact: an average that does not terminate is reported as inexact.
|
|
55
55
|
*/
|
|
56
|
-
/**
|
|
57
|
-
|
|
56
|
+
/**
|
|
57
|
+
* The functions a formula may call — THE one list, `@ai-matrx/kit/formula` (mirrors the store's
|
|
58
|
+
* custom.formula_node_kinds(); architecture D6). The gate parses with kit's parser too, and keeps
|
|
59
|
+
* only its own EXACT evaluator below: numbers are read from the digits as typed into fractions.
|
|
60
|
+
*/
|
|
61
|
+
declare const FORMULA_FUNCTION_NAMES: ReadonlySet<string>;
|
|
58
62
|
type FxNode = {
|
|
59
63
|
k: "num";
|
|
60
64
|
v: Q;
|
|
@@ -77,8 +81,8 @@ type FxNode = {
|
|
|
77
81
|
f: string;
|
|
78
82
|
args: FxNode[];
|
|
79
83
|
};
|
|
80
|
-
/** Parse a formula text, or say what is wrong with it. */
|
|
81
|
-
declare function
|
|
84
|
+
/** Parse a formula text with the one parser, or say what is wrong with it. */
|
|
85
|
+
declare function parseGateFormula(text: string): FxNode | string;
|
|
82
86
|
/** Every `{Label}` a formula reads. */
|
|
83
87
|
declare function formulaRefs(n: FxNode): string[];
|
|
84
88
|
/**
|
|
@@ -944,4 +948,4 @@ interface SafeReusesResult {
|
|
|
944
948
|
}
|
|
945
949
|
declare function safeReuses(spec: TemplateSpec, reuses: Reuse[], existingTables: ExistingTable[]): SafeReusesResult;
|
|
946
950
|
|
|
947
|
-
export { AgentSnapshotRow, type AggregateOutcome, type ApplyResult, type AutofixResult, BAD_OUTCOME, BOOKING_AVAILABILITY_FACTS, type CapabilityStatus, CapabilityWord, DESIGNATED_REAL_NUMBERS, type DerivedUseCase, type DescribeCheckResult, type DescribeCtx, type DescribePlan, type DescribePlanDoor, type DescribePlanTable, type DescribeProblem, type DescribeResult, type DoorsPart, type ExistingTable,
|
|
951
|
+
export { AgentSnapshotRow, type AggregateOutcome, type ApplyResult, type AutofixResult, BAD_OUTCOME, BOOKING_AVAILABILITY_FACTS, type CapabilityStatus, CapabilityWord, DESIGNATED_REAL_NUMBERS, type DerivedUseCase, type DescribeCheckResult, type DescribeCtx, type DescribePlan, type DescribePlanDoor, type DescribePlanTable, type DescribeProblem, type DescribeResult, type DoorsPart, type ExistingTable, FORMULA_FUNCTION_NAMES, type FieldRequest, GALLERY_ONLY, GOOD_OUTCOME, INSTALL_PLAN_VERSION, IndustryGroup, MAIN_TABLE_ROWS_MAX, MAIN_TABLE_ROWS_MIN, PUBLIC_MAIL_DOMAINS, RECORDS_UI_CALENDAR_MODES, RECORDS_UI_FIELD_SURFACES, RECORDS_UI_VIEW_LAYOUTS, type RepairAnswer, type RepairPatch, type RepairSlice, SERVER_DATE_GRAMMAR, type SafeReusesResult, type SeedRow, SharedBlockId, TABLES_MAX, TABLES_MIN, TEMPLATE_PLAN_DOORS, TIME_BOUND_STAGE, TITLE_DISTINCT_SHARE, type TablesPart, TeachesFeature, TemplateAgent, type TemplateAgentBinding, type TemplateAgentCopyRequest, type TemplateAssetRow, type TemplateAttachment, TemplateAutomation, TemplateBooking, TemplateBookingWindow, type TemplateCard, TemplateChecklist, TemplateDashboard, type TemplateDeclaration, TemplateDigest, TemplateDimensions, TemplateDocument, type TemplateDoorAnswer, type TemplateDoorRun, TemplateDrillDown, type TemplateFamilyDoor, TemplateField, TemplateFootprint, TemplateForm, type TemplateHostExtras, type TemplateInstallPlan, TemplateJob, type TemplateMadeKind, TemplateMergeBinding, TemplateNotification, type TemplatePlanAgent, type TemplatePlanBinding, type TemplatePlanDoor, type TemplatePlanExtraAgent, type TemplatePlanStep, TemplatePortal, TemplateRowAction, TemplateSpec, type TemplateSpecWithAttachments, TemplateStageRules, type TemplateStatus, TemplateTable, TemplateTryIt, type TemplateUpgradeAnswer, type TemplateUpgradeHint, type TemplateUpgradeRun, type TemplateVerdict, TemplateView, TemplateViewKind, TemplateWorkflow, type TrimResult, VIEW_SHAPE_FACTS, type ValidateOptions, type ViewsPart, agentCopyRequest, allTables, anyOfWhere, applyRepairPatches, assertTemplate, attachmentProblems, autofixDescribeSpec, automationHeld, blockTable, bookingArgs, bookingColumnsProblem, capabilitiesUsed, capabilityStatus, checklistSpec, choiceDisplayFormat, compileHostExtras, compileInstallPlan, dashboardBlocks, deferredRelationFields, deferredRelations, derivedFieldSpec, describeCheck, describeSpec, describeVocabulary, digestSpec, documentBody, domainsIn, drillDownDashboard, evalFormula, extrasProblems, fallbackView, foreignTextProblems, formArgs, formulaFieldSpec, formulaOrder, formulaRefs, foundationTokens, isSelfDeclaredField, isTimedField, lastResortTrim, meaningWords, mergeDescribeParts, normalizeForPhones, notificationParts, numberText, numberedStreet, packageDescribeResult, parseAt, parseGateFormula, parseNumeric, pathOfAt, peopleOf, phonesOutsideFictionalRange, planTables, portalArgs, relationFieldSpec, relationPatches, relativeHasTime, repairSlices, requiredCircleProblem, resolveDateToken, resolvePath, resolveRelativeDates, reusesOf, rowActionList, rowLevels, rowsFor, ruleBreak, runTemplateDoor, safeReuses, sameMeaning, selfDeclaredFieldSpec, sensitivityFloorOf, shellsPayload, stageFieldOf, stageRulesSpec, storeAggregate, storeFilterMatches, storeText, tableShellPayload, templateCard, templateDeclaration, templateText, templateUpgradeHint, timedFieldSpec, toUseCase, unwrap, upgradeTemplateInstall, useCaseProblemsOf, validateTemplate, viewMatches, viewSpec, zoneOffset };
|
|
@@ -53,8 +53,12 @@ type AggregateOutcome = {
|
|
|
53
53
|
* is not a number is a refusal; no values at all is NULL, not 0); filled/empty/unique by
|
|
54
54
|
* `nullif(text,'')`; percent_empty/percent_filled as 100 x share of the rows (NULL over none). Exact: an average that does not terminate is reported as inexact.
|
|
55
55
|
*/
|
|
56
|
-
/**
|
|
57
|
-
|
|
56
|
+
/**
|
|
57
|
+
* The functions a formula may call — THE one list, `@ai-matrx/kit/formula` (mirrors the store's
|
|
58
|
+
* custom.formula_node_kinds(); architecture D6). The gate parses with kit's parser too, and keeps
|
|
59
|
+
* only its own EXACT evaluator below: numbers are read from the digits as typed into fractions.
|
|
60
|
+
*/
|
|
61
|
+
declare const FORMULA_FUNCTION_NAMES: ReadonlySet<string>;
|
|
58
62
|
type FxNode = {
|
|
59
63
|
k: "num";
|
|
60
64
|
v: Q;
|
|
@@ -77,8 +81,8 @@ type FxNode = {
|
|
|
77
81
|
f: string;
|
|
78
82
|
args: FxNode[];
|
|
79
83
|
};
|
|
80
|
-
/** Parse a formula text, or say what is wrong with it. */
|
|
81
|
-
declare function
|
|
84
|
+
/** Parse a formula text with the one parser, or say what is wrong with it. */
|
|
85
|
+
declare function parseGateFormula(text: string): FxNode | string;
|
|
82
86
|
/** Every `{Label}` a formula reads. */
|
|
83
87
|
declare function formulaRefs(n: FxNode): string[];
|
|
84
88
|
/**
|
|
@@ -944,4 +948,4 @@ interface SafeReusesResult {
|
|
|
944
948
|
}
|
|
945
949
|
declare function safeReuses(spec: TemplateSpec, reuses: Reuse[], existingTables: ExistingTable[]): SafeReusesResult;
|
|
946
950
|
|
|
947
|
-
export { AgentSnapshotRow, type AggregateOutcome, type ApplyResult, type AutofixResult, BAD_OUTCOME, BOOKING_AVAILABILITY_FACTS, type CapabilityStatus, CapabilityWord, DESIGNATED_REAL_NUMBERS, type DerivedUseCase, type DescribeCheckResult, type DescribeCtx, type DescribePlan, type DescribePlanDoor, type DescribePlanTable, type DescribeProblem, type DescribeResult, type DoorsPart, type ExistingTable,
|
|
951
|
+
export { AgentSnapshotRow, type AggregateOutcome, type ApplyResult, type AutofixResult, BAD_OUTCOME, BOOKING_AVAILABILITY_FACTS, type CapabilityStatus, CapabilityWord, DESIGNATED_REAL_NUMBERS, type DerivedUseCase, type DescribeCheckResult, type DescribeCtx, type DescribePlan, type DescribePlanDoor, type DescribePlanTable, type DescribeProblem, type DescribeResult, type DoorsPart, type ExistingTable, FORMULA_FUNCTION_NAMES, type FieldRequest, GALLERY_ONLY, GOOD_OUTCOME, INSTALL_PLAN_VERSION, IndustryGroup, MAIN_TABLE_ROWS_MAX, MAIN_TABLE_ROWS_MIN, PUBLIC_MAIL_DOMAINS, RECORDS_UI_CALENDAR_MODES, RECORDS_UI_FIELD_SURFACES, RECORDS_UI_VIEW_LAYOUTS, type RepairAnswer, type RepairPatch, type RepairSlice, SERVER_DATE_GRAMMAR, type SafeReusesResult, type SeedRow, SharedBlockId, TABLES_MAX, TABLES_MIN, TEMPLATE_PLAN_DOORS, TIME_BOUND_STAGE, TITLE_DISTINCT_SHARE, type TablesPart, TeachesFeature, TemplateAgent, type TemplateAgentBinding, type TemplateAgentCopyRequest, type TemplateAssetRow, type TemplateAttachment, TemplateAutomation, TemplateBooking, TemplateBookingWindow, type TemplateCard, TemplateChecklist, TemplateDashboard, type TemplateDeclaration, TemplateDigest, TemplateDimensions, TemplateDocument, type TemplateDoorAnswer, type TemplateDoorRun, TemplateDrillDown, type TemplateFamilyDoor, TemplateField, TemplateFootprint, TemplateForm, type TemplateHostExtras, type TemplateInstallPlan, TemplateJob, type TemplateMadeKind, TemplateMergeBinding, TemplateNotification, type TemplatePlanAgent, type TemplatePlanBinding, type TemplatePlanDoor, type TemplatePlanExtraAgent, type TemplatePlanStep, TemplatePortal, TemplateRowAction, TemplateSpec, type TemplateSpecWithAttachments, TemplateStageRules, type TemplateStatus, TemplateTable, TemplateTryIt, type TemplateUpgradeAnswer, type TemplateUpgradeHint, type TemplateUpgradeRun, type TemplateVerdict, TemplateView, TemplateViewKind, TemplateWorkflow, type TrimResult, VIEW_SHAPE_FACTS, type ValidateOptions, type ViewsPart, agentCopyRequest, allTables, anyOfWhere, applyRepairPatches, assertTemplate, attachmentProblems, autofixDescribeSpec, automationHeld, blockTable, bookingArgs, bookingColumnsProblem, capabilitiesUsed, capabilityStatus, checklistSpec, choiceDisplayFormat, compileHostExtras, compileInstallPlan, dashboardBlocks, deferredRelationFields, deferredRelations, derivedFieldSpec, describeCheck, describeSpec, describeVocabulary, digestSpec, documentBody, domainsIn, drillDownDashboard, evalFormula, extrasProblems, fallbackView, foreignTextProblems, formArgs, formulaFieldSpec, formulaOrder, formulaRefs, foundationTokens, isSelfDeclaredField, isTimedField, lastResortTrim, meaningWords, mergeDescribeParts, normalizeForPhones, notificationParts, numberText, numberedStreet, packageDescribeResult, parseAt, parseGateFormula, parseNumeric, pathOfAt, peopleOf, phonesOutsideFictionalRange, planTables, portalArgs, relationFieldSpec, relationPatches, relativeHasTime, repairSlices, requiredCircleProblem, resolveDateToken, resolvePath, resolveRelativeDates, reusesOf, rowActionList, rowLevels, rowsFor, ruleBreak, runTemplateDoor, safeReuses, sameMeaning, selfDeclaredFieldSpec, sensitivityFloorOf, shellsPayload, stageFieldOf, stageRulesSpec, storeAggregate, storeFilterMatches, storeText, tableShellPayload, templateCard, templateDeclaration, templateText, templateUpgradeHint, timedFieldSpec, toUseCase, unwrap, upgradeTemplateInstall, useCaseProblemsOf, validateTemplate, viewMatches, viewSpec, zoneOffset };
|
package/dist/templates/index.js
CHANGED
|
@@ -327,6 +327,7 @@ var CATALOGUE_STATUSES = ["planned", "authoring", "checking", "waiting_on_lane_1
|
|
|
327
327
|
|
|
328
328
|
// src/templates/validate.ts
|
|
329
329
|
import { isUuidShape } from "@ai-matrx/kit/uuid";
|
|
330
|
+
import { FORMULA_FUNCTIONS as KIT_FORMULA_FUNCTIONS, parseFormula as parseFormulaText } from "@ai-matrx/kit/formula";
|
|
330
331
|
|
|
331
332
|
// src/templates/confidential.ts
|
|
332
333
|
var TABLE_KERNEL_ID = "11111111-0000-4000-8000-000000000001";
|
|
@@ -2738,134 +2739,28 @@ function storeFilterMatches(row, filter, _timeZone) {
|
|
|
2738
2739
|
return have === String(want);
|
|
2739
2740
|
});
|
|
2740
2741
|
}
|
|
2741
|
-
var
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
"NOT",
|
|
2764
|
-
"OR",
|
|
2765
|
-
"REGEX_MATCH",
|
|
2766
|
-
"RIGHT",
|
|
2767
|
-
"ROUND",
|
|
2768
|
-
"SUBSTITUTE",
|
|
2769
|
-
"SUM",
|
|
2770
|
-
"SWITCH",
|
|
2771
|
-
"TODAY",
|
|
2772
|
-
"NOW",
|
|
2773
|
-
"TRIM",
|
|
2774
|
-
"UPPER",
|
|
2775
|
-
"WORKDAY",
|
|
2776
|
-
"YEAR"
|
|
2777
|
-
]);
|
|
2778
|
-
function fxTokens(text) {
|
|
2779
|
-
const out = [];
|
|
2780
|
-
let i = 0;
|
|
2781
|
-
while (i < text.length) {
|
|
2782
|
-
const c = text[i];
|
|
2783
|
-
if (/\s/.test(c)) i += 1;
|
|
2784
|
-
else if (c === "{") {
|
|
2785
|
-
const j = text.indexOf("}", i);
|
|
2786
|
-
if (j < 0) return "a { has no closing }";
|
|
2787
|
-
out.push({ t: "ref", v: text.slice(i + 1, j).trim() });
|
|
2788
|
-
i = j + 1;
|
|
2789
|
-
} else if (c === "'" || c === '"') {
|
|
2790
|
-
const j = text.indexOf(c, i + 1);
|
|
2791
|
-
if (j < 0) return "a quoted word has no closing quote";
|
|
2792
|
-
out.push({ t: "str", v: text.slice(i + 1, j) });
|
|
2793
|
-
i = j + 1;
|
|
2794
|
-
} else if (/[0-9.]/.test(c)) {
|
|
2795
|
-
const m = /^[0-9]*\.?[0-9]+/.exec(text.slice(i));
|
|
2796
|
-
out.push({ t: "num", v: m[0] });
|
|
2797
|
-
i += m[0].length;
|
|
2798
|
-
} else if (/[A-Za-z_]/.test(c)) {
|
|
2799
|
-
const m = /^[A-Za-z_][A-Za-z_0-9]*/.exec(text.slice(i));
|
|
2800
|
-
out.push({ t: "name", v: m[0] });
|
|
2801
|
-
i += m[0].length;
|
|
2802
|
-
} else if ("+-*/(),%".includes(c)) {
|
|
2803
|
-
out.push({ t: "op", v: c });
|
|
2804
|
-
i += 1;
|
|
2805
|
-
} else return `"${c}" is not part of a formula`;
|
|
2806
|
-
}
|
|
2807
|
-
return out;
|
|
2808
|
-
}
|
|
2809
|
-
function parseFormula(text) {
|
|
2810
|
-
const toks = fxTokens(text);
|
|
2811
|
-
if (typeof toks === "string") return toks;
|
|
2812
|
-
let p = 0;
|
|
2813
|
-
const peek = () => toks[p];
|
|
2814
|
-
const fail = (why) => {
|
|
2815
|
-
throw new Error(why);
|
|
2816
|
-
};
|
|
2817
|
-
const expr = () => {
|
|
2818
|
-
let a = term();
|
|
2819
|
-
while (peek()?.t === "op" && (peek().v === "+" || peek().v === "-")) {
|
|
2820
|
-
const op = toks[p++].v;
|
|
2821
|
-
a = { k: "bin", op, a, b: term() };
|
|
2822
|
-
}
|
|
2823
|
-
return a;
|
|
2824
|
-
};
|
|
2825
|
-
const term = () => {
|
|
2826
|
-
let a = factor();
|
|
2827
|
-
while (peek()?.t === "op" && (peek().v === "*" || peek().v === "/" || peek().v === "%")) {
|
|
2828
|
-
const op = toks[p++].v;
|
|
2829
|
-
a = { k: "bin", op, a, b: factor() };
|
|
2830
|
-
}
|
|
2831
|
-
return a;
|
|
2832
|
-
};
|
|
2833
|
-
const factor = () => {
|
|
2834
|
-
const tk = toks[p++];
|
|
2835
|
-
if (!tk) return fail("the formula ends too early");
|
|
2836
|
-
if (tk.t === "num") return { k: "num", v: parseNumeric(tk.v) };
|
|
2837
|
-
if (tk.t === "str") return { k: "str", v: tk.v };
|
|
2838
|
-
if (tk.t === "ref") return { k: "ref", v: tk.v };
|
|
2839
|
-
if (tk.t === "op" && tk.v === "-") return { k: "neg", a: factor() };
|
|
2840
|
-
if (tk.t === "op" && tk.v === "(") {
|
|
2841
|
-
const e = expr();
|
|
2842
|
-
if (toks[p++]?.v !== ")") fail("a ( has no closing )");
|
|
2843
|
-
return e;
|
|
2844
|
-
}
|
|
2845
|
-
if (tk.t === "name") {
|
|
2846
|
-
const f = tk.v.toUpperCase();
|
|
2847
|
-
if (!FORMULA_FUNCTIONS.has(f)) fail(`${tk.v} is not a formula function the store knows`);
|
|
2848
|
-
if (toks[p++]?.v !== "(") fail(`${f} is followed by its arguments in ( )`);
|
|
2849
|
-
const args = [];
|
|
2850
|
-
if (peek()?.v !== ")") {
|
|
2851
|
-
args.push(expr());
|
|
2852
|
-
while (peek()?.v === ",") {
|
|
2853
|
-
p += 1;
|
|
2854
|
-
args.push(expr());
|
|
2855
|
-
}
|
|
2856
|
-
}
|
|
2857
|
-
if (toks[p++]?.v !== ")") fail(`${f}( has no closing )`);
|
|
2858
|
-
return { k: "call", f, args };
|
|
2859
|
-
}
|
|
2860
|
-
return fail(`"${tk.v}" is out of place`);
|
|
2861
|
-
};
|
|
2862
|
-
try {
|
|
2863
|
-
const e = expr();
|
|
2864
|
-
if (p !== toks.length) return `"${toks[p].v}" is out of place`;
|
|
2865
|
-
return e;
|
|
2866
|
-
} catch (err) {
|
|
2867
|
-
return err.message;
|
|
2868
|
-
}
|
|
2742
|
+
var FORMULA_FUNCTION_NAMES = new Set(KIT_FORMULA_FUNCTIONS.map((f) => f.name));
|
|
2743
|
+
function toFx(n) {
|
|
2744
|
+
switch (n.kind) {
|
|
2745
|
+
case "number":
|
|
2746
|
+
return { k: "num", v: parseNumeric(n.raw) };
|
|
2747
|
+
case "string":
|
|
2748
|
+
return { k: "str", v: n.value };
|
|
2749
|
+
case "boolean":
|
|
2750
|
+
return { k: "call", f: n.value ? "TRUE" : "FALSE", args: [] };
|
|
2751
|
+
case "reference":
|
|
2752
|
+
return { k: "ref", v: n.name };
|
|
2753
|
+
case "unary":
|
|
2754
|
+
return { k: "neg", a: toFx(n.operand) };
|
|
2755
|
+
case "binary":
|
|
2756
|
+
return { k: "bin", op: n.operator, a: toFx(n.left), b: toFx(n.right) };
|
|
2757
|
+
case "call":
|
|
2758
|
+
return { k: "call", f: n.name, args: n.args.map(toFx) };
|
|
2759
|
+
}
|
|
2760
|
+
}
|
|
2761
|
+
function parseGateFormula(text) {
|
|
2762
|
+
const parsed = parseFormulaText(text);
|
|
2763
|
+
return parsed.ok ? toFx(parsed.ast) : parsed.error;
|
|
2869
2764
|
}
|
|
2870
2765
|
function formulaRefs(n) {
|
|
2871
2766
|
if (n.k === "ref") return [n.v];
|
|
@@ -2905,7 +2800,7 @@ function evalFormula(n, valueOf) {
|
|
|
2905
2800
|
if (n.op === "*") return { ok: true, v: q(a.n * b.n, a.d * b.d) };
|
|
2906
2801
|
if (b.n === 0n) return { ok: false, why: "it divides by zero on a row" };
|
|
2907
2802
|
if (n.op === "/") return { ok: true, v: q(a.n * b.d, a.d * b.n) };
|
|
2908
|
-
return { ok: false, why:
|
|
2803
|
+
return { ok: false, why: `${n.op} is not mirrored` };
|
|
2909
2804
|
}
|
|
2910
2805
|
case "call": {
|
|
2911
2806
|
if (n.f === "ABS" && n.args.length === 1) {
|
|
@@ -3648,7 +3543,7 @@ function validateTemplate(raw, options = {}) {
|
|
|
3648
3543
|
return isComputed(pf) ? computedOf(target, pf, { key: far.key, values: far.values }, depth + 1) : { ok: true, v: far.values?.[f.pick] ?? null };
|
|
3649
3544
|
}
|
|
3650
3545
|
if (f.parityType === "formula" && f.formula) {
|
|
3651
|
-
const ast =
|
|
3546
|
+
const ast = parseGateFormula(f.formula);
|
|
3652
3547
|
if (typeof ast === "string") return { ok: false, why: ast };
|
|
3653
3548
|
let why = null;
|
|
3654
3549
|
const r2 = evalFormula(ast, (label2) => {
|
|
@@ -3678,7 +3573,7 @@ function validateTemplate(raw, options = {}) {
|
|
|
3678
3573
|
if (!f) return false;
|
|
3679
3574
|
if (isNumber(f)) return true;
|
|
3680
3575
|
if (f.parityType !== "formula" || !f.formula) return false;
|
|
3681
|
-
const ast =
|
|
3576
|
+
const ast = parseGateFormula(f.formula);
|
|
3682
3577
|
if (typeof ast === "string") return false;
|
|
3683
3578
|
const refsStored = formulaRefs(ast).every((l) => {
|
|
3684
3579
|
const rf = byToken.get(table)?.fields.find((x) => x.label === l);
|
|
@@ -4985,7 +4880,7 @@ function validateTemplate(raw, options = {}) {
|
|
|
4985
4880
|
say(fat, `"${f.label}" is a formula; write it in formula, naming fields in braces: {Total} - {Paid}.`);
|
|
4986
4881
|
continue;
|
|
4987
4882
|
}
|
|
4988
|
-
const ast =
|
|
4883
|
+
const ast = parseGateFormula(f.formula);
|
|
4989
4884
|
if (typeof ast === "string") {
|
|
4990
4885
|
say(fat, `The formula "${f.formula}" cannot be read: ${ast}.`);
|
|
4991
4886
|
continue;
|
|
@@ -7118,13 +7013,15 @@ function fixFictionalPhones(spec, fixes) {
|
|
|
7118
7013
|
Object.assign(spec, next);
|
|
7119
7014
|
fixes.push(`phones: ${n} number(s) that could reach a real phone replaced with fictional ones (555-0100\u20260199, UK Ofcom drama range)`);
|
|
7120
7015
|
}
|
|
7121
|
-
function fixTeamBlockCopy(spec, fixes) {
|
|
7016
|
+
function fixTeamBlockCopy(spec, fixes, existing = []) {
|
|
7122
7017
|
const block = SHARED_BLOCKS.team_member;
|
|
7123
7018
|
const used = /* @__PURE__ */ new Set();
|
|
7124
7019
|
for (const v of spec.views ?? []) for (const k of ["groupBy", "dateField", "startField", "endField", "coverField", "swimlaneBy", "measure"]) if (v.table && v[k]) used.add(`${v.table}.${v[k]}`);
|
|
7125
7020
|
for (const fm of spec.forms ?? []) for (const q2 of fm.fields ?? []) used.add(`${fm.table}.${q2.fieldKey}`);
|
|
7126
7021
|
for (const e of spec.extras ?? []) for (const q2 of e.questions ?? []) used.add(`${e.table}.${q2.fieldKey}`);
|
|
7127
7022
|
for (const t of spec.tables) {
|
|
7023
|
+
const keys = t.fields.map((f) => f.key).sort().join("|");
|
|
7024
|
+
if (existing.some((e) => e.fields.map((f) => f.key).sort().join("|") === keys)) continue;
|
|
7128
7025
|
const meaning = (f) => block.fields.find((bf) => bf.parityType === f.parityType && bf.sameAs.some((w) => same3(w, f.label) || same3(w, f.key)));
|
|
7129
7026
|
const hits = t.fields.map((f) => ({ f, bf: meaning(f) })).filter((x) => x.bf);
|
|
7130
7027
|
if (hits.length < block.copyThreshold) continue;
|
|
@@ -7478,7 +7375,7 @@ function autofixDescribeSpec(input, ctx = {}) {
|
|
|
7478
7375
|
dropDuplicateViews(spec, autoFixes);
|
|
7479
7376
|
fixInverseKeys(spec, autoFixes);
|
|
7480
7377
|
fixRollupFilters(spec, autoFixes);
|
|
7481
|
-
fixTeamBlockCopy(spec, autoFixes);
|
|
7378
|
+
fixTeamBlockCopy(spec, autoFixes, ctx.existingTables ?? []);
|
|
7482
7379
|
fixFictionalPhones(spec, autoFixes);
|
|
7483
7380
|
fixMissingQuestionFields(spec, autoFixes);
|
|
7484
7381
|
raiseSensitivity(spec, autoFixes);
|
|
@@ -7830,7 +7727,7 @@ export {
|
|
|
7830
7727
|
DEFAULT_TEMPLATE_AGENT,
|
|
7831
7728
|
DESIGNATED_REAL_NUMBERS,
|
|
7832
7729
|
ENTITY_REFERENCE_KINDS,
|
|
7833
|
-
|
|
7730
|
+
FORMULA_FUNCTION_NAMES,
|
|
7834
7731
|
GALLERY_ONLY,
|
|
7835
7732
|
GOOD_OUTCOME,
|
|
7836
7733
|
INDUSTRY_GROUPS,
|
|
@@ -7913,7 +7810,7 @@ export {
|
|
|
7913
7810
|
numberedStreet,
|
|
7914
7811
|
packageDescribeResult,
|
|
7915
7812
|
parseAt,
|
|
7916
|
-
|
|
7813
|
+
parseGateFormula,
|
|
7917
7814
|
parseNumeric,
|
|
7918
7815
|
pathOfAt,
|
|
7919
7816
|
peopleOf,
|