UNPKG

@sheetxl/scripting

Version:

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

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