import secrets import string from typing import Dict, Any, TypedDict def generate_secure_token(length=20): charset = string.ascii_letters + string.digits + "!@#$%^&*()[]{}=+-_~" return ''.join(secrets.choice(charset) for _ in range(length)) def rename_blocks(block_json: dict, opcode_count: dict) -> tuple[dict, dict]: """ Replace each block key in block_json and each identifier in opcode_count with a newly generated secure token. Args: block_json: Mapping of block_key -> block_data. opcode_count: Mapping of opcode -> list of block_keys. Returns: A tuple of (new_block_json, new_opcode_count) with updated keys. """ # Step 1: Generate a secure token mapping for every existing block key token_map = {} for old_key in block_json.keys(): # Ensure uniqueness in the unlikely event of a collision while True: new_key = generate_secure_token() if new_key not in token_map.values(): break token_map[old_key] = new_key # Step 2: Rebuild block_json with new keys new_block_json = {} for old_key, block in block_json.items(): new_key = token_map[old_key] new_block_json[new_key] = block.copy() # Update parent and next references if 'parent' in block and block['parent'] in token_map: new_block_json[new_key]['parent'] = token_map[block['parent']] if 'next' in block and block['next'] in token_map: new_block_json[new_key]['next'] = token_map[block['next']] # Update inputs if they reference blocks for inp_key, inp_val in block.get('inputs', {}).items(): if isinstance(inp_val, list) and len(inp_val) == 2: idx, ref = inp_val if idx in (2, 3) and isinstance(ref, str) and ref in token_map: new_block_json[new_key]['inputs'][inp_key] = [idx, token_map[ref]] # Step 3: Update opcode count map new_opcode_count = {} for opcode, key_list in opcode_count.items(): new_opcode_count[opcode] = [token_map.get(k, k) for k in key_list] return new_block_json, new_opcode_count # Example usage: if __name__ == "__main__": blocks = {'event_whenflagclicked_1': {'opcode': 'event_whenflagclicked', 'inputs': {}, 'fields': {}, 'shadow': False, 'topLevel': True, 'parent': None, 'next': 'motion_gotoxy_1'}, 'motion_gotoxy_1': {'opcode': 'motion_gotoxy', 'inputs': {'X': [1, [4, '240']], 'Y': [1, [4, '-135']]}, 'fields': {}, 'shadow': False, 'topLevel': False, 'parent': 'event_whenflagclicked_1', 'next': 'data_setvariableto_1'}, 'motion_xposition_1': {'opcode': 'motion_xposition', 'inputs': {}, 'fields': {}, 'shadow': False, 'topLevel': False, 'parent': 'operator_lt_1', 'next': None}, 'motion_setx_1': {'opcode': 'motion_setx', 'inputs': {'X': [1, [4, '240']]}, 'fields': {}, 'shadow': False, 'topLevel': False, 'parent': 'control_if_1', 'next': None}, 'control_forever_1': {'opcode': 'control_forever', 'inputs': {'SUBSTACK': [2, 'control_if_1']}, 'fields': {}, 'shadow': False, 'topLevel': False, 'parent': 'event_whenflagclicked_1', 'next': None}, 'control_if_1': {'opcode': 'control_if', 'inputs': {'CONDITION': [2, 'operator_lt_1'], 'SUBSTACK': [2, 'motion_setx_1']}, 'fields': {}, 'shadow': False, 'topLevel': False, 'parent': 'control_forever_1', 'next': 'control_if_2'}, 'control_if_2': {'opcode': 'control_if', 'inputs': {'CONDITION': [2, 'sensing_touchingobject_1'], 'SUBSTACK': [2, 'event_broadcast_1']}, 'fields': {}, 'shadow': False, 'topLevel': False, 'parent': 'control_forever_1', 'next': None}, 'control_stop_1': {'opcode': 'control_stop', 'inputs': {}, 'fields': {'STOP_OPTION': ['all ', None]}, 'shadow': False, 'topLevel': False, 'parent': 'control_if_2', 'next': None, 'mutation': {'tagName': 'mutation', 'children': [], 'hasnext': 'false'}}, 'operator_lt_1': {'opcode': 'operator_lt', 'inputs': {'OPERAND1': [3, 'motion_xposition_1', [10, '']], 'OPERAND2': [1, [4, '-235']]}, 'fields': {}, 'shadow': False, 'topLevel': False, 'parent': 'control_if_1', 'next': None}, 'sensing_touchingobject_1': {'opcode': 'sensing_touchingobject', 'inputs': {'TOUCHINGOBJECTMENU': [1, 'sensing_touchingobjectmenu_1']}, 'fields': {}, 'shadow': False, 'topLevel': False, 'parent': 'control_if_2', 'next': None}, 'sensing_touchingobjectmenu_1': {'opcode': 'sensing_touchingobjectmenu', 'inputs': {}, 'fields': {'TOUCHINGOBJECTMENU': ['sprite1', None]}, 'shadow': True, 'topLevel': False, 'parent': 'sensing_touchingobject_1', 'next': None}, 'sensing_touchingobjectmenu_2': {'opcode': 'sensing_touchingobjectmenu', 'inputs': {}, 'fields': {'TOUCHINGOBJECTMENU': ['_mouse_', None]}, 'shadow': False, 'topLevel': False, 'parent': None, 'next': None}, 'event_broadcast_1': {'opcode': 'event_broadcast', 'inputs': {'BROADCAST_INPUT': [1, [11, 'Game Over', '']]}, 'fields': {}, 'shadow': False, 'topLevel': False, 'parent': 'control_if_2', 'next': 'control_stop_1'}, 'data_setvariableto_1': {'opcode': 'data_setvariableto', 'inputs': {'VALUE': [1, [4, '1']]}, 'fields': {'VARIABLE': ['score', 'score']}, 'shadow': False, 'topLevel': False, 'parent': 'event_whenflagclicked_1', 'next': 'data_setvariableto_2'}, 'data_setvariableto_2': {'opcode': 'data_setvariableto', 'inputs': {'VALUE': [1, [4, '1']]}, 'fields': {'VARIABLE': ['speed', 'speed']}, 'shadow': False, 'topLevel': False, 'parent': 'event_whenflagclicked_1', 'next': 'data_showvariable_1'}, 'data_showvariable_1': {'opcode': 'data_showvariable', 'inputs': {}, 'fields': {'VARIABLE': ['score', 'score']}, 'shadow': False, 'topLevel': False, 'parent': 'event_whenflagclicked_1', 'next': 'data_showvariable_2'}, 'data_showvariable_2': {'opcode': 'data_showvariable', 'inputs': {}, 'fields': {'VARIABLE': ['speed', 'speed']}, 'shadow': False, 'topLevel': False, 'parent': 'event_whenflagclicked_1', 'next': 'control_forever_1'}} # your first JSON opcode_keys = {'event_whenflagclicked': ['event_whenflagclicked_1'], 'motion_gotoxy': ['motion_gotoxy_1'], 'motion_xposition': ['motion_xposition_1'], 'motion_setx': ['motion_setx_1'], 'control_forever': ['control_forever_1'], 'control_if': ['control_if_1', 'control_if_2'], 'control_stop': ['control_stop_1'], 'operator_lt': ['operator_lt_1'], 'sensing_touchingobject': ['sensing_touchingobject_1'], 'sensing_touchingobjectmenu': ['sensing_touchingobjectmenu_1', 'sensing_touchingobjectmenu_2'], 'event_broadcast': ['event_broadcast_1'], 'data_setvariableto': ['data_setvariableto_1', 'data_setvariableto_2'], 'data_showvariable': ['data_showvariable_1', 'data_showvariable_2']} # your second JSON renamed_blocks, renamed_counts = rename_blocks(blocks, opcode_keys) print(renamed_blocks)