ethercalc
Version:
Multi-User Spreadsheet Server — TypeScript rewrite (Cloudflare fullstack)
60 lines (47 loc) • 2.18 kB
JavaScript
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const input = path.join(__dirname, '../node_modules/socialcalc/dist/SocialCalc.js');
const output = path.join(__dirname, '../src/socialcalc.bundled.ts'); // Save as TS so it resolves correctly in vitest
let src = fs.readFileSync(input, 'utf8');
// SocialCalc 2.3.0 from github:audreyt/socialcalc is strict-mode clean and
// already has `factory.call(root, root)` (transform #3 from AGENTS.md §16.A).
// The remaining transforms are the two DOM shim redirects:
// (1) route document.createElement through our ShimNode namespace
// (2) silence alert() on error paths
// Plus one wrapper-level rewrite so our host-binding IIFE still captures root:
// (3) neutralize the UMD's `globalThis` fallback so `root === this === host`
// and `window === host` inside the factory — otherwise workerd's real
// async setTimeout leaks in and recalc never unrolls synchronously.
src = src.replace(/document\.createElement\(/g, 'SocialCalc.document.createElement(');
src = src.replace(/alert\(/g, '(function(){})(');
src = src.replace(
"typeof globalThis !== 'undefined' ? globalThis : this",
"this",
);
const wrapped = `// @ts-nocheck
// Generated by scripts/build.js from audreyt/socialcalc. Do not hand-edit.
import { ShimNode } from './dom-shim';
export function createSocialCalcFactory() {
const host = {
setTimeout: function(cb) { cb(); return 0; },
clearTimeout: function() {}
};
let SocialCalc;
(function() {
var navigator = { language: "", userAgent: "" };
// Force the UMD's Node branch so nothing lands on the real
// globalThis.SocialCalc. define stays undefined so AMD is also skipped.
var module = { exports: {} };
var define = undefined;
${src}
SocialCalc = module.exports;
}).call(host);
SocialCalc.document = SocialCalc.document || {};
SocialCalc.document.createElement = function (tag) { return new ShimNode(tag); };
return SocialCalc;
}
`;
fs.writeFileSync(output, wrapped);
console.log('Generated socialcalc.bundled.ts');