feat: Private property access#2594
Conversation
|
pkg.pr.new packages benchmark commit |
Bundle size comparison (
|
| 🟢 Decreased | ➖ Unchanged | 🔴 Increased | ❔ Unknown |
|---|---|---|---|
| 0 | 320 | 0 | 0 |
import { ... } in PR vs import * as ... in PR (is the library tree-Shakeable?):
Click to reveal the results table (297 entries).
| Test | tsdown |
|---|---|
| d_Void.ts | 87.65 kB ( |
| d_sampler.ts | 87.66 kB ( |
| d_isPtr.ts | 87.65 kB ( |
| d_comparisonSampler.ts | 87.67 kB ( |
| d_isSizeAttrib.ts | 87.66 kB ( |
| d_isWgslArray.ts | 87.66 kB ( |
| d_isAlignAttrib.ts | 87.66 kB ( |
| d_isWgslStruct.ts | 87.66 kB ( |
| d_isAtomic.ts | 87.66 kB ( |
| d_isBuiltinAttrib.ts | 87.66 kB ( |
| d_isLocationAttrib.ts | 87.67 kB ( |
| d_isDecorated.ts | 87.66 kB ( |
| d_isInterpolateAttrib.ts | 87.67 kB ( |
| d_atomic.ts | 87.66 kB ( |
| d_ptrHandle.ts | 87.66 kB ( |
| d_ptrUniform.ts | 87.66 kB ( |
| d_ptrStorage.ts | 87.66 kB ( |
| d_ptrPrivate.ts | 87.66 kB ( |
| d_ptrFn.ts | 87.65 kB ( |
| d_ptrWorkgroup.ts | 87.66 kB ( |
| d_textureExternal.ts | 87.66 kB ( |
| d_textureStorage1d.ts | 87.67 kB ( |
| d_textureStorage2d.ts | 87.67 kB ( |
| d_textureStorage3d.ts | 87.67 kB ( |
| d_textureStorage2dArray.ts | 87.67 kB ( |
| d_isDisarray.ts | 87.66 kB ( |
| d_isUnstruct.ts | 87.66 kB ( |
| d_isLooseDecorated.ts | 87.67 kB ( |
| d_isLooseData.ts | 87.66 kB ( |
| d_isWgslData.ts | 87.66 kB ( |
| d_unstruct.ts | 87.66 kB ( |
| d_isData.ts | 87.66 kB ( |
| d_deepEqual.ts | 87.66 kB ( |
| d_struct.ts | 87.66 kB ( |
| d_ref.ts | 87.65 kB ( |
| std_discard.ts | 105.47 kB ( |
| std_isBeingTranspiled.ts | 105.48 kB ( |
| std_copy.ts | 105.47 kB ( |
| std_arrayLength.ts | 105.48 kB ( |
| std_getTargetShaderLanguage.ts | 105.49 kB ( |
| std_extensionEnabled.ts | 105.48 kB ( |
| std_range.ts | 105.47 kB ( |
| std_dpdx.ts | 105.47 kB ( |
| std_fwidthCoarse.ts | 105.48 kB ( |
| std_dpdxCoarse.ts | 105.47 kB ( |
| std_dpdyCoarse.ts | 105.47 kB ( |
| std_fwidthFine.ts | 105.47 kB ( |
| std_dpdxFine.ts | 105.47 kB ( |
| std_dpdyFine.ts | 105.47 kB ( |
| std_fwidth.ts | 105.47 kB ( |
| std_dpdy.ts | 105.47 kB ( |
| d_bool.ts | 87.65 kB ( |
| d_f16.ts | 87.65 kB ( |
| d_f32.ts | 87.65 kB ( |
| d_i32.ts | 87.65 kB ( |
| d_u32.ts | 87.65 kB ( |
| d_u16.ts | 87.65 kB ( |
| std_atomicLoad.ts | 105.47 kB ( |
| std_textureBarrier.ts | 105.48 kB ( |
| std_atomicStore.ts | 105.48 kB ( |
| std_workgroupBarrier.ts | 105.48 kB ( |
| std_storageBarrier.ts | 105.48 kB ( |
| std_atomicAdd.ts | 105.47 kB ( |
| std_atomicAnd.ts | 105.47 kB ( |
| std_atomicMax.ts | 105.47 kB ( |
| std_atomicMin.ts | 105.47 kB ( |
| std_atomicSub.ts | 105.47 kB ( |
| std_atomicXor.ts | 105.47 kB ( |
| std_atomicOr.ts | 105.47 kB ( |
| d_textureDepth2d.ts | 87.66 kB ( |
| d_textureDepthCube.ts | 87.67 kB ( |
| d_texture1d.ts | 87.66 kB ( |
| d_texture2d.ts | 87.66 kB ( |
| d_texture3d.ts | 87.66 kB ( |
| d_textureDepth2dArray.ts | 87.67 kB ( |
| d_textureCube.ts | 87.66 kB ( |
| d_textureDepthCubeArray.ts | 87.67 kB ( |
| d_textureDepthMultisampled2d.ts | 87.67 kB ( |
| d_texture2dArray.ts | 87.66 kB ( |
| d_textureCubeArray.ts | 87.67 kB ( |
| d_textureMultisampled2d.ts | 87.67 kB ( |
| d_disarrayOf.ts | 87.66 kB ( |
| d_vec2b.ts | 87.65 kB ( |
| d_vec2f.ts | 87.65 kB ( |
| d_vec2h.ts | 87.65 kB ( |
| d_vec2i.ts | 87.65 kB ( |
| d_vec2u.ts | 87.65 kB ( |
| d_vec3b.ts | 87.65 kB ( |
| d_vec3f.ts | 87.65 kB ( |
| d_vec3h.ts | 87.65 kB ( |
| d_vec3i.ts | 87.65 kB ( |
| d_vec3u.ts | 87.65 kB ( |
| d_vec4b.ts | 87.65 kB ( |
| d_vec4f.ts | 87.65 kB ( |
| d_vec4h.ts | 87.65 kB ( |
| d_vec4i.ts | 87.65 kB ( |
| d_vec4u.ts | 87.65 kB ( |
| std_subgroupAdd.ts | 105.48 kB ( |
| std_subgroupBroadcastFirst.ts | 105.49 kB ( |
| std_subgroupExclusiveAdd.ts | 105.48 kB ( |
| std_subgroupExclusiveMul.ts | 105.48 kB ( |
| std_subgroupInclusiveAdd.ts | 105.48 kB ( |
| std_subgroupInclusiveMul.ts | 105.48 kB ( |
| std_subgroupShuffleDown.ts | 105.48 kB ( |
| std_subgroupShuffleXor.ts | 105.48 kB ( |
| std_subgroupBroadcast.ts | 105.48 kB ( |
| std_subgroupShuffleUp.ts | 105.48 kB ( |
| std_subgroupShuffle.ts | 105.48 kB ( |
| std_subgroupBallot.ts | 105.48 kB ( |
| std_subgroupElect.ts | 105.48 kB ( |
| std_subgroupAll.ts | 105.48 kB ( |
| std_subgroupAnd.ts | 105.48 kB ( |
| std_subgroupAny.ts | 105.48 kB ( |
| std_subgroupMax.ts | 105.48 kB ( |
| std_subgroupMin.ts | 105.48 kB ( |
| std_subgroupMul.ts | 105.48 kB ( |
| std_subgroupXor.ts | 105.48 kB ( |
| std_subgroupOr.ts | 105.47 kB ( |
| d_formatToWGSLType.ts | 87.67 kB ( |
| d_uint8.ts | 87.65 kB ( |
| d_unorm10_10_10_2.ts | 87.66 kB ( |
| d_unorm8x4_bgra.ts | 87.66 kB ( |
| d_float16x2.ts | 87.66 kB ( |
| d_float16x4.ts | 87.66 kB ( |
| d_float32x2.ts | 87.66 kB ( |
| d_float32x3.ts | 87.66 kB ( |
| d_float32x4.ts | 87.66 kB ( |
| d_snorm16x2.ts | 87.66 kB ( |
| d_snorm16x4.ts | 87.66 kB ( |
| d_unorm16x2.ts | 87.66 kB ( |
| d_unorm16x4.ts | 87.66 kB ( |
| d_sint16x2.ts | 87.66 kB ( |
| d_sint16x4.ts | 87.66 kB ( |
| d_sint32x2.ts | 87.66 kB ( |
| d_sint32x3.ts | 87.66 kB ( |
| d_sint32x4.ts | 87.66 kB ( |
| d_snorm8x2.ts | 87.66 kB ( |
| d_snorm8x4.ts | 87.66 kB ( |
| d_uint16x2.ts | 87.66 kB ( |
| d_uint16x4.ts | 87.66 kB ( |
| d_uint32x2.ts | 87.66 kB ( |
| d_uint32x3.ts | 87.66 kB ( |
| d_uint32x4.ts | 87.66 kB ( |
| d_unorm8x2.ts | 87.66 kB ( |
| d_unorm8x4.ts | 87.66 kB ( |
| d_float16.ts | 87.66 kB ( |
| d_float32.ts | 87.66 kB ( |
| d_sint8x2.ts | 87.66 kB ( |
| d_sint8x4.ts | 87.66 kB ( |
| d_snorm16.ts | 87.66 kB ( |
| d_uint8x2.ts | 87.66 kB ( |
| d_uint8x4.ts | 87.66 kB ( |
| d_unorm16.ts | 87.66 kB ( |
| d_sint16.ts | 87.66 kB ( |
| d_sint32.ts | 87.66 kB ( |
| d_snorm8.ts | 87.66 kB ( |
| d_uint16.ts | 87.66 kB ( |
| d_uint32.ts | 87.66 kB ( |
| d_unorm8.ts | 87.66 kB ( |
| d_sint8.ts | 87.65 kB ( |
| d_packedFormats.ts | 87.66 kB ( |
| d_isPackedData.ts | 87.66 kB ( |
| std_textureDimensions.ts | 105.48 kB ( |
| std_textureGather.ts | 105.48 kB ( |
| std_textureSampleBaseClampToEdge.ts | 105.49 kB ( |
| std_textureSampleCompareLevel.ts | 105.49 kB ( |
| std_textureSampleCompare.ts | 105.48 kB ( |
| std_textureSampleLevel.ts | 105.48 kB ( |
| std_textureSampleBias.ts | 105.48 kB ( |
| std_textureSampleGrad.ts | 105.48 kB ( |
| std_textureSample.ts | 105.48 kB ( |
| std_textureStore.ts | 105.48 kB ( |
| std_textureLoad.ts | 105.48 kB ( |
| d_alignmentOf.ts | 87.66 kB ( |
| std_translation4.ts | 105.48 kB ( |
| std_rotationX4.ts | 105.47 kB ( |
| std_rotationY4.ts | 105.47 kB ( |
| std_rotationZ4.ts | 105.47 kB ( |
| std_identity2.ts | 105.47 kB ( |
| std_identity3.ts | 105.47 kB ( |
| std_identity4.ts | 105.47 kB ( |
| std_scaling4.ts | 105.47 kB ( |
| d_isBuiltin.ts | 87.66 kB ( |
| d_sizeOf.ts | 87.66 kB ( |
| d_isContiguous.ts | 87.66 kB ( |
| d_getLongestContiguousPrefix.ts | 87.67 kB ( |
| d_arrayOf.ts | 87.66 kB ( |
| d_size.ts | 87.65 kB ( |
| d_align.ts | 87.65 kB ( |
| d_location.ts | 87.66 kB ( |
| d_interpolate.ts | 87.66 kB ( |
| d_invariant.ts | 87.66 kB ( |
| d_mat4x4f.ts | 87.66 kB ( |
| d_mat2x2f.ts | 87.66 kB ( |
| d_mat3x3f.ts | 87.66 kB ( |
| d_matToArray.ts | 87.66 kB ( |
| d_builtin.ts | 87.66 kB ( |
| std_unpack2x16float.ts | 105.48 kB ( |
| std_unpack4x8unorm.ts | 105.48 kB ( |
| std_pack2x16float.ts | 105.48 kB ( |
| std_pack4x8unorm.ts | 105.48 kB ( |
| std_bitcastU32toF32.ts | 105.48 kB ( |
| std_bitcastU32toI32.ts | 105.48 kB ( |
| std_neg.ts | 105.47 kB ( |
| std_bitShiftRight.ts | 105.48 kB ( |
| std_bitShiftLeft.ts | 105.48 kB ( |
| std_add.ts | 105.47 kB ( |
| std_div.ts | 105.47 kB ( |
| std_mod.ts | 105.47 kB ( |
| std_mul.ts | 105.47 kB ( |
| std_sub.ts | 105.47 kB ( |
| std_translate4.ts | 105.47 kB ( |
| std_rotateX4.ts | 105.47 kB ( |
| std_scale4.ts | 105.47 kB ( |
| std_rotateY4.ts | 105.47 kB ( |
| std_rotateZ4.ts | 105.47 kB ( |
| d_memoryLayoutOf.ts | 87.66 kB ( |
| std_and.ts | 105.47 kB ( |
| std_or.ts | 105.47 kB ( |
| std_select.ts | 105.47 kB ( |
| std_allEq.ts | 105.47 kB ( |
| std_all.ts | 105.47 kB ( |
| std_not.ts | 105.47 kB ( |
| std_eq.ts | 105.47 kB ( |
| std_lt.ts | 105.47 kB ( |
| std_ne.ts | 105.47 kB ( |
| std_isCloseTo.ts | 105.47 kB ( |
| std_any.ts | 105.47 kB ( |
| std_ge.ts | 105.47 kB ( |
| std_gt.ts | 105.47 kB ( |
| std_le.ts | 105.47 kB ( |
| std_dot4U8Packed.ts | 105.48 kB ( |
| std_length.ts | 105.47 kB ( |
| std_countTrailingZeros.ts | 105.48 kB ( |
| std_distance.ts | 105.47 kB ( |
| std_dot.ts | 105.47 kB ( |
| std_countLeadingZeros.ts | 105.48 kB ( |
| std_firstTrailingBit.ts | 105.48 kB ( |
| std_firstLeadingBit.ts | 105.48 kB ( |
| std_fract.ts | 105.47 kB ( |
| std_frexp.ts | 105.47 kB ( |
| std_modf.ts | 105.47 kB ( |
| std_quantizeToF16.ts | 105.48 kB ( |
| std_mix.ts | 105.47 kB ( |
| std_countOneBits.ts | 105.48 kB ( |
| std_dot4I8Packed.ts | 105.48 kB ( |
| std_determinant.ts | 105.48 kB ( |
| std_extractBits.ts | 105.48 kB ( |
| std_faceForward.ts | 105.48 kB ( |
| std_inverseSqrt.ts | 105.48 kB ( |
| std_reverseBits.ts | 105.48 kB ( |
| std_insertBits.ts | 105.47 kB ( |
| std_smoothstep.ts | 105.47 kB ( |
| std_normalize.ts | 105.47 kB ( |
| std_transpose.ts | 105.47 kB ( |
| std_saturate.ts | 105.47 kB ( |
| std_degrees.ts | 105.47 kB ( |
| std_radians.ts | 105.47 kB ( |
| std_reflect.ts | 105.47 kB ( |
| std_refract.ts | 105.47 kB ( |
| std_acosh.ts | 105.47 kB ( |
| std_asinh.ts | 105.47 kB ( |
| std_atan2.ts | 105.47 kB ( |
| std_atanh.ts | 105.47 kB ( |
| std_clamp.ts | 105.47 kB ( |
| std_cross.ts | 105.47 kB ( |
| std_floor.ts | 105.47 kB ( |
| std_ldexp.ts | 105.47 kB ( |
| std_round.ts | 105.47 kB ( |
| std_trunc.ts | 105.47 kB ( |
| std_acos.ts | 105.47 kB ( |
| std_asin.ts | 105.47 kB ( |
| std_atan.ts | 105.47 kB ( |
| std_ceil.ts | 105.47 kB ( |
| std_cosh.ts | 105.47 kB ( |
| std_exp2.ts | 105.47 kB ( |
| std_log2.ts | 105.47 kB ( |
| std_sign.ts | 105.47 kB ( |
| std_sinh.ts | 105.47 kB ( |
| std_sqrt.ts | 105.47 kB ( |
| std_step.ts | 105.47 kB ( |
| std_tanh.ts | 105.47 kB ( |
| std_abs.ts | 105.47 kB ( |
| std_cos.ts | 105.47 kB ( |
| std_exp.ts | 105.47 kB ( |
| std_fma.ts | 105.47 kB ( |
| std_log.ts | 105.47 kB ( |
| std_max.ts | 105.47 kB ( |
| std_min.ts | 105.47 kB ( |
| std_pow.ts | 105.47 kB ( |
| std_sin.ts | 105.47 kB ( |
| std_tan.ts | 105.47 kB ( |
| common_fullScreenTriangle.ts | 57.15 kB ( |
| common_writeSoA.ts | 57.14 kB ( |
| STATIC_allImports.ts | 289.38 kB ( |
| STATIC_d.ts | 87.65 kB ( |
| STATIC_std.ts | 105.46 kB ( |
If you wish to run a comparison for other, slower bundlers, run the 'Tree-shake test' from the GitHub Actions menu.
Resolution Time Benchmark---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Random Branching (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [0.97, 1.96, 4.54, 6.77, 8.14, 13.03, 23.92, 25.43]
line [1.00, 2.07, 4.34, 6.84, 8.65, 14.73, 24.72, 27.06]
line [0.97, 1.93, 4.13, 6.66, 8.37, 11.18, 24.31, 25.28]
---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Linear Recursion (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [0.31, 0.52, 0.68, 0.85, 1.13, 1.17, 1.44, 1.55]
line [0.33, 0.56, 0.72, 0.90, 1.22, 1.24, 1.53, 1.66]
line [0.33, 0.62, 0.77, 0.92, 1.20, 1.28, 1.61, 1.69]
---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Full Tree (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [0.99, 2.41, 4.14, 6.98, 12.34, 26.43, 58.00, 118.34]
line [0.85, 2.17, 3.89, 7.00, 12.85, 28.32, 60.01, 120.44]
line [1.00, 2.16, 4.36, 6.91, 13.99, 27.46, 59.58, 123.47]
|
There was a problem hiding this comment.
Pull request overview
Adds support across the TypeGPU toolchain (parser → unplugin metadata → runtime resolution → linting) for accessing class private fields (e.g. this.#prop) from 'use gpu' functions, and updates tests to cover the new syntax.
Changes:
- Teach
tinyest-for-wgslto parse/transpile private identifiers and include them in external-name extraction. - Update
unplugin-typegpuexternals serialization + auto-naming to handle class private properties and#...keys. - Relax ESLint rule coverage to allow private identifiers in
'use gpu'functions and add related tests.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/unplugin-typegpu/test/nested-externals.test.ts | Adds regression tests ensuring externals gathering supports this.#prop for Babel/Rollup transforms. |
| packages/unplugin-typegpu/test/auto-naming.test.ts | Adds auto-naming coverage for class private fields (named + anonymous classes) in Babel/Rollup transforms. |
| packages/unplugin-typegpu/src/core/factory.ts | Quotes #... externals keys when generating metadata code strings. |
| packages/unplugin-typegpu/src/core/common.ts | Enables auto-naming for ClassPrivateProperty and adds requiresQuotation() helper. |
| packages/unplugin-typegpu/src/babel.ts | Quotes #... externals keys when generating Babel AST metadata nodes. |
| packages/typegpu/tests/externalPropAccess.test.ts | Adds runtime resolution tests for private property access and '#'-containing property names. |
| packages/tinyest-for-wgsl/tests/parsers.test.ts | Adds parser test asserting this.#v becomes an external name under "this"."#v". |
| packages/tinyest-for-wgsl/src/parsers.ts | Adds transpilers for PrivateName / PrivateIdentifier. |
| packages/tinyest-for-wgsl/src/externals.ts | Extends prop-access chain extraction to include private member names. |
| packages/eslint-plugin/tests/rules/noUnsupportedSyntax.test.ts | Updates rule tests to treat private identifiers as valid in 'use gpu' scope. |
| packages/eslint-plugin/src/rules/noUnsupportedSyntax.ts | Stops reporting PrivateIdentifier as unsupported syntax inside 'use gpu'. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@pullfrog review |
There was a problem hiding this comment.
Important
The Rollup externals test isn't actually testing the Rollup path, and the combined public/private #prop case silently resolves the wrong resource. Both need addressing before merge.
Reviewed changes — this PR enables JavaScript private class properties as TypeGPU externals, adds auto-naming for ClassPrivateProperty, and removes the lint rule that unconditionally banned private identifiers.
- Lift the blanket
PrivateIdentifierlint ban inpackages/eslint-plugin/src/rules/noUnsupportedSyntax.tssothis.#propaccess is allowed. - Track
#propchains inpackages/tinyest-for-wgsl/src/externals.tsby handling both BabelPrivateNameand acornPrivateIdentifier. - Auto-name private class fields in
packages/unplugin-typegpu/src/core/common.tsvia a newClassPrivatePropertyvisitor and matchingextractLabelledExpressionbranch. - Add test coverage for private property access across
tinyest-for-wgsl,typegpu, andunplugin-typegpu.
Collision between private #prop and string-key "#prop"
A class that defines both a public '#prop' and a private #prop currently routes both this['#prop'].$ and this.#prop.$ through the same this.#prop external key. The runtime object-based external replacement then resolves the public property value, so the private field value is silently dropped. This matches the limitation noted in the PR body; please either fix the key encoding or add a tracking issue/TODO so the limitation is visible to users and future maintainers.
Technical details
# Collision between private `#prop` and string-key `"#prop"`
## Affected sites
- packages/tinyest-for-wgsl/src/externals.ts:32-35 — private names are encoded as `this.#prop`, identical to the runtime object-property replacement path used for `this["#prop"]`.
- packages/typegpu/src/core/resolve/externals.ts:104-129 — object external replacement uses `externalName\\.(?<prop>...)` and matches `this.#prop` for `this` externals.
## Required outcome
- `this.#prop` (private field) and `this["#prop"]` (public string key) resolve to distinct resources when both are present.
## Suggested approach
Consider encoding private names with a distinct prefix or namespace (e.g., `this.private.#prop`) and teaching the resolver to map that prefix back to the private-field accessor. Alternatively, document the limitation and add a failing/todo test linking to an issue.
## Open questions for the human
- Is the combined case expected to be fixed in this PR, or is there a follow-up issue already planned? Please link it in a code comment so the next agent doesn't re-discover it.Kimi K2 (free via Pullfrog for OSS) | 𝕏
| }); | ||
|
|
||
| it('works for ROLLUP', async () => { | ||
| expect(extractExternals(babelTransform(code))).toMatchInlineSnapshot(` |
There was a problem hiding this comment.
This ROLLUP test calls babelTransform, so it doesn't exercise the Rollup plugin path and the inline snapshot only reflects Babel's formatting. Use await rollupTransform(code) here and update the snapshot.

Blocked by #2425
Only the case with both
"#prop"and#proppresent breaks.