// Copyright (c) 2026 Chris Pressey, Cat's Eye Technologies.
//
// SPDX-License-Identifier: LicenseRef-MIT-X-Jaft
import { describe, it, expect } from "vitest";
import { bless } from "concoctor";
import { concoctJaft as concoct } from "../src/jaftConcoctor.js";
describe("Concoct...", () => {
describe("concoct with ternary", () => {
it("should create function using ternary operator", () => {
const gt = bless((a, b) => a > b);
const neg = bless((a) => 0 - a);
const abs = concoct({ gt, neg }, "(x) => gt(x, 0) ? x : neg(x)");
expect(abs(5)).toBe(5);
expect(abs(-5)).toBe(5);
});
it("should handle nested ternary", () => {
const gt = bless((a, b) => a > b);
const neg = bless((a) => 0 - a);
const sign = concoct(
{ gt, neg },
"(x) => gt(x, 0) ? 1 : (gt(0, x) ? neg(1) : 0)",
);
expect(sign(5)).toBe(1);
expect(sign(0)).toBe(0);
expect(sign(-5)).toBe(-1);
});
});
describe("concoct with let", () => {
it("should create function using let expression", () => {
const add = bless((a, b) => a + b);
const mul = bless((a, b) => a * b);
const formula = concoct(
{ add, mul },
"(a, b) => let x = add(a, b); mul(x, x)",
);
expect(formula(3, 4)).toBe(49); // (3 + 4)^2 = 49
});
it("should handle multiple bindings in let", () => {
const add = bless((a, b) => a + b);
const mul = bless((a, b) => a * b);
const formula = concoct(
{ add, mul },
"(a, b) => let x = add(a, b), y = mul(a, b); add(x, y)",
);
expect(formula(3, 4)).toBe(19); // (3 + 4) + (3 * 4) = 7 + 12 = 19
});
it("should handle nested let expressions", () => {
const add = bless((a, b) => a + b);
const nested = concoct(
{ add },
"(a) => let x = add(a, 1); let y = add(x, 1); add(y, 1)",
);
expect(nested(5)).toBe(8); // 5 + 1 + 1 + 1 = 8
});
});
describe("concoct with const", () => {
it("should create function using const expression", () => {
const add = bless((a, b) => a + b);
const mul = bless((a, b) => a * b);
const formula = concoct(
{ add, mul },
"(a, b) => const x = add(a, b); mul(x, x)",
);
expect(formula(3, 4)).toBe(49); // (3 + 4)^2 = 49
});
});
});
describe("Binary operators", () => {
describe("concoct with binops", () => {
it("should create function using arithmetic operators", () => {
const formula = concoct({}, "(a, b, c) => a + b * c");
expect(formula(2, 3, 4)).toBe(14); // 2 + (3 * 4)
});
it("should create function using comparison and arithmetic", () => {
const compare = concoct({}, "(x, y) => x * 2 >= y + 10");
expect(compare(10, 5)).toBe(true); // 20 >= 15
expect(compare(5, 10)).toBe(false); // 10 >= 20
});
it("should handle division, modulo, and subtraction", () => {
const calc = concoct({}, "(a, b) => a / b + a % b - 1");
expect(calc(10, 2)).toBe(4); // 5 + 0 - 1 = 4
});
it("should support member access", () => {
const getLength = concoct({}, "(obj) => obj.length");
expect(getLength({ length: 5 })).toBe(5);
expect(getLength([1, 2, 3])).toBe(3);
});
it("should combine operators with ternary and let", () => {
const complex = concoct(
{},
"(x) => let y = x * 2; y >= 10 ? y + 1 : y - 1",
);
expect(complex(6)).toBe(13); // y=12, 12>=10, so 12+1
expect(complex(3)).toBe(5); // y=6, 6<10, so 6-1
});
it("should allow operators to replace blessed function calls", () => {
// Previously needed: bless((a,b) => a+b) and bless((a,b) => a*b)
const formula = concoct({}, "(a, b) => (a + 1) * (b + 1)");
expect(formula(2, 3)).toBe(12); // (2+1) * (3+1) = 3 * 4
});
it("should handle strict equality", () => {
const strictEq = concoct({}, "(a, b) => a === b");
expect(strictEq(5, 5)).toBe(true);
expect(strictEq(5, "5")).toBe(false);
});
});
});