react-code-canvas
Version:
A browser-based canvas for rendering React components at runtime
58 lines (57 loc) • 2.71 kB
TypeScript
export type IssueType = "empty" | "syntax" | "transform" | "compile" | "import-statement" | "unknown-identifier" | "no-default-export";
export type CodeIssue = {
type: IssueType;
message: string;
/** identifier name, for unknown-identifier */
name?: string;
line?: number;
column?: number;
};
export type AnalysisResult = {
/** false when any issue would stop the code rendering in the canvas */
valid: boolean;
issues: CodeIssue[];
/** globals the code relies on that the scope does provide */
referencedGlobals: string[];
/** globals the code relies on that nothing provides -- these throw at runtime */
unknownGlobals: string[];
hasDefaultExport: boolean;
};
export type AnalyzeOptions = {
/** scope the code will run against. Omit to check against what the canvas
* itself would load for this code (base scope plus the lucide/recharts/motion
* names it references). Passing one replaces that entirely. */
scope?: Record<string, unknown>;
/** extra names to treat as available (host-injected globals, etc.) */
allowedGlobals?: string[];
/** treat `import` statements as an issue. Default true -- the canvas strips
* them, so imported bindings resolve to undefined at runtime. */
forbidImports?: boolean;
};
/**
* Statically check whether a code string can render in the canvas -- no DOM and
* no React rendering required, so it is safe to run in Node (CI, migrations,
* batch audits).
*
* Runs the same stages the canvas does, stopping short of execution:
* 1. parse (Babel) -- for the AST used by the scope checks below
* 2. transform (sucrase) -- the actual transpiler the canvas uses
* 3. compile (`new Function`, constructed but never called)
*
* Catches the failures that matter in practice:
* - syntax errors (the code never parses)
* - transform errors from sucrase specifically
* - compile errors, notably redeclaring an injected global such as
* `const useState = 1`, which is valid standalone JS but a duplicate
* declaration once scope entries become function parameters
* - references to names nothing provides, in both expression and JSX position
* -- a runtime ReferenceError that transpiling alone never reveals, and the
* usual symptom of code written against a different scope than it now runs
* against
* - code that compiles but produces no component (no default export, no
* `render(...)` call), which renders blank
*
* It does NOT execute the code, so it cannot catch logic errors or anything
* that only fails once mounted.
*/
export declare function analyzeReactCode(code: string, options?: AnalyzeOptions): Promise<AnalysisResult>;