UNPKG

@sheetxl/scripting

Version:

Scripting - Scripting engine for Macros and formulas; includes TypeScript and EsBuild.

267 lines (266 loc) 13.5 kB
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 };