UNPKG

unplugin-typegpu

Version:

Build plugins for TypeGPU, enabling seamless JavaScript -> WGSL transpilation and improved debugging.

135 lines (132 loc) 6.09 kB
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 };