diff --git a/packages/base-formula/src/functions/coercion.ts b/packages/base-formula/src/functions/coercion.ts new file mode 100644 index 000000000..64a7ad5c6 --- /dev/null +++ b/packages/base-formula/src/functions/coercion.ts @@ -0,0 +1,17 @@ +// packages/base-formula/src/functions/coercion.ts +import { register } from "./registry"; + +register({ + name: "toNumber", arity: { min: 1, max: 1 }, paramTypes: "any", returnType: "number", + eval: ([v]) => { + if (v == null) return null; + const n = Number(v); + return Number.isFinite(n) ? n : null; + }, + doc: "Parses the value as a number, or null.", category: "coercion", +}); +register({ + name: "toString", arity: { min: 1, max: 1 }, paramTypes: "any", returnType: "string", + eval: ([v]) => v == null ? "" : String(v), + doc: "Converts the value to a string.", category: "coercion", +}); diff --git a/packages/base-formula/src/functions/string.ts b/packages/base-formula/src/functions/string.ts new file mode 100644 index 000000000..05f68a2d4 --- /dev/null +++ b/packages/base-formula/src/functions/string.ts @@ -0,0 +1,35 @@ +// packages/base-formula/src/functions/string.ts +import { register } from "./registry"; + +const s = (v: unknown): string => v == null ? "" : String(v); + +register({ + name: "concat", arity: { min: 1, max: null }, paramTypes: "variadic-any", returnType: "string", + eval: (args) => args.map(s).join(""), + doc: "Concatenates strings.", category: "string", +}); +register({ + name: "length", arity: { min: 1, max: 1 }, paramTypes: ["string"], returnType: "number", + eval: ([v]) => s(v).length, + doc: "Length of a string.", category: "string", +}); +register({ + name: "contains", arity: { min: 2, max: 2 }, paramTypes: ["string", "string"], returnType: "boolean", + eval: ([a, b]) => s(a).includes(s(b)), + doc: "Returns true if the first string contains the second.", category: "string", +}); +register({ + name: "lower", arity: { min: 1, max: 1 }, paramTypes: ["string"], returnType: "string", + eval: ([v]) => s(v).toLowerCase(), + doc: "Lowercases the string.", category: "string", +}); +register({ + name: "upper", arity: { min: 1, max: 1 }, paramTypes: ["string"], returnType: "string", + eval: ([v]) => s(v).toUpperCase(), + doc: "Uppercases the string.", category: "string", +}); +register({ + name: "trim", arity: { min: 1, max: 1 }, paramTypes: ["string"], returnType: "string", + eval: ([v]) => s(v).trim(), + doc: "Strips whitespace from both ends.", category: "string", +});