@@ -214,17 +214,22 @@ export class CubePropContextTranspiler implements TranspilerInterface {
214214
215215 protected static collectKnownIdentifiersAndTransform ( resolveSymbol : SymbolResolver , path : NodePath ) : string [ ] {
216216 const identifiers : string [ ] = [ ] ;
217+ const isAccessPolicy = this . isAccessPolicyPath ( path ) ;
217218
218219 if ( path . node . type === 'Identifier' ) {
219- CubePropContextTranspiler . matchAndTransformIdentifier ( path , resolveSymbol , identifiers ) ;
220+ CubePropContextTranspiler . transformCubeCloudShorthandIdentifier ( path as NodePath < t . Identifier > , identifiers , isAccessPolicy , resolveSymbol ) ;
221+ if ( path . node . type === 'Identifier' ) {
222+ CubePropContextTranspiler . matchAndTransformIdentifier ( path , resolveSymbol , identifiers ) ;
223+ }
220224 }
221225
222226 path . traverse ( {
223227 Identifier : ( p ) => {
228+ CubePropContextTranspiler . transformCubeCloudShorthandIdentifier ( p , identifiers , isAccessPolicy , resolveSymbol ) ;
224229 CubePropContextTranspiler . matchAndTransformIdentifier ( p , resolveSymbol , identifiers ) ;
225230 } ,
226231 MemberExpression : ( p ) => {
227- CubePropContextTranspiler . transformUserAttributesMemberExpression ( p ) ;
232+ CubePropContextTranspiler . transformCubeCloudShorthandMemberExpression ( p , isAccessPolicy , resolveSymbol ) ;
228233 }
229234 } ) ;
230235
@@ -238,39 +243,83 @@ export class CubePropContextTranspiler implements TranspilerInterface {
238243 ) &&
239244 resolveSymbol ( path . node . name )
240245 ) {
241- // Special handling for userAttributes - replace in parameter list with securityContext
242- const fullPath = this . fullPath ( path ) ;
243- if ( ( path . node . name === 'userAttributes' || path . node . name === 'user_attributes' ) && ( fullPath . startsWith ( 'accessPolicy' ) || fullPath . startsWith ( 'access_policy' ) ) ) {
244- identifiers . push ( 'securityContext' ) ;
245- } else {
246- identifiers . push ( path . node . name ) ;
246+ identifiers . push ( path . node . name ) ;
247+ }
248+ }
249+
250+ private static readonly CUBE_CLOUD_SHORTHAND_IDENTIFIERS = [ 'userAttributes' , 'user_attributes' , 'groups' ] ;
251+
252+ private static isAccessPolicyPath ( path : NodePath ) : boolean {
253+ // @ts -ignore
254+ const target = ( ! path ?. node ?. key && path ?. parentPath && t . isObjectProperty ( path . parentPath . node ) )
255+ ? path . parentPath
256+ : path ;
257+ const fp = this . fullPath ( target ) ;
258+ return fp . startsWith ( 'accessPolicy' ) || fp . startsWith ( 'access_policy' ) ;
259+ }
260+
261+ private static securityContextIdentifier ( isAccessPolicy : boolean ) : t . Identifier {
262+ return t . identifier ( isAccessPolicy ? 'securityContext' : 'SECURITY_CONTEXT' ) ;
263+ }
264+
265+ private static isShadowedByFunctionParam ( name : string , path : NodePath ) : boolean {
266+ let current : NodePath | null = path . parentPath ;
267+ while ( current ) {
268+ const { node } = current ;
269+ if (
270+ ( t . isArrowFunctionExpression ( node ) || t . isFunctionExpression ( node ) ) &&
271+ node . params . some ( p => t . isIdentifier ( p ) && p . name === name )
272+ ) {
273+ return true ;
247274 }
275+ current = current . parentPath ;
248276 }
277+ return false ;
249278 }
250279
251- protected static transformUserAttributesMemberExpression ( path : NodePath < t . MemberExpression > ) {
252- // Check if this is userAttributes.someProperty (object should be identifier named 'userAttributes')
253- const fullPath = this . fullPath ( path ) ;
280+ protected static transformCubeCloudShorthandIdentifier ( path : NodePath < t . Identifier > , identifiers : string [ ] , isAccessPolicy : boolean , resolveSymbol : SymbolResolver ) {
281+ if ( ! this . CUBE_CLOUD_SHORTHAND_IDENTIFIERS . includes ( path . node . name ) ) {
282+ return ;
283+ }
284+ if ( resolveSymbol ( path . node . name ) ) {
285+ return ;
286+ }
254287 if (
255- ( t . isIdentifier ( path . node . object , { name : 'userAttributes' } ) || t . isIdentifier ( path . node . object , { name : 'user_attributes' } ) ) &&
256- ( fullPath . startsWith ( 'accessPolicy' ) || fullPath . startsWith ( 'access_policy' ) )
288+ path . parent &&
289+ ( path . parent . type === 'MemberExpression' || path . parent . type === 'OptionalMemberExpression' ) &&
290+ path . key === 'property'
257291 ) {
258- // Replace userAttributes with securityContext.cubeCloud.userAttributes
259- const securityContext = t . identifier ( 'securityContext' ) ;
260- const cubeCloud = t . memberExpression ( securityContext , t . identifier ( 'cubeCloud' ) ) ;
261- const userAttributes = t . memberExpression ( cubeCloud , t . identifier ( 'userAttributes' ) ) ;
262- const newMemberExpression = t . memberExpression ( userAttributes , path . node . property , path . node . computed ) ;
292+ return ;
293+ }
294+ if ( this . isShadowedByFunctionParam ( path . node . name , path ) ) {
295+ return ;
296+ }
297+ const contextId = this . securityContextIdentifier ( isAccessPolicy ) ;
298+ const cubeCloud = t . memberExpression ( contextId , t . identifier ( 'cubeCloud' ) ) ;
299+ const prop = path . node . name === 'user_attributes' ? 'userAttributes' : path . node . name ;
300+ const newExpr = t . memberExpression ( cubeCloud , t . identifier ( prop ) ) ;
301+ path . replaceWith ( newExpr ) ;
302+ identifiers . push ( contextId . name ) ;
303+ }
263304
305+ protected static transformCubeCloudShorthandMemberExpression ( path : NodePath < t . MemberExpression > , isAccessPolicy : boolean , resolveSymbol : SymbolResolver ) {
306+ if (
307+ t . isIdentifier ( path . node . object ) &&
308+ this . CUBE_CLOUD_SHORTHAND_IDENTIFIERS . includes ( path . node . object . name ) &&
309+ ! resolveSymbol ( path . node . object . name ) &&
310+ ! this . isShadowedByFunctionParam ( path . node . object . name , path )
311+ ) {
312+ const contextId = this . securityContextIdentifier ( isAccessPolicy ) ;
313+ const cubeCloud = t . memberExpression ( contextId , t . identifier ( 'cubeCloud' ) ) ;
314+ const prop = path . node . object . name === 'user_attributes' ? 'userAttributes' : path . node . object . name ;
315+ const shorthand = t . memberExpression ( cubeCloud , t . identifier ( prop ) ) ;
316+ const newMemberExpression = t . memberExpression ( shorthand , path . node . property , path . node . computed ) ;
264317 path . replaceWith ( newMemberExpression ) ;
265318 } else if (
266- t . isMemberExpression ( path . node . object ) &&
319+ ( t . isMemberExpression ( path . node . object ) || t . isOptionalMemberExpression ( path . node . object ) ) &&
267320 t . isIdentifier ( path . node . object . property , { name : 'user_attributes' } ) &&
268- ! path . node . object . computed &&
269- ( fullPath . startsWith ( 'accessPolicy' ) || fullPath . startsWith ( 'access_policy' ) )
321+ ! path . node . object . computed
270322 ) {
271- // Also handle case where user_attributes appears within a MemberExpression chain like
272- // securityContext.cubeCloud.user_attributes
273- // We need to convert user_attributes to userAttributes in such chains
274323 const newObject = t . memberExpression (
275324 path . node . object . object ,
276325 t . identifier ( 'userAttributes' ) ,
0 commit comments