From 9bc794598c082a4b9e29a046b188744622f8752a Mon Sep 17 00:00:00 2001 From: Aleksander Katan <56294622+aleksanderkatan@users.noreply.github.com> Date: Mon, 8 Jun 2026 17:31:38 +0200 Subject: [PATCH 1/9] Wrap prop names in "" --- packages/typegpu/tests/unplugin/autoname.test.ts | 2 +- packages/unplugin-typegpu/src/core/factory.ts | 2 +- packages/unplugin-typegpu/test/auto-naming.test.ts | 2 +- .../unplugin-typegpu/test/nested-externals.test.ts | 8 ++++---- .../unplugin-typegpu/test/tgsl-transpiling.test.ts | 6 +++--- .../unplugin-typegpu/test/use-gpu-directive.test.ts | 12 ++++++------ 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/typegpu/tests/unplugin/autoname.test.ts b/packages/typegpu/tests/unplugin/autoname.test.ts index c1350b31fa..740389b81a 100644 --- a/packages/typegpu/tests/unplugin/autoname.test.ts +++ b/packages/typegpu/tests/unplugin/autoname.test.ts @@ -207,7 +207,7 @@ describe('autonaming', () => { v: 2, name: undefined, ast: {"params":[],"body":[0,[[6,"myFun",[]]]],"externalNames":["myFun"]}, - externals: { myFun: () => myFun } + externals: { "myFun": () => myFun } }) && $.f)({}))), "main")); return main; }" diff --git a/packages/unplugin-typegpu/src/core/factory.ts b/packages/unplugin-typegpu/src/core/factory.ts index 9ecd354ef2..f8c893f24a 100644 --- a/packages/unplugin-typegpu/src/core/factory.ts +++ b/packages/unplugin-typegpu/src/core/factory.ts @@ -38,7 +38,7 @@ function externalsToString(externals: Externals | string): string { return `() => ${externals}`; } const entries = Object.entries(externals).map( - ([key, value]) => `${key}: ${externalsToString(value)}`, + ([key, value]) => `"${key}": ${externalsToString(value)}`, ); return `{ ${entries.join(', ')} }`; } diff --git a/packages/unplugin-typegpu/test/auto-naming.test.ts b/packages/unplugin-typegpu/test/auto-naming.test.ts index a01f7cae12..dc25531f4c 100644 --- a/packages/unplugin-typegpu/test/auto-naming.test.ts +++ b/packages/unplugin-typegpu/test/auto-naming.test.ts @@ -662,7 +662,7 @@ describe('[ROLLUP] auto naming', () => { v: 2, name: undefined, ast: {"params":[],"body":[0,[[10,[6,[7,"d","vec4f"],[]]]]],"externalNames":["d"]}, - externals: { d: { vec4f: () => d.vec4f } } + externals: { "d": { "vec4f": () => d.vec4f } } }) && $.f)({})), ), "myFragmentFn")); " diff --git a/packages/unplugin-typegpu/test/nested-externals.test.ts b/packages/unplugin-typegpu/test/nested-externals.test.ts index ddf40f7b91..5a6f1eb704 100644 --- a/packages/unplugin-typegpu/test/nested-externals.test.ts +++ b/packages/unplugin-typegpu/test/nested-externals.test.ts @@ -137,7 +137,7 @@ describe('externals gathering', () => { const code = codes['allows multiple usages of one external']; expect(extractExternals(await rollupTransform(code))).toMatchInlineSnapshot( - `"{ ext: { value: () => ext.value, config: { multiplier: () => ext.config.multiplier, zero: () => ext.config.zero } } }"`, + `"{ "ext": { "value": () => ext.value, "config": { "multiplier": () => ext.config.multiplier, "zero": () => ext.config.zero } } }"`, ); }); @@ -145,7 +145,7 @@ describe('externals gathering', () => { const code = codes['treats dereference like a regular external']; expect(extractExternals(await rollupTransform(code))).toMatchInlineSnapshot( - `"{ buffer: { $: { x: () => buffer.$.x } } }"`, + `"{ "buffer": { "$": { "x": () => buffer.$.x } } }"`, ); }); @@ -153,7 +153,7 @@ describe('externals gathering', () => { const code = codes['skips computed prop access']; expect(extractExternals(await rollupTransform(code))).toMatchInlineSnapshot( - `"{ ext: () => ext }"`, + `"{ "ext": () => ext }"`, ); }); @@ -161,7 +161,7 @@ describe('externals gathering', () => { const code = codes['skips calls']; expect(extractExternals(await rollupTransform(code))).toMatchInlineSnapshot( - `"{ ext: { comptime: () => ext.comptime, runtime: () => ext.runtime } }"`, + `"{ "ext": { "comptime": () => ext.comptime, "runtime": () => ext.runtime } }"`, ); }); }); diff --git a/packages/unplugin-typegpu/test/tgsl-transpiling.test.ts b/packages/unplugin-typegpu/test/tgsl-transpiling.test.ts index 22c81d4931..c7316a27fa 100644 --- a/packages/unplugin-typegpu/test/tgsl-transpiling.test.ts +++ b/packages/unplugin-typegpu/test/tgsl-transpiling.test.ts @@ -305,7 +305,7 @@ describe('[ROLLUP] plugin for transpiling tgsl functions to tinyest', () => { v: 2, name: undefined, ast: {"params":[{"type":"i","name":"input"}],"body":[0,[[13,"tmp",[7,[7,"counter","$"],"x"]],[2,[7,[7,"counter","$"],"x"],"=",[7,[7,"counter","$"],"y"]],[2,[7,[7,"counter","$"],"y"],"+=","tmp"],[2,[7,[7,"counter","$"],"z"],"+=",[6,[7,"d","f32"],[[7,[7,"input","num"],"x"]]]]]],"externalNames":["counter","d"]}, - externals: { counter: { $: { x: () => counter.$.x, y: () => counter.$.y, z: () => counter.$.z } }, d: { f32: () => d.f32 } } + externals: { "counter": { "$": { "x": () => counter.$.x, "y": () => counter.$.y, "z": () => counter.$.z } }, "d": { "f32": () => d.f32 } } }) && $.f)({}))); " `); @@ -353,7 +353,7 @@ describe('[ROLLUP] plugin for transpiling tgsl functions to tinyest', () => { v: 2, name: undefined, ast: {"params":[],"body":[0,[[10,"cx"]]],"externalNames":["cx"]}, - externals: { cx: () => cx } + externals: { "cx": () => cx } }) && $.f)({}))); tgpu.fn([])('() {}'); @@ -410,7 +410,7 @@ describe('[ROLLUP] plugin for transpiling tgsl functions to tinyest', () => { v: 2, name: undefined, ast: {"params":[],"body":[0,[[10,[7,[7,"this","myBuffer"],"$"]]]],"externalNames":["this"]}, - externals: { this: { myBuffer: { $: () => this.myBuffer.$ } } } + externals: { "this": { "myBuffer": { "$": () => this.myBuffer.$ } } } }) && $.f)({}))); } diff --git a/packages/unplugin-typegpu/test/use-gpu-directive.test.ts b/packages/unplugin-typegpu/test/use-gpu-directive.test.ts index 7916af8369..6fa053b12a 100644 --- a/packages/unplugin-typegpu/test/use-gpu-directive.test.ts +++ b/packages/unplugin-typegpu/test/use-gpu-directive.test.ts @@ -477,7 +477,7 @@ describe('marked object methods', () => { v: 2, name: "isPrime", ast: {"params":[{"type":"i","name":"n"}],"body":[0,[[11,[1,"n","<=",[5,"1"]],[0,[[10,false]]]],[14,[12,"i",[5,"2"]],[1,"i","<","n"],[102,"++","i"],[0,[[11,[1,[6,[7,"obj","mod"],["n","i"]],"===",[5,"0"]],[0,[[10,false]]]]]]],[10,true]]],"externalNames":["obj"]}, - externals: { obj: { mod: () => obj.mod } } + externals: { "obj": { "mod": () => obj.mod } } }) && $.f)({})); console.log(obj, isPrime); @@ -561,7 +561,7 @@ describe('transforms numeric operations', () => { v: 2, name: "main", ast: {"params":[{"type":"i","name":"a"},{"type":"i","name":"b"}],"body":[0,[[12,"c",[1,[1,"a","+","b"],"+",[5,"2"]]],[2,"c","+=",[1,[5,"2"],"*","b"]],[2,[7,"countMutable","$"],"+=",[5,"3"]]]],"externalNames":["countMutable"]}, - externals: { countMutable: { $: () => countMutable.$ } } + externals: { "countMutable": { "$": () => countMutable.$ } } }) && $.f)({})); console.log(main); @@ -998,7 +998,7 @@ describe('hoists function statements marked with "use gpu", scoped inside an if v: 2, name: "mul", ast: {"params":[{"type":"i","name":"a"},{"type":"i","name":"b"}],"body":[0,[[10,[1,[1,"a","*","b"],"*","c"]]]],"externalNames":["c"]}, - externals: { c: () => c } + externals: { "c": () => c } }) && $.f)({})); /** ADD */ @@ -1010,7 +1010,7 @@ describe('hoists function statements marked with "use gpu", scoped inside an if v: 2, name: "add", ast: {"params":[{"type":"i","name":"a"},{"type":"i","name":"b"}],"body":[0,[[10,[1,[1,"a","+","b"],"+","c"]]]],"externalNames":["c"]}, - externals: { c: () => c } + externals: { "c": () => c } }) && $.f)({})); console.log(add, mul); @@ -1131,7 +1131,7 @@ describe('replaces function statements marked with "use gpu" in place when condi v: 2, name: "add", ast: {"params":[{"type":"i","name":"a"},{"type":"i","name":"b"}],"body":[0,[[10,[1,[1,"a","+","b"],"+","c"]]]],"externalNames":["c"]}, - externals: { c: () => c } + externals: { "c": () => c } }) && $.f)({})); @@ -1146,7 +1146,7 @@ describe('replaces function statements marked with "use gpu" in place when condi v: 2, name: "mul", ast: {"params":[{"type":"i","name":"a"},{"type":"i","name":"b"}],"body":[0,[[10,[1,[1,"a","*","b"],"*","c"]]]],"externalNames":["c"]}, - externals: { c: () => c } + externals: { "c": () => c } }) && $.f)({})); From 2427b8720855a0307869b1ad0f78afd529986710 Mon Sep 17 00:00:00 2001 From: Aleksander Katan <56294622+aleksanderkatan@users.noreply.github.com> Date: Mon, 8 Jun 2026 17:41:12 +0200 Subject: [PATCH 2/9] Add private prop autonaming tests --- .../unplugin-typegpu/test/auto-naming.test.ts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/packages/unplugin-typegpu/test/auto-naming.test.ts b/packages/unplugin-typegpu/test/auto-naming.test.ts index dc25531f4c..f908cbbcdf 100644 --- a/packages/unplugin-typegpu/test/auto-naming.test.ts +++ b/packages/unplugin-typegpu/test/auto-naming.test.ts @@ -384,6 +384,20 @@ describe('[BABEL] auto naming', () => { `); }); + it('works with class private properties', () => { + const code = `\ + class Foo { + #const = tgpu.const(d.u32, 1); + } + `; + + expect(babelTransform(code, { autoNamingEnabled: true })).toMatchInlineSnapshot(` + "class Foo { + #const = tgpu.const(d.u32, 1); + }" + `); + }); + it('works with object properties', () => { const code = `\ import tgpu from 'typegpu'; @@ -875,6 +889,23 @@ describe('[ROLLUP] auto naming', () => { `); }); + it('works with class private properties', async () => { + const code = `\ + class Foo { + #const = tgpu.const(d.u32, 1); + } + console.log(Foo); + `; + + expect(await rollupTransform(code, { autoNamingEnabled: true })).toMatchInlineSnapshot(` + "class Foo { + #const = tgpu.const(d.u32, 1); + } + console.log(Foo); + " + `); + }); + it('works with object properties', async () => { const code = `\ import tgpu from 'typegpu'; From 25b87a6245bfd6306d794e753f7863bf6b4845f5 Mon Sep 17 00:00:00 2001 From: Aleksander Katan <56294622+aleksanderkatan@users.noreply.github.com> Date: Mon, 8 Jun 2026 17:53:22 +0200 Subject: [PATCH 3/9] Autoname private properties --- packages/unplugin-typegpu/src/core/common.ts | 17 +++++++- .../unplugin-typegpu/test/auto-naming.test.ts | 41 ++++++++++++++++++- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/packages/unplugin-typegpu/src/core/common.ts b/packages/unplugin-typegpu/src/core/common.ts index 833a0c481d..951a8a7f82 100644 --- a/packages/unplugin-typegpu/src/core/common.ts +++ b/packages/unplugin-typegpu/src/core/common.ts @@ -278,6 +278,15 @@ function extractLabelledExpression(path: NodePath): [string, NodePath]; + } else if ( + path.node.type === 'ClassPrivateProperty' && + path.node.value && + path.node.key.type === 'PrivateName' + ) { + // class Class { + // #key = value; + // } + return [path.node.key.id.name, path.get('value') as NodePath]; } } @@ -381,7 +390,7 @@ function tryFindIdentifier(node: t.Node): string | undefined { /** * Checks if `node` contains a label and a tgpu expression that could be named. - * If so, it calls the provided callback. Nodes selected for naming include: + * If so, it calls the provided callback. Nodes selected for naming include (but are not limited to): * * `let name = tgpu.bindGroupLayout({});` (VariableDeclarator) * @@ -498,6 +507,12 @@ export const functionVisitor: TraverseOptions = { ); }, + ClassPrivateProperty(path, state) { + performExpressionNaming(state, path, (pathToName, name) => + state.wrapInAutoName(pathToName, name), + ); + }, + AssignmentExpression: { exit(path, state) { const runtimeFn = operators[path.node.operator as keyof typeof operators]; diff --git a/packages/unplugin-typegpu/test/auto-naming.test.ts b/packages/unplugin-typegpu/test/auto-naming.test.ts index f908cbbcdf..1a1f062863 100644 --- a/packages/unplugin-typegpu/test/auto-naming.test.ts +++ b/packages/unplugin-typegpu/test/auto-naming.test.ts @@ -393,11 +393,29 @@ describe('[BABEL] auto naming', () => { expect(babelTransform(code, { autoNamingEnabled: true })).toMatchInlineSnapshot(` "class Foo { - #const = tgpu.const(d.u32, 1); + #const = /*#__PURE__*/(globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu.const(d.u32, 1), "const"); }" `); }); + it('works with anonymous classes', () => { + const code = `\ + const cls = new (class { + myConst = tgpu.const(d.u32, 0); + #const = tgpu.const(d.u32, 1); + })(); + console.log(cls); + `; + + expect(babelTransform(code, { autoNamingEnabled: true })).toMatchInlineSnapshot(` + "const cls = new class { + myConst = /*#__PURE__*/(globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu.const(d.u32, 0), "myConst"); + #const = /*#__PURE__*/(globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu.const(d.u32, 1), "const"); + }(); + console.log(cls);" + `); + }); + it('works with object properties', () => { const code = `\ import tgpu from 'typegpu'; @@ -899,13 +917,32 @@ describe('[ROLLUP] auto naming', () => { expect(await rollupTransform(code, { autoNamingEnabled: true })).toMatchInlineSnapshot(` "class Foo { - #const = tgpu.const(d.u32, 1); + #const = (/*#__PURE__*/(globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu.const(d.u32, 1), "const")); } console.log(Foo); " `); }); + it('works with anonymous classes', async () => { + const code = `\ + const cls = new (class { + myConst = tgpu.const(d.u32, 0); + #const = tgpu.const(d.u32, 1); + })(); + console.log(cls); + `; + + expect(await rollupTransform(code, { autoNamingEnabled: true })).toMatchInlineSnapshot(` + "const cls = new (class { + myConst = (/*#__PURE__*/(globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu.const(d.u32, 0), "myConst")); + #const = (/*#__PURE__*/(globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu.const(d.u32, 1), "const")); + })(); + console.log(cls); + " + `); + }); + it('works with object properties', async () => { const code = `\ import tgpu from 'typegpu'; From cc4e34ee34df3d89e537f0189abf5b6a82b2c2eb Mon Sep 17 00:00:00 2001 From: Aleksander Katan <56294622+aleksanderkatan@users.noreply.github.com> Date: Tue, 9 Jun 2026 10:16:35 +0200 Subject: [PATCH 4/9] Handle private property access --- packages/tinyest-for-wgsl/src/externals.ts | 7 +++- packages/tinyest-for-wgsl/src/parsers.ts | 8 ++++ .../tinyest-for-wgsl/tests/parsers.test.ts | 33 ++++++++++++++- .../typegpu/tests/externalPropAccess.test.ts | 40 ++++++++++++++++++ .../test/nested-externals.test.ts | 42 ++++++++++++++++++- 5 files changed, 127 insertions(+), 3 deletions(-) diff --git a/packages/tinyest-for-wgsl/src/externals.ts b/packages/tinyest-for-wgsl/src/externals.ts index d75fba1d94..f923bd3e42 100644 --- a/packages/tinyest-for-wgsl/src/externals.ts +++ b/packages/tinyest-for-wgsl/src/externals.ts @@ -16,9 +16,14 @@ function extractPropAccessChain(ancestorChain: JsNode[]): string[] { chain.push(current.name); } else if (current.type === 'ThisExpression') { chain.push('this'); - } else if (current.type === 'MemberExpression' && !current.computed) { + } else if (current.type === 'MemberExpression') { if (current.computed) { break; + } + if (current.property.type === 'PrivateName') { + chain.push(`#${current.property.id.name}`); + } else if (current.property.type === 'PrivateIdentifier') { + chain.push(`#${current.property.name}`); } else if (current.property.type === 'Identifier') { chain.push(current.property.name); } else { diff --git a/packages/tinyest-for-wgsl/src/parsers.ts b/packages/tinyest-for-wgsl/src/parsers.ts index 6ca5cdafab..7645939e35 100644 --- a/packages/tinyest-for-wgsl/src/parsers.ts +++ b/packages/tinyest-for-wgsl/src/parsers.ts @@ -112,6 +112,14 @@ const Transpilers: Partial<{ return [NODE.memberAccess, object, property]; }, + PrivateName(ctx, node) { + return `#${node.id.name}`; + }, + + PrivateIdentifier(ctx, node) { + return `#${node.name}`; + }, + UpdateExpression(ctx, node) { const operator = node.operator; const argument = transpile(ctx, node.argument) as tinyest.Expression; diff --git a/packages/tinyest-for-wgsl/tests/parsers.test.ts b/packages/tinyest-for-wgsl/tests/parsers.test.ts index 4f42ba9bed..1de826fdb8 100644 --- a/packages/tinyest-for-wgsl/tests/parsers.test.ts +++ b/packages/tinyest-for-wgsl/tests/parsers.test.ts @@ -1,5 +1,5 @@ import babel from '@babel/parser'; -import type { Node } from '@babel/types'; +import type { ClassDeclaration, ClassProperty, Expression, Node } from '@babel/types'; import * as acorn from 'acorn'; import { describe, expect, it } from 'vitest'; import { transpileFn } from '../src/parsers.ts'; @@ -258,4 +258,35 @@ describe('transpileFn', () => { `); }), ); + + it( + 'handles property access via private name', + dualTest((p) => { + // `this.#v` is only valid inside a class body, so we parse a class and pluck out the arrow function. + const tree = p(` + class Foo { + #v = 0; + fn = () => { + const k = this.#v; + }; + } + `) as ClassDeclaration | acorn.Program; + const cls = (tree.type === 'Program' ? tree.body[0] : tree) as + | ClassDeclaration + | acorn.ClassDeclaration; + const props = cls.body.body; + const lastProp = props.at(-1) as ClassProperty | acorn.PropertyDefinition; + const fn = lastProp.value as Expression | acorn.Expression; + + const { externalNames } = transpileFn(fn); + + expect(externalNames).toMatchInlineSnapshot(` + { + "this": { + "#v": "this.#v", + }, + } + `); + }), + ); }); diff --git a/packages/typegpu/tests/externalPropAccess.test.ts b/packages/typegpu/tests/externalPropAccess.test.ts index 8eb2a35651..391a51be6b 100644 --- a/packages/typegpu/tests/externalPropAccess.test.ts +++ b/packages/typegpu/tests/externalPropAccess.test.ts @@ -107,4 +107,44 @@ describe('external prop access', () => { }" `); }); + + it('supports private property access', () => { + class Cls { + #const = tgpu.const(d.u32, 1); + + fn = () => { + 'use gpu'; + const a = this.#const.$; + }; + } + + const cls = new Cls(); + + expect(tgpu.resolve([cls.fn])).toMatchInlineSnapshot(` + "const const_1: u32 = 1u; + + fn fn_1() { + const a = const_1; + }" + `); + }); + + it('supports private property access in anonymous class', () => { + const cls = new (class { + #const = tgpu.const(d.u32, 1); + + fn = () => { + 'use gpu'; + const a = this.#const.$; + }; + })(); + + expect(tgpu.resolve([cls.fn])).toMatchInlineSnapshot(` + "const const_1: u32 = 1u; + + fn fn_1() { + const a = const_1; + }" + `); + }); }); diff --git a/packages/unplugin-typegpu/test/nested-externals.test.ts b/packages/unplugin-typegpu/test/nested-externals.test.ts index 5a6f1eb704..0299b3fdf5 100644 --- a/packages/unplugin-typegpu/test/nested-externals.test.ts +++ b/packages/unplugin-typegpu/test/nested-externals.test.ts @@ -73,7 +73,25 @@ const codes = { }; console.log(fn);`, - // TODO(#2591): private access test + 'allows for private access': `\ + import tgpu, { d } from 'typegpu'; + + const cls = new (class { + #const; + + constructor() { + this.#const = tgpu.const(d.u32, 1); + } + + get fn() { + return () => { + 'use gpu'; + const a = this.#const.$; + }; + } + })(); + + console.log(cls);`, }; describe('externals gathering', () => { @@ -130,6 +148,20 @@ describe('externals gathering', () => { }" `); }); + + it('allows for private access', () => { + const code = codes['allows for private access']; + + expect(extractExternals(babelTransform(code))).toMatchInlineSnapshot(` + "{ + this: { + #const: { + $: () => this.#const.$ + } + } + }" + `); + }); }); describe('ROLLUP', () => { @@ -164,5 +196,13 @@ describe('externals gathering', () => { `"{ "ext": { "comptime": () => ext.comptime, "runtime": () => ext.runtime } }"`, ); }); + + it('allows for private access', async () => { + const code = codes['allows for private access']; + + expect(extractExternals(await rollupTransform(code))).toMatchInlineSnapshot( + `"{ "this": { "#const": { "$": () => this.#const.$ } } }"`, + ); + }); }); }); From 203e37c0c83d247749cfb98f8e45ffd039a6e414 Mon Sep 17 00:00:00 2001 From: Aleksander Katan <56294622+aleksanderkatan@users.noreply.github.com> Date: Tue, 9 Jun 2026 10:26:35 +0200 Subject: [PATCH 5/9] Wrap prop names in "" in babel --- packages/unplugin-typegpu/src/babel.ts | 2 +- .../unplugin-typegpu/test/auto-naming.test.ts | 4 +-- .../test/nested-externals.test.ts | 30 +++++++++---------- .../test/tgsl-transpiling.test.ts | 22 +++++++------- .../test/use-gpu-directive.test.ts | 16 +++++----- 5 files changed, 37 insertions(+), 37 deletions(-) diff --git a/packages/unplugin-typegpu/src/babel.ts b/packages/unplugin-typegpu/src/babel.ts index f4dbef3c9a..6f19de582e 100644 --- a/packages/unplugin-typegpu/src/babel.ts +++ b/packages/unplugin-typegpu/src/babel.ts @@ -31,7 +31,7 @@ function externalsToNode(externals: Externals | string): t.Expression { } return t.objectExpression( Object.entries(externals).map(([name, value]) => - t.objectProperty(i(name), externalsToNode(value), false), + t.objectProperty(t.stringLiteral(name), externalsToNode(value), false), ), ); } diff --git a/packages/unplugin-typegpu/test/auto-naming.test.ts b/packages/unplugin-typegpu/test/auto-naming.test.ts index 1a1f062863..6570d6ee30 100644 --- a/packages/unplugin-typegpu/test/auto-naming.test.ts +++ b/packages/unplugin-typegpu/test/auto-naming.test.ts @@ -179,8 +179,8 @@ describe('[BABEL] auto naming', () => { externalNames: ["d"] }, externals: { - d: { - vec4f: () => d.vec4f + "d": { + "vec4f": () => d.vec4f } } }) && $.f)({})), "myFragmentFn");" diff --git a/packages/unplugin-typegpu/test/nested-externals.test.ts b/packages/unplugin-typegpu/test/nested-externals.test.ts index 0299b3fdf5..e3661962c4 100644 --- a/packages/unplugin-typegpu/test/nested-externals.test.ts +++ b/packages/unplugin-typegpu/test/nested-externals.test.ts @@ -101,11 +101,11 @@ describe('externals gathering', () => { expect(extractExternals(babelTransform(code))).toMatchInlineSnapshot(` "{ - ext: { - value: () => ext.value, - config: { - multiplier: () => ext.config.multiplier, - zero: () => ext.config.zero + "ext": { + "value": () => ext.value, + "config": { + "multiplier": () => ext.config.multiplier, + "zero": () => ext.config.zero } } }" @@ -117,9 +117,9 @@ describe('externals gathering', () => { expect(extractExternals(babelTransform(code))).toMatchInlineSnapshot(` "{ - buffer: { - $: { - x: () => buffer.$.x + "buffer": { + "$": { + "x": () => buffer.$.x } } }" @@ -131,7 +131,7 @@ describe('externals gathering', () => { expect(extractExternals(babelTransform(code))).toMatchInlineSnapshot(` "{ - ext: () => ext + "ext": () => ext }" `); }); @@ -141,9 +141,9 @@ describe('externals gathering', () => { expect(extractExternals(babelTransform(code))).toMatchInlineSnapshot(` "{ - ext: { - comptime: () => ext.comptime, - runtime: () => ext.runtime + "ext": { + "comptime": () => ext.comptime, + "runtime": () => ext.runtime } }" `); @@ -154,9 +154,9 @@ describe('externals gathering', () => { expect(extractExternals(babelTransform(code))).toMatchInlineSnapshot(` "{ - this: { - #const: { - $: () => this.#const.$ + "this": { + "#const": { + "$": () => this.#const.$ } } }" diff --git a/packages/unplugin-typegpu/test/tgsl-transpiling.test.ts b/packages/unplugin-typegpu/test/tgsl-transpiling.test.ts index c7316a27fa..128498c10e 100644 --- a/packages/unplugin-typegpu/test/tgsl-transpiling.test.ts +++ b/packages/unplugin-typegpu/test/tgsl-transpiling.test.ts @@ -48,15 +48,15 @@ describe('[BABEL] plugin for transpiling tgsl functions to tinyest', () => { externalNames: ["counter", "d"] }, externals: { - counter: { - $: { - x: () => counter.$.x, - y: () => counter.$.y, - z: () => counter.$.z + "counter": { + "$": { + "x": () => counter.$.x, + "y": () => counter.$.y, + "z": () => counter.$.z } }, - d: { - f32: () => d.f32 + "d": { + "f32": () => d.f32 } } }) && $.f)({}));" @@ -122,7 +122,7 @@ describe('[BABEL] plugin for transpiling tgsl functions to tinyest', () => { externalNames: ["cx"] }, externals: { - cx: () => cx + "cx": () => cx } }) && $.f)({})); const d = tgpu.fn([])('() {}');" @@ -252,9 +252,9 @@ describe('[BABEL] plugin for transpiling tgsl functions to tinyest', () => { externalNames: ["this"] }, externals: { - this: { - myBuffer: { - $: () => this.myBuffer.$ + "this": { + "myBuffer": { + "$": () => this.myBuffer.$ } } } diff --git a/packages/unplugin-typegpu/test/use-gpu-directive.test.ts b/packages/unplugin-typegpu/test/use-gpu-directive.test.ts index 6fa053b12a..640879b387 100644 --- a/packages/unplugin-typegpu/test/use-gpu-directive.test.ts +++ b/packages/unplugin-typegpu/test/use-gpu-directive.test.ts @@ -436,8 +436,8 @@ describe('marked object methods', () => { externalNames: ["obj"] }, externals: { - obj: { - mod: () => obj.mod + "obj": { + "mod": () => obj.mod } } }) && $.f)({}); @@ -534,8 +534,8 @@ describe('transforms numeric operations', () => { externalNames: ["countMutable"] }, externals: { - countMutable: { - $: () => countMutable.$ + "countMutable": { + "$": () => countMutable.$ } } }) && $.f)({}); @@ -953,7 +953,7 @@ describe('hoists function statements marked with "use gpu", scoped inside an if externalNames: ["c"] }, externals: { - c: () => c + "c": () => c } }) && $.f)({}); /** ADD */ @@ -977,7 +977,7 @@ describe('hoists function statements marked with "use gpu", scoped inside an if externalNames: ["c"] }, externals: { - c: () => c + "c": () => c } }) && $.f)({}); console.log(add, mul); @@ -1081,7 +1081,7 @@ describe('replaces function statements marked with "use gpu" in place when condi externalNames: ["c"] }, externals: { - c: () => c + "c": () => c } }) && $.f)({}); break; @@ -1107,7 +1107,7 @@ describe('replaces function statements marked with "use gpu" in place when condi externalNames: ["c"] }, externals: { - c: () => c + "c": () => c } }) && $.f)({}); break; From d6808caea6da48c540f92ac5a1e149ed0655d94f Mon Sep 17 00:00:00 2001 From: Aleksander Katan <56294622+aleksanderkatan@users.noreply.github.com> Date: Tue, 9 Jun 2026 10:37:59 +0200 Subject: [PATCH 6/9] Only wrap when necessary --- packages/unplugin-typegpu/src/babel.ts | 7 +++- packages/unplugin-typegpu/src/core/common.ts | 7 ++++ packages/unplugin-typegpu/src/core/factory.ts | 3 +- .../unplugin-typegpu/test/auto-naming.test.ts | 6 +-- .../test/nested-externals.test.ts | 38 +++++++++---------- .../test/tgsl-transpiling.test.ts | 28 +++++++------- .../test/use-gpu-directive.test.ts | 28 +++++++------- 7 files changed, 65 insertions(+), 52 deletions(-) diff --git a/packages/unplugin-typegpu/src/babel.ts b/packages/unplugin-typegpu/src/babel.ts index 6f19de582e..3c3a3e608e 100644 --- a/packages/unplugin-typegpu/src/babel.ts +++ b/packages/unplugin-typegpu/src/babel.ts @@ -10,6 +10,7 @@ import { getBlockScope, initPluginState, makeAstBackwardsCompatible, + requiresQuotation, } from './core/common.ts'; import { createFilterForId } from './core/filter.ts'; @@ -31,7 +32,11 @@ function externalsToNode(externals: Externals | string): t.Expression { } return t.objectExpression( Object.entries(externals).map(([name, value]) => - t.objectProperty(t.stringLiteral(name), externalsToNode(value), false), + t.objectProperty( + requiresQuotation(name) ? t.stringLiteral(name) : i(name), + externalsToNode(value), + false, + ), ), ); } diff --git a/packages/unplugin-typegpu/src/core/common.ts b/packages/unplugin-typegpu/src/core/common.ts index 951a8a7f82..c49c34d30e 100644 --- a/packages/unplugin-typegpu/src/core/common.ts +++ b/packages/unplugin-typegpu/src/core/common.ts @@ -388,6 +388,13 @@ function tryFindIdentifier(node: t.Node): string | undefined { } } +/** + * Checks if the given prop in externals needs to be wrapped in "" + */ +export function requiresQuotation(prop: string): boolean { + return prop.startsWith('#'); +} + /** * Checks if `node` contains a label and a tgpu expression that could be named. * If so, it calls the provided callback. Nodes selected for naming include (but are not limited to): diff --git a/packages/unplugin-typegpu/src/core/factory.ts b/packages/unplugin-typegpu/src/core/factory.ts index f8c893f24a..3547ec5447 100644 --- a/packages/unplugin-typegpu/src/core/factory.ts +++ b/packages/unplugin-typegpu/src/core/factory.ts @@ -14,6 +14,7 @@ import { getBlockScope, METADATA_FORMAT_VERSION, makeAstBackwardsCompatible, + requiresQuotation, } from './common.ts'; import type { Options, UnpluginPluginState, MetadatableFunction, NodeLocation } from './common.ts'; @@ -38,7 +39,7 @@ function externalsToString(externals: Externals | string): string { return `() => ${externals}`; } const entries = Object.entries(externals).map( - ([key, value]) => `"${key}": ${externalsToString(value)}`, + ([key, value]) => `${requiresQuotation(key) ? `"${key}"` : key}: ${externalsToString(value)}`, ); return `{ ${entries.join(', ')} }`; } diff --git a/packages/unplugin-typegpu/test/auto-naming.test.ts b/packages/unplugin-typegpu/test/auto-naming.test.ts index 6570d6ee30..16f5c356b2 100644 --- a/packages/unplugin-typegpu/test/auto-naming.test.ts +++ b/packages/unplugin-typegpu/test/auto-naming.test.ts @@ -179,8 +179,8 @@ describe('[BABEL] auto naming', () => { externalNames: ["d"] }, externals: { - "d": { - "vec4f": () => d.vec4f + d: { + vec4f: () => d.vec4f } } }) && $.f)({})), "myFragmentFn");" @@ -694,7 +694,7 @@ describe('[ROLLUP] auto naming', () => { v: 2, name: undefined, ast: {"params":[],"body":[0,[[10,[6,[7,"d","vec4f"],[]]]]],"externalNames":["d"]}, - externals: { "d": { "vec4f": () => d.vec4f } } + externals: { d: { vec4f: () => d.vec4f } } }) && $.f)({})), ), "myFragmentFn")); " diff --git a/packages/unplugin-typegpu/test/nested-externals.test.ts b/packages/unplugin-typegpu/test/nested-externals.test.ts index e3661962c4..1b24cb13e4 100644 --- a/packages/unplugin-typegpu/test/nested-externals.test.ts +++ b/packages/unplugin-typegpu/test/nested-externals.test.ts @@ -101,11 +101,11 @@ describe('externals gathering', () => { expect(extractExternals(babelTransform(code))).toMatchInlineSnapshot(` "{ - "ext": { - "value": () => ext.value, - "config": { - "multiplier": () => ext.config.multiplier, - "zero": () => ext.config.zero + ext: { + value: () => ext.value, + config: { + multiplier: () => ext.config.multiplier, + zero: () => ext.config.zero } } }" @@ -117,9 +117,9 @@ describe('externals gathering', () => { expect(extractExternals(babelTransform(code))).toMatchInlineSnapshot(` "{ - "buffer": { - "$": { - "x": () => buffer.$.x + buffer: { + $: { + x: () => buffer.$.x } } }" @@ -131,7 +131,7 @@ describe('externals gathering', () => { expect(extractExternals(babelTransform(code))).toMatchInlineSnapshot(` "{ - "ext": () => ext + ext: () => ext }" `); }); @@ -141,9 +141,9 @@ describe('externals gathering', () => { expect(extractExternals(babelTransform(code))).toMatchInlineSnapshot(` "{ - "ext": { - "comptime": () => ext.comptime, - "runtime": () => ext.runtime + ext: { + comptime: () => ext.comptime, + runtime: () => ext.runtime } }" `); @@ -154,9 +154,9 @@ describe('externals gathering', () => { expect(extractExternals(babelTransform(code))).toMatchInlineSnapshot(` "{ - "this": { + this: { "#const": { - "$": () => this.#const.$ + $: () => this.#const.$ } } }" @@ -169,7 +169,7 @@ describe('externals gathering', () => { const code = codes['allows multiple usages of one external']; expect(extractExternals(await rollupTransform(code))).toMatchInlineSnapshot( - `"{ "ext": { "value": () => ext.value, "config": { "multiplier": () => ext.config.multiplier, "zero": () => ext.config.zero } } }"`, + `"{ ext: { value: () => ext.value, config: { multiplier: () => ext.config.multiplier, zero: () => ext.config.zero } } }"`, ); }); @@ -177,7 +177,7 @@ describe('externals gathering', () => { const code = codes['treats dereference like a regular external']; expect(extractExternals(await rollupTransform(code))).toMatchInlineSnapshot( - `"{ "buffer": { "$": { "x": () => buffer.$.x } } }"`, + `"{ buffer: { $: { x: () => buffer.$.x } } }"`, ); }); @@ -185,7 +185,7 @@ describe('externals gathering', () => { const code = codes['skips computed prop access']; expect(extractExternals(await rollupTransform(code))).toMatchInlineSnapshot( - `"{ "ext": () => ext }"`, + `"{ ext: () => ext }"`, ); }); @@ -193,7 +193,7 @@ describe('externals gathering', () => { const code = codes['skips calls']; expect(extractExternals(await rollupTransform(code))).toMatchInlineSnapshot( - `"{ "ext": { "comptime": () => ext.comptime, "runtime": () => ext.runtime } }"`, + `"{ ext: { comptime: () => ext.comptime, runtime: () => ext.runtime } }"`, ); }); @@ -201,7 +201,7 @@ describe('externals gathering', () => { const code = codes['allows for private access']; expect(extractExternals(await rollupTransform(code))).toMatchInlineSnapshot( - `"{ "this": { "#const": { "$": () => this.#const.$ } } }"`, + `"{ this: { "#const": { $: () => this.#const.$ } } }"`, ); }); }); diff --git a/packages/unplugin-typegpu/test/tgsl-transpiling.test.ts b/packages/unplugin-typegpu/test/tgsl-transpiling.test.ts index 128498c10e..22c81d4931 100644 --- a/packages/unplugin-typegpu/test/tgsl-transpiling.test.ts +++ b/packages/unplugin-typegpu/test/tgsl-transpiling.test.ts @@ -48,15 +48,15 @@ describe('[BABEL] plugin for transpiling tgsl functions to tinyest', () => { externalNames: ["counter", "d"] }, externals: { - "counter": { - "$": { - "x": () => counter.$.x, - "y": () => counter.$.y, - "z": () => counter.$.z + counter: { + $: { + x: () => counter.$.x, + y: () => counter.$.y, + z: () => counter.$.z } }, - "d": { - "f32": () => d.f32 + d: { + f32: () => d.f32 } } }) && $.f)({}));" @@ -122,7 +122,7 @@ describe('[BABEL] plugin for transpiling tgsl functions to tinyest', () => { externalNames: ["cx"] }, externals: { - "cx": () => cx + cx: () => cx } }) && $.f)({})); const d = tgpu.fn([])('() {}');" @@ -252,9 +252,9 @@ describe('[BABEL] plugin for transpiling tgsl functions to tinyest', () => { externalNames: ["this"] }, externals: { - "this": { - "myBuffer": { - "$": () => this.myBuffer.$ + this: { + myBuffer: { + $: () => this.myBuffer.$ } } } @@ -305,7 +305,7 @@ describe('[ROLLUP] plugin for transpiling tgsl functions to tinyest', () => { v: 2, name: undefined, ast: {"params":[{"type":"i","name":"input"}],"body":[0,[[13,"tmp",[7,[7,"counter","$"],"x"]],[2,[7,[7,"counter","$"],"x"],"=",[7,[7,"counter","$"],"y"]],[2,[7,[7,"counter","$"],"y"],"+=","tmp"],[2,[7,[7,"counter","$"],"z"],"+=",[6,[7,"d","f32"],[[7,[7,"input","num"],"x"]]]]]],"externalNames":["counter","d"]}, - externals: { "counter": { "$": { "x": () => counter.$.x, "y": () => counter.$.y, "z": () => counter.$.z } }, "d": { "f32": () => d.f32 } } + externals: { counter: { $: { x: () => counter.$.x, y: () => counter.$.y, z: () => counter.$.z } }, d: { f32: () => d.f32 } } }) && $.f)({}))); " `); @@ -353,7 +353,7 @@ describe('[ROLLUP] plugin for transpiling tgsl functions to tinyest', () => { v: 2, name: undefined, ast: {"params":[],"body":[0,[[10,"cx"]]],"externalNames":["cx"]}, - externals: { "cx": () => cx } + externals: { cx: () => cx } }) && $.f)({}))); tgpu.fn([])('() {}'); @@ -410,7 +410,7 @@ describe('[ROLLUP] plugin for transpiling tgsl functions to tinyest', () => { v: 2, name: undefined, ast: {"params":[],"body":[0,[[10,[7,[7,"this","myBuffer"],"$"]]]],"externalNames":["this"]}, - externals: { "this": { "myBuffer": { "$": () => this.myBuffer.$ } } } + externals: { this: { myBuffer: { $: () => this.myBuffer.$ } } } }) && $.f)({}))); } diff --git a/packages/unplugin-typegpu/test/use-gpu-directive.test.ts b/packages/unplugin-typegpu/test/use-gpu-directive.test.ts index 640879b387..7916af8369 100644 --- a/packages/unplugin-typegpu/test/use-gpu-directive.test.ts +++ b/packages/unplugin-typegpu/test/use-gpu-directive.test.ts @@ -436,8 +436,8 @@ describe('marked object methods', () => { externalNames: ["obj"] }, externals: { - "obj": { - "mod": () => obj.mod + obj: { + mod: () => obj.mod } } }) && $.f)({}); @@ -477,7 +477,7 @@ describe('marked object methods', () => { v: 2, name: "isPrime", ast: {"params":[{"type":"i","name":"n"}],"body":[0,[[11,[1,"n","<=",[5,"1"]],[0,[[10,false]]]],[14,[12,"i",[5,"2"]],[1,"i","<","n"],[102,"++","i"],[0,[[11,[1,[6,[7,"obj","mod"],["n","i"]],"===",[5,"0"]],[0,[[10,false]]]]]]],[10,true]]],"externalNames":["obj"]}, - externals: { "obj": { "mod": () => obj.mod } } + externals: { obj: { mod: () => obj.mod } } }) && $.f)({})); console.log(obj, isPrime); @@ -534,8 +534,8 @@ describe('transforms numeric operations', () => { externalNames: ["countMutable"] }, externals: { - "countMutable": { - "$": () => countMutable.$ + countMutable: { + $: () => countMutable.$ } } }) && $.f)({}); @@ -561,7 +561,7 @@ describe('transforms numeric operations', () => { v: 2, name: "main", ast: {"params":[{"type":"i","name":"a"},{"type":"i","name":"b"}],"body":[0,[[12,"c",[1,[1,"a","+","b"],"+",[5,"2"]]],[2,"c","+=",[1,[5,"2"],"*","b"]],[2,[7,"countMutable","$"],"+=",[5,"3"]]]],"externalNames":["countMutable"]}, - externals: { "countMutable": { "$": () => countMutable.$ } } + externals: { countMutable: { $: () => countMutable.$ } } }) && $.f)({})); console.log(main); @@ -953,7 +953,7 @@ describe('hoists function statements marked with "use gpu", scoped inside an if externalNames: ["c"] }, externals: { - "c": () => c + c: () => c } }) && $.f)({}); /** ADD */ @@ -977,7 +977,7 @@ describe('hoists function statements marked with "use gpu", scoped inside an if externalNames: ["c"] }, externals: { - "c": () => c + c: () => c } }) && $.f)({}); console.log(add, mul); @@ -998,7 +998,7 @@ describe('hoists function statements marked with "use gpu", scoped inside an if v: 2, name: "mul", ast: {"params":[{"type":"i","name":"a"},{"type":"i","name":"b"}],"body":[0,[[10,[1,[1,"a","*","b"],"*","c"]]]],"externalNames":["c"]}, - externals: { "c": () => c } + externals: { c: () => c } }) && $.f)({})); /** ADD */ @@ -1010,7 +1010,7 @@ describe('hoists function statements marked with "use gpu", scoped inside an if v: 2, name: "add", ast: {"params":[{"type":"i","name":"a"},{"type":"i","name":"b"}],"body":[0,[[10,[1,[1,"a","+","b"],"+","c"]]]],"externalNames":["c"]}, - externals: { "c": () => c } + externals: { c: () => c } }) && $.f)({})); console.log(add, mul); @@ -1081,7 +1081,7 @@ describe('replaces function statements marked with "use gpu" in place when condi externalNames: ["c"] }, externals: { - "c": () => c + c: () => c } }) && $.f)({}); break; @@ -1107,7 +1107,7 @@ describe('replaces function statements marked with "use gpu" in place when condi externalNames: ["c"] }, externals: { - "c": () => c + c: () => c } }) && $.f)({}); break; @@ -1131,7 +1131,7 @@ describe('replaces function statements marked with "use gpu" in place when condi v: 2, name: "add", ast: {"params":[{"type":"i","name":"a"},{"type":"i","name":"b"}],"body":[0,[[10,[1,[1,"a","+","b"],"+","c"]]]],"externalNames":["c"]}, - externals: { "c": () => c } + externals: { c: () => c } }) && $.f)({})); @@ -1146,7 +1146,7 @@ describe('replaces function statements marked with "use gpu" in place when condi v: 2, name: "mul", ast: {"params":[{"type":"i","name":"a"},{"type":"i","name":"b"}],"body":[0,[[10,[1,[1,"a","*","b"],"*","c"]]]],"externalNames":["c"]}, - externals: { "c": () => c } + externals: { c: () => c } }) && $.f)({})); From 1c36feb9379c260b4d1f2153de4da29451c56573 Mon Sep 17 00:00:00 2001 From: Aleksander Katan <56294622+aleksanderkatan@users.noreply.github.com> Date: Tue, 9 Jun 2026 11:59:13 +0200 Subject: [PATCH 7/9] Update tests --- .../tinyest-for-wgsl/tests/parsers.test.ts | 2 +- .../typegpu/tests/externalPropAccess.test.ts | 19 ++++++++++++++ .../typegpu/tests/unplugin/autoname.test.ts | 2 +- .../unplugin-typegpu/test/auto-naming.test.ts | 19 ++++++++++++++ .../test/nested-externals.test.ts | 26 +++++++------------ 5 files changed, 50 insertions(+), 18 deletions(-) diff --git a/packages/tinyest-for-wgsl/tests/parsers.test.ts b/packages/tinyest-for-wgsl/tests/parsers.test.ts index 1de826fdb8..2dd4a57c38 100644 --- a/packages/tinyest-for-wgsl/tests/parsers.test.ts +++ b/packages/tinyest-for-wgsl/tests/parsers.test.ts @@ -260,7 +260,7 @@ describe('transpileFn', () => { ); it( - 'handles property access via private name', + 'handles private property access', dualTest((p) => { // `this.#v` is only valid inside a class body, so we parse a class and pluck out the arrow function. const tree = p(` diff --git a/packages/typegpu/tests/externalPropAccess.test.ts b/packages/typegpu/tests/externalPropAccess.test.ts index 391a51be6b..bfd90d74b3 100644 --- a/packages/typegpu/tests/externalPropAccess.test.ts +++ b/packages/typegpu/tests/externalPropAccess.test.ts @@ -147,4 +147,23 @@ describe('external prop access', () => { }" `); }); + + it('supports props containing #', () => { + const cls = new (class { + '#const' = tgpu.const(d.u32, 0); + + fn = () => { + 'use gpu'; + const a = this['#const'].$; + }; + })(); + + expect(tgpu.resolve([cls.fn])).toMatchInlineSnapshot(` + "const item: u32 = 0u; + + fn fn_1() { + const a = item; + }" + `); + }); }); diff --git a/packages/typegpu/tests/unplugin/autoname.test.ts b/packages/typegpu/tests/unplugin/autoname.test.ts index 740389b81a..c1350b31fa 100644 --- a/packages/typegpu/tests/unplugin/autoname.test.ts +++ b/packages/typegpu/tests/unplugin/autoname.test.ts @@ -207,7 +207,7 @@ describe('autonaming', () => { v: 2, name: undefined, ast: {"params":[],"body":[0,[[6,"myFun",[]]]],"externalNames":["myFun"]}, - externals: { "myFun": () => myFun } + externals: { myFun: () => myFun } }) && $.f)({}))), "main")); return main; }" diff --git a/packages/unplugin-typegpu/test/auto-naming.test.ts b/packages/unplugin-typegpu/test/auto-naming.test.ts index 16f5c356b2..07ad8ef741 100644 --- a/packages/unplugin-typegpu/test/auto-naming.test.ts +++ b/packages/unplugin-typegpu/test/auto-naming.test.ts @@ -388,12 +388,21 @@ describe('[BABEL] auto naming', () => { const code = `\ class Foo { #const = tgpu.const(d.u32, 1); + #buff; + + constructor() { + this.#buff = root.createUniform(d.u32); + } } `; expect(babelTransform(code, { autoNamingEnabled: true })).toMatchInlineSnapshot(` "class Foo { #const = /*#__PURE__*/(globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu.const(d.u32, 1), "const"); + #buff; + constructor() { + this.#buff = /*#__PURE__*/(globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(root.createUniform(d.u32), "buff"); + } }" `); }); @@ -911,6 +920,11 @@ describe('[ROLLUP] auto naming', () => { const code = `\ class Foo { #const = tgpu.const(d.u32, 1); + #buff; + + constructor() { + this.#buff = root.createUniform(d.u32); + } } console.log(Foo); `; @@ -918,6 +932,11 @@ describe('[ROLLUP] auto naming', () => { expect(await rollupTransform(code, { autoNamingEnabled: true })).toMatchInlineSnapshot(` "class Foo { #const = (/*#__PURE__*/(globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu.const(d.u32, 1), "const")); + #buff; + + constructor() { + this.#buff = (/*#__PURE__*/(globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(root.createUniform(d.u32), "buff")); + } } console.log(Foo); " diff --git a/packages/unplugin-typegpu/test/nested-externals.test.ts b/packages/unplugin-typegpu/test/nested-externals.test.ts index 1b24cb13e4..1d14c21717 100644 --- a/packages/unplugin-typegpu/test/nested-externals.test.ts +++ b/packages/unplugin-typegpu/test/nested-externals.test.ts @@ -77,18 +77,12 @@ const codes = { import tgpu, { d } from 'typegpu'; const cls = new (class { - #const; + #const = tgpu.const(d.u32, 1); - constructor() { - this.#const = tgpu.const(d.u32, 1); - } - - get fn() { - return () => { - 'use gpu'; - const a = this.#const.$; - }; - } + fn = () => { + 'use gpu'; + const a = this.#const.$; + }; })(); console.log(cls);`, @@ -154,12 +148,12 @@ describe('externals gathering', () => { expect(extractExternals(babelTransform(code))).toMatchInlineSnapshot(` "{ - this: { - "#const": { - $: () => this.#const.$ - } + this: { + "#const": { + $: () => this.#const.$ } - }" + } + }" `); }); }); From a1d7d129b4dc09c59de951c5162e93bf935281b9 Mon Sep 17 00:00:00 2001 From: Aleksander Katan <56294622+aleksanderkatan@users.noreply.github.com> Date: Tue, 9 Jun 2026 12:04:00 +0200 Subject: [PATCH 8/9] Stop linting private property --- .../eslint-plugin/src/rules/noUnsupportedSyntax.ts | 7 ------- .../tests/rules/noUnsupportedSyntax.test.ts | 10 +--------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/packages/eslint-plugin/src/rules/noUnsupportedSyntax.ts b/packages/eslint-plugin/src/rules/noUnsupportedSyntax.ts index 6397524c34..00773ef0d4 100644 --- a/packages/eslint-plugin/src/rules/noUnsupportedSyntax.ts +++ b/packages/eslint-plugin/src/rules/noUnsupportedSyntax.ts @@ -140,13 +140,6 @@ export const noUnsupportedSyntax = createRule({ report(node, `'new' expression`); }, - PrivateIdentifier(node) { - if (!directives.getEnclosingTypegpuFunction()) { - return; - } - report(node, 'private identifier'); - }, - Property(node) { if (!directives.getEnclosingTypegpuFunction()) { return; diff --git a/packages/eslint-plugin/tests/rules/noUnsupportedSyntax.test.ts b/packages/eslint-plugin/tests/rules/noUnsupportedSyntax.test.ts index c808e702d0..bcadaa993b 100644 --- a/packages/eslint-plugin/tests/rules/noUnsupportedSyntax.test.ts +++ b/packages/eslint-plugin/tests/rules/noUnsupportedSyntax.test.ts @@ -8,6 +8,7 @@ describe('noUnsupportedSyntax', () => { "const fn = () => { 'use gpu'; const x = 1; }", "const fn = () => { 'use gpu'; const x = Struct({ prop: 1}); }", "const fn = () => { 'use gpu'; let x = 1; }", + "const fn = () => { 'use gpu'; obj.#buffer.$ = 1; }", ], invalid: [ { @@ -209,15 +210,6 @@ describe('noUnsupportedSyntax', () => { }, ], }, - { - code: "const fn = () => { 'use gpu'; obj.#buffer.$ = 1; }", - errors: [ - { - messageId: 'unexpected', - data: { snippet: '#buffer', syntax: 'private identifier' }, - }, - ], - }, { code: "const fn = () => { 'use gpu'; const obj = { [key]: 1 }; }", errors: [ From c3b2b63b4f29cdd4a9f7db17b2b27dfd5a85e8e6 Mon Sep 17 00:00:00 2001 From: Aleksander Katan <56294622+aleksanderkatan@users.noreply.github.com> Date: Tue, 9 Jun 2026 12:58:03 +0200 Subject: [PATCH 9/9] Review fix --- packages/eslint-plugin/tests/rules/noUnsupportedSyntax.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/tests/rules/noUnsupportedSyntax.test.ts b/packages/eslint-plugin/tests/rules/noUnsupportedSyntax.test.ts index bcadaa993b..1e04b7d909 100644 --- a/packages/eslint-plugin/tests/rules/noUnsupportedSyntax.test.ts +++ b/packages/eslint-plugin/tests/rules/noUnsupportedSyntax.test.ts @@ -8,7 +8,7 @@ describe('noUnsupportedSyntax', () => { "const fn = () => { 'use gpu'; const x = 1; }", "const fn = () => { 'use gpu'; const x = Struct({ prop: 1}); }", "const fn = () => { 'use gpu'; let x = 1; }", - "const fn = () => { 'use gpu'; obj.#buffer.$ = 1; }", + "const cls = new (class { #priv = 1; fn = () => { 'use gpu'; const a = this.#priv; } } )()", ], invalid: [ {