Files

792 lines
28 KiB
Python

"""
PA Generation Rules — Single Source of Truth for Migration
==========================================================
This module defines ALL rules governing platform-abstraction (PA) generation.
Both analyze.py and scan_codebase.py import from here.
DESIGN PRINCIPLE: Every section is a flat data structure (dict, list, or scalar).
To add a new rule, just append an entry. No classes, no inheritance, no builders.
HOW TO USE:
from pa_rules import EXISTING_MAPPINGS # replaces hardcoded KNOWN_PA
from pa_rules import classify_type # get classification for any MC type
from pa_rules import get_pa_name # get semantic PA interface name
from pa_rules import get_service_target # get service routing for SERVICE types
from pa_rules import resolve_param_type # resolve MC type → PA type for params
HOW TO EXTEND:
- New PA mapping completed? → Add to EXISTING_MAPPINGS
- New type to classify? → Add to FORCE_INTERFACE, FORCE_SERVICE, FORCE_TRANSFORM, or SUPPRESS
- New semantic name? → Add to NAMING
- New service routing? → Add to SERVICE_ROUTING
- New obfuscated method name? → Add to OBFUSCATED_METHOD_NAMES
"""
import re
# ============================================================
# SECTION 1: EXISTING MAPPINGS
# Types already abstracted in platform-api.
# Used as the single source of truth for readiness scoring.
#
# Format: "net.minecraft.fully.qualified.Name": "PAInterfaceName"
#
# HOW TO UPDATE: When you complete a PA interface migration,
# add the MC FQN → PA name mapping here. Both analyze.py and
# scan_codebase.py will pick it up automatically.
# ============================================================
EXISTING_MAPPINGS = {
# --- NBT ---
"net.minecraft.nbt.NBTTagCompound": "INbt",
"net.minecraft.nbt.NBTTagList": "INbtList",
# --- Entity ---
"net.minecraft.entity.Entity": "IEntity",
"net.minecraft.entity.EntityLivingBase": "IEntityLivingBase",
"net.minecraft.entity.EntityLiving": "IEntityLiving",
"net.minecraft.entity.player.EntityPlayer": "IPlayer",
"net.minecraft.entity.player.EntityPlayerMP": "IPlayer",
# --- Item ---
"net.minecraft.item.ItemStack": "IItemStack",
# --- World ---
"net.minecraft.world.World": "IWorld",
"net.minecraft.world.WorldServer": "IWorld",
# --- Combat ---
"net.minecraft.util.DamageSource": "IDamageSource",
}
# ============================================================
# SECTION 2: TYPE CLASSIFICATION
# Controls how unabstracted MC types are handled during migration.
# Every MC type falls into exactly ONE category:
#
# EXISTING — Already has a PA interface (in EXISTING_MAPPINGS)
# INTERFACE — Should become a standalone PA interface (I*.java)
# SERVICE — Methods should be added to PlatformService or a domain service
# TRANSFORM — Handled by Static-Transform regex replacement
# SUPPRESS — Should NEVER be abstracted (client-only, debug, stays in mc1710)
# AUTO — Not explicitly classified; use heuristics (surface-miner data)
#
# HOW TO ADD: Put the MC simple class name (not FQN) in the right list.
# ============================================================
# --- Auto-classification thresholds (for types not in any list) ---
# Used by the classify command when a type isn't explicitly categorized.
# If more than this fraction of a type's used methods are static → SERVICE
STATIC_THRESHOLD = 0.6
# If a type has fewer than this many unique methods used → SERVICE (not worth an interface)
MIN_METHODS_FOR_INTERFACE = 3
# If a type is used in fewer than this many files → consider suppressing
MIN_FILES_FOR_INTERFACE = 5
# --- INTERFACE: Types that MUST become standalone PA interfaces ---
# These have rich instance-method surfaces and appear as parameters/return types.
# They represent concepts that exist across MC versions.
FORCE_INTERFACE = [
# Command/Chat system
"ICommandSender", # 5 instance methods, used for command execution context
"IChatComponent", # Chat message abstraction (→ ITextComponent)
"ChatComponentText", # Concrete text component (→ ITextComponent)
"ChatComponentTranslation", # Translatable text (→ ITextComponent)
"ChatStyle", # Text formatting (→ ITextStyle)
# Geometry / Math
"AxisAlignedBB", # Bounding boxes (→ IBoundingBox)
"Vec3", # 3D vector (→ IVector3)
"MovingObjectPosition", # Raytrace result (→ IRayTraceResult)
# Resources
"ResourceLocation", # Asset/registry identifiers (→ IResourceLocation)
# Effects
"Potion", # Potion type registry (→ IPotionType)
"PotionEffect", # Active potion effect instance (→ IPotionEffect)
# Enchantment
"Enchantment", # Enchantment type (→ IEnchantment)
# Auth
"GameProfile", # Mojang auth profile (→ IGameProfile)
# NBT extension (if needed beyond INbt)
"NBTBase", # Base NBT tag (→ INbtBase, if needed)
]
# --- SERVICE: Types whose methods → PlatformService or domain service ---
# These are static utility classes or singleton accessors.
# Java 7 can't have static methods in interfaces, so these MUST go to services.
FORCE_SERVICE = [
"CompressedStreamTools", # → NBTIO: readCompressed, writeCompressed, read
"PlayerSelector", # → PlatformService: matchPlayers (1 static method)
"MinecraftServer", # → PlatformService: getServer, isDedicatedServer, worldServerForDimension
"StringTranslate", # → PlatformService: translate
"FMLCommonHandler", # → PlatformService: getSide, getEffectiveSide
"ServerConfigurationManager", # → PlatformService: getPlayerList, sendPacketToAllPlayers
"JsonToNBT", # → PlatformService: parseNbt (1 static method)
"StatCollector", # → PlatformService: translateToLocal, translateToLocalFormatted
]
# --- TRANSFORM: Types handled by regex-based Static-Transform ---
# These are annotations, enums, or trivially-replaceable patterns.
# The actual regex patterns are in TRANSFORM_PATTERNS below.
FORCE_TRANSFORM = [
"Side", # @SideOnly(Side.CLIENT) → @ClientOnly
"SideOnly", # Annotation carrier (handled by Side patterns)
"MathHelper", # MathHelper.clamp_int → ValueUtil.clampInt (pure static math)
"EnumChatFormatting", # Color codes → string constants or ITextFormatting enum
"EnumFacing", # Direction enum (if used in core)
]
# --- SUPPRESS: Types that should NEVER be abstracted ---
# Client-only, networking, debug, entity AI internals, registration.
# These stay in mc1710 forever. Don't waste time classifying them.
SUPPRESS = [
# ---- Client-only (GUI, rendering) — never goes to core ----
"GuiButton",
"GuiScreen",
"GuiTextField",
"GuiContainer",
"GuiSlot",
"Minecraft",
"FontRenderer",
"Tessellator",
"RenderHelper",
"GL11",
"GL12",
"OpenGlHelper",
"RenderGlobal",
"TextureManager",
"IIcon",
"ScaledResolution",
"RenderManager",
"Render",
"RenderLiving",
"RenderPlayer",
"EntityRenderer",
"TileEntitySpecialRenderer",
"ModelBase",
"ModelRenderer",
"ModelBiped",
"ModelPlayer",
"EnumParticleTypes",
"WorldRenderer",
"AbstractClientPlayer",
"EntityClientPlayerMP",
"ResourcePack",
"IResourcePack",
# ---- Networking — stays in mc1710 platform layer ----
"Packet",
"PacketBuffer",
"ByteBuf",
"ByteBufInputStream",
"SimpleNetworkWrapper",
"IMessage",
"IMessageHandler",
"MessageContext",
"FMLProxyPacket",
# ---- Entity AI internals — entities extend MC directly ----
"EntityAIBase",
"EntityAITasks",
"PathNavigate",
"DataWatcher",
"EntityAITarget",
"EntityAIWatchClosest",
"PathFinder",
"NavigationPath",
"PathPoint",
"PathEntity",
# ---- Debug / Internal ----
"Profiler",
"CrashReport",
"CrashReportCategory",
# ---- Forge event system — stays in mc1710 ----
"Event",
"EventBus",
"SubscribeEvent",
"ForgeEventFactory",
"MinecraftForge",
"FMLEvent",
"FMLPreInitializationEvent",
"FMLInitializationEvent",
"FMLPostInitializationEvent",
"FMLServerStartingEvent",
"FMLServerStoppingEvent",
# ---- Registration — platform-specific forever ----
"GameRegistry",
"LanguageRegistry",
"EntityRegistry",
"NetworkRegistry",
"TickRegistry",
# ---- Mixin internals ----
"SpongePowered",
"Mixin",
"Shadow",
"Inject",
# ---- Recipe system (NEVER list in AGENTS.md) ----
"ShapedRecipes",
"ShapelessRecipes",
"CraftingManager",
"IRecipe",
# ---- Block/Tile internals that stay platform-side ----
# (IBlock/ITileEntity exist but wrap ScriptedBlock, not raw MC Block)
"CreativeTabs",
"MapColor",
# ---- Inventory internals ----
"InventoryBasic",
"InventoryPlayer",
]
# ============================================================
# SECTION 3: NAMING
# Semantic name overrides for generated PA interfaces.
# Maps MC simple class name → PA interface name.
#
# WHY: MC names are version-specific (ChatComponentText in 1.7,
# TextComponent in 1.16, Component in 1.19). PA names must be
# version-agnostic and stable across all versions.
#
# DEFAULT: If not listed here, the generated name is "I" + MCClassName.
#
# HOW TO ADD: When you decide on a semantic name for a type,
# add it here. The classify and generate-pa commands use this.
# ============================================================
NAMING = {
# ---- Chat / Text system ----
# 1.7: ChatComponentText, 1.16: StringTextComponent, 1.19: Component.literal()
"ChatComponentText": "ITextComponent",
"ChatComponentTranslation": "ITextComponent",
"ChatComponentScore": "ITextComponent",
"IChatComponent": "ITextComponent",
"ChatStyle": "ITextStyle",
"EnumChatFormatting": "ITextFormatting",
# ---- Server ----
# 1.7: MinecraftServer.getServer(), 1.13+: different access patterns
"MinecraftServer": "IServer",
"DedicatedServer": "IServer",
"IntegratedServer": "IServer",
"ServerConfigurationManager": "IPlayerManager",
# ---- Geometry ----
# 1.7: AxisAlignedBB, 1.14+: same name but different package
"AxisAlignedBB": "IBoundingBox",
"Vec3": "IVector3",
"ChunkCoordinates": "IPos", # IPos already exists in PA
"MovingObjectPosition": "IRayTraceResult",
# ---- Effects ----
# 1.7: Potion, 1.9+: different registry system but same concept
"Potion": "IPotionType",
"PotionEffect": "IPotionEffect",
# ---- Entity merges ----
# Multiple MC classes → single PA interface (wraps closest common ancestor)
"EntityPlayer": "IPlayer",
"EntityPlayerMP": "IPlayer",
"EntityLivingBase": "IEntityLivingBase",
"EntityLiving": "IEntityLiving",
"EntityCreature": "IEntityLiving",
# ---- Resources ----
# 1.7: ResourceLocation, all versions: same concept
"ResourceLocation": "IResourceLocation",
# ---- Auth ----
"GameProfile": "IGameProfile",
# ---- Enchantment ----
"Enchantment": "IEnchantment",
# ---- NBT base ----
"NBTBase": "INbtBase",
# ---- World ----
"WorldServer": "IWorld",
# ---- Command ----
"ICommandSender": "ICommandSender", # Keep same name (already good)
}
# ============================================================
# SECTION 4: ROUTING
# Where generated interfaces and service methods go.
#
# HOW TO UPDATE:
# - New sub-package needed? → Add a pattern to PACKAGE_ROUTING
# - New service target? → Add to SERVICE_ROUTING
# ============================================================
# Default output locations
DEFAULT_INTERFACE_PACKAGE = "noppes.npcs.api"
DEFAULT_INTERFACE_DIR = "platform-api/src/main/java/noppes/npcs/api/"
# Sub-package routing: regex on PA interface name → sub-package
# First match wins. If nothing matches → DEFAULT_INTERFACE_PACKAGE.
PACKAGE_ROUTING = [
(r"IPlayer|IEntity|ILiving|ICustomNpc", "noppes.npcs.api.entity"),
(r"IItem", "noppes.npcs.api.item"),
(r"IScoreboard", "noppes.npcs.api.scoreboard"),
(r"IOverlay", "noppes.npcs.api.overlay"),
(r"IJob", "noppes.npcs.api.jobs"),
(r"IRole", "noppes.npcs.api.roles"),
(r"IHandler|IPlayerData|IPlayerQuest", "noppes.npcs.api.handler"),
# Everything else → default package
]
# Service routing: MC simple name → service target
# Defines WHERE service methods go for FORCE_SERVICE types.
SERVICE_ROUTING = {
"CompressedStreamTools": {
"service": "NBTIO",
"file": "platform-api/src/main/java/noppes/npcs/platform/nbt/NBTIO.java",
"reason": "NBT I/O operations belong with NBT infrastructure",
},
"PlayerSelector": {
"service": "PlatformService",
"file": "platform-api/src/main/java/kamkeel/npcs/platform/PlatformService.java",
"reason": "Single static method (matchPlayers), too small for own service",
},
"MinecraftServer": {
"service": "PlatformService",
"file": "platform-api/src/main/java/kamkeel/npcs/platform/PlatformService.java",
"reason": "Server access is a core platform concern (getServer, isDedicatedServer)",
},
"StringTranslate": {
"service": "PlatformService",
"file": "platform-api/src/main/java/kamkeel/npcs/platform/PlatformService.java",
"reason": "Translation is platform-specific (different I18n in each version)",
},
"FMLCommonHandler": {
"service": "PlatformService",
"file": "platform-api/src/main/java/kamkeel/npcs/platform/PlatformService.java",
"reason": "Side detection is platform infrastructure",
},
"ServerConfigurationManager": {
"service": "PlatformService",
"file": "platform-api/src/main/java/kamkeel/npcs/platform/PlatformService.java",
"reason": "Player management access is core platform concern",
},
"JsonToNBT": {
"service": "NBTIO",
"file": "platform-api/src/main/java/noppes/npcs/platform/nbt/NBTIO.java",
"reason": "JSON↔NBT conversion belongs with NBT infrastructure",
},
"StatCollector": {
"service": "PlatformService",
"file": "platform-api/src/main/java/kamkeel/npcs/platform/PlatformService.java",
"reason": "Translation/localization is platform-specific",
},
}
# ============================================================
# SECTION 5: STATIC TRANSFORM PATTERNS
# Regex patterns for FORCE_TRANSFORM types.
# Used by Static-Transform.ps1 during migration waves.
#
# Format: "MCTypeName": [(regex_pattern, replacement), ...]
#
# HOW TO ADD: When you identify a new pattern for a TRANSFORM type,
# add the regex + replacement here. The classify command shows
# these patterns in its output.
# ============================================================
TRANSFORM_PATTERNS = {
"Side": [
(r"@SideOnly\s*\(\s*Side\.CLIENT\s*\)", "@ClientOnly"),
(r"@SideOnly\s*\(\s*Side\.SERVER\s*\)", "@ServerOnly"),
],
"SideOnly": [], # Handled by Side patterns above
"MathHelper": [
(r"MathHelper\.clamp_int\s*\(", "ValueUtil.clampInt("),
(r"MathHelper\.clamp_float\s*\(", "ValueUtil.clampFloat("),
(r"MathHelper\.clamp_double\s*\(", "ValueUtil.clampDouble("),
(r"MathHelper\.sqrt_double\s*\(", "Math.sqrt("),
(r"MathHelper\.sqrt_float\s*\(", "(float)Math.sqrt("),
(r"MathHelper\.floor_double\s*\(", "ValueUtil.floorDouble("),
(r"MathHelper\.floor_float\s*\(", "ValueUtil.floorFloat("),
],
"EnumChatFormatting": [
# Typically replaced with string constants or suppressed in core
# Add specific patterns as migration progresses
],
"EnumFacing": [
# Direction enum — add patterns when core code needs directions
],
}
# ============================================================
# SECTION 6: PARAMETER TYPE RESOLUTION
# When generating PA interface method signatures, MC types in
# parameters and return types need to be resolved to PA types.
#
# Strategy for types NOT in this map:
# "object" — use Object (pragmatic, safe, fast)
# "recursive" — also generate interfaces for param types (thorough)
# ============================================================
UNRESOLVED_PARAM_STRATEGY = "object"
# Known parameter type mappings: MC simple name → PA type name
# Used when generating interface method signatures.
PARAM_TYPE_MAP = {
# ---- Already abstracted (mirrors EXISTING_MAPPINGS by simple name) ----
"EntityPlayer": "IPlayer",
"EntityPlayerMP": "IPlayer",
"NBTTagCompound": "INbt",
"NBTTagList": "INbtList",
"ItemStack": "IItemStack",
"World": "IWorld",
"WorldServer": "IWorld",
"DamageSource": "IDamageSource",
"Entity": "IEntity",
"EntityLivingBase": "IEntityLivingBase",
"EntityLiving": "IEntityLiving",
# ---- Planned abstractions (use the NAMING value) ----
"ResourceLocation": "IResourceLocation",
"ChatComponentText": "ITextComponent",
"ChatComponentTranslation": "ITextComponent",
"IChatComponent": "ITextComponent",
"AxisAlignedBB": "IBoundingBox",
"Vec3": "IVector3",
"GameProfile": "IGameProfile",
"PotionEffect": "IPotionEffect",
"Potion": "IPotionType",
"Enchantment": "IEnchantment",
"ICommandSender": "ICommandSender",
"MovingObjectPosition": "IRayTraceResult",
# ---- Java primitives (pass through unchanged) ----
"String": "String",
"int": "int",
"float": "float",
"double": "double",
"boolean": "boolean",
"long": "long",
"byte": "byte",
"short": "short",
"char": "char",
"void": "void",
"byte[]": "byte[]",
"int[]": "int[]",
"String[]": "String[]",
"float[]": "float[]",
"double[]": "double[]",
# ---- Java standard library (pass through unchanged) ----
"List": "List",
"ArrayList": "List",
"Map": "Map",
"HashMap": "Map",
"Set": "Set",
"HashSet": "Set",
"Collection": "Collection",
"File": "File",
"UUID": "UUID",
"InputStream": "InputStream",
"OutputStream": "OutputStream",
"DataInputStream": "DataInputStream",
"DataOutputStream": "DataOutputStream",
"Object": "Object",
"Runnable": "Runnable",
}
# ============================================================
# SECTION 7: METHOD FILTERING
# Controls which methods are included/excluded in generated interfaces.
# ============================================================
# Methods to ALWAYS exclude from generated interfaces
# (inherited Object methods that never belong in PA interfaces)
EXCLUDED_METHODS = [
"toString",
"hashCode",
"equals",
"clone",
"finalize",
"getClass",
"notify",
"notifyAll",
"wait",
]
# Obfuscated MCP method names → readable names
# When surface-miner finds these, use the readable name in generated interfaces.
OBFUSCATED_METHOD_NAMES = {
"func_152457_a": "decompress",
"func_150296_c": "getTagType",
"func_150299_b": "getKeySet",
"func_74875_a": "getTagList",
"func_82580_o": "getShort",
"func_150295_c": "merge",
"func_74737_a": "copy",
"func_74732_a": "getId",
}
# If True, obfuscated methods (matching func_\d+_[a-z]) that are NOT in
# OBFUSCATED_METHOD_NAMES are excluded from generated interfaces.
EXCLUDE_UNMAPPED_OBFUSCATED = True
# ============================================================
# SECTION 8: JAVA CONSTRAINTS
# Compile-time constraints that affect generated code shape.
# ============================================================
# Java language level for generated interfaces.
# Java 7: no default methods, no static interface methods.
# Java 8: default and static methods allowed.
JAVA_TARGET = 7
# If True, add @Override on wrapper methods implementing PA interfaces.
ADD_OVERRIDE = True
# ============================================================
# SECTION 9: HELPER FUNCTIONS
# Convenience functions for consuming the rules above.
# These are the primary API for other modules.
# ============================================================
def _simple_name(fqn_or_simple):
"""Extract simple class name from FQN or return as-is."""
return fqn_or_simple.rsplit(".", 1)[-1] if "." in fqn_or_simple else fqn_or_simple
def is_existing(fqn):
"""Check if a fully-qualified MC type already has a PA abstraction."""
return fqn in EXISTING_MAPPINGS
def get_existing_pa(fqn):
"""Get the PA interface name for an already-abstracted MC type, or None."""
return EXISTING_MAPPINGS.get(fqn)
def classify_type(simple_name, surface_data=None):
"""
Classify an MC type into a migration category.
Args:
simple_name: MC class simple name (e.g. "MinecraftServer")
surface_data: Optional dict from surface-miner with keys:
"methods": [{"name": str, "kind": "static"|"instance", "count": int}, ...]
If provided, enables AUTO classification with heuristics.
Returns:
dict with keys:
"classification": "EXISTING"|"INTERFACE"|"SERVICE"|"TRANSFORM"|"SUPPRESS"|"AUTO"
"reason": str explaining why
"pa_name": str or None (the PA interface/service name)
"target": str or None (service file path for SERVICE types)
"transform_patterns": list or None (regex patterns for TRANSFORM types)
"""
name = _simple_name(simple_name)
# Check EXISTING first (by simple name match against EXISTING_MAPPINGS values)
for fqn, pa in EXISTING_MAPPINGS.items():
if _simple_name(fqn) == name:
return {
"classification": "EXISTING",
"reason": f"Already abstracted as {pa}",
"pa_name": pa,
"target": None,
"transform_patterns": None,
}
# Check SUPPRESS
if name in SUPPRESS:
return {
"classification": "SUPPRESS",
"reason": "Suppressed (client-only, debug, networking, or stays in mc1710)",
"pa_name": None,
"target": None,
"transform_patterns": None,
}
# Check FORCE_TRANSFORM
if name in FORCE_TRANSFORM:
patterns = TRANSFORM_PATTERNS.get(name, [])
return {
"classification": "TRANSFORM",
"reason": f"Static-Transform ({len(patterns)} regex patterns)",
"pa_name": None,
"target": None,
"transform_patterns": patterns,
}
# Check FORCE_SERVICE
if name in FORCE_SERVICE:
routing = SERVICE_ROUTING.get(name, {})
return {
"classification": "SERVICE",
"reason": routing.get("reason", "Force-classified as service"),
"pa_name": None,
"target": routing.get("file"),
"service_name": routing.get("service", "PlatformService"),
"transform_patterns": None,
}
# Check FORCE_INTERFACE
if name in FORCE_INTERFACE:
pa_name = get_pa_name(name)
return {
"classification": "INTERFACE",
"reason": "Force-classified as interface",
"pa_name": pa_name,
"target": _resolve_interface_path(pa_name),
"transform_patterns": None,
}
# AUTO classification using surface data (if provided)
if surface_data and surface_data.get("methods"):
methods = surface_data["methods"]
total = len(methods)
static_count = sum(1 for m in methods if m.get("kind") == "static")
static_ratio = static_count / total if total > 0 else 0
if total < MIN_METHODS_FOR_INTERFACE:
return {
"classification": "SERVICE",
"reason": f"Auto: only {total} methods (< {MIN_METHODS_FOR_INTERFACE} threshold)",
"pa_name": None,
"target": "platform-api/src/main/java/kamkeel/npcs/platform/PlatformService.java",
"service_name": "PlatformService",
"transform_patterns": None,
}
if static_ratio > STATIC_THRESHOLD:
return {
"classification": "SERVICE",
"reason": f"Auto: {static_ratio:.0%} static methods (> {STATIC_THRESHOLD:.0%} threshold)",
"pa_name": None,
"target": "platform-api/src/main/java/kamkeel/npcs/platform/PlatformService.java",
"service_name": "PlatformService",
"transform_patterns": None,
}
pa_name = get_pa_name(name)
return {
"classification": "INTERFACE",
"reason": f"Auto: {total} methods, {static_ratio:.0%} static → instance-heavy",
"pa_name": pa_name,
"target": _resolve_interface_path(pa_name),
"transform_patterns": None,
}
# No data, no explicit rule → UNKNOWN
return {
"classification": "AUTO",
"reason": "Not classified. Run with --surface to enable auto-classification.",
"pa_name": get_pa_name(name),
"target": None,
"transform_patterns": None,
}
def get_pa_name(simple_name):
"""
Get the PA interface name for an MC type.
Uses NAMING overrides, falls back to "I" + simple_name.
"""
name = _simple_name(simple_name)
return NAMING.get(name, f"I{name}")
def get_service_target(simple_name):
"""
Get the service routing for a SERVICE-classified type.
Returns dict with 'service', 'file', 'reason' or None.
"""
name = _simple_name(simple_name)
return SERVICE_ROUTING.get(name)
def resolve_param_type(mc_type_name):
"""
Resolve an MC type name to its PA equivalent for use in method signatures.
Returns the PA type name, or "Object" if unresolved (per UNRESOLVED_PARAM_STRATEGY).
"""
name = _simple_name(mc_type_name)
resolved = PARAM_TYPE_MAP.get(name)
if resolved:
return resolved
if UNRESOLVED_PARAM_STRATEGY == "object":
return "Object"
return name # "recursive" strategy — caller handles generation
def should_exclude_method(method_name):
"""Check if a method should be excluded from generated interfaces."""
if method_name in EXCLUDED_METHODS:
return True
if EXCLUDE_UNMAPPED_OBFUSCATED and re.match(r"func_\d+_[a-z]", method_name):
return method_name not in OBFUSCATED_METHOD_NAMES
return False
def resolve_obfuscated_method(method_name):
"""Resolve an obfuscated MCP method name to readable, or return as-is."""
return OBFUSCATED_METHOD_NAMES.get(method_name, method_name)
def get_interface_package(pa_name):
"""Determine which package a PA interface should go in based on its name."""
for pattern, package in PACKAGE_ROUTING:
if re.search(pattern, pa_name):
return package
return DEFAULT_INTERFACE_PACKAGE
def _resolve_interface_path(pa_name):
"""Build the full file path for a PA interface."""
package = get_interface_package(pa_name)
package_path = package.replace(".", "/")
return f"platform-api/src/main/java/{package_path}/{pa_name}.java"
# ============================================================
# SECTION 10: QUICK REFERENCE
# Summary of all classified types for fast lookup.
# Run: python -m pa_rules to see the full classification table.
# ============================================================
if __name__ == "__main__":
print("=" * 72)
print("PA GENERATION RULES — CLASSIFICATION SUMMARY")
print("=" * 72)
print(f"\n EXISTING ({len(EXISTING_MAPPINGS)} types):")
for fqn, pa in sorted(EXISTING_MAPPINGS.items(), key=lambda x: x[1]):
print(f" {_simple_name(fqn):30s} → {pa}")
print(f"\n INTERFACE ({len(FORCE_INTERFACE)} types):")
for t in sorted(FORCE_INTERFACE):
pa = get_pa_name(t)
path = _resolve_interface_path(pa)
print(f" {t:30s} → {pa:20s} {path}")
print(f"\n SERVICE ({len(FORCE_SERVICE)} types):")
for t in sorted(FORCE_SERVICE):
routing = SERVICE_ROUTING.get(t, {})
svc = routing.get("service", "PlatformService")
print(f" {t:30s} → {svc}")
print(f"\n TRANSFORM ({len(FORCE_TRANSFORM)} types):")
for t in sorted(FORCE_TRANSFORM):
patterns = TRANSFORM_PATTERNS.get(t, [])
print(f" {t:30s} ({len(patterns)} patterns)")
print(f"\n SUPPRESS ({len(SUPPRESS)} types):")
for i in range(0, len(SUPPRESS), 6):
chunk = SUPPRESS[i : i + 6]
print(f" {', '.join(chunk)}")
total = (
len(EXISTING_MAPPINGS)
+ len(FORCE_INTERFACE)
+ len(FORCE_SERVICE)
+ len(FORCE_TRANSFORM)
+ len(SUPPRESS)
)
print(f"\n TOTAL CLASSIFIED: {total}")
print(f" REMAINING AUTO: {400 - total} (of ~400 MC types in codebase)")
print(f"\n Run 'python analyze.py classify <type>' for per-type classification.")