joist-orm icon indicating copy to clipboard operation
joist-orm copied to clipboard

Add esbuild compatible transformer

Open stephenh opened this issue 9 months ago • 1 comments

Given the ~50% speedup from getter-izing relations, it'd be nice to have tsx/esbuild support for the transformer.

Or maybe the @accessor decorator does this for us eventually.

stephenh avatar Apr 08 '25 16:04 stephenh

Maybe something like:

const fs = require("fs/promises");
const path = require("path");

module.exports = {
  name: "fast-joist-rewrite",
  setup(build) {
    build.onLoad({ filter: /\.ts$/ }, async (args) => {
      let source = await fs.readFile(args.path, "utf8");

      let didTransform = false;
      const lines = source.split("\n");
      const transformedLines = [];

      for (const line of lines) {
        const match = line.match(/^\s*(\w+)\s*:\s*(Reactive|Async(Property|Method)|Collection|Reference)<.*>\s*=\s*(.+);$/);
        if (match) {
          didTransform = true;
          const [_, name, _type, __, initializer] = match;

          transformedLines.push(
            `get ${name}() {`,
            `  return this.__data.relations.${name} ??= (setCurrentlyInstantiatingEntity(this), ${initializer});`,
            `}`,
          );
        } else {
          transformedLines.push(line);
        }
      }

      if (didTransform) {
        const importLine = `import { setCurrentlyInstantiatingEntity } from "joist-orm";`;
        // Naively inject after existing imports
        const firstNonImport = transformedLines.findIndex(line => !line.startsWith("import"));
        transformedLines.splice(firstNonImport, 0, importLine);
      }

      return {
        contents: transformedLines.join("\n"),
        loader: "ts",
      };
    });
  }
};
TSX_ESBUILD_PLUGIN=./fast-joist-rewrite-plugin.js tsx some-entity.ts

stephenh avatar Apr 08 '25 16:04 stephenh