unplugin-typegpu
Version:
Build plugins for TypeGPU, enabling seamless JavaScript -> WGSL transpilation and improved debugging.
135 lines (132 loc) • 6.09 kB
JavaScript
import { a as getBlockScope, i as functionVisitor, n as defaultOptions, o as initPluginState, t as METADATA_FORMAT_VERSION } from "./common-CK7zOjbK.js";
import defu from "defu";
import { transpileFn } from "tinyest-for-wgsl";
import * as t from "@babel/types";
import { resolve } from "pathe";
import picomatch from "picomatch";
//#region src/core/filter.ts
function toArray(array) {
const result = array || [];
if (Array.isArray(result)) return result;
return [result];
}
const BACKSLASH_REGEX = /\\/g;
function normalize(path) {
return path.replace(BACKSLASH_REGEX, "/");
}
const ABSOLUTE_PATH_REGEX = /^(?:\/|(?:[A-Z]:)?[/\\|])/i;
function isAbsolute(path) {
return ABSOLUTE_PATH_REGEX.test(path);
}
function getMatcherString(glob, cwd) {
if (glob.startsWith("**") || isAbsolute(glob)) return normalize(glob);
return normalize(resolve(cwd, glob));
}
function patternToIdFilter(pattern) {
if (pattern instanceof RegExp) return (id) => {
const normalizedId = normalize(id);
const result = pattern.test(normalizedId);
pattern.lastIndex = 0;
return result;
};
const matcher = picomatch(getMatcherString(pattern, process.cwd()), { dot: true });
return (id) => {
return matcher(normalize(id));
};
}
function createFilter(exclude, include) {
if (!exclude && !include) return;
return (input) => {
if (exclude === null || exclude === void 0 ? void 0 : exclude.some((filter) => filter(input))) return false;
if (include === null || include === void 0 ? void 0 : include.some((filter) => filter(input))) return true;
return !(include && include.length > 0);
};
}
function normalizeFilter(filter) {
if (typeof filter === "string" || filter instanceof RegExp) return { include: [filter] };
if (Array.isArray(filter)) return { include: filter };
return {
exclude: filter.exclude ? toArray(filter.exclude) : void 0,
include: filter.include ? toArray(filter.include) : void 0
};
}
function createIdFilter(filter) {
if (!filter) return;
const { exclude, include } = normalizeFilter(filter);
return createFilter(exclude === null || exclude === void 0 ? void 0 : exclude.map(patternToIdFilter), include === null || include === void 0 ? void 0 : include.map(patternToIdFilter));
}
function createFilterForId(filter) {
const filterFunction = createIdFilter(filter);
return filterFunction ? (id) => !!filterFunction(id) : void 0;
}
//#endregion
//#region src/babel.ts
function i(identifier) {
return t.identifier(identifier);
}
function assignMetadata(path, name, ast) {
const metadata = t.objectExpression([
t.objectProperty(i("v"), t.numericLiteral(METADATA_FORMAT_VERSION)),
t.objectProperty(i("name"), t.valueToNode(name)),
t.objectProperty(i("ast"), t.valueToNode(ast)),
t.objectProperty(i("externals"), t.arrowFunctionExpression([], t.blockStatement([t.returnStatement(t.objectExpression(ast.externalNames.map((name$1) => name$1 === "this" ? t.objectProperty(i("this"), t.thisExpression()) : t.objectProperty(i(name$1), i(name$1), false, name$1 !== "this"))))])))
]);
let expression;
const visibility = t.isFunctionDeclaration(path.node) ? getBlockScope(path) : void 0;
if (t.isFunctionDeclaration(path.node)) expression = t.functionExpression(path.node.id, path.node.params, path.node.body);
else expression = path.node;
const callExpr = t.callExpression(t.arrowFunctionExpression([i("$")], t.logicalExpression("&&", t.callExpression(t.memberExpression(t.assignmentExpression("??=", t.memberExpression(i("globalThis"), i("__TYPEGPU_META__")), t.newExpression(i("WeakMap"), [])), i("set")), [t.assignmentExpression("=", t.memberExpression(i("$"), i("f")), expression), metadata]), t.memberExpression(i("$"), i("f")))), [t.objectExpression([])]);
t.addComment(callExpr, "leading", "#__PURE__");
let replacement = callExpr;
if (t.isFunctionDeclaration(path.node) && path.node.id) {
const declaration = t.variableDeclaration("const", [t.variableDeclarator(path.node.id, callExpr)]);
t.inheritLeadingComments(declaration, path.node);
if (path.parentPath && (path.parentPath.isExportNamedDeclaration() || path.parentPath.isExportDefaultDeclaration())) {
t.inheritLeadingComments(declaration, path.parentPath.node);
path.parentPath.node.leadingComments = null;
}
replacement = declaration;
}
if (visibility) {
visibility.unshiftContainer("body", replacement);
this.alreadyTransformed.add(expression);
const id = t.isFunctionDeclaration(path.node) ? path.node.id : void 0;
if (id && path.parentPath.isExportNamedDeclaration()) path.parentPath.replaceWith(t.exportNamedDeclaration(null, [t.exportSpecifier(t.cloneNode(id), t.cloneNode(id))]));
else if (id && path.parentPath.isExportDefaultDeclaration()) path.parentPath.replaceWith(t.exportDefaultDeclaration(t.cloneNode(id)));
else path.remove();
} else path.replaceWith(replacement);
path.skip();
}
function wrapInAutoName(path, name) {
const callExpr = t.callExpression(t.logicalExpression("??", t.memberExpression(i("globalThis"), i("__TYPEGPU_AUTONAME__")), t.arrowFunctionExpression([i("a")], i("a"))), [path.node, t.stringLiteral(name)]);
t.addComment(callExpr, "leading", "#__PURE__");
path.replaceWith(callExpr);
}
function replaceWithAssignmentOverload(path, runtimeFn) {
path.replaceWith(t.assignmentExpression("=", path.node.left, t.callExpression(i(runtimeFn), [path.node.left, path.node.right])));
}
function replaceWithBinaryOverload(path, runtimeFn) {
path.replaceWith(t.callExpression(i(runtimeFn), [path.node.left, path.node.right]));
}
function TypeGPUPlugin() {
return {
name: "typegpu",
pre() {
this.opts = defu(this.opts, defaultOptions);
initPluginState(this, {
warn: (message) => console.warn(message),
assignMetadata,
wrapInAutoName,
replaceWithAssignmentOverload,
replaceWithBinaryOverload
});
},
visitor: { Program(path, state) {
const filter = createFilterForId(state.opts);
if (state.filename && filter && !(filter === null || filter === void 0 ? void 0 : filter(state.filename))) return;
path.traverse(functionVisitor, state);
} }
};
}
//#endregion
export { TypeGPUPlugin as t };