Restructure to skill-manager conventions
- Move the TypeScript project under scripts/ (src, tsconfig, package.json, pnpm lockfile/workspace, canonical .gitignore); drop the npm package-lock - Add scripts/Taskfile.yml aggregator plus .scripts modules (loggers, base, cli) with build, run, and validate tasks - Move the six SKILL-*.md docs into references/ with kebab names and extract the connector-routing sections from SKILL.md into references/routing-best-practices.md (SKILL.md 666 -> ~310 lines) - Add license/metadata/compatibility frontmatter, an Available scripts section, and update all CLI paths in README and references skill-manager validate: 13/13 passed, 0 warnings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* dom-polyfill.ts
|
||||
*
|
||||
* Sets up (or extends) the global DOM environment required by @maxgraph/core
|
||||
* when running in Node.js. Safe to import multiple times — idempotent.
|
||||
*
|
||||
* The parser (drawio-parser/parser.ts) already sets up a partial DOM polyfill
|
||||
* for the basic maxGraph model/serializer classes. This module extends it with
|
||||
* the additional globals needed by Graph+GraphView (rendering pipeline):
|
||||
* - location
|
||||
* - SVGElement, MouseEvent, KeyboardEvent, TouchEvent
|
||||
* - requestAnimationFrame / cancelAnimationFrame
|
||||
*
|
||||
* Must be imported before any maxGraph Graph/GraphView usage.
|
||||
*/
|
||||
|
||||
import { JSDOM } from "jsdom";
|
||||
|
||||
// Use the same DOM that may already be set up by parser.ts, or create a new one.
|
||||
// We detect by checking whether global.document already exists.
|
||||
let win: Record<string, unknown>;
|
||||
|
||||
if ((globalThis as Record<string, unknown>)["document"]) {
|
||||
// Parser already set up a DOM — re-use the existing window
|
||||
win = (globalThis as Record<string, unknown>)["window"] as Record<string, unknown>;
|
||||
} else {
|
||||
const dom = new JSDOM(
|
||||
'<!DOCTYPE html><html><body></body></html>',
|
||||
{ pretendToBeVisual: true }
|
||||
);
|
||||
win = dom.window as unknown as Record<string, unknown>;
|
||||
(globalThis as Record<string, unknown>)["document"] = win["document"];
|
||||
(globalThis as Record<string, unknown>)["window"] = win;
|
||||
(globalThis as Record<string, unknown>)["DOMParser"] = win["DOMParser"];
|
||||
(globalThis as Record<string, unknown>)["XMLSerializer"] = win["XMLSerializer"];
|
||||
(globalThis as Record<string, unknown>)["HTMLElement"] = win["HTMLElement"];
|
||||
(globalThis as Record<string, unknown>)["Element"] = win["Element"];
|
||||
(globalThis as Record<string, unknown>)["Node"] = win["Node"];
|
||||
(globalThis as Record<string, unknown>)["Event"] = win["Event"];
|
||||
try {
|
||||
Object.defineProperty(globalThis, "navigator", {
|
||||
value: win["navigator"],
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
} catch { /* already defined */ }
|
||||
}
|
||||
|
||||
// Add/overwrite globals needed specifically for Graph+GraphView rendering
|
||||
const g = globalThis as Record<string, unknown>;
|
||||
|
||||
if (!g["SVGElement"]) g["SVGElement"] = win["SVGElement"] ?? class SVGElement {};
|
||||
if (!g["MouseEvent"]) g["MouseEvent"] = win["MouseEvent"] ?? class MouseEvent {};
|
||||
if (!g["KeyboardEvent"]) g["KeyboardEvent"] = win["KeyboardEvent"] ?? class KeyboardEvent {};
|
||||
if (!g["TouchEvent"]) g["TouchEvent"] = win["TouchEvent"] ?? class TouchEvent {};
|
||||
if (!g["requestAnimationFrame"]) {
|
||||
g["requestAnimationFrame"] = (fn: () => void) => setTimeout(fn, 0);
|
||||
}
|
||||
if (!g["cancelAnimationFrame"]) {
|
||||
g["cancelAnimationFrame"] = clearTimeout;
|
||||
}
|
||||
// location is needed by UrlConverter (used when rendering image shapes)
|
||||
if (!g["location"]) {
|
||||
g["location"] = {
|
||||
protocol: "http:",
|
||||
host: "localhost",
|
||||
href: "http://localhost/",
|
||||
pathname: "/",
|
||||
};
|
||||
}
|
||||
|
||||
export {};
|
||||
Reference in New Issue
Block a user