@ai-matrx/records 0.82.1 → 0.83.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.
@@ -30,7 +30,7 @@ __export(templates_exports, {
30
30
  DEFAULT_TEMPLATE_AGENT: () => DEFAULT_TEMPLATE_AGENT,
31
31
  DESIGNATED_REAL_NUMBERS: () => DESIGNATED_REAL_NUMBERS,
32
32
  ENTITY_REFERENCE_KINDS: () => ENTITY_REFERENCE_KINDS,
33
- FORMULA_FUNCTIONS: () => FORMULA_FUNCTIONS,
33
+ FORMULA_FUNCTION_NAMES: () => FORMULA_FUNCTION_NAMES,
34
34
  GALLERY_ONLY: () => GALLERY_ONLY,
35
35
  GOOD_OUTCOME: () => GOOD_OUTCOME,
36
36
  INDUSTRY_GROUPS: () => INDUSTRY_GROUPS,
@@ -113,7 +113,7 @@ __export(templates_exports, {
113
113
  numberedStreet: () => numberedStreet,
114
114
  packageDescribeResult: () => packageDescribeResult,
115
115
  parseAt: () => parseAt,
116
- parseFormula: () => parseFormula,
116
+ parseGateFormula: () => parseGateFormula,
117
117
  parseNumeric: () => parseNumeric,
118
118
  pathOfAt: () => pathOfAt,
119
119
  peopleOf: () => peopleOf,
@@ -492,6 +492,7 @@ var CATALOGUE_STATUSES = ["planned", "authoring", "checking", "waiting_on_lane_1
492
492
 
493
493
  // src/templates/validate.ts
494
494
  var import_uuid = require("@ai-matrx/kit/uuid");
495
+ var import_formula = require("@ai-matrx/kit/formula");
495
496
 
496
497
  // src/templates/confidential.ts
497
498
  var TABLE_KERNEL_ID = "11111111-0000-4000-8000-000000000001";
@@ -2903,134 +2904,28 @@ function storeFilterMatches(row, filter, _timeZone) {
2903
2904
  return have === String(want);
2904
2905
  });
2905
2906
  }
2906
- var FORMULA_FUNCTIONS = /* @__PURE__ */ new Set([
2907
- "ABS",
2908
- "AND",
2909
- "ARRAYCOMPACT",
2910
- "ARRAYJOIN",
2911
- "AVERAGE",
2912
- "BLANK",
2913
- "CONCATENATE",
2914
- "CONTAINS",
2915
- "DATEADD",
2916
- "DATEDIFF",
2917
- "DATETIME_FORMAT",
2918
- "DAY",
2919
- "FIND",
2920
- "IF",
2921
- "ISBLANK",
2922
- "LEFT",
2923
- "LEN",
2924
- "LOWER",
2925
- "MAX",
2926
- "MIN",
2927
- "MONTH",
2928
- "NOT",
2929
- "OR",
2930
- "REGEX_MATCH",
2931
- "RIGHT",
2932
- "ROUND",
2933
- "SUBSTITUTE",
2934
- "SUM",
2935
- "SWITCH",
2936
- "TODAY",
2937
- "NOW",
2938
- "TRIM",
2939
- "UPPER",
2940
- "WORKDAY",
2941
- "YEAR"
2942
- ]);
2943
- function fxTokens(text) {
2944
- const out = [];
2945
- let i = 0;
2946
- while (i < text.length) {
2947
- const c = text[i];
2948
- if (/\s/.test(c)) i += 1;
2949
- else if (c === "{") {
2950
- const j = text.indexOf("}", i);
2951
- if (j < 0) return "a { has no closing }";
2952
- out.push({ t: "ref", v: text.slice(i + 1, j).trim() });
2953
- i = j + 1;
2954
- } else if (c === "'" || c === '"') {
2955
- const j = text.indexOf(c, i + 1);
2956
- if (j < 0) return "a quoted word has no closing quote";
2957
- out.push({ t: "str", v: text.slice(i + 1, j) });
2958
- i = j + 1;
2959
- } else if (/[0-9.]/.test(c)) {
2960
- const m = /^[0-9]*\.?[0-9]+/.exec(text.slice(i));
2961
- out.push({ t: "num", v: m[0] });
2962
- i += m[0].length;
2963
- } else if (/[A-Za-z_]/.test(c)) {
2964
- const m = /^[A-Za-z_][A-Za-z_0-9]*/.exec(text.slice(i));
2965
- out.push({ t: "name", v: m[0] });
2966
- i += m[0].length;
2967
- } else if ("+-*/(),%".includes(c)) {
2968
- out.push({ t: "op", v: c });
2969
- i += 1;
2970
- } else return `"${c}" is not part of a formula`;
2971
- }
2972
- return out;
2973
- }
2974
- function parseFormula(text) {
2975
- const toks = fxTokens(text);
2976
- if (typeof toks === "string") return toks;
2977
- let p = 0;
2978
- const peek = () => toks[p];
2979
- const fail = (why) => {
2980
- throw new Error(why);
2981
- };
2982
- const expr = () => {
2983
- let a = term();
2984
- while (peek()?.t === "op" && (peek().v === "+" || peek().v === "-")) {
2985
- const op = toks[p++].v;
2986
- a = { k: "bin", op, a, b: term() };
2987
- }
2988
- return a;
2989
- };
2990
- const term = () => {
2991
- let a = factor();
2992
- while (peek()?.t === "op" && (peek().v === "*" || peek().v === "/" || peek().v === "%")) {
2993
- const op = toks[p++].v;
2994
- a = { k: "bin", op, a, b: factor() };
2995
- }
2996
- return a;
2997
- };
2998
- const factor = () => {
2999
- const tk = toks[p++];
3000
- if (!tk) return fail("the formula ends too early");
3001
- if (tk.t === "num") return { k: "num", v: parseNumeric(tk.v) };
3002
- if (tk.t === "str") return { k: "str", v: tk.v };
3003
- if (tk.t === "ref") return { k: "ref", v: tk.v };
3004
- if (tk.t === "op" && tk.v === "-") return { k: "neg", a: factor() };
3005
- if (tk.t === "op" && tk.v === "(") {
3006
- const e = expr();
3007
- if (toks[p++]?.v !== ")") fail("a ( has no closing )");
3008
- return e;
3009
- }
3010
- if (tk.t === "name") {
3011
- const f = tk.v.toUpperCase();
3012
- if (!FORMULA_FUNCTIONS.has(f)) fail(`${tk.v} is not a formula function the store knows`);
3013
- if (toks[p++]?.v !== "(") fail(`${f} is followed by its arguments in ( )`);
3014
- const args = [];
3015
- if (peek()?.v !== ")") {
3016
- args.push(expr());
3017
- while (peek()?.v === ",") {
3018
- p += 1;
3019
- args.push(expr());
3020
- }
3021
- }
3022
- if (toks[p++]?.v !== ")") fail(`${f}( has no closing )`);
3023
- return { k: "call", f, args };
3024
- }
3025
- return fail(`"${tk.v}" is out of place`);
3026
- };
3027
- try {
3028
- const e = expr();
3029
- if (p !== toks.length) return `"${toks[p].v}" is out of place`;
3030
- return e;
3031
- } catch (err) {
3032
- return err.message;
3033
- }
2907
+ var FORMULA_FUNCTION_NAMES = new Set(import_formula.FORMULA_FUNCTIONS.map((f) => f.name));
2908
+ function toFx(n) {
2909
+ switch (n.kind) {
2910
+ case "number":
2911
+ return { k: "num", v: parseNumeric(n.raw) };
2912
+ case "string":
2913
+ return { k: "str", v: n.value };
2914
+ case "boolean":
2915
+ return { k: "call", f: n.value ? "TRUE" : "FALSE", args: [] };
2916
+ case "reference":
2917
+ return { k: "ref", v: n.name };
2918
+ case "unary":
2919
+ return { k: "neg", a: toFx(n.operand) };
2920
+ case "binary":
2921
+ return { k: "bin", op: n.operator, a: toFx(n.left), b: toFx(n.right) };
2922
+ case "call":
2923
+ return { k: "call", f: n.name, args: n.args.map(toFx) };
2924
+ }
2925
+ }
2926
+ function parseGateFormula(text) {
2927
+ const parsed = (0, import_formula.parseFormula)(text);
2928
+ return parsed.ok ? toFx(parsed.ast) : parsed.error;
3034
2929
  }
3035
2930
  function formulaRefs(n) {
3036
2931
  if (n.k === "ref") return [n.v];
@@ -3070,7 +2965,7 @@ function evalFormula(n, valueOf) {
3070
2965
  if (n.op === "*") return { ok: true, v: q(a.n * b.n, a.d * b.d) };
3071
2966
  if (b.n === 0n) return { ok: false, why: "it divides by zero on a row" };
3072
2967
  if (n.op === "/") return { ok: true, v: q(a.n * b.d, a.d * b.n) };
3073
- return { ok: false, why: "% is not mirrored" };
2968
+ return { ok: false, why: `${n.op} is not mirrored` };
3074
2969
  }
3075
2970
  case "call": {
3076
2971
  if (n.f === "ABS" && n.args.length === 1) {
@@ -3813,7 +3708,7 @@ function validateTemplate(raw, options = {}) {
3813
3708
  return isComputed(pf) ? computedOf(target, pf, { key: far.key, values: far.values }, depth + 1) : { ok: true, v: far.values?.[f.pick] ?? null };
3814
3709
  }
3815
3710
  if (f.parityType === "formula" && f.formula) {
3816
- const ast = parseFormula(f.formula);
3711
+ const ast = parseGateFormula(f.formula);
3817
3712
  if (typeof ast === "string") return { ok: false, why: ast };
3818
3713
  let why = null;
3819
3714
  const r2 = evalFormula(ast, (label2) => {
@@ -3843,7 +3738,7 @@ function validateTemplate(raw, options = {}) {
3843
3738
  if (!f) return false;
3844
3739
  if (isNumber(f)) return true;
3845
3740
  if (f.parityType !== "formula" || !f.formula) return false;
3846
- const ast = parseFormula(f.formula);
3741
+ const ast = parseGateFormula(f.formula);
3847
3742
  if (typeof ast === "string") return false;
3848
3743
  const refsStored = formulaRefs(ast).every((l) => {
3849
3744
  const rf = byToken.get(table)?.fields.find((x) => x.label === l);
@@ -5150,7 +5045,7 @@ function validateTemplate(raw, options = {}) {
5150
5045
  say(fat, `"${f.label}" is a formula; write it in formula, naming fields in braces: {Total} - {Paid}.`);
5151
5046
  continue;
5152
5047
  }
5153
- const ast = parseFormula(f.formula);
5048
+ const ast = parseGateFormula(f.formula);
5154
5049
  if (typeof ast === "string") {
5155
5050
  say(fat, `The formula "${f.formula}" cannot be read: ${ast}.`);
5156
5051
  continue;