@sheetxl/scripting
Version:
Scripting - Scripting engine for Macros and formulas; includes TypeScript and EsBuild.
267 lines (266 loc) • 13.5 kB
JavaScript
import { ScalarType as F } from "@sheetxl/primitives";
import { CommonUtils as le } from "@sheetxl/utils";
/**
* @license @sheetxl/scripting - Scripting - Scripting engine for Macros and formulas; includes TypeScript and EsBuild. - v0.7.27
*
* (C) 2025-present SheetXL Inc. & Michael T. Ford
* License: The license can be found at https://www.sheetxl.com/license.
*/
let L = null, B = null;
const se = { compilerOptions: { target: "esnext" } };
async function ce(h, x, S = "/script.js", w = "__SHEETXL") {
try {
const $ = await (async function() {
if (L) return L;
if (B) {
if (await B, !L) throw new Error("ESBuild initialization promise resolved, but instance is not available.");
return L;
}
let p, b;
B = new Promise((o, T) => {
p = o, b = T;
});
try {
const { initialize: o } = await import("./BeDi9Rjq6Mj_zC_O.mjs");
return L = await o(), p(), L;
} catch (o) {
throw console.error("Failed to import or initialize esbuild:", o), B = null, b(o), o;
}
})(), I = "@sheetxl/primitives", n = `
export const FormulaContext = globalThis.${w}?.FormulaContext;
export const ScalarType = globalThis.${w}?.ScalarType;
export const Observable = globalThis.${w}?.Observable;
export const IRange = globalThis.${w}?.IRange;
export const FormulaError = globalThis.${w}?.FormulaError;
// Add more exports as needed
`, C = { name: "sheetxl-esbuild-in-memory", setup(p) {
const b = "sheetxl-" + (/* @__PURE__ */ new Date()).getTime();
p.onResolve({ filter: new RegExp(`^(${S.replace("/", "\\/")}|${I})$`) }, (o) => ({ path: o.path, namespace: b })), p.onResolve({ filter: /.*/ }, (o) => {
if (o.namespace !== b) return console.warn(`esbuild: Treating import "${o.path}" as external.`), { path: o.path, external: !0 };
}), p.onLoad({ filter: /.*/, namespace: b }, (o) => {
let T;
if (o.path === S) T = x;
else {
if (o.path !== I) return { errors: [{ text: `Cannot load unknown path in ${b}: ${o.path}` }] };
T = n;
}
return { contents: T, loader: "ts" };
});
} }, y = await $.build({ entryPoints: [S], bundle: !0, write: !1, format: "esm", plugins: [C], sourcemap: "inline", tsconfigRaw: se, minify: !0, platform: "neutral" });
if (y.outputFiles && y.outputFiles.length > 0) return y.outputFiles[0].text;
throw y.errors && y.errors.length > 0 ? new Error(`esbuild bundling failed: ${y.errors.map((p) => p.text).join(`
`)}`) : new Error("esbuild did not produce an output file.");
} catch ($) {
throw console.error("esbuild bundling process failed:", $), $;
}
}
const de = async () => `
interface FirstTest {
isTrue?: boolean;
}
`, ee = /* @__PURE__ */ new Map([["IReferenceRange", "r"], ["IRange", "l"]]), te = /* @__PURE__ */ new Map([["IWorkbook", "workbook"], ["ISheet", "sheet"], ["ICellRanges", "ranges"], ["ICellRange", "range"], ["IFormulaContext", "context"]]), X = (h, x) => {
Array.from(x.keys()).forEach((S) => {
const w = x.get(S);
x.set(`${h}.${S}`, w);
});
}, ue = /* @__PURE__ */ new Map([["Scalar", "*"], ["FormulaError.Known", F.Error], ["Date", "Date"], ["JSON", "JSON"]]), pe = /* @__PURE__ */ new Map([]), _ = "SheetXL";
X(_, ee), X(_, te), X(_, pe);
const me = /* @__PURE__ */ new Map([["Promise", () => ({ async: !0 })], ["Observable", () => ({ stream: !0 })]]);
let J = null;
async function fe() {
if (J) return J;
try {
return await (await import("./C9oTtQ5kcPvveo9r.mjs")).initialize();
} catch (h) {
throw J = null, h;
} finally {
J = null;
}
}
async function he(h) {
const x = h?.source ?? null;
if (!x) return null;
const S = (h.disableBundle || h.declarationsOnly) ?? !1, w = [de(), fe()], $ = await Promise.all(w), I = $[0], n = $[1];
let C = "", y = null;
const p = [], b = { allowJs: !0, declaration: !1, sourceMap: !1, inlineSourceMap: !1, inlineSources: !1, isolatedModules: !0, preserveConstEnums: !1, module: 99, noResolve: !0, emitDeclarationOnly: !1, target: n.ScriptTarget.ES2020 }, o = "script", T = `${o}.ts`, H = "lib.d.ts", W = "global.d.ts", R = { [T]: x, [H]: `
/**
* Represents the completion of an asynchronous operation
*/
interface Promise<T> {
/**
* Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The
* resolved value cannot be modified from the callback.
* @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected).
* @returns A Promise for the completion of the callback.
*/
finally(onfinally?: (() => void) | undefined | null): Promise<T>;
}
`, [W]: I }, ne = { getSourceFile: (e, t, u, m) => n.createSourceFile(e, R[e], n.ScriptTarget.Latest, !0), fileExists: (e) => R[e] !== void 0, readFile: (e) => R[e], writeFile: (e, t) => {
R[e] = t;
}, getCurrentDirectory: () => "./", getCanonicalFileName: (e) => e, useCaseSensitiveFileNames: () => !0, getDefaultLibFileName: (e) => H, getNewLine: () => `
` }, U = n.createProgram([T, W], b, ne), O = U.getTypeChecker(), re = U.getSourceFile(T), G = U.emit();
G.diagnostics.length > 0 && console.warn(G.diagnostics), C = R[`${o}.js`];
const P = (e, t, u, m) => {
if (e) {
if (e.kind === n.SyntaxKind.NumberKeyword) t.scalar = F.Number;
else if (e.kind === n.SyntaxKind.StringKeyword) t.scalar = F.String;
else if (e.kind === n.SyntaxKind.BooleanKeyword) t.scalar = F.Boolean;
else if (e.kind === n.SyntaxKind.UndefinedKeyword || e.kind === n.SyntaxKind.NullKeyword || e.kind === n.SyntaxKind.VoidKeyword) {
if (m) return void k(e, new Error(`'undefined' is not a valid type for input: '${e?.parent?.name?.escapedText}'.`));
t.scalar = F.Null;
} else if (e.kind === n.SyntaxKind.BigIntKeyword) t.scalar = F.Number;
else if (e.kind === n.SyntaxKind.AnyKeyword) t.scalar = F.Null;
else if (e.kind === n.SyntaxKind.ArrayType) {
const a = e.elementType;
if (!a) return void k(e, new Error(`'Array' must be typed: '${e?.parent?.name?.escapedText}'.`));
t.arrayDepth = (t.arrayDepth ?? 0) + 1, P(a, t, u, m);
} else if (e.kind !== n.SyntaxKind.TupleType) {
if (e.kind === n.SyntaxKind.TypeReference) {
const a = e.typeName?.getText?.() ?? null, M = ee.get(a);
let E = !1;
M && (t.range = M, E = !0);
const D = ue.get(a);
if (D && (t.scalar = D), D !== void 0 && (E = !0), m) {
const r = te.get(a);
if (r) return r;
} else {
const r = me.get(a);
if (r) {
const l = { ...t, ...r() };
let g = 0;
if (l.async && g++, l.stream && g++, g > 1) return void k(e, new Error(`'${a}' cannot have multiple modifiers: '${e?.parent?.name?.escapedText}'.`));
t = l, E = !0;
}
}
if (!E) return void k("node", new Error(`'${a}' is not a valid type: '${e?.parent?.name?.escapedText}'.`));
const c = e.typeArguments;
if (c) {
if (c.length !== 1) return void k(e, new Error(`'${a}' must be typed with exactly 1 type: '${e?.parent?.name?.escapedText}'.`));
P(c[0], t, u, m);
}
}
}
} else k(e, new Error(`Type is not defined for '${t?.name ?? "return"}'.`));
}, z = [], k = (e, t) => {
z.push(t);
};
if (n.forEachChild(re, (e) => {
if (((t) => (n.getCombinedModifierFlags(t) & n.ModifierFlags.Export) !== 0)(e) && n.isFunctionDeclaration(e)) {
const t = {}, u = { parameters: {} }, m = e?.name?.getText();
try {
t.name = m;
const a = O.getSymbolAtLocation(e.name).getDocumentationComment(O);
if (a && a.length > 0 && a[0].text) {
let c = a[0].text;
c = c.replace(/[\r\n]+/g, "\\n").trim(), u.summary = c;
}
const M = {};
P(e.type, M, t, !1), t.returnType = M;
const E = {};
((c) => (n.getCombinedModifierFlags(c) & n.ModifierFlags.Default) !== 0)(e) && (E.default = !0, y = m), Object.keys(E).length > 0 && (t.behavior = E), t.parameters = [];
const D = /* @__PURE__ */ new Map();
for (let c = 0; c < e.parameters.length; c++) {
const r = e.parameters[c], l = {};
l.name = r.name?.getText();
const g = P(r.type, l, t, !0);
if (g) {
if (t.parameters.length !== 0) {
const s = e?.parent, i = s?.name?.getText();
return void k(e, new Error(`'${t.name}' contexts must be the first parameter: '${i}'.`));
}
t.context = g;
continue;
}
let j;
if ((r.initializer !== void 0 && r.initializer !== null || r.questionToken !== void 0 && r.questionToken !== null) && (l.optional = !0, r.initializer)) try {
j = r.initializer.kind === n.SyntaxKind.StringLiteral ? r.initializer.text : r.initializer.kind === n.SyntaxKind.NumericLiteral ? parseFloat(r.initializer.text) : r.initializer.kind === n.SyntaxKind.TrueKeyword || r.initializer.kind === n.SyntaxKind.FalseKeyword ? r.initializer.kind === n.SyntaxKind.TrueKeyword : r.initializer.kind === n.SyntaxKind.NullKeyword ? null : r.initializer.kind === n.SyntaxKind.ObjectLiteralExpression || r.initializer.kind === n.SyntaxKind.ArrayLiteralExpression ? r.initializer.getText() : r.initializer.getText?.();
} catch (s) {
console.warn(`Couldn't extract default value for parameter '${l.name}'`, s);
}
r.dotDotDotToken && (l.rest = !0), t.parameters.push(l);
const v = { description: "" };
u.parameters[l.name] = v;
const f = O.getSymbolAtLocation(r.name).getDocumentationComment(O);
f && f.length > 0 && f[0].text && (v.description = f[0].text), j !== void 0 && (v.defaultValue = j), D.set(l.name, l);
}
if (e.jsDoc && e.jsDoc.length > 0) {
const c = e.jsDoc, r = c.length;
for (let l = 0; l < r; l++) {
const g = c[l]?.tags;
if (!g) continue;
const j = g.length;
for (let v = 0; v < j; v++) {
const f = g[v];
let s = f?.tagName?.text;
if (!s) continue;
s = s.toLowerCase();
let i = f.comment;
const Y = s === "hidden";
if ((typeof i == "string" || Y) && (typeof i == "string" && (i = i.replace(/[\r\n]+/g, "\\n").trim()), Y || !i || (i = i.split(/\\n/)[0], i && i.length !== 0))) {
if (i && typeof i == "string") {
const d = /\{@link(code|plain)?\s+([^}|]+)(?:\s*\|\s*([^}]+))?\}/g;
let K, N = i, A = [];
for (; (K = d.exec(i)) !== null; ) {
const [V, q, oe, Z] = K, ae = [oe.trim()];
Z && ae.push(Z.trim());
}
i = N, A.length > 0 && s === "see" && (u.links || (u.links = []), u.links.push(...A));
}
if (s === "name") {
const d = i;
d !== m && (u.name = d);
} else if (s !== "description") {
if (s === "summary") {
const d = i;
d && (u.summary = d);
} else if (s === "param") {
const d = f.name?.text, K = D.get(d);
if (!K) {
z.push(new Error(`Parameter '${d}' not found in function '${m}'.`));
continue;
}
if (f.typeExpression && f.typeExpression.type) try {
const N = f.typeExpression.type;
if (N.kind === n.SyntaxKind.UnionType) {
const A = [];
K.enums = A, N.types.forEach((V) => {
if (V.kind === n.SyntaxKind.LiteralType) {
const q = V.literal.text;
q && A.push(q);
}
});
}
} catch (N) {
console.warn("Error parsing JSDoc type expression:", N);
}
} else if (s === "returns" || s === "return") t.returnType.description = i;
else if (s === "category") u.category = i;
else if (s === "hidden") {
let d = !0;
const K = i?.toLowerCase();
K === "false" ? d = !1 : K !== "true" && (d = i), d !== !1 && (u.hidden = d ?? !0);
}
}
}
}
}
}
Object.keys(t.returnType).length === 0 && delete t.returnType, p.push([t, u]);
} catch (a) {
k(e, new Error(`'${m}': ${a.message}`));
}
}
}), z.length > 0) throw console.warn(z), new Error("There were compilation errors.", { cause: z });
if (p.length === 0) throw new Error("No exported functions.");
const ie = `${le.uuidV4()}-script`;
try {
S || z.length !== 0 || (C = await ce(0, C, o));
} catch {
console.warn("Error bundling script");
}
const Q = { functions: p, commitId: ie, source: x, name: "Script", language: "typescript", compiled: C };
return y && (Q.autoRun = y), Q;
}
export {
he as compileModule
};