@workos/oagen 0.30.1 → 0.30.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.mjs +135 -30
- package/dist/cli/index.mjs.map +1 -1
- package/dist/compat/index.d.mts +2 -2
- package/dist/compat/index.mjs +2 -2
- package/dist/{diff-DMFiDAI6.mjs → diff-BO5FieX5.mjs} +4 -2
- package/dist/{diff-DMFiDAI6.mjs.map → diff-BO5FieX5.mjs.map} +1 -1
- package/dist/{differ-DHldxZMr.d.mts → differ-nZSxhCfC.d.mts} +2 -2
- package/dist/{differ-DHldxZMr.d.mts.map → differ-nZSxhCfC.d.mts.map} +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +130 -32
- package/dist/index.mjs.map +1 -1
- package/dist/{overlay-BhXruu32.mjs → overlay-DWAHPofk.mjs} +3 -2
- package/dist/overlay-DWAHPofk.mjs.map +1 -0
- package/dist/scripts/smoke/baseline.mjs +128 -30
- package/dist/scripts/smoke/baseline.mjs.map +1 -1
- package/dist/smoke.d.mts +8 -0
- package/dist/smoke.d.mts.map +1 -1
- package/dist/smoke.mjs +128 -30
- package/dist/smoke.mjs.map +1 -1
- package/dist/{tree-sitter-C6HB4OrC.mjs → tree-sitter-CDKm3n64.mjs} +2 -1
- package/dist/tree-sitter-CDKm3n64.mjs.map +1 -0
- package/dist/{types-yrBidOg3.d.mts → types-BcbGLNkh.d.mts} +9 -1
- package/dist/{types-yrBidOg3.d.mts.map → types-BcbGLNkh.d.mts.map} +1 -1
- package/dist/verify/index.d.mts +2 -2
- package/dist/verify/index.mjs +3 -3
- package/docs/architecture/ir-types.md +5 -0
- package/package.json +1 -1
- package/dist/overlay-BhXruu32.mjs.map +0 -1
- package/dist/tree-sitter-C6HB4OrC.mjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"overlay-BhXruu32.mjs","names":["defaultNodeHints"],"sources":["../src/compat/policy.ts","../src/compat/schema.ts","../src/compat/ir.ts","../src/compat/config.ts","../src/compat/classify.ts","../src/compat/language-hints.ts","../src/compat/spec-filter.ts","../src/compat/differ.ts","../src/compat/extractor-registry.ts","../src/compat/overlay.ts"],"sourcesContent":["/**\n * Language-aware compatibility policy.\n *\n * Defines which aspects of the public API surface are breaking in each\n * language. Built-in defaults capture language semantics (e.g., PHP has\n * named arguments, Go does not). Config overrides allow per-SDK divergence.\n */\n\nimport type { LanguageId } from './ir.js';\n\n/** Policy hints that determine what constitutes a breaking change. */\nexport interface CompatPolicyHints {\n /** Callers reference parameter names at the call site (PHP named args, Python/Ruby keyword args, Kotlin/C# named args). */\n callerUsesParamNames: boolean;\n /** Constructor positional order is part of the public API. */\n constructorOrderMatters: boolean;\n /** Method parameter names are visible to callers. */\n methodParameterNamesArePublicApi: boolean;\n /** Constructor parameter names are visible to callers. */\n constructorParameterNamesArePublicApi: boolean;\n /** Method overload sets are part of the public API (Kotlin, C#). */\n overloadsArePublicApi: boolean;\n /** Function arity is part of the public API (Elixir, Go). */\n arityIsPublicApi: boolean;\n}\n\n/** Built-in language defaults. */\nconst LANGUAGE_DEFAULTS: Record<LanguageId, CompatPolicyHints> = {\n php: {\n callerUsesParamNames: true,\n constructorOrderMatters: true,\n methodParameterNamesArePublicApi: true,\n constructorParameterNamesArePublicApi: true,\n overloadsArePublicApi: false,\n arityIsPublicApi: false,\n },\n python: {\n callerUsesParamNames: true,\n constructorOrderMatters: true,\n methodParameterNamesArePublicApi: true,\n constructorParameterNamesArePublicApi: true,\n overloadsArePublicApi: false,\n arityIsPublicApi: false,\n },\n ruby: {\n callerUsesParamNames: true,\n constructorOrderMatters: true,\n methodParameterNamesArePublicApi: true,\n constructorParameterNamesArePublicApi: true,\n overloadsArePublicApi: false,\n arityIsPublicApi: false,\n },\n go: {\n callerUsesParamNames: false,\n constructorOrderMatters: true,\n methodParameterNamesArePublicApi: false,\n constructorParameterNamesArePublicApi: false,\n overloadsArePublicApi: false,\n arityIsPublicApi: true,\n },\n kotlin: {\n callerUsesParamNames: true,\n constructorOrderMatters: false,\n methodParameterNamesArePublicApi: true,\n constructorParameterNamesArePublicApi: true,\n overloadsArePublicApi: true,\n arityIsPublicApi: false,\n },\n dotnet: {\n callerUsesParamNames: true,\n constructorOrderMatters: false,\n methodParameterNamesArePublicApi: true,\n constructorParameterNamesArePublicApi: true,\n overloadsArePublicApi: true,\n arityIsPublicApi: false,\n },\n elixir: {\n callerUsesParamNames: true,\n constructorOrderMatters: false,\n methodParameterNamesArePublicApi: true,\n constructorParameterNamesArePublicApi: false,\n overloadsArePublicApi: false,\n arityIsPublicApi: true,\n },\n rust: {\n callerUsesParamNames: false,\n constructorOrderMatters: true,\n methodParameterNamesArePublicApi: false,\n constructorParameterNamesArePublicApi: false,\n overloadsArePublicApi: false,\n arityIsPublicApi: true,\n },\n // Swift: argument labels are mandatory and order-sensitive at the call\n // site, so both names and positions are public API. Overloading is legal.\n ios: {\n callerUsesParamNames: true,\n constructorOrderMatters: true,\n methodParameterNamesArePublicApi: true,\n constructorParameterNamesArePublicApi: true,\n overloadsArePublicApi: true,\n arityIsPublicApi: false,\n },\n node: {\n callerUsesParamNames: false,\n constructorOrderMatters: false,\n methodParameterNamesArePublicApi: false,\n constructorParameterNamesArePublicApi: false,\n overloadsArePublicApi: false,\n arityIsPublicApi: false,\n },\n};\n\n/** Get the built-in default policy for a language. */\nexport function getDefaultPolicy(language: LanguageId): CompatPolicyHints {\n return { ...LANGUAGE_DEFAULTS[language] };\n}\n\n/** Merge user overrides onto language defaults. Only provided keys are overridden. */\nexport function mergePolicy(defaults: CompatPolicyHints, overrides: Partial<CompatPolicyHints>): CompatPolicyHints {\n return { ...defaults, ...overrides };\n}\n\n/** All supported language IDs. */\nexport const ALL_LANGUAGE_IDS: readonly LanguageId[] = Object.keys(LANGUAGE_DEFAULTS) as LanguageId[];\n","/**\n * Schema versioning for compatibility snapshots.\n *\n * Snapshots are versioned so consumers can detect format changes and\n * apply migration logic if needed.\n */\n\nimport type { CompatSnapshot } from './ir.js';\n\n/** Current schema version for compatibility snapshots. */\nexport const COMPAT_SCHEMA_VERSION = '1';\n\n/** Validate that a parsed snapshot has a compatible schema version. */\nexport function isCompatibleSchemaVersion(snapshot: { schemaVersion?: string }): boolean {\n return snapshot.schemaVersion === COMPAT_SCHEMA_VERSION;\n}\n\n/** Validate the basic structure of a parsed compat snapshot. */\nexport function validateSnapshot(data: unknown): data is CompatSnapshot {\n if (typeof data !== 'object' || data === null) return false;\n const obj = data as Record<string, unknown>;\n return (\n typeof obj.schemaVersion === 'string' &&\n typeof obj.source === 'object' &&\n obj.source !== null &&\n typeof obj.policies === 'object' &&\n obj.policies !== null &&\n Array.isArray(obj.symbols)\n );\n}\n","/**\n * Rich compatibility IR for cross-language compatibility verification.\n *\n * These types represent the public API surface of an SDK in a language-aware,\n * machine-readable format. They extend the basic ApiSurface with richer\n * parameter semantics, sensitivity flags, and provenance metadata.\n */\n\nimport type { CompatPolicyHints } from './policy.js';\n\n/** Language identifier for emitter targets. */\nexport type LanguageId = 'node' | 'php' | 'python' | 'ruby' | 'go' | 'kotlin' | 'dotnet' | 'elixir' | 'rust' | 'ios';\n\n/** A full compatibility snapshot of an SDK's public API surface. */\nexport interface CompatSnapshot {\n schemaVersion: string;\n source: {\n specSha?: string;\n extractedAt: string;\n /** Language the snapshot was extracted for. Older snapshots omit this;\n * the differ falls back to no type-form normalization when absent. */\n language?: LanguageId;\n };\n policies: CompatPolicyHints;\n symbols: CompatSymbol[];\n}\n\n/** Kind of public API symbol. */\nexport type CompatSymbolKind =\n | 'service_accessor'\n | 'callable'\n | 'constructor'\n | 'field'\n | 'property'\n | 'enum'\n | 'enum_member'\n | 'alias';\n\n/** Visibility level of a symbol. */\nexport type CompatVisibility = 'public' | 'protected' | 'internal';\n\n/** Stability classification of a symbol. */\nexport type CompatStability = 'stable' | 'unstable' | 'deprecated';\n\n/** How the symbol was generated. */\nexport type CompatSourceKind =\n | 'generated_service_wrapper'\n | 'generated_model_constructor'\n | 'generated_resource_constructor'\n | 'generated_enum'\n | 'compat_alias';\n\n/** A single public API symbol with its full metadata. */\nexport interface CompatSymbol {\n id: string;\n kind: CompatSymbolKind;\n fqName: string;\n ownerFqName?: string;\n displayName: string;\n visibility: CompatVisibility;\n stability: CompatStability;\n sourceKind: CompatSourceKind;\n operationId?: string;\n schemaName?: string;\n route?: {\n method: string;\n path: string;\n };\n parameters?: CompatParameter[];\n returns?: CompatTypeRef;\n /** Type reference for field/property symbols. */\n typeRef?: CompatTypeRef;\n /** Value for enum member symbols. */\n value?: string | number;\n /** Whether a callable is a static/type-level method. Absent when the\n * extractor does not capture staticness; the classifier only compares\n * it when both snapshots define it, so older snapshots never diff. */\n isStatic?: boolean;\n /** Relative path to the source file where this symbol is defined. */\n sourceFile?: string;\n}\n\n/** How a parameter is passed at the call site. */\nexport type CompatPassingStyle =\n | 'positional'\n | 'keyword'\n | 'named'\n | 'keyword_or_positional'\n | 'options_object'\n | 'builder';\n\n/** A parameter on a callable or constructor symbol. */\nexport interface CompatParameter {\n publicName: string;\n wireName?: string;\n position: number;\n required: boolean;\n nullable: boolean;\n hasDefault: boolean;\n passing: CompatPassingStyle;\n type: CompatTypeRef;\n sensitivity: ParameterSensitivity;\n}\n\n/** Which aspects of this parameter are part of the public API contract. */\nexport interface ParameterSensitivity {\n order: boolean;\n publicName: boolean;\n requiredness: boolean;\n type: boolean;\n}\n\n/** A type reference — either a named type or an inline description. */\nexport interface CompatTypeRef {\n name: string;\n nullable?: boolean;\n array?: boolean;\n generic?: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Bridge: ApiSurface → CompatSnapshot\n// ---------------------------------------------------------------------------\n\nimport type { ApiSurface, ApiParam } from './types.js';\nimport { getDefaultPolicy } from './policy.js';\nimport { COMPAT_SCHEMA_VERSION } from './schema.js';\n\n/**\n * Convert a legacy ApiSurface to a CompatSnapshot.\n *\n * This bridge allows existing extractors (which produce ApiSurface) to feed\n * into the new classified diff engine without requiring immediate migration.\n */\nexport function apiSurfaceToSnapshot(surface: ApiSurface): CompatSnapshot {\n const language = (surface.language || 'node') as LanguageId;\n const symbols: CompatSymbol[] = [];\n\n // Convert classes → service_accessor symbols + callable/constructor children\n for (const [className, cls] of Object.entries(surface.classes)) {\n symbols.push({\n id: `class:${className}`,\n kind: 'service_accessor',\n fqName: className,\n displayName: className,\n visibility: 'public',\n stability: cls.deprecationMessage ? 'deprecated' : 'stable',\n sourceKind: 'generated_service_wrapper',\n ...(cls.sourceFile ? { sourceFile: cls.sourceFile } : {}),\n });\n\n // Constructor\n if (cls.constructorParams.length > 0) {\n symbols.push({\n id: `ctor:${className}`,\n kind: 'constructor',\n fqName: `${className}.constructor`,\n ownerFqName: className,\n displayName: `new ${className}`,\n visibility: 'public',\n stability: 'stable',\n sourceKind: 'generated_resource_constructor',\n parameters: cls.constructorParams.map((p, i) => apiParamToCompatParam(p, i, language)),\n ...(cls.sourceFile ? { sourceFile: cls.sourceFile } : {}),\n });\n }\n\n // Methods\n for (const [methodName, overloads] of Object.entries(cls.methods)) {\n for (let oi = 0; oi < overloads.length; oi++) {\n const method = overloads[oi];\n const suffix = overloads.length > 1 ? `#${oi}` : '';\n symbols.push({\n id: `method:${className}.${methodName}${suffix}`,\n kind: 'callable',\n fqName: `${className}.${methodName}`,\n ownerFqName: className,\n displayName: `${className}.${methodName}`,\n visibility: 'public',\n stability: 'stable',\n sourceKind: 'generated_service_wrapper',\n parameters: method.params.map((p, i) => apiParamToCompatParam(p, i, language)),\n returns: { name: method.returnType },\n ...(method.isStatic !== undefined ? { isStatic: method.isStatic } : {}),\n ...(cls.sourceFile ? { sourceFile: cls.sourceFile } : {}),\n });\n }\n }\n\n // Properties\n for (const [propName, prop] of Object.entries(cls.properties)) {\n symbols.push({\n id: `prop:${className}.${propName}`,\n kind: 'property',\n fqName: `${className}.${propName}`,\n ownerFqName: className,\n displayName: `${className}.${propName}`,\n visibility: 'public',\n stability: 'stable',\n sourceKind: 'generated_service_wrapper',\n typeRef: { name: prop.type },\n ...(cls.sourceFile ? { sourceFile: cls.sourceFile } : {}),\n });\n }\n }\n\n // Convert interfaces → field symbols\n for (const [ifaceName, iface] of Object.entries(surface.interfaces)) {\n symbols.push({\n id: `iface:${ifaceName}`,\n kind: 'alias',\n fqName: ifaceName,\n displayName: ifaceName,\n visibility: 'public',\n stability: 'stable',\n sourceKind: 'generated_resource_constructor',\n ...(iface.sourceFile ? { sourceFile: iface.sourceFile } : {}),\n });\n\n for (const [fieldName, field] of Object.entries(iface.fields)) {\n symbols.push({\n id: `field:${ifaceName}.${fieldName}`,\n kind: 'field',\n fqName: `${ifaceName}.${fieldName}`,\n ownerFqName: ifaceName,\n displayName: `${ifaceName}.${fieldName}`,\n visibility: 'public',\n stability: 'stable',\n sourceKind: 'generated_resource_constructor',\n typeRef: { name: field.type },\n ...(iface.sourceFile ? { sourceFile: iface.sourceFile } : {}),\n });\n }\n\n // Constructor if interface has one\n if (iface.hasCustomConstructor) {\n symbols.push({\n id: `ctor:${ifaceName}`,\n kind: 'constructor',\n fqName: `${ifaceName}.constructor`,\n ownerFqName: ifaceName,\n displayName: `new ${ifaceName}`,\n visibility: 'public',\n stability: 'stable',\n sourceKind: 'generated_resource_constructor',\n ...(iface.sourceFile ? { sourceFile: iface.sourceFile } : {}),\n });\n }\n }\n\n // Convert type aliases\n for (const [aliasName, alias] of Object.entries(surface.typeAliases)) {\n symbols.push({\n id: `alias:${aliasName}`,\n kind: 'alias',\n fqName: aliasName,\n displayName: aliasName,\n visibility: 'public',\n stability: 'stable',\n sourceKind: 'generated_resource_constructor',\n ...(alias.sourceFile ? { sourceFile: alias.sourceFile } : {}),\n });\n }\n\n // Convert enums\n for (const [enumName, enumDef] of Object.entries(surface.enums)) {\n symbols.push({\n id: `enum:${enumName}`,\n kind: 'enum',\n fqName: enumName,\n displayName: enumName,\n visibility: 'public',\n stability: 'stable',\n sourceKind: 'generated_enum',\n ...(enumDef.sourceFile ? { sourceFile: enumDef.sourceFile } : {}),\n });\n\n for (const [memberName, memberValue] of Object.entries(enumDef.members)) {\n symbols.push({\n id: `enum_member:${enumName}.${memberName}`,\n kind: 'enum_member',\n fqName: `${enumName}.${memberName}`,\n ownerFqName: enumName,\n displayName: `${enumName}.${memberName}`,\n visibility: 'public',\n stability: 'stable',\n sourceKind: 'generated_enum',\n value: memberValue,\n ...(enumDef.sourceFile ? { sourceFile: enumDef.sourceFile } : {}),\n });\n }\n }\n\n return {\n schemaVersion: COMPAT_SCHEMA_VERSION,\n source: { extractedAt: surface.extractedAt, language },\n policies: getDefaultPolicy(language),\n symbols,\n };\n}\n\n/** Convert a legacy ApiParam to a CompatParameter. */\nfunction apiParamToCompatParam(param: ApiParam, position: number, language: LanguageId): CompatParameter {\n const policy = getDefaultPolicy(language);\n const passing = param.passingStyle ?? inferPassingStyle(language);\n return {\n publicName: param.name,\n position,\n required: !param.optional,\n nullable: false,\n hasDefault: param.optional,\n passing,\n type: { name: param.type },\n sensitivity: {\n // Method-call order matters only when callers pass positionally. keyword\n // (Ruby/Python/Elixir) and options_object (Node) hide position entirely;\n // named (PHP/Kotlin/C#) is handled as soft-risk in classify.\n order: passing === 'positional',\n publicName: policy.methodParameterNamesArePublicApi,\n requiredness: true,\n type: true,\n },\n };\n}\n\n/** Infer the default parameter passing style for a language. */\nfunction inferPassingStyle(language: LanguageId): CompatPassingStyle {\n switch (language) {\n case 'python':\n case 'ruby':\n case 'elixir':\n return 'keyword';\n case 'php':\n case 'kotlin':\n case 'dotnet':\n return 'named';\n case 'node':\n return 'options_object';\n // Swift argument labels are mandatory at the call site and fixed in\n // declaration order, so parameters behave like labeled positional args.\n case 'ios':\n default:\n return 'positional';\n }\n}\n","/**\n * Compat configuration types for `oagen.config.ts`.\n *\n * The `compat` section of the config holds human-authored policy:\n * fail thresholds, language overrides, and intentional break approvals.\n * Generated state (manifests, snapshots, reports) lives elsewhere.\n */\n\nimport type { LanguageId } from './ir.js';\nimport type { CompatPolicyHints } from './policy.js';\n\n// ---------------------------------------------------------------------------\n// Change categories\n// ---------------------------------------------------------------------------\n\n/** Breaking change categories — changes that break callers. */\nexport type BreakingChangeCategory =\n | 'symbol_removed'\n | 'symbol_renamed'\n | 'parameter_removed'\n | 'parameter_renamed'\n | 'parameter_requiredness_increased'\n | 'parameter_type_narrowed'\n | 'parameter_position_changed_order_sensitive'\n | 'constructor_position_changed_order_sensitive'\n | 'named_arg_name_removed'\n | 'keyword_name_removed'\n | 'overload_removed'\n | 'union_wrapper_migration_without_compat_alias'\n | 'field_type_changed'\n | 'return_type_changed'\n | 'enum_member_value_changed'\n | 'staticness_changed';\n\n/** Soft-risk change categories — may affect callers depending on usage. */\nexport type SoftRiskChangeCategory =\n | 'parameter_added_non_terminal_optional'\n | 'constructor_reordered_named_friendly'\n | 'default_value_changed'\n | 'wrapper_stricter_than_previous_sdk_but_matches_spec'\n | 'doc_surface_drift';\n\n/** Additive change categories — safe to ship. */\nexport type AdditiveChangeCategory =\n | 'symbol_added'\n | 'parameter_added_optional_terminal'\n | 'new_constructor_overload_added'\n | 'new_wrapper_alias_added';\n\n/** All change categories. */\nexport type CompatChangeCategory = BreakingChangeCategory | SoftRiskChangeCategory | AdditiveChangeCategory;\n\n/** Change severity levels. */\nexport type CompatChangeSeverity = 'breaking' | 'soft-risk' | 'additive';\n\n/** Provenance bucket — where the drift originated. */\nexport type CompatProvenance =\n | 'spec_shape_change'\n | 'spec_ordering_change'\n | 'emitter_template_change'\n | 'compat_extractor_change'\n | 'operation_hint_change'\n | 'manual_override_change'\n | 'normalization_change'\n | 'unknown';\n\n// ---------------------------------------------------------------------------\n// Fail threshold\n// ---------------------------------------------------------------------------\n\n/** Level at which `verify` should fail. */\nexport type CompatFailLevel = 'none' | 'breaking' | 'soft-risk';\n\n// ---------------------------------------------------------------------------\n// Approvals\n// ---------------------------------------------------------------------------\n\n/** A single intentional-break approval in `oagen.config.ts`. */\nexport interface CompatApproval {\n /** Fully-qualified symbol (e.g., \"Acme\\\\Service\\\\Users::createUser\"). */\n symbol: string;\n /** The kind of change being approved. */\n category: CompatChangeCategory;\n /** Languages this approval applies to. Omit for all impacted languages. */\n appliesTo?: LanguageId[] | 'all-impacted-languages';\n /** Optional narrowing criteria. */\n match?: {\n parameter?: string;\n member?: string;\n oldName?: string;\n newName?: string;\n };\n /** Minimum release level required for this break. */\n allowedReleaseLevel?: 'major' | 'minor' | 'patch';\n /** Human-readable reason for this approval. */\n reason: string;\n /** Issue tracker reference (e.g., \"SDK-1234\"). */\n issue?: string;\n /** Auto-expire this approval after a version is released. */\n expiresAfterVersion?: string;\n /** Whether this approval is currently active. */\n approved?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Config section\n// ---------------------------------------------------------------------------\n\n/** The `compat` section of `oagen.config.ts`. */\nexport interface CompatConfig {\n /** Level at which `oagen verify` should fail. Default: 'breaking'. */\n failOn?: CompatFailLevel;\n /** Path to write the machine-readable compat report. */\n reportPath?: string;\n /** Include provenance explanations in reports. */\n explain?: boolean;\n /** Path to the baseline compatibility snapshot. */\n baselinePath?: string;\n /** Per-language policy overrides. Sparse — only override what diverges. */\n languagePolicy?: Partial<Record<LanguageId, Partial<CompatPolicyHints>>>;\n /** Intentional break approvals. */\n allow?: CompatApproval[];\n}\n\n// ---------------------------------------------------------------------------\n// Category → severity mapping\n// ---------------------------------------------------------------------------\n\nconst BREAKING_CATEGORIES: ReadonlySet<BreakingChangeCategory> = new Set<BreakingChangeCategory>([\n 'symbol_removed',\n 'symbol_renamed',\n 'parameter_removed',\n 'parameter_renamed',\n 'parameter_requiredness_increased',\n 'parameter_type_narrowed',\n 'parameter_position_changed_order_sensitive',\n 'constructor_position_changed_order_sensitive',\n 'named_arg_name_removed',\n 'keyword_name_removed',\n 'overload_removed',\n 'union_wrapper_migration_without_compat_alias',\n 'field_type_changed',\n 'return_type_changed',\n 'enum_member_value_changed',\n 'staticness_changed',\n]);\n\nconst SOFT_RISK_CATEGORIES: ReadonlySet<SoftRiskChangeCategory> = new Set<SoftRiskChangeCategory>([\n 'parameter_added_non_terminal_optional',\n 'constructor_reordered_named_friendly',\n 'default_value_changed',\n 'wrapper_stricter_than_previous_sdk_but_matches_spec',\n 'doc_surface_drift',\n]);\n\n/** Get the default severity for a change category. */\nexport function defaultSeverityForCategory(category: CompatChangeCategory): CompatChangeSeverity {\n if (BREAKING_CATEGORIES.has(category as BreakingChangeCategory)) return 'breaking';\n if (SOFT_RISK_CATEGORIES.has(category as SoftRiskChangeCategory)) return 'soft-risk';\n return 'additive';\n}\n\n/** Check whether a severity meets or exceeds a fail threshold. */\nexport function severityMeetsThreshold(severity: CompatChangeSeverity, threshold: CompatFailLevel): boolean {\n if (threshold === 'none') return false;\n if (threshold === 'soft-risk') return severity === 'breaking' || severity === 'soft-risk';\n return severity === 'breaking';\n}\n","/**\n * Change classifier for compatibility verification.\n *\n * Takes raw diffs between baseline and candidate compat snapshots and\n * classifies each change into a specific category with policy-aware severity.\n */\n\nimport type { CompatSymbol, CompatParameter, LanguageId } from './ir.js';\nimport type { CompatPolicyHints } from './policy.js';\nimport type { CompatChangeCategory, CompatChangeSeverity, CompatProvenance } from './config.js';\nimport { defaultSeverityForCategory } from './config.js';\n\n/** A single classified compatibility change. */\nexport interface ClassifiedChange {\n /** Specific change category. */\n category: CompatChangeCategory;\n /** Policy-aware severity (may differ from defaultSeverityForCategory). */\n severity: CompatChangeSeverity;\n /** Fully-qualified symbol path. */\n symbol: string;\n /** Deterministic ID for grouping related changes across languages. */\n conceptualChangeId: string;\n /** Where the drift originated. */\n provenance: CompatProvenance;\n /** Description of the old state. */\n old: Record<string, string>;\n /** Description of the new state. */\n new: Record<string, string>;\n /** Human-readable explanation. */\n message: string;\n /**\n * Optional spec-level remediation hint. Set by post-classification rules\n * (see `detectForkedSchemas` in differ.ts) when a change has a recognized\n * upstream root cause that the spec author can fix. Surfaces in both the\n * machine-readable report and the human-readable summary.\n */\n remediation?: string;\n}\n\n/** Result of classifying all changes between two snapshots. */\nexport interface ClassificationResult {\n changes: ClassifiedChange[];\n summary: {\n breaking: number;\n softRisk: number;\n additive: number;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Type-form normalization\n// ---------------------------------------------------------------------------\n\n/**\n * Normalize a type annotation string to a canonical form before equality\n * comparison. Emitters evolve their annotation style across releases (e.g.\n * Python's PEP 604 `X | None` replacing `Optional[X]`, PEP 585 lowercase\n * generics, or dropping quotes from forward refs); such changes are cosmetic\n * and must not register as breaking type changes. Only Python needs this\n * today — other languages encode optionality with a single stable spelling\n * (`*Foo`, `Option<T>`, `T?`, `T.nilable(Foo)`) so they use exact comparison.\n * String-literal *values* inside `Literal[...]` are preserved verbatim so a\n * genuine change to a wire value stays visible. When `language` is absent\n * (older snapshots) no normalization is applied, preserving prior behaviour.\n */\nfunction normalizeType(type: string, language?: LanguageId): string {\n if (!type) return type;\n if (language !== 'python') return type;\n return canonicalizePythonType(type);\n}\n\n/** PEP 585 capitalized builtins that map to their lowercase spellings, so\n * `List[str]` and `list[str]` compare equal. */\nconst PEP585_BUILTINS: Record<string, string> = {\n List: 'list',\n Dict: 'dict',\n Tuple: 'tuple',\n Set: 'set',\n FrozenSet: 'frozenset',\n Type: 'type',\n};\n\n/** Recursively canonicalize a Python annotation. Structural forms are\n * normalized (`Optional[X]`→`X | None`, `Union[...]`→` | ` joins, PEP 585\n * builtins, quoted forward refs, parenthesized unions), but `Literal[...]`\n * arguments are preserved verbatim — their quotes and inner whitespace are\n * part of the wire value, not cosmetic. */\nfunction canonicalizePythonType(s: string): string {\n const t = s.trim();\n if (t.length === 0) return t;\n // Strip a wrapping pair of parentheses — the emitter sometimes groups\n // multi-line unions as `(A | B)`. Recurse in case of nested wrapping.\n if (t.startsWith('(') && t.endsWith(')')) {\n return canonicalizePythonType(t.slice(1, -1));\n }\n // Literal[...] holds *values*, not types. Normalize the quote *character*\n // (single ↔ double) so a cosmetic emitter quote-style flip doesn't register\n // as a change, but preserve each argument's inner content verbatim so a\n // real change to a wire value (e.g. `\"a b\"` → `\"a b\"`) stays visible.\n // Only spacing between arguments is normalized.\n if (t.startsWith('Literal[') && t.endsWith(']')) {\n const inner = t.slice('Literal['.length, -1);\n return `Literal[${splitTopLevel(inner, ',')\n .map((p) => p.trim())\n .filter((p) => p.length > 0)\n .map(canonicalizeLiteralArg)\n .join(', ')}]`;\n }\n if (t.startsWith('Optional[') && t.endsWith(']')) {\n return `${canonicalizePythonType(t.slice('Optional['.length, -1))} | None`;\n }\n if (t.startsWith('Union[') && t.endsWith(']')) {\n return splitTopLevel(t.slice('Union['.length, -1), ',')\n .map((p) => p.trim())\n .filter((p) => p.length > 0)\n .map(canonicalizePythonType)\n .join(' | ');\n }\n // PEP 604 union at top level: split on `|` and canonicalize each arm.\n if (t.includes('|')) {\n const arms = splitTopLevel(t, '|')\n .map((p) => p.trim())\n .filter((p) => p.length > 0);\n if (arms.length > 1) return arms.map(canonicalizePythonType).join(' | ');\n }\n // Other generic (Dict[str, Any], list[Foo]): preserve the outer constructor,\n // lowercase PEP 585 builtins, and canonicalize each type argument.\n const open = t.indexOf('[');\n if (open !== -1 && t.endsWith(']')) {\n const outer = t.slice(0, open).trim();\n const inner = t.slice(open + 1, -1);\n const canonicalOuter = PEP585_BUILTINS[outer] ?? outer;\n return `${canonicalOuter}[${splitTopLevel(inner, ',')\n .map((p) => p.trim())\n .filter((p) => p.length > 0)\n .map(canonicalizePythonType)\n .join(', ')}]`;\n }\n // Quoted forward ref: \"Foo\" / 'Foo' → Foo. The emitter quotes type names\n // defined later in the file; the quotes are cosmetic. String-literal values\n // are preserved by the Literal branch above, so this only strips quotes from\n // bare type-name references.\n if (\n (t.startsWith('\"') && t.endsWith('\"') && t.length >= 2) ||\n (t.startsWith(\"'\") && t.endsWith(\"'\") && t.length >= 2)\n ) {\n return t.slice(1, -1);\n }\n return PEP585_BUILTINS[t] ?? t;\n}\n\n/** Canonicalize one `Literal[...]` argument so semantically identical string\n * values compare equal regardless of quote style or escape form. The value\n * is decoded (backslash escapes processed) then re-encoded in a canonical\n * double-quoted form, so `Literal['say \"hi\"']` and `Literal[\"say \\\\\"hi\\\\\"\"]`\n * both canonicalize to `\"say \\\"hi\\\"\"`. Bare (unquoted) arguments — e.g. an\n * enum name or a number — are returned unchanged. */\nfunction canonicalizeLiteralArg(arg: string): string {\n const a = arg.trim();\n if (a.length < 2) return a;\n let quote: '\"' | \"'\" | null = null;\n if (a.startsWith('\"') && a.endsWith('\"')) quote = '\"';\n else if (a.startsWith(\"'\") && a.endsWith(\"'\")) quote = \"'\";\n if (!quote) return a; // bare arg (type ref / number) — not a string literal\n const value = decodeStringLiteral(a.slice(1, -1));\n return `\"${encodeDoubleQuoted(value)}\"`;\n}\n\n/** Decode the backslash escapes inside a Python string literal's content.\n * Only the delimiter-relevant escapes (`\\\\`, `\\'`, `\\\"`) are processed;\n * other sequences (`\\n`, `\\t`, `\\u…`) are kept verbatim since they're\n * written identically regardless of quote style and so compare equal already. */\nfunction decodeStringLiteral(content: string): string {\n let out = '';\n for (let i = 0; i < content.length; i++) {\n const c = content[i];\n if (c === '\\\\' && i + 1 < content.length) {\n const next = content[i + 1];\n if (next === '\\\\' || next === '\"' || next === \"'\") {\n out += next;\n i++;\n continue;\n }\n out += c + next; // preserve unknown escape verbatim\n i++;\n continue;\n }\n out += c;\n }\n return out;\n}\n\n/** Re-encode a decoded value as a canonical double-quoted Python string. */\nfunction encodeDoubleQuoted(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n}\n\n/** Split on a separator that sits at bracket-depth 0 and outside string\n * literals, so commas/pipes inside `Literal[\"a,b\"]` or `\"x|y\"` are not split.\n * An escaped matching quote (`\\\"` inside a double-quoted string) does not\n * close the string: only a quote preceded by an even number of backslashes\n * (zero counts) is a real closing delimiter. */\nfunction splitTopLevel(s: string, sep: string): string[] {\n const parts: string[] = [];\n let depth = 0;\n let inStr: string | null = null;\n let start = 0;\n for (let i = 0; i < s.length; i++) {\n const c = s[i];\n if (inStr) {\n if (c === inStr) {\n let precedingBackslashes = 0;\n for (let j = i - 1; j >= 0 && s[j] === '\\\\'; j--) precedingBackslashes++;\n if (precedingBackslashes % 2 === 0) inStr = null;\n }\n continue;\n }\n if (c === '\"' || c === \"'\") {\n inStr = c;\n continue;\n }\n if (c === '[') depth++;\n else if (c === ']') depth--;\n else if (c === sep && depth === 0) {\n parts.push(s.slice(start, i));\n start = i + 1;\n }\n }\n parts.push(s.slice(start));\n return parts;\n}\n\n// ---------------------------------------------------------------------------\n// Classification engine\n// ---------------------------------------------------------------------------\n\n/**\n * Classify changes between a baseline and candidate symbol.\n * Returns one or more classified changes for the diff.\n */\nexport function classifySymbolChanges(\n baseline: CompatSymbol,\n candidate: CompatSymbol | undefined,\n policy: CompatPolicyHints,\n language?: LanguageId,\n): ClassifiedChange[] {\n const changes: ClassifiedChange[] = [];\n\n // Build spec-level ref for cross-language grouping.\n // Prefer schemaName from either symbol (baseline for removals, candidate for adds).\n const specRef = baseline.schemaName ?? candidate?.schemaName;\n\n // Symbol removed\n if (!candidate) {\n changes.push(\n makeChange({\n category: 'symbol_removed',\n symbol: baseline.fqName,\n old: { symbol: baseline.fqName },\n new: { symbol: '(removed)' },\n message: `Symbol \"${baseline.displayName}\" was removed`,\n policy,\n specRef,\n }),\n );\n return changes;\n }\n\n // Symbol renamed\n if (baseline.fqName !== candidate.fqName && baseline.id === candidate.id) {\n changes.push(\n makeChange({\n category: 'symbol_renamed',\n symbol: baseline.fqName,\n old: { name: baseline.fqName },\n new: { name: candidate.fqName },\n message: `Symbol renamed from \"${baseline.displayName}\" to \"${candidate.displayName}\"`,\n policy,\n specRef,\n }),\n );\n }\n\n // Parameter-level changes (for callables and constructors)\n if (baseline.parameters && candidate.parameters) {\n changes.push(...classifyParameterChanges(baseline, candidate, policy, specRef, language));\n }\n\n // Return type changes (for callables)\n if (\n baseline.returns &&\n candidate.returns &&\n normalizeType(baseline.returns.name, language) !== normalizeType(candidate.returns.name, language)\n ) {\n changes.push(\n makeChange({\n category: 'return_type_changed',\n symbol: baseline.fqName,\n old: { returnType: baseline.returns.name },\n new: { returnType: candidate.returns.name },\n message: `Return type changed for \"${baseline.displayName}\" from \"${baseline.returns.name}\" to \"${candidate.returns.name}\"`,\n policy,\n specRef,\n }),\n );\n }\n\n // Static ↔ instance flips (for callables). Compared only when both\n // snapshots record staticness — extractors that don't capture it and\n // snapshots written before the field existed never produce this change.\n if (baseline.isStatic !== undefined && candidate.isStatic !== undefined && baseline.isStatic !== candidate.isStatic) {\n changes.push(\n makeChange({\n category: 'staticness_changed',\n symbol: baseline.fqName,\n old: { static: String(baseline.isStatic) },\n new: { static: String(candidate.isStatic) },\n message:\n `\"${baseline.displayName}\" changed from ${baseline.isStatic ? 'static' : 'instance'} ` +\n `to ${candidate.isStatic ? 'static' : 'instance'} — call sites must migrate`,\n policy,\n specRef,\n }),\n );\n }\n\n // Field/property type changes\n if (\n baseline.typeRef &&\n candidate.typeRef &&\n normalizeType(baseline.typeRef.name, language) !== normalizeType(candidate.typeRef.name, language)\n ) {\n changes.push(\n makeChange({\n category: 'field_type_changed',\n symbol: baseline.fqName,\n old: { type: baseline.typeRef.name },\n new: { type: candidate.typeRef.name },\n message: `Type changed for \"${baseline.displayName}\" from \"${baseline.typeRef.name}\" to \"${candidate.typeRef.name}\"`,\n policy,\n specRef,\n }),\n );\n }\n\n // Enum member value changes\n if (\n baseline.kind === 'enum_member' &&\n candidate.kind === 'enum_member' &&\n baseline.value !== undefined &&\n candidate.value !== undefined &&\n baseline.value !== candidate.value\n ) {\n changes.push(\n makeChange({\n category: 'enum_member_value_changed',\n symbol: baseline.fqName,\n old: { value: String(baseline.value) },\n new: { value: String(candidate.value) },\n message: `Enum value changed for \"${baseline.displayName}\" from \"${baseline.value}\" to \"${candidate.value}\"`,\n policy,\n }),\n );\n }\n\n return changes;\n}\n\n/**\n * Classify parameter-level changes between two symbol versions.\n */\nfunction classifyParameterChanges(\n baseline: CompatSymbol,\n candidate: CompatSymbol,\n policy: CompatPolicyHints,\n specRef?: string,\n language?: LanguageId,\n): ClassifiedChange[] {\n const changes: ClassifiedChange[] = [];\n const baseParams = baseline.parameters ?? [];\n const candParams = candidate.parameters ?? [];\n\n const baseByName = new Map(baseParams.map((p) => [p.publicName, p]));\n const candByName = new Map(candParams.map((p) => [p.publicName, p]));\n const isConstructor = baseline.kind === 'constructor';\n\n // Check each baseline parameter\n for (const baseParam of baseParams) {\n const candParam = candByName.get(baseParam.publicName);\n\n if (!candParam) {\n // Parameter removed — check if it was renamed\n const positionalMatch = candParams[baseParam.position];\n if (positionalMatch && !baseByName.has(positionalMatch.publicName)) {\n // Position preserved but name changed → rename\n const isBreakingRename = parameterNameIsPublicApi(baseParam, policy, isConstructor);\n changes.push(\n makeChange({\n category: 'parameter_renamed',\n symbol: baseline.fqName,\n old: { parameter: baseParam.publicName },\n new: { parameter: positionalMatch.publicName },\n message: `Parameter \"${baseParam.publicName}\" renamed to \"${positionalMatch.publicName}\" on \"${baseline.displayName}\"`,\n policy,\n specRef,\n severityOverride: isBreakingRename ? undefined : 'soft-risk',\n }),\n );\n } else {\n // Truly removed\n changes.push(\n makeChange({\n category: 'parameter_removed',\n symbol: baseline.fqName,\n old: { parameter: baseParam.publicName },\n new: { parameter: '(removed)' },\n message: `Parameter \"${baseParam.publicName}\" removed from \"${baseline.displayName}\"`,\n policy,\n specRef,\n }),\n );\n }\n continue;\n }\n\n // Requiredness increased (optional → required)\n if (!baseParam.required && candParam.required) {\n changes.push(\n makeChange({\n category: 'parameter_requiredness_increased',\n symbol: baseline.fqName,\n old: { parameter: baseParam.publicName, required: 'false' },\n new: { parameter: candParam.publicName, required: 'true' },\n message: `Parameter \"${baseParam.publicName}\" became required on \"${baseline.displayName}\"`,\n policy,\n specRef,\n }),\n );\n }\n\n // Type narrowed\n if (normalizeType(baseParam.type.name, language) !== normalizeType(candParam.type.name, language)) {\n changes.push(\n makeChange({\n category: 'parameter_type_narrowed',\n symbol: baseline.fqName,\n old: { parameter: baseParam.publicName, type: baseParam.type.name },\n new: { parameter: candParam.publicName, type: candParam.type.name },\n message: `Parameter type changed for \"${baseParam.publicName}\" on \"${baseline.displayName}\"`,\n policy,\n specRef,\n }),\n );\n }\n\n // Position changed.\n //\n // Constructors are governed by `policy.constructorOrderMatters` — some\n // languages treat ctor positional order as part of the public API even\n // when method args are named.\n //\n // For methods, the parameter's `passing` style decides:\n // - 'positional' → callers reference by index; reorder is breaking\n // - 'named' → both styles work; reorder is soft-risk (positional callers exist)\n // - 'keyword' → callers MUST use names (Ruby kwargs, Python kw-only, Elixir); position invisible\n // - 'options_object' → callers pass a single object literal (Node); position invisible\n if (baseParam.position !== candParam.position) {\n if (isConstructor) {\n if (policy.constructorOrderMatters) {\n changes.push(\n makeChange({\n category: 'constructor_position_changed_order_sensitive',\n symbol: baseline.fqName,\n old: { parameter: baseParam.publicName, position: String(baseParam.position) },\n new: { parameter: candParam.publicName, position: String(candParam.position) },\n message: `Parameter \"${baseParam.publicName}\" moved from position ${baseParam.position} to ${candParam.position} on \"${baseline.displayName}\"`,\n policy,\n specRef,\n }),\n );\n } else {\n changes.push(\n makeChange({\n category: 'constructor_reordered_named_friendly',\n symbol: baseline.fqName,\n old: { parameter: baseParam.publicName, position: String(baseParam.position) },\n new: { parameter: candParam.publicName, position: String(candParam.position) },\n message: `Parameter \"${baseParam.publicName}\" reordered on \"${baseline.displayName}\" (named-friendly language)`,\n policy,\n specRef,\n }),\n );\n }\n } else if (baseParam.passing === 'positional') {\n changes.push(\n makeChange({\n category: 'parameter_position_changed_order_sensitive',\n symbol: baseline.fqName,\n old: { parameter: baseParam.publicName, position: String(baseParam.position) },\n new: { parameter: candParam.publicName, position: String(candParam.position) },\n message: `Parameter \"${baseParam.publicName}\" moved from position ${baseParam.position} to ${candParam.position} on \"${baseline.displayName}\"`,\n policy,\n specRef,\n }),\n );\n } else if (baseParam.passing === 'named') {\n changes.push(\n makeChange({\n category: 'constructor_reordered_named_friendly',\n symbol: baseline.fqName,\n old: { parameter: baseParam.publicName, position: String(baseParam.position) },\n new: { parameter: candParam.publicName, position: String(candParam.position) },\n message: `Parameter \"${baseParam.publicName}\" reordered on \"${baseline.displayName}\" (named-friendly language)`,\n policy,\n specRef,\n }),\n );\n }\n // keyword / options_object: position is invisible to callers — no change emitted.\n }\n }\n\n // Check for new parameters in candidate\n for (const candParam of candParams) {\n if (!baseByName.has(candParam.publicName)) {\n // Check if this was already captured as a rename\n const isRename = changes.some(\n (c) => c.category === 'parameter_renamed' && c.new.parameter === candParam.publicName,\n );\n if (isRename) continue;\n\n // Record where the parameter landed: a non-terminal insertion displaces\n // every later positional parameter, and consumers reconcile those\n // order-sensitive position changes against the insertion point.\n const isTerminal = candParam.position === candParams.length - 1;\n const category: CompatChangeCategory = candParam.required\n ? 'parameter_requiredness_increased'\n : isTerminal\n ? 'parameter_added_optional_terminal'\n : 'parameter_added_non_terminal_optional';\n\n if (candParam.required) {\n changes.push(\n makeChange({\n category,\n symbol: baseline.fqName,\n old: { parameter: '(absent)' },\n new: { parameter: candParam.publicName, required: 'true', position: String(candParam.position) },\n message: `Required parameter \"${candParam.publicName}\" added to \"${baseline.displayName}\"`,\n policy,\n specRef,\n }),\n );\n } else {\n changes.push(\n makeChange({\n category,\n symbol: baseline.fqName,\n old: { parameter: '(absent)' },\n new: { parameter: candParam.publicName, position: String(candParam.position) },\n message: `Optional parameter \"${candParam.publicName}\" added to \"${baseline.displayName}\"`,\n policy,\n specRef,\n }),\n );\n }\n }\n }\n\n return changes;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction parameterNameIsPublicApi(param: CompatParameter, policy: CompatPolicyHints, isConstructor: boolean): boolean {\n if (param.sensitivity.publicName) return true;\n if (isConstructor) return policy.constructorParameterNamesArePublicApi;\n return policy.methodParameterNamesArePublicApi;\n}\n\n/**\n * Build a deterministic conceptual change ID.\n *\n * When `specRef` is provided (e.g. \"GenerateLinkBody.admin_emails\"), it is\n * used instead of the language-specific symbol name. This ensures the same\n * spec entity produces the same ID across all languages, enabling cross-\n * language rollup in reports.\n */\nfunction buildConceptualChangeId(\n category: CompatChangeCategory,\n symbol: string,\n match: Record<string, string>,\n specRef?: string,\n): string {\n const identity = specRef ?? symbol;\n const parts = ['chg', category, identity.replace(/[^a-zA-Z0-9_.]/g, '_')];\n if (match.parameter) parts.push(match.parameter);\n if (match.member) parts.push(match.member);\n return parts.join('_').toLowerCase();\n}\n\nfunction makeChange(opts: {\n category: CompatChangeCategory;\n symbol: string;\n old: Record<string, string>;\n new: Record<string, string>;\n message: string;\n policy: CompatPolicyHints;\n provenance?: CompatProvenance;\n severityOverride?: CompatChangeSeverity;\n specRef?: string;\n}): ClassifiedChange {\n return {\n category: opts.category,\n severity: opts.severityOverride ?? defaultSeverityForCategory(opts.category),\n symbol: opts.symbol,\n conceptualChangeId: buildConceptualChangeId(opts.category, opts.symbol, opts.old, opts.specRef),\n provenance: opts.provenance ?? 'unknown',\n old: opts.old,\n new: opts.new,\n message: opts.message,\n };\n}\n\n/**\n * Classify a new symbol as additive.\n */\nexport function classifyAddedSymbol(symbol: CompatSymbol): ClassifiedChange {\n return {\n category: 'symbol_added',\n severity: 'additive',\n symbol: symbol.fqName,\n conceptualChangeId: buildConceptualChangeId('symbol_added', symbol.fqName, {}, symbol.schemaName),\n provenance: 'unknown',\n old: { symbol: '(absent)' },\n new: { symbol: symbol.fqName },\n message: `Symbol \"${symbol.displayName}\" was added`,\n };\n}\n\n/** Summarize a list of classified changes by severity. */\nexport function summarizeChanges(changes: ClassifiedChange[]): ClassificationResult['summary'] {\n let breaking = 0;\n let softRisk = 0;\n let additive = 0;\n for (const c of changes) {\n if (c.severity === 'breaking') breaking++;\n else if (c.severity === 'soft-risk') softRisk++;\n else additive++;\n }\n return { breaking, softRisk, additive };\n}\n","import type { ApiSurface, LanguageHints } from './types.js';\nimport { splitWords } from '../utils/naming.js';\n\n/** Untyped map patterns — hoisted to avoid allocation on every isTypeEquivalent call. */\nconst UNTYPED_MAP_PATTERNS = new Set([\n 'Record<string, unknown>',\n 'Record<string, any>',\n '{ [key: string]: any; }',\n '{ [key: string]: unknown; }',\n 'any',\n]);\n\nexport const NAMED_TYPE_RE = /^[A-Z][a-zA-Z0-9]*$/;\n\n/** Check whether a type name exists as an interface, class, or enum in a surface. */\nexport function typeExistsInSurface(name: string, surface: ApiSurface): boolean {\n return !!(surface.interfaces[name] || surface.classes[name] || surface.enums[name]);\n}\n\n/** Split a PascalCase string into words, keeping only words > 2 chars. */\nfunction splitPascalWords(s: string): string[] {\n return splitWords(s).filter((w) => w.length > 2);\n}\n\n/**\n * Check whether two named types share enough PascalCase word components to\n * be considered equivalent (handles name reordering from Json merges, etc.).\n * Both names have `Response$` stripped before comparison.\n */\nexport function namedTypeWordsOverlap(a: string, b: string, minOverlap = 1): boolean {\n const aNoResp = a.replace(/Response$/, '');\n const bNoResp = b.replace(/Response$/, '');\n const aWords = new Set(splitPascalWords(aNoResp).map((w) => w.toLowerCase()));\n const bWords = new Set(splitPascalWords(bNoResp).map((w) => w.toLowerCase()));\n const overlap = [...aWords].filter((w) => bWords.has(w));\n return overlap.length >= minOverlap && overlap.length >= Math.min(aWords.size, bWords.size) - 1;\n}\n\n/** Split a pipe-delimited union string into trimmed, non-empty members. */\nfunction parseUnionMembers(s: string): string[] {\n return s\n .split('|')\n .map((p) => p.trim())\n .filter(Boolean);\n}\n\n/**\n * Default implementation of isNullableOnlyDifference — shared across extractors.\n * Returns true when stripping nullable wrappers from both sides yields the same\n * type, but the original types differ (i.e., the only difference is nullability).\n */\nexport function defaultIsNullableOnlyDifference(\n hints: Pick<LanguageHints, 'stripNullable'>,\n a: string,\n b: string,\n): boolean {\n return (hints.stripNullable(a) ?? a) === (hints.stripNullable(b) ?? b) && a !== b;\n}\n\n/**\n * Node/TypeScript language hints — reference implementation.\n * Extracted from the hardcoded logic previously in differ.ts and overlay.ts.\n */\nexport const nodeHints: LanguageHints = {\n stripNullable(type: string): string | null {\n const members = parseUnionMembers(type);\n const stripped = members.filter((p) => p !== 'null');\n if (stripped.length === members.length) {\n return null; // no null member found\n }\n return stripped.join(' | ');\n },\n\n isNullableOnlyDifference(a: string, b: string): boolean {\n return (nodeHints.stripNullable(a) ?? a) === (nodeHints.stripNullable(b) ?? b) && a !== b;\n },\n\n isUnionReorder(a: string, b: string): boolean {\n const membersA = parseUnionMembers(a).sort();\n const membersB = parseUnionMembers(b).sort();\n if (membersA.length !== membersB.length || membersA.length < 2) return false;\n return membersA.every((m, i) => m === membersB[i]);\n },\n\n isGenericTypeParam(type: string): boolean {\n if (/^[A-Z]$/.test(type)) return true;\n if (/^T[A-Z][a-zA-Z]*$/.test(type)) return true;\n if (/^[A-Z]\\[\\]$/.test(type) || /^T[A-Z][a-zA-Z]*\\[\\]$/.test(type)) return true;\n return false;\n },\n\n isExtractionArtifact(type: string): boolean {\n return type === 'any' || type === 'Record<string, unknown>';\n },\n\n tolerateCategoryMismatch: true,\n\n extractReturnTypeName(returnType: string): string | null {\n let inner = returnType;\n while (inner.startsWith('Promise<') && inner.endsWith('>')) {\n inner = inner.slice(8, -1);\n }\n const genericMatch = inner.match(/^[A-Za-z]+<(.+)>$/);\n if (genericMatch) {\n inner = genericMatch[1];\n }\n inner = inner.replace(/\\[\\]$/, '');\n if (['void', 'string', 'number', 'boolean', 'any', 'unknown', 'null', 'undefined'].includes(inner)) {\n return null;\n }\n return inner;\n },\n\n extractParamTypeName(paramType: string): string | null {\n if (['string', 'number', 'boolean', 'any', 'unknown'].includes(paramType)) {\n return null;\n }\n return paramType;\n },\n\n propertyMatchesClass(propertyName: string, className: string): boolean {\n // Support both camelCase and snake_case properties matching PascalCase classes\n // e.g., \"organizations\" ≡ \"Organizations\", \"api_keys\" ≡ \"ApiKeys\"\n const normalizedProp = propertyName.replace(/[-_]/g, '').toLowerCase();\n return normalizedProp === className.toLowerCase();\n },\n\n derivedModelNames(modelName: string): string[] {\n return [`${modelName}Response`, `Serialized${modelName}`];\n },\n\n isTypeEquivalent(baselineType: string, candidateType: string, candidateSurface: ApiSurface): boolean {\n // Check if one side is a named enum and the other is an inline union\n // of that enum's string literal values.\n // e.g., baseline: '\"active\" | \"inactive\"', candidate: 'ConnectionState'\n // or baseline: 'ConnectionState', candidate: '\"active\" | \"inactive\"'\n\n // Try: candidate is enum name, baseline is inline union of string literals.\n // The generated enum may have MORE members than the baseline (new spec values),\n // so check that all baseline members exist in the enum (subset match).\n const candEnum = candidateSurface.enums[candidateType];\n if (candEnum) {\n const enumValuesSet = new Set(Object.values(candEnum.members).flatMap((v) => [`\"${v}\"`, `'${v}'`]));\n const baseMembers = parseUnionMembers(baselineType);\n if (baseMembers.length > 0 && baseMembers.every((m) => enumValuesSet.has(m))) {\n return true;\n }\n }\n\n // Tolerate untyped-map equivalences:\n // { [key: string]: any; } ≡ Record<string, unknown> ≡ Record<string, any>\n if (UNTYPED_MAP_PATTERNS.has(baselineType) && UNTYPED_MAP_PATTERNS.has(candidateType)) {\n return true;\n }\n\n // Tolerate inline object literal vs named model in candidate.\n // e.g., baseline: '{ type: \"organization\"; id: string; }', candidate: 'ApiKeyOwner'\n // The named model is more structured but semantically equivalent.\n if (baselineType.startsWith('{') && baselineType.endsWith('}')) {\n if (typeExistsInSurface(candidateType, candidateSurface)) {\n return true;\n }\n }\n\n // Tolerate named-type-to-named-type mismatches when both types exist\n // as models/interfaces/enums in their respective surfaces. This handles\n // cases where the parser qualifies inline types with parent names while\n // the live SDK uses shared types:\n // baseline: RoleResponse, candidate: OrganizationMembershipRole\n // baseline: ConnectionType, candidate: ProfileConnectionType\n // baseline: AuditLogTargetSchema[], candidate: AuditLogSchemaJsonTarget[]\n const baseClean = baselineType.replace(/\\[\\]$/, '');\n const candClean = candidateType.replace(/\\[\\]$/, '');\n const sameArrayness = baselineType.endsWith('[]') === candidateType.endsWith('[]');\n\n // Response suffix equivalence (both directions)\n if (sameArrayness) {\n if (candClean === baseClean + 'Response' || baseClean === candClean + 'Response') {\n return true;\n }\n }\n\n // Both are named types (PascalCase, no operators) — check if candidate\n // is a known model/interface/enum, and baseline looks like a named type too.\n // This tolerates the parser's qualified naming vs the live SDK's shared naming.\n if (sameArrayness && NAMED_TYPE_RE.test(baseClean) && NAMED_TYPE_RE.test(candClean)) {\n if (typeExistsInSurface(candClean, candidateSurface)) {\n // One name contains the other (e.g., ProfileConnectionType contains ConnectionType)\n if (candClean.includes(baseClean) || baseClean.includes(candClean)) {\n return true;\n }\n // Strip Response suffix and check containment\n const baseNoResp = baseClean.replace(/Response$/, '');\n const candNoResp = candClean.replace(/Response$/, '');\n if (candNoResp.includes(baseNoResp) || baseNoResp.includes(candNoResp)) {\n return true;\n }\n // Word-component overlap: split PascalCase into words and check\n // if they share enough meaningful words (handles name reordering\n // from Json merges: AuditLogTargetSchema vs AuditLogSchemaJsonTarget)\n if (namedTypeWordsOverlap(baseClean, candClean, 2)) {\n return true;\n }\n }\n }\n\n return false;\n },\n};\n\n/**\n * Merge partial language hint overrides over nodeHints defaults.\n * Any hint not provided falls back to the Node/TypeScript implementation.\n */\nexport function resolveHints(overrides: Partial<LanguageHints>): LanguageHints {\n return { ...nodeHints, ...overrides };\n}\n","import type { ApiSpec, TypeRef } from '../ir/types.js';\nimport { walkTypeRef } from '../ir/types.js';\nimport type { ApiSurface, LanguageHints } from './types.js';\n\n/**\n * Compute the set of symbol names that are derivable from the OpenAPI spec.\n * Only these names should be compared during compat verification — everything\n * else in the baseline is hand-written and out of scope for generation.\n */\nexport function specDerivedNames(spec: ApiSpec, hints: LanguageHints): Set<string> {\n const names = new Set<string>();\n\n // Build set of top-level enum names for filtering inline enums\n const topLevelEnumNames = new Set(spec.enums.map((e) => e.name));\n\n // Service classes\n for (const service of spec.services) {\n names.add(service.name);\n for (const op of service.operations) {\n // Operation methods are matched by the class diff, not by name here\n collectTypeRefNames(op.response, names, hints, topLevelEnumNames);\n if (op.requestBody) collectTypeRefNames(op.requestBody, names, hints, topLevelEnumNames);\n for (const p of [...op.pathParams, ...op.queryParams, ...op.headerParams, ...(op.cookieParams ?? [])]) {\n collectTypeRefNames(p.type, names, hints, topLevelEnumNames);\n }\n }\n }\n\n // Models → domain interface + language-specific derived names\n for (const model of spec.models) {\n names.add(model.name);\n for (const derived of hints.derivedModelNames(model.name)) {\n names.add(derived);\n }\n for (const field of model.fields) {\n collectTypeRefNames(field.type, names, hints, topLevelEnumNames);\n }\n }\n\n // Enums → type aliases\n for (const e of spec.enums) {\n names.add(e.name);\n }\n\n return names;\n}\n\n/**\n * Compute a map of enum name → set of wire values that appear in the spec.\n * Used by filterSurface to exclude hand-added enum members that aren't in the spec.\n */\nexport function specDerivedEnumValues(spec: ApiSpec): Map<string, Set<string | number>> {\n const result = new Map<string, Set<string | number>>();\n for (const e of spec.enums) {\n result.set(e.name, new Set(e.values.map((v) => v.value)));\n }\n return result;\n}\n\n/**\n * Compute the set of field paths (e.g., \"Organization.name\") that are defined\n * in the OpenAPI spec's model schemas. Used by filterSurface to exclude\n * hand-added SDK fields that reference spec-derived types.\n */\nexport function specDerivedFieldPaths(spec: ApiSpec, hints: LanguageHints): Set<string> {\n const paths = new Set<string>();\n for (const model of spec.models) {\n for (const field of model.fields) {\n paths.add(`${model.name}.${field.name}`);\n }\n // Also add field paths for derived model names (e.g., OrganizationResponse.name)\n for (const derived of hints.derivedModelNames(model.name)) {\n for (const field of model.fields) {\n paths.add(`${derived}.${field.name}`);\n }\n }\n }\n return paths;\n}\n\n/**\n * Compute the set of method paths (e.g., \"Auth.authorize\") that are defined\n * as operations in the OpenAPI spec's services. Used by filterSurface to\n * exclude hand-written SDK methods that don't correspond to spec operations.\n */\nexport function specDerivedMethodPaths(spec: ApiSpec): Set<string> {\n const paths = new Set<string>();\n for (const service of spec.services) {\n for (const op of service.operations) {\n paths.add(`${service.name}.${op.name}`);\n }\n }\n return paths;\n}\n\n/**\n * Compute the set of HTTP operation keys (e.g., \"GET /auth/authorize\") that\n * exist in the spec. Used for overlay-based method matching.\n */\nexport function specDerivedHttpKeys(spec: ApiSpec): Set<string> {\n const keys = new Set<string>();\n for (const service of spec.services) {\n for (const op of service.operations) {\n keys.add(`${op.httpMethod.toUpperCase()} ${op.path}`);\n }\n }\n return keys;\n}\n\nfunction collectTypeRefNames(ref: TypeRef, out: Set<string>, hints: LanguageHints, topLevelEnums?: Set<string>): void {\n walkTypeRef(ref, {\n model: (r) => {\n out.add(r.name);\n for (const derived of hints.derivedModelNames(r.name)) {\n out.add(derived);\n }\n },\n enum: (r) => {\n // Only include enums that are top-level (in spec.enums). Inline enums\n // embedded in TypeRefs (e.g., query parameter enums) may not be emitted\n // by all emitters, so they should not create false-positive violations.\n if (!topLevelEnums || topLevelEnums.has(r.name)) {\n out.add(r.name);\n }\n },\n });\n}\n\nfunction filterRecord<T>(record: Record<string, T>, allowed: Set<string>): Record<string, T> {\n const result: Record<string, T> = {};\n for (const [name, value] of Object.entries(record)) {\n if (allowed.has(name)) result[name] = value;\n }\n return result;\n}\n\n/**\n * Filter an ApiSurface to only include symbols whose names appear in the\n * allowed set. Symbols not in the set are dropped entirely — they won't\n * count toward the total or produce violations.\n *\n * For interfaces: when fieldPaths is provided, only keeps fields that appear\n * in the spec-derived field paths. This prevents false positives from hand-added\n * SDK fields that reference spec-derived types but aren't defined in the spec.\n *\n * For classes: when methodPaths is provided, only keeps methods whose names\n * appear in the spec-derived method paths. This prevents false positives from\n * hand-written SDK methods (e.g., Auth.authorization_url, Webhooks.construct_event)\n * that don't correspond to spec operations. Properties on service classes are\n * also filtered: only UPPER_CASE constants that are spec-derivable are kept.\n */\nexport function filterSurface(\n surface: ApiSurface,\n allowedNames: Set<string>,\n opts?: {\n fieldPaths?: Set<string>;\n methodPaths?: Set<string>;\n enumValues?: Map<string, Set<string | number>>;\n },\n): ApiSurface {\n const { fieldPaths, methodPaths, enumValues } = opts ?? {};\n const filteredInterfaces = filterRecord(surface.interfaces, allowedNames);\n\n // Filter interface fields by spec-derived field paths if provided\n if (fieldPaths) {\n for (const [name, iface] of Object.entries(filteredInterfaces)) {\n const filteredFields: Record<string, (typeof iface.fields)[string]> = {};\n for (const [fieldName, field] of Object.entries(iface.fields)) {\n // Keep the field if its path is spec-derived\n if (fieldPaths.has(`${name}.${fieldName}`)) {\n filteredFields[fieldName] = field;\n }\n }\n filteredInterfaces[name] = { ...iface, fields: filteredFields };\n }\n }\n\n let filteredClasses = filterRecord(surface.classes, allowedNames);\n\n // Filter class methods and properties by spec-derived method paths if provided\n if (methodPaths) {\n // Build a set of service-class names that have spec-derived methods.\n // Only filter methods on these classes; non-service model classes keep all members.\n const serviceClassNames = new Set<string>();\n for (const path of methodPaths) {\n const dot = path.indexOf('.');\n if (dot !== -1) serviceClassNames.add(path.slice(0, dot));\n }\n\n const newClasses: Record<string, (typeof filteredClasses)[string]> = {};\n for (const [name, cls] of Object.entries(filteredClasses)) {\n if (serviceClassNames.has(name)) {\n // Service class — filter methods and properties by spec-derived method paths\n const filteredMethods: typeof cls.methods = {};\n for (const [methodName, overloads] of Object.entries(cls.methods)) {\n if (methodPaths.has(`${name}.${methodName}`)) {\n filteredMethods[methodName] = overloads;\n }\n }\n\n // Filter properties: only keep properties that are spec-derivable.\n // Hand-written constants (PROVIDERS, DEFAULT_TOLERANCE, WIDGET_SCOPES)\n // are not derivable from the spec and should be excluded.\n const filteredProperties: typeof cls.properties = {};\n for (const [propName, prop] of Object.entries(cls.properties)) {\n if (methodPaths.has(`${name}.${propName}`)) {\n filteredProperties[propName] = prop;\n }\n }\n\n newClasses[name] = {\n ...cls,\n methods: filteredMethods,\n properties: filteredProperties,\n };\n } else if (fieldPaths) {\n // Non-service (model) class — filter properties by spec-derived field paths.\n // In some languages (Ruby, PHP), models are represented as classes with\n // properties rather than interfaces with fields. Apply the same field-level\n // filtering used for interfaces to exclude hand-added SDK fields.\n const filteredProperties: typeof cls.properties = {};\n for (const [propName, prop] of Object.entries(cls.properties)) {\n if (fieldPaths.has(`${name}.${propName}`)) {\n filteredProperties[propName] = prop;\n }\n }\n\n // Also filter methods on model classes: convenience methods like\n // `primary_email` are hand-written and not spec-derivable.\n // Keep utility methods (from_json, to_json, etc.) if they appear in fieldPaths,\n // otherwise drop non-spec methods.\n const filteredMethods: typeof cls.methods = {};\n for (const [methodName, overloads] of Object.entries(cls.methods)) {\n if (fieldPaths.has(`${name}.${methodName}`) || methodPaths.has(`${name}.${methodName}`)) {\n filteredMethods[methodName] = overloads;\n }\n }\n\n newClasses[name] = {\n ...cls,\n methods: filteredMethods,\n properties: filteredProperties,\n };\n } else {\n // No filtering available — keep as-is\n newClasses[name] = cls;\n }\n }\n filteredClasses = newClasses;\n }\n\n // Filter enum members by spec-derived values if provided\n let filteredEnums = filterRecord(surface.enums, allowedNames);\n if (enumValues) {\n const newEnums: Record<string, (typeof filteredEnums)[string]> = {};\n for (const [name, enumDef] of Object.entries(filteredEnums)) {\n const specValues = enumValues.get(name);\n if (!specValues) {\n // Enum not in spec values map — keep as-is\n newEnums[name] = enumDef;\n continue;\n }\n // Filter members: keep only those whose wire value is in the spec.\n // Use case-insensitive comparison since some extractors produce\n // PascalCase values (e.g., \"Pending\") while the spec has lowercase.\n const specValuesLower = new Set([...specValues].map((v) => String(v).toLowerCase()));\n const filteredMembers: typeof enumDef.members = {};\n for (const [member, value] of Object.entries(enumDef.members)) {\n if (specValues.has(value) || specValuesLower.has(String(value).toLowerCase())) {\n filteredMembers[member] = value;\n }\n }\n newEnums[name] = { ...enumDef, members: filteredMembers };\n }\n filteredEnums = newEnums;\n }\n\n return {\n ...surface,\n classes: filteredClasses,\n interfaces: filteredInterfaces,\n typeAliases: filterRecord(surface.typeAliases, allowedNames),\n enums: filteredEnums,\n exports: {}, // exports are structural, not symbol-level — skip for scoped comparison\n };\n}\n","/**\n * Compatibility diff engine.\n *\n * Compares two API surfaces (or compat snapshots) and produces classified\n * changes with policy-aware severity, provenance, and conceptual change IDs.\n *\n * This replaces the previous unclassified diff engine with a richer model\n * that supports cross-language severity analysis and approval matching.\n */\n\nimport type { ApiSurface, ApiMethod, LanguageHints, DiffResult, Violation, Addition } from './types.js';\nimport type { CompatSnapshot, CompatSymbol } from './ir.js';\nimport type { CompatPolicyHints } from './policy.js';\nimport type { ClassifiedChange, ClassificationResult } from './classify.js';\nimport { classifySymbolChanges, classifyAddedSymbol, summarizeChanges } from './classify.js';\nimport { NAMED_TYPE_RE, typeExistsInSurface } from './language-hints.js';\n\nexport {\n specDerivedNames,\n specDerivedFieldPaths,\n specDerivedMethodPaths,\n specDerivedHttpKeys,\n specDerivedEnumValues,\n filterSurface,\n} from './spec-filter.js';\n\n// ---------------------------------------------------------------------------\n// New: CompatSnapshot-based diff\n// ---------------------------------------------------------------------------\n\n/** Result of diffing two compat snapshots. */\nexport interface CompatDiffResult {\n changes: ClassifiedChange[];\n summary: ClassificationResult['summary'];\n}\n\n/**\n * Diff two compat snapshots, producing classified changes with\n * policy-aware severity.\n */\nexport function diffSnapshots(\n baseline: CompatSnapshot,\n candidate: CompatSnapshot,\n policy?: CompatPolicyHints,\n): CompatDiffResult {\n const effectivePolicy = policy ?? baseline.policies;\n const changes: ClassifiedChange[] = [];\n\n // Build set of service wrapper fqNames from both snapshots so we can\n // suppress constructor noise — users never instantiate service classes\n // directly, so their constructor changes are not public-API breaking.\n const serviceAccessors = new Set<string>();\n for (const sym of baseline.symbols) {\n if (sym.kind === 'service_accessor') serviceAccessors.add(sym.fqName);\n }\n for (const sym of candidate.symbols) {\n if (sym.kind === 'service_accessor') serviceAccessors.add(sym.fqName);\n }\n\n // Index candidate symbols by ID and fqName for lookup\n const candById = new Map<string, CompatSymbol>();\n const candByFqName = new Map<string, CompatSymbol>();\n for (const sym of candidate.symbols) {\n candById.set(sym.id, sym);\n candByFqName.set(sym.fqName, sym);\n }\n\n // Index baseline symbols by fqName\n const baseByFqName = new Set<string>();\n for (const sym of baseline.symbols) {\n baseByFqName.add(sym.fqName);\n }\n\n // Compare each baseline symbol against candidate\n for (const baseSym of baseline.symbols) {\n if (isServiceWrapperConstructor(baseSym, serviceAccessors)) continue;\n const candSym = candById.get(baseSym.id) ?? candByFqName.get(baseSym.fqName);\n changes.push(...classifySymbolChanges(baseSym, candSym, effectivePolicy, baseline.source.language));\n }\n\n // Detect added symbols\n for (const candSym of candidate.symbols) {\n if (!baseByFqName.has(candSym.fqName)) {\n if (isServiceWrapperConstructor(candSym, serviceAccessors)) continue;\n changes.push(classifyAddedSymbol(candSym));\n }\n }\n\n // Post-pass: attach spec-level remediation hints when recognized upstream\n // patterns are detected. Currently flags the \"schema fork\" antipattern —\n // a path's response type was redirected to a brand-new schema whose field\n // set is a superset of the prior schema, which forces a breaking SDK\n // signature change instead of an additive field on the existing schema.\n detectForkedSchemas(changes, baseline, candidate);\n\n // Post-pass: detect type and enum *renames* — cases where a baseline\n // symbol disappears and a structurally-equivalent symbol takes its place\n // in the candidate. These are reported as `symbol_removed` (breaking) by\n // the symbol-level walker because the fqName is gone, but consumer code\n // that uses the type's fields/methods or the enum's wire values continues\n // to work — only explicit type annotations and (in dotnet) un-aliased\n // enum class references actually need to migrate. Downgrade these to\n // soft-risk so CI gates default-pass while the change stays visible.\n //\n // Ordered after detectForkedSchemas so the fork detector's remediation\n // hint is preserved on the typed cases it owns; renames operate on\n // pure removals where no fork hint applies.\n const typeRenames = detectTypeRenames(changes, baseline, candidate);\n const enumRenames = detectEnumRenames(changes, baseline, candidate);\n // Transitive pass: when a typed field on a renamed parent points at an\n // alias type that has no extractable children of its own (common for\n // discriminated-union owner types — e.g. Go's `APIKeyWithValueOwner`,\n // generated alongside its parent type), the structural detector can't\n // pair them on its own. Use the recorded parent rename + the field\n // typeRefs to derive the secondary rename.\n inferTransitiveTypeRenames(typeRenames, baseline, candidate, changes);\n cascadeRenameDowngrades(changes, typeRenames, enumRenames, baseline, candidate);\n\n return {\n changes,\n summary: summarizeChanges(changes),\n };\n}\n\n/**\n * Detect \"schema fork\" antipattern and attach a remediation hint.\n *\n * Fires when:\n * 1. A return type or field type changed from `OldType` → `NewType`.\n * 2. `NewType` is newly added in the candidate snapshot.\n * 3. `NewType.fields ⊇ OldType.fields` (every field on the old type still\n * exists on the new one — the new schema is a strict superset, so the\n * same fields could have been added to the existing schema additively).\n *\n * Mutates `changes` in place: sets `remediation` on the matching change.\n * Leaves the original category and severity alone — this is just a hint.\n *\n * Identity match is by `displayName` of the type symbol, which corresponds\n * to the type name as it appears in `change.old.returnType` / `.type` and\n * `change.new.returnType` / `.type`.\n */\nfunction detectForkedSchemas(changes: ClassifiedChange[], baseline: CompatSnapshot, candidate: CompatSnapshot): void {\n // Build name → field-name set maps from each snapshot. A \"type\" here is any\n // symbol that owns field/property children (alias, service_accessor, enum).\n const baselineTypeFields = collectTypeFieldSets(baseline);\n const candidateTypeFields = collectTypeFieldSets(candidate);\n const baselineTypeNames = new Set(baselineTypeFields.keys());\n\n for (const change of changes) {\n if (change.remediation) continue;\n\n let oldType: string | undefined;\n let newType: string | undefined;\n if (change.category === 'return_type_changed') {\n oldType = change.old.returnType;\n newType = change.new.returnType;\n } else if (change.category === 'field_type_changed') {\n oldType = change.old.type;\n newType = change.new.type;\n } else {\n continue;\n }\n if (!oldType || !newType || oldType === newType) continue;\n\n // Strip array/nullable decorations so we compare bare type names. This\n // covers e.g. `FooList` vs `BarList`, plus simple `Foo[]` vs `Bar[]`.\n const oldTypeBare = bareTypeName(oldType);\n const newTypeBare = bareTypeName(newType);\n\n // The new type must be newly introduced.\n if (baselineTypeNames.has(newTypeBare)) continue;\n\n const oldFields = baselineTypeFields.get(oldTypeBare);\n const newFields = candidateTypeFields.get(newTypeBare);\n if (!oldFields || !newFields) continue;\n if (oldFields.size === 0) continue;\n\n // newFields must be a (non-strict) superset of oldFields.\n let isSuperset = true;\n for (const f of oldFields) {\n if (!newFields.has(f)) {\n isSuperset = false;\n break;\n }\n }\n if (!isSuperset) continue;\n\n change.remediation =\n `Schema \"${newTypeBare}\" looks like \"${oldTypeBare}\" with additional fields. ` +\n `Consider adding the new fields to \"${oldTypeBare}\" instead of forking a new schema — ` +\n `forking forces a breaking type-name change in typed SDKs, while extending the existing ` +\n `schema is additive.`;\n }\n}\n\n/**\n * Build a map from type fqName → set of (lowercased) child field names.\n * Used by `detectForkedSchemas` for superset comparison.\n */\nfunction collectTypeFieldSets(snapshot: CompatSnapshot): Map<string, Set<string>> {\n const result = new Map<string, Set<string>>();\n for (const sym of snapshot.symbols) {\n if (sym.kind !== 'field' && sym.kind !== 'property') continue;\n if (!sym.ownerFqName) continue;\n const localName = sym.fqName.includes('.') ? sym.fqName.slice(sym.fqName.lastIndexOf('.') + 1) : sym.fqName;\n let set = result.get(sym.ownerFqName);\n if (!set) {\n set = new Set<string>();\n result.set(sym.ownerFqName, set);\n }\n set.add(localName.toLowerCase());\n }\n return result;\n}\n\n/**\n * Detect type renames: a baseline type symbol disappears and a candidate\n * type symbol with the same (or superset) field set takes its place.\n *\n * Common when an upstream spec promotes a single schema into multiple\n * (e.g. `ApiKey` → `OrganizationApiKey` + `UserApiKey`). The wire shape\n * returned by individual endpoints is unchanged — `OrganizationApiKey`\n * has the same fields `ApiKey` had — so consumer code accessing those\n * fields *through a return value* keeps working. The parent symbol\n * itself, however, is gone: callers who referenced it by name (Sorbet\n * annotations, `is_a?` checks, pattern matches, deserialization targets)\n * will fail at runtime. The parent removal therefore stays `breaking`;\n * we only attach a remediation hint pointing at the new name.\n *\n * Identity criteria (must all hold):\n * 1. The removed symbol owns ≥ 1 field/property in the baseline (i.e.\n * it's a type-shaped symbol — model/interface/class — not a plain\n * function or constant).\n * 2. Some candidate type that did *not* exist in the baseline has a\n * field set that is a non-strict superset of the removed type's\n * fields. (Strict-subset would mean fields were lost — a real break.)\n * 3. The candidate type is the alphabetically-first such match, so\n * pairing is deterministic when multiple candidates fit (e.g. both\n * `OrganizationApiKey` and `UserApiKey` share the original fields).\n *\n * Returns a `removedName -> newName` map so a downstream cascade pass\n * can downgrade owned-field removals and `*_type_changed` pointing at\n * the same pair — those *are* downgraded to `soft-risk`, since values\n * flowing through the new type continue to expose the same fields.\n *\n * Mutates matching `symbol_removed` entries in `changes`: attaches a\n * `remediation` describing the rename. Severity is left at `breaking`.\n */\nfunction detectTypeRenames(\n changes: ClassifiedChange[],\n baseline: CompatSnapshot,\n candidate: CompatSnapshot,\n): Map<string, string> {\n const renameMap = new Map<string, string>();\n const baselineTypeFields = collectTypeFieldSets(baseline);\n const candidateTypeFields = collectTypeFieldSets(candidate);\n const baselineTypeNames = new Set(baselineTypeFields.keys());\n const candidateTypesSorted = [...candidateTypeFields.entries()].sort((a, b) => a[0].localeCompare(b[0]));\n\n // Index parent `symbol_removed` changes by fqName so we can downgrade\n // them when a rename is detected. Some languages (Go's enum-alias path\n // for ordering enums; emitters that emit `type Old = New`) preserve the\n // old fqName as a candidate alias and never report a removal — that's\n // fine, the rename map is still populated for the cascade pass.\n const parentRemovalByName = new Map<string, ClassifiedChange>();\n for (const change of changes) {\n if (change.category === 'symbol_removed' && change.severity === 'breaking') {\n parentRemovalByName.set(change.old.symbol ?? '', change);\n }\n }\n\n // Walk every baseline type *directly*, not via `symbol_removed` events.\n // The parent-removal path alone misses rename-as-alias cases (e.g. Go\n // emits `type ApiKey = OrganizationApiKey` to preserve the old name)\n // because no `symbol_removed` fires for the old name. The structural\n // match (field-set superset) is what matters, regardless of whether\n // the old fqName persists as an alias.\n for (const [baselineTypeName, baselineFields] of baselineTypeFields) {\n if (baselineFields.size === 0) continue;\n\n // No-op: same name, same fields still in candidate.\n const sameNameFields = candidateTypeFields.get(baselineTypeName);\n if (sameNameFields && setEquals(baselineFields, sameNameFields)) continue;\n\n // Find a newly-added candidate type (not in baseline) whose field set\n // is a non-strict superset of the baseline type's fields.\n const match = candidateTypesSorted.find(([candName, candFields]) => {\n if (baselineTypeNames.has(candName)) return false;\n for (const f of baselineFields) {\n if (!candFields.has(f)) return false;\n }\n return true;\n });\n if (!match) continue;\n const [newName] = match;\n\n renameMap.set(baselineTypeName, newName);\n\n // Attach a remediation hint to the parent removal so reviewers can see\n // where the symbol moved. Severity stays `breaking`: the symbol's name\n // is gone, and callers who referenced it directly (Sorbet annotations,\n // `is_a?` checks, pattern matches, deserialization targets) will fail\n // at runtime. Languages that emit a `type Old = New` alias keep the\n // parent symbol alive, so this branch may not fire — but the rename is\n // still recorded for the cascade pass to use on field/return-type swaps.\n const parentRemoval = parentRemovalByName.get(baselineTypeName);\n if (parentRemoval) {\n parentRemoval.remediation =\n `Type \"${baselineTypeName}\" appears to have been renamed to \"${newName}\" — ` +\n `the new type has every field of the old (a non-strict superset). ` +\n `Field accesses and method calls on values of type \"${newName}\" continue to work; ` +\n `only explicit \"${baselineTypeName}\" type annotations need to migrate. ` +\n `Consider emitting a deprecated alias \\`type ${baselineTypeName} = ${newName}\\` in languages that support it.`;\n }\n }\n\n return renameMap;\n}\n\n/**\n * Transitive rename inference. After `detectTypeRenames` records direct\n * structural matches (e.g. `ApiKeyWithValue → OrganizationApiKeyWithValue`),\n * walk the parent's fields and follow the `typeRef.name` of each: if the\n * baseline parent's field references an alias-type `OldOwner` and the new\n * parent's same-named field references a different alias `NewOwner`, the\n * pair is the same type-concept under a renamed name. Record the\n * secondary rename so the cascade can downgrade any `field_type_changed`\n * pointing at the pair, and attach a remediation hint to `OldOwner`'s\n * `symbol_removed` (which stays `breaking` — see `detectTypeRenames`).\n *\n * Why this is necessary: discriminated-union owner types (Go's\n * `APIKeyWithValueOwner`, PHP/Python's nested constructor params) are\n * frequently emitted as `kind: 'alias'` symbols with no extractable\n * field children — so `collectTypeFieldSets` returns empty for them and\n * the structural matcher can't pair them directly. The transitive\n * lookup gives us a deterministic, conservative way to propagate the\n * rename: it only fires when the parent rename has already been\n * positively identified, and only follows fields that share the same\n * wire name across baseline and candidate.\n */\nfunction inferTransitiveTypeRenames(\n typeRenames: Map<string, string>,\n baseline: CompatSnapshot,\n candidate: CompatSnapshot,\n changes: ClassifiedChange[],\n): void {\n if (typeRenames.size === 0) return;\n\n // Index field/property symbols by `${ownerFqName}.${localName}` so we\n // can read the typeRef both sides of the rename.\n const baselineFieldType = new Map<string, string>();\n for (const sym of baseline.symbols) {\n if (sym.kind !== 'field' && sym.kind !== 'property') continue;\n if (!sym.ownerFqName || !sym.typeRef) continue;\n const localName = sym.fqName.includes('.') ? sym.fqName.slice(sym.fqName.lastIndexOf('.') + 1) : sym.fqName;\n baselineFieldType.set(`${sym.ownerFqName}.${localName.toLowerCase()}`, sym.typeRef.name);\n }\n const candidateFieldType = new Map<string, string>();\n for (const sym of candidate.symbols) {\n if (sym.kind !== 'field' && sym.kind !== 'property') continue;\n if (!sym.ownerFqName || !sym.typeRef) continue;\n const localName = sym.fqName.includes('.') ? sym.fqName.slice(sym.fqName.lastIndexOf('.') + 1) : sym.fqName;\n candidateFieldType.set(`${sym.ownerFqName}.${localName.toLowerCase()}`, sym.typeRef.name);\n }\n\n // Index parent `symbol_removed` changes for downgrade.\n const parentRemovalByName = new Map<string, ClassifiedChange>();\n for (const change of changes) {\n if (change.category === 'symbol_removed' && change.severity === 'breaking') {\n parentRemovalByName.set(change.old.symbol ?? '', change);\n }\n }\n\n // Walk a snapshot of the rename map — we may mutate it inside the loop\n // but only via `set`, never `delete`, and we don't re-iterate on the\n // additions in the same pass (one transitive hop is enough; deeper\n // chains can be handled by re-running, which we don't need today).\n const initialEntries = [...typeRenames.entries()];\n for (const [oldOwner, newOwner] of initialEntries) {\n // Find every baseline field on the renamed owner whose typeRef points\n // at a *different* type than the same-named field on the new owner.\n for (const [baselineKey, baselineFieldTypeRef] of baselineFieldType) {\n if (!baselineKey.startsWith(`${oldOwner}.`)) continue;\n const localName = baselineKey.slice(oldOwner.length + 1);\n const candidateKey = `${newOwner}.${localName}`;\n const candidateFieldTypeRef = candidateFieldType.get(candidateKey);\n if (!candidateFieldTypeRef) continue;\n\n const oldT = bareTypeName(baselineFieldTypeRef);\n const newT = bareTypeName(candidateFieldTypeRef);\n if (!oldT || !newT || oldT === newT) continue;\n if (typeRenames.has(oldT)) continue; // already recorded\n\n typeRenames.set(oldT, newT);\n const removal = parentRemovalByName.get(oldT);\n if (removal) {\n // Severity stays `breaking` — see `detectTypeRenames` for the\n // rationale. We only attach a remediation hint here.\n removal.remediation =\n `Type \"${oldT}\" appears to have been renamed to \"${newT}\" — ` +\n `inferred transitively because the renamed parent \"${oldOwner}\" → \"${newOwner}\" ` +\n `has a \"${localName}\" field whose type swapped from \"${oldT}\" to \"${newT}\". ` +\n `Consider emitting a deprecated alias \\`type ${oldT} = ${newT}\\` in languages that support it.`;\n }\n }\n }\n}\n\n/**\n * Detect enum canonical-flips: a baseline enum disappears and a candidate\n * enum with the **same wire-value set** takes its place.\n *\n * Caused by the emitter's enum-dedup heuristic picking a different\n * canonical name when a new same-shape enum joins the spec. Languages\n * that emit type aliases (Go, Ruby, Python, PHP, Kotlin) handle this\n * transparently via `type Old = New`; languages without first-class\n * aliases (dotnet) report the old enum as removed. The wire values are\n * unchanged — every legal value still serializes to the same JSON — so\n * consumer code constructing or matching on these enum values keeps\n * working. Only references to the typed enum class need migration.\n *\n * Identity criterion: a removed enum's value set is *exactly* equal to\n * a newly-added enum's value set (not superset — narrowing the value\n * set would be a real break for consumers expecting the dropped values).\n */\nfunction detectEnumRenames(\n changes: ClassifiedChange[],\n baseline: CompatSnapshot,\n candidate: CompatSnapshot,\n): Map<string, string> {\n const renameMap = new Map<string, string>();\n const baselineEnumValues = collectEnumValueSets(baseline);\n const candidateEnumValues = collectEnumValueSets(candidate);\n const baselineEnumNames = new Set(baselineEnumValues.keys());\n\n const candidateEnumsSorted = [...candidateEnumValues.entries()].sort((a, b) => a[0].localeCompare(b[0]));\n\n // Index `symbol_removed` changes by fqName for O(1) lookup when downgrading\n // a parent removal (only some languages report one; others alias).\n const parentRemovalByName = new Map<string, ClassifiedChange>();\n for (const change of changes) {\n if (change.category === 'symbol_removed' && change.severity === 'breaking') {\n parentRemovalByName.set(change.old.symbol ?? '', change);\n }\n }\n\n // Walk every baseline enum *directly*, not via `symbol_removed` events.\n // The parent-removal path alone misses canonical-flips in languages that\n // alias non-canonical enums (Go, Ruby, Python, PHP, Kotlin): the old\n // fqName persists as `type ApplicationsOrder = APIKeysOrder`, no parent\n // `symbol_removed` fires, and the rename map stays empty — so the\n // member-removal cascade never runs. Iterating baseline enums fixes this\n // by deciding \"did this enum's value set move to a different owner?\"\n // independent of whether the parent symbol survived.\n for (const [baselineEnumName, baselineValues] of baselineEnumValues) {\n if (baselineValues.size === 0) continue;\n\n // No-op case: same name, same value set still present in candidate.\n const sameNameValues = candidateEnumValues.get(baselineEnumName);\n if (sameNameValues && setEquals(baselineValues, sameNameValues)) continue;\n\n // Find a newly-added candidate enum (not present under that name in\n // the baseline) with an exactly-equal wire-value set.\n const match = candidateEnumsSorted.find(\n ([candName, candValues]) => !baselineEnumNames.has(candName) && setEquals(baselineValues, candValues),\n );\n if (!match) continue;\n const [newName] = match;\n\n renameMap.set(baselineEnumName, newName);\n\n // Attach a remediation hint to the parent removal if one was reported\n // (dotnet path). Severity stays `breaking`: even though the wire values\n // are unchanged, the typed enum class is gone, so callers referencing\n // it by name will fail to compile or resolve. See `detectTypeRenames`\n // for the full rationale.\n const parentRemoval = parentRemovalByName.get(baselineEnumName);\n if (parentRemoval) {\n parentRemoval.remediation =\n `Enum \"${baselineEnumName}\" appears to have been renamed to \"${newName}\" — ` +\n `both enums have identical wire values, so on-the-wire serialization is unchanged. ` +\n `This is typically the emitter's dedup canonical-flip after a new same-shape enum joined the spec. ` +\n `Consider emitting a deprecated alias in languages that support it, or pinning the canonical via emitter config.`;\n }\n }\n\n return renameMap;\n}\n\n/**\n * Cascade rename downgrades to changes whose meaning depends on a renamed\n * symbol. Walks every change and:\n *\n * - Downgrades child removals (`Owner.field` removed where `Owner` was\n * renamed) — the field still exists, just under a new owner fqName.\n * Same logic for enum members under a renamed enum.\n * - Downgrades `return_type_changed` / `field_type_changed` whose\n * old → new pair matches a recorded rename — the type swap is the\n * rename itself, not a meaningful signature break.\n *\n * Each cascaded change gets a remediation pointing at the parent rename\n * so the reviewer can find the explanation in the report.\n */\nfunction cascadeRenameDowngrades(\n changes: ClassifiedChange[],\n typeRenames: Map<string, string>,\n enumRenames: Map<string, string>,\n baseline: CompatSnapshot,\n candidate: CompatSnapshot,\n): void {\n // Lazy-built field-set maps for the structural-equivalence fallback used\n // by `*_type_changed`. Both maps are needed even when no renames were\n // recorded — the structural test handles cases where both old and new\n // types coexist (e.g. a method's return type was redirected from an\n // existing schema to a structurally-equivalent newly-added schema, the\n // canonical fork antipattern).\n let baselineTypeFields: Map<string, Set<string>> | undefined;\n let candidateTypeFields: Map<string, Set<string>> | undefined;\n const getBaselineFields = (): Map<string, Set<string>> => {\n if (!baselineTypeFields) baselineTypeFields = collectTypeFieldSets(baseline);\n return baselineTypeFields;\n };\n const getCandidateFields = (): Map<string, Set<string>> => {\n if (!candidateTypeFields) candidateTypeFields = collectTypeFieldSets(candidate);\n return candidateTypeFields;\n };\n\n /**\n * Structural equivalence: candidate type's field set is a non-strict\n * superset of baseline type's field set, AND the candidate type was\n * newly added in this diff (not a swap to a pre-existing type, which\n * is a real signature break the consumer chose). When `New ⊇ Old` and\n * `New` is new, every field the consumer accessed on the old type\n * still exists on the value they receive — so the swap is non-breaking\n * at the value level even though the declared type changed. This is\n * the fork-detector's positive signal, applied as a severity\n * downgrade in addition to the existing remediation hint.\n */\n const isStructurallyEquivalent = (oldT: string, newT: string): boolean => {\n if (!oldT || !newT || oldT === newT) return false;\n const baselineFields = getBaselineFields();\n const candidateFields = getCandidateFields();\n // The new type must be newly introduced — a swap to an existing type\n // is a real signature change the consumer chose, not a rename.\n if (baselineFields.has(newT)) return false;\n const oldFields = baselineFields.get(oldT);\n const newFields = candidateFields.get(newT);\n if (!oldFields || !newFields) return false;\n if (oldFields.size === 0) return false;\n for (const f of oldFields) {\n if (!newFields.has(f)) return false;\n }\n return true;\n };\n\n for (const change of changes) {\n if (change.severity !== 'breaking') continue;\n\n if (change.category === 'symbol_removed') {\n const removed = change.old.symbol ?? '';\n const dotIdx = removed.indexOf('.');\n if (dotIdx <= 0) continue;\n const ownerName = removed.slice(0, dotIdx);\n const renamedTo = typeRenames.get(ownerName) ?? enumRenames.get(ownerName);\n if (!renamedTo) continue;\n change.severity = 'soft-risk';\n change.remediation =\n `Owned by renamed symbol \"${ownerName}\" (now \"${renamedTo}\"). ` +\n `The same member exists on the new symbol under \"${renamedTo}.${removed.slice(dotIdx + 1)}\".`;\n continue;\n }\n\n if (change.category === 'return_type_changed') {\n const oldT = bareTypeName(change.old.returnType ?? '');\n const newT = bareTypeName(change.new.returnType ?? '');\n if (typeRenames.get(oldT) === newT) {\n change.severity = 'soft-risk';\n change.remediation =\n `Return type swap matches recorded rename \"${oldT}\" → \"${newT}\". ` +\n `The underlying field set is preserved (see the rename advisory on \"${oldT}\").`;\n } else if (isStructurallyEquivalent(oldT, newT)) {\n // Downgrade severity for the structural-equivalence case (the\n // fork-detector's positive signal). Preserve any remediation\n // already attached by `detectForkedSchemas` — its message\n // already explains the situation; we only need to flip severity.\n change.severity = 'soft-risk';\n if (!change.remediation) {\n change.remediation =\n `Return type swap from \"${oldT}\" to \"${newT}\" is structurally equivalent — ` +\n `every field on \"${oldT}\" still exists on \"${newT}\". ` +\n `Consumer code accessing fields on the returned value continues to work; ` +\n `only explicit \"${oldT}\" type annotations need to migrate.`;\n }\n }\n continue;\n }\n\n if (change.category === 'field_type_changed') {\n const oldT = bareTypeName(change.old.type ?? '');\n const newT = bareTypeName(change.new.type ?? '');\n const renamedTo = typeRenames.get(oldT) ?? enumRenames.get(oldT);\n if (renamedTo === newT) {\n change.severity = 'soft-risk';\n change.remediation =\n `Field type swap matches recorded rename \"${oldT}\" → \"${newT}\". ` +\n `On-the-wire shape is unchanged (see the rename advisory on \"${oldT}\").`;\n } else if (isStructurallyEquivalent(oldT, newT)) {\n change.severity = 'soft-risk';\n if (!change.remediation) {\n change.remediation =\n `Field type swap from \"${oldT}\" to \"${newT}\" is structurally equivalent — ` +\n `every field on \"${oldT}\" still exists on \"${newT}\".`;\n }\n }\n }\n }\n}\n\n/**\n * Build a map from enum fqName → set of wire values. Used by\n * `detectEnumRenames` to find structurally-identical enums across\n * baseline and candidate. Wire values come from `enum_member.value`\n * (the JSON-level value) — not the member names, which are\n * language-specific PascalCase forms.\n *\n * Members whose `value` is undefined are skipped — they contribute no\n * identity information.\n */\nfunction collectEnumValueSets(snapshot: CompatSnapshot): Map<string, Set<string>> {\n const result = new Map<string, Set<string>>();\n for (const sym of snapshot.symbols) {\n if (sym.kind !== 'enum_member') continue;\n if (!sym.ownerFqName) continue;\n if (sym.value === undefined) continue;\n let set = result.get(sym.ownerFqName);\n if (!set) {\n set = new Set<string>();\n result.set(sym.ownerFqName, set);\n }\n set.add(String(sym.value));\n }\n return result;\n}\n\n/** Set equality for the small string sets used by rename detection. */\nfunction setEquals(a: Set<string>, b: Set<string>): boolean {\n if (a.size !== b.size) return false;\n for (const v of a) {\n if (!b.has(v)) return false;\n }\n return true;\n}\n\n/**\n * Strip array/nullable suffixes so we compare bare type names. Languages\n * encode these differently (`Foo[]`, `Foo | null`, `Foo?`, `List<Foo>`,\n * `Optional[Foo]`); this is a best-effort common-case stripper, not an\n * exhaustive parser.\n */\nfunction bareTypeName(t: string): string {\n let s = t.trim();\n // Go pointer prefix: `*Foo` → `Foo`. Strip first because the rest of the\n // patterns expect a leading identifier character.\n s = s.replace(/^\\*/, '');\n // PHP namespace prefix: `\\Vendor\\Pkg\\Foo` → `Foo`. PHP fully-qualified\n // type references in generated method signatures lead with a backslash\n // and use backslash-separated segments. Split on the last segment to\n // preserve nested generics inside the path.\n if (s.startsWith('\\\\')) {\n const lastBackslash = s.lastIndexOf('\\\\');\n s = s.slice(lastBackslash + 1);\n }\n // Nullable suffixes: `Foo | null`, `Foo?`.\n s = s.replace(/\\s*\\|\\s*null$/, '').replace(/\\?$/, '');\n // Array suffix: `Foo[]`.\n s = s.replace(/\\[\\]$/, '');\n // Single-arg generic. Two encodings to support:\n // - angle brackets: `Iterator<Foo>`, `Optional<Foo>`, `List<Foo>`\n // - square brackets: `Iterator[Foo]` (Go iterator returns from the\n // emitter, e.g. `*Iterator[APIKey]`)\n const angleGeneric = s.match(/^[A-Za-z_][A-Za-z0-9_.]*<\\s*([A-Za-z_*][A-Za-z0-9_.*]*)\\s*>$/);\n if (angleGeneric) return bareTypeName(angleGeneric[1]);\n const bracketGeneric = s.match(/^[A-Za-z_][A-Za-z0-9_.]*\\[\\s*([A-Za-z_*][A-Za-z0-9_.*]*)\\s*\\]$/);\n if (bracketGeneric) return bareTypeName(bracketGeneric[1]);\n return s;\n}\n\n/**\n * Check if a symbol is a constructor belonging to a service wrapper class.\n *\n * Service wrapper constructors are internal plumbing (taking a client/config\n * object) — users interact with services via `client.admin_portal`, not\n * `new AdminPortal(...)`. Changes to these constructors should not be\n * reported as breaking.\n *\n * Catches two patterns:\n * - Ruby: kind === 'constructor', ownerFqName is a service_accessor\n * - PHP: kind === 'callable' with fqName ending in '.__construct'\n */\nfunction isServiceWrapperConstructor(sym: CompatSymbol, serviceAccessors: Set<string>): boolean {\n if (!sym.ownerFqName || !serviceAccessors.has(sym.ownerFqName)) return false;\n if (sym.kind === 'constructor') return true;\n if (sym.kind === 'callable' && sym.fqName.endsWith('.__construct')) return true;\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Legacy: ApiSurface-based diff (delegates to existing logic)\n// ---------------------------------------------------------------------------\n\n/**\n * Compare two ApiSurface objects and return a DiffResult.\n *\n * This preserves the existing diffing behavior used by the overlay retry loop,\n * compat check, and all existing tests. The internal implementation uses the\n * same algorithms as before to maintain full backward compatibility with\n * overlay patching and verification workflows.\n */\nexport function diffSurfaces(baseline: ApiSurface, candidate: ApiSurface, hints: LanguageHints): DiffResult {\n const violations: Violation[] = [];\n const additions: Addition[] = [];\n let totalBaseline = 0;\n let preserved = 0;\n\n // Diff classes\n for (const [name, baseClass] of Object.entries(baseline.classes)) {\n totalBaseline++;\n const candClass = candidate.classes[name];\n if (!candClass) {\n violations.push({\n category: 'public-api',\n severity: 'breaking',\n symbolPath: name,\n baseline: name,\n candidate: '(missing)',\n message: `Class \"${name}\" exists in baseline but not in generated output`,\n });\n totalBaseline += Object.values(baseClass.methods).reduce((sum, overloads) => sum + overloads.length, 0);\n totalBaseline += Object.keys(baseClass.properties).length;\n continue;\n }\n preserved++;\n\n // Diff methods (each method name maps to an array of overloads)\n for (const [methodName, baseOverloads] of Object.entries(baseClass.methods)) {\n const candOverloads = candClass.methods[methodName];\n for (const baseMethod of baseOverloads) {\n totalBaseline++;\n if (!candOverloads || candOverloads.length === 0) {\n violations.push({\n category: 'public-api',\n severity: 'breaking',\n symbolPath: `${name}.${methodName}`,\n baseline: methodName,\n candidate: '(missing)',\n message: `Method \"${name}.${methodName}\" exists in baseline but not in generated output`,\n });\n continue;\n }\n const candMethod = candOverloads.find((c) => signaturesMatch(baseMethod, c));\n if (!candMethod) {\n // Fallback: check language-specific signature equivalence\n const equivalentMethod = hints.isSignatureEquivalent\n ? candOverloads.find((c) => hints.isSignatureEquivalent!(baseMethod, c, candidate))\n : undefined;\n if (equivalentMethod) {\n preserved++;\n continue;\n }\n violations.push({\n category: 'signature',\n severity: 'breaking',\n symbolPath: `${name}.${methodName}`,\n baseline: formatSignature(baseMethod),\n candidate: formatSignature(candOverloads[0]),\n message: `Signature mismatch for \"${name}.${methodName}\"`,\n });\n continue;\n }\n preserved++;\n }\n }\n\n // Check for new methods (additions)\n for (const methodName of Object.keys(candClass.methods)) {\n if (!baseClass.methods[methodName]) {\n additions.push({ symbolPath: `${name}.${methodName}`, symbolType: 'method' });\n }\n }\n\n // Diff properties\n for (const [propName, baseProp] of Object.entries(baseClass.properties)) {\n totalBaseline++;\n const candProp = candClass.properties[propName];\n if (!candProp) {\n violations.push({\n category: 'public-api',\n severity: 'breaking',\n symbolPath: `${name}.${propName}`,\n baseline: baseProp.type,\n candidate: '(missing)',\n message: `Property \"${name}.${propName}\" exists in baseline but not in generated output`,\n });\n continue;\n }\n if (baseProp.type !== candProp.type) {\n const nullableOnly = hints.isNullableOnlyDifference(baseProp.type, candProp.type);\n violations.push({\n category: 'signature',\n severity: nullableOnly ? 'warning' : 'breaking',\n symbolPath: `${name}.${propName}`,\n baseline: baseProp.type,\n candidate: candProp.type,\n message: `Property type mismatch for \"${name}.${propName}\"`,\n });\n if (nullableOnly) preserved++;\n continue;\n }\n preserved++;\n }\n\n // Check for new properties (additions)\n for (const propName of Object.keys(candClass.properties)) {\n if (!baseClass.properties[propName]) {\n additions.push({ symbolPath: `${name}.${propName}`, symbolType: 'property' });\n }\n }\n }\n\n // Check for new classes (additions)\n for (const name of Object.keys(candidate.classes)) {\n if (!baseline.classes[name]) {\n additions.push({ symbolPath: name, symbolType: 'class' });\n }\n }\n\n // Precompute lowercased field/property name sets for field-structure matching\n const candIfaceFieldSets = new Map<string, Set<string>>();\n for (const [n, iface] of Object.entries(candidate.interfaces)) {\n candIfaceFieldSets.set(n, new Set(Object.keys(iface.fields).map((f) => f.toLowerCase())));\n }\n const candClassPropSets = new Map<string, Set<string>>();\n for (const [n, cls] of Object.entries(candidate.classes)) {\n candClassPropSets.set(n, new Set(Object.keys(cls.properties).map((f) => f.toLowerCase())));\n }\n\n // Diff interfaces\n for (const [name, baseIface] of Object.entries(baseline.interfaces)) {\n totalBaseline++;\n const candIface = candidate.interfaces[name];\n if (!candIface) {\n let tolerated = false;\n if (hints.tolerateCategoryMismatch && name.startsWith('Serialized')) {\n const baseName = name.slice('Serialized'.length);\n if (candidate.interfaces[baseName] || candidate.classes[baseName]) {\n tolerated = true;\n }\n }\n if (tolerated) {\n preserved++;\n totalBaseline += Object.keys(baseIface.fields).length;\n preserved += Object.keys(baseIface.fields).length;\n continue;\n }\n if (!tolerated) {\n const baseFieldNamesLower = new Set(Object.keys(baseIface.fields).map((f) => f.toLowerCase()));\n if (baseFieldNamesLower.size > 0) {\n for (const [, candFieldNamesLower] of candIfaceFieldSets) {\n if (\n candFieldNamesLower.size === baseFieldNamesLower.size &&\n [...baseFieldNamesLower].every((f) => candFieldNamesLower.has(f))\n ) {\n tolerated = true;\n break;\n }\n }\n if (!tolerated) {\n for (const [, candPropNamesLower] of candClassPropSets) {\n if (\n candPropNamesLower.size === baseFieldNamesLower.size &&\n [...baseFieldNamesLower].every((f) => candPropNamesLower.has(f))\n ) {\n tolerated = true;\n break;\n }\n }\n }\n } else {\n tolerated = true;\n }\n }\n if (tolerated) {\n preserved++;\n totalBaseline += Object.keys(baseIface.fields).length;\n preserved += Object.keys(baseIface.fields).length;\n continue;\n }\n violations.push({\n category: 'public-api',\n severity: 'breaking',\n symbolPath: name,\n baseline: name,\n candidate: '(missing)',\n message: `Interface \"${name}\" exists in baseline but not in generated output`,\n });\n totalBaseline += Object.keys(baseIface.fields).length;\n continue;\n }\n preserved++;\n\n for (const [fieldName, baseField] of Object.entries(baseIface.fields)) {\n totalBaseline++;\n const candField = candIface.fields[fieldName];\n if (!candField) {\n const baseTypeClean = baseField.type.replace(/\\[\\]$/, '').replace(/ \\| null$/, '');\n const typeIsUnresolvable = NAMED_TYPE_RE.test(baseTypeClean) && !typeExistsInSurface(baseTypeClean, candidate);\n violations.push({\n category: 'public-api',\n severity: typeIsUnresolvable ? 'warning' : 'breaking',\n symbolPath: `${name}.${fieldName}`,\n baseline: baseField.type,\n candidate: '(missing)',\n message: `Field \"${name}.${fieldName}\" exists in baseline but not in generated output`,\n });\n if (typeIsUnresolvable) preserved++;\n continue;\n }\n if (baseField.type !== candField.type) {\n if (hints.isUnionReorder(baseField.type, candField.type)) {\n preserved++;\n continue;\n }\n if (hints.isTypeEquivalent?.(baseField.type, candField.type, candidate)) {\n preserved++;\n continue;\n }\n const nullableOnly = hints.isNullableOnlyDifference(baseField.type, candField.type);\n const genericParam = hints.isGenericTypeParam(baseField.type);\n const extractionArtifact = hints.isExtractionArtifact(candField.type);\n const isWarning = nullableOnly || genericParam || extractionArtifact;\n violations.push({\n category: 'signature',\n severity: isWarning ? 'warning' : 'breaking',\n symbolPath: `${name}.${fieldName}`,\n baseline: baseField.type,\n candidate: candField.type,\n message: `Field type mismatch for \"${name}.${fieldName}\"`,\n });\n if (isWarning) preserved++;\n continue;\n }\n preserved++;\n }\n\n for (const fieldName of Object.keys(candIface.fields)) {\n if (!baseIface.fields[fieldName]) {\n additions.push({ symbolPath: `${name}.${fieldName}`, symbolType: 'property' });\n }\n }\n }\n\n // Check for new interfaces (additions)\n for (const name of Object.keys(candidate.interfaces)) {\n if (!baseline.interfaces[name]) {\n additions.push({ symbolPath: name, symbolType: 'interface' });\n }\n }\n\n // Diff type aliases\n for (const [name, baseAlias] of Object.entries(baseline.typeAliases)) {\n totalBaseline++;\n const candAlias = candidate.typeAliases[name];\n if (!candAlias) {\n if (hints.tolerateCategoryMismatch && typeExistsInSurface(name, candidate)) {\n preserved++;\n continue;\n }\n violations.push({\n category: 'public-api',\n severity: 'breaking',\n symbolPath: name,\n baseline: baseAlias.value,\n candidate: '(missing)',\n message: `Type alias \"${name}\" exists in baseline but not in generated output`,\n });\n continue;\n }\n if (baseAlias.value !== candAlias.value) {\n if (hints.isUnionReorder(baseAlias.value, candAlias.value)) {\n preserved++;\n continue;\n }\n const nullableOnly = hints.isNullableOnlyDifference(baseAlias.value, candAlias.value);\n violations.push({\n category: 'signature',\n severity: nullableOnly ? 'warning' : 'breaking',\n symbolPath: name,\n baseline: baseAlias.value,\n candidate: candAlias.value,\n message: `Type alias value mismatch for \"${name}\"`,\n });\n if (nullableOnly) preserved++;\n continue;\n }\n preserved++;\n }\n\n // Check for new type aliases (additions)\n for (const name of Object.keys(candidate.typeAliases)) {\n if (!baseline.typeAliases[name]) {\n additions.push({ symbolPath: name, symbolType: 'type-alias' });\n }\n }\n\n // Diff enums\n for (const [name, baseEnum] of Object.entries(baseline.enums)) {\n totalBaseline++;\n const candEnum = candidate.enums[name];\n if (!candEnum) {\n violations.push({\n category: 'public-api',\n severity: 'breaking',\n symbolPath: name,\n baseline: name,\n candidate: '(missing)',\n message: `Enum \"${name}\" exists in baseline but not in generated output`,\n });\n continue;\n }\n\n const candValueToMembers = new Map<string | number, string[]>();\n for (const [candMember, candValue] of Object.entries(candEnum.members)) {\n const existing = candValueToMembers.get(candValue);\n if (existing) {\n existing.push(candMember);\n } else {\n candValueToMembers.set(candValue, [candMember]);\n }\n }\n\n let enumMatch = true;\n for (const [member, value] of Object.entries(baseEnum.members)) {\n if (candEnum.members[member] === value) {\n continue;\n }\n\n const valueMatches = candValueToMembers.get(value);\n if (valueMatches && valueMatches.length > 0) {\n violations.push({\n category: 'signature',\n severity: 'warning',\n symbolPath: `${name}.${member}`,\n baseline: `${member}=${String(value)}`,\n candidate: `${valueMatches[0]}=${String(value)}`,\n message: `Enum member name differs for \"${name}.${member}\" (value \"${value}\" preserved as \"${valueMatches[0]}\")`,\n });\n continue;\n }\n\n const lowerValue = String(value).toLowerCase();\n const caseInsensitiveMatch = [...candValueToMembers.entries()].find(\n ([candVal]) => String(candVal).toLowerCase() === lowerValue,\n );\n if (caseInsensitiveMatch) {\n violations.push({\n category: 'signature',\n severity: 'warning',\n symbolPath: `${name}.${member}`,\n baseline: `${member}=${String(value)}`,\n candidate: `${caseInsensitiveMatch[1][0]}=${String(caseInsensitiveMatch[0])}`,\n message: `Enum member value case differs for \"${name}.${member}\" (baseline \"${value}\" vs candidate \"${caseInsensitiveMatch[0]}\")`,\n });\n continue;\n }\n\n const isExtractionArtifact =\n String(value) === member || member === 'JsonEnumDefaultValue' || member === 'JsonProperty';\n if (isExtractionArtifact) {\n violations.push({\n category: 'signature',\n severity: 'warning',\n symbolPath: `${name}.${member}`,\n baseline: String(value),\n candidate: '(extraction artifact)',\n message: `Enum member \"${name}.${member}\" appears to be an extraction artifact`,\n });\n continue;\n }\n\n violations.push({\n category: 'signature',\n severity: 'breaking',\n symbolPath: `${name}.${member}`,\n baseline: String(value),\n candidate: member in candEnum.members ? String(candEnum.members[member]) : '(missing)',\n message: `Enum member mismatch for \"${name}.${member}\"`,\n });\n enumMatch = false;\n }\n if (enumMatch) {\n preserved++;\n }\n }\n\n // Check for new enums (additions)\n for (const name of Object.keys(candidate.enums)) {\n if (!baseline.enums[name]) {\n additions.push({ symbolPath: name, symbolType: 'enum' });\n }\n }\n\n // Diff barrel exports\n for (const [path, baseExports] of Object.entries(baseline.exports)) {\n const candExports = candidate.exports[path];\n if (!candExports) {\n for (const exp of baseExports) {\n violations.push({\n category: 'export-structure',\n severity: 'warning',\n symbolPath: `exports[${path}].${exp}`,\n baseline: exp,\n candidate: '(missing)',\n message: `Export \"${exp}\" from \"${path}\" not found in generated output`,\n });\n }\n continue;\n }\n const candSet = new Set(candExports);\n for (const exp of baseExports) {\n if (!candSet.has(exp)) {\n violations.push({\n category: 'export-structure',\n severity: 'warning',\n symbolPath: `exports[${path}].${exp}`,\n baseline: exp,\n candidate: '(missing)',\n message: `Export \"${exp}\" from \"${path}\" not found in generated output`,\n });\n }\n }\n }\n\n return {\n preservationScore: totalBaseline > 0 ? Math.round((preserved / totalBaseline) * 100) : 100,\n totalBaselineSymbols: totalBaseline,\n preservedSymbols: preserved,\n violations,\n additions,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers (legacy)\n// ---------------------------------------------------------------------------\n\nfunction signaturesMatch(baseline: ApiMethod, candidate: ApiMethod): boolean {\n if (baseline.returnType !== candidate.returnType) return false;\n for (let i = 0; i < baseline.params.length; i++) {\n const baseParam = baseline.params[i];\n const candParam = candidate.params[i];\n if (!candParam) return false;\n if (baseParam.type !== candParam.type) return false;\n if (baseParam.name !== candParam.name) return false;\n }\n for (let i = baseline.params.length; i < candidate.params.length; i++) {\n if (!candidate.params[i].optional) return false;\n }\n return true;\n}\n\nfunction formatSignature(method: ApiMethod): string {\n const params = method.params.map((p) => `${p.name}${p.optional ? '?' : ''}: ${p.type}`).join(', ');\n return `(${params}) => ${method.returnType}`;\n}\n","import { RegistryError } from '../errors.js';\nimport type { Extractor } from './types.js';\n\nconst extractors = new Map<string, Extractor>();\n\nexport function registerExtractor(extractor: Extractor): void {\n extractors.set(extractor.language, extractor);\n}\n\nexport function getExtractor(language: string): Extractor {\n const extractor = extractors.get(language);\n if (!extractor) {\n const available = [...extractors.keys()].join(', ') || '(none)';\n throw new RegistryError(\n `No extractor registered for language: ${language}. Available: ${available}`,\n `Register an extractor for \"${language}\" via registerExtractor() or add one in your oagen.config.ts plugin.`,\n );\n }\n return extractor;\n}\n","import type { ApiSurface, ApiInterface, ApiMethod, OverlayLookup, LanguageHints } from './types.js';\nimport type { ClassifiedChange } from './classify.js';\nimport type { ApiSpec, Model } from '../ir/types.js';\nimport { toSnakeCase, splitWords } from '../utils/naming.js';\nimport { nodeHints as defaultNodeHints } from './language-hints.js';\n\nexport type { MethodOverlay, OverlayLookup } from './types.js';\n\nexport interface ManifestEntry {\n operationId: string;\n sdkResourceProperty: string;\n sdkMethodName: string;\n httpMethod: string;\n path: string;\n pathParams: string[];\n bodyFields: string[];\n queryFields: string[];\n}\n\n/**\n * Find the class name that owns a given SDK resource property.\n * E.g. if the surface has a class \"Organizations\" with property \"organizations\",\n * and sdkResourceProperty is \"organizations\", return \"Organizations\".\n */\nfunction findClassForProperty(\n surface: ApiSurface,\n sdkResourceProperty: string,\n hints: LanguageHints,\n): string | undefined {\n for (const [className, cls] of Object.entries(surface.classes)) {\n // Check if the class itself maps to this property (language-specific match)\n if (hints.propertyMatchesClass(sdkResourceProperty, className)) {\n return className;\n }\n // Check properties — resolve to the property's type class, not the parent.\n // This prevents generic parent classes (e.g., Client) from being returned\n // when the actual resource class (e.g., ApiKeys) should be used.\n for (const [propName, prop] of Object.entries(cls.properties)) {\n if (propName === sdkResourceProperty) {\n const propType = (prop as { type?: string }).type;\n if (propType && surface.classes[propType]) {\n return propType;\n }\n // Property type not in surface — skip rather than return the parent\n return undefined;\n }\n }\n }\n\n // Strategy 3: Word-suffix fallback\n // \"adminPortal\" → [\"admin\",\"portal\"]; class \"Portal\" → [\"portal\"]\n // [\"portal\"] is a suffix of [\"admin\",\"portal\"] → match\n const propWords = splitWords(sdkResourceProperty).map((w) => w.toLowerCase());\n if (propWords.length > 1) {\n for (const [className] of Object.entries(surface.classes)) {\n const classWords = splitWords(className).map((w) => w.toLowerCase());\n if (classWords.length > 0 && classWords.length < propWords.length) {\n const suffix = propWords.slice(propWords.length - classWords.length);\n if (classWords.every((w, i) => w === suffix[i])) {\n return className;\n }\n }\n }\n }\n\n return undefined;\n}\n\nexport function buildOverlayLookup(\n surface: ApiSurface,\n manifest?: ManifestEntry[],\n spec?: ApiSpec,\n hints?: LanguageHints,\n options?: { strictModelMatch?: boolean },\n): OverlayLookup {\n const resolvedHints = hints ?? defaultNodeHints;\n const lookup: OverlayLookup = {\n methodByOperation: new Map(),\n httpKeyByMethod: new Map(),\n interfaceByName: new Map(),\n typeAliasByName: new Map(),\n requiredExports: new Map(),\n modelNameByIR: new Map(),\n fileBySymbol: new Map(),\n };\n\n // If manifest available, map operationId → HTTP method + path → existing method\n if (manifest) {\n for (const entry of manifest) {\n const key = `${entry.httpMethod.toUpperCase()} ${entry.path}`;\n const className = findClassForProperty(surface, entry.sdkResourceProperty, resolvedHints);\n if (className) {\n let resolvedMethodName = entry.sdkMethodName;\n let methods = surface.classes[className]?.methods[resolvedMethodName];\n\n // Exact match failed — try prefix match on the resolved class.\n // Handles cases where the generated name is shorter than the existing name\n // (e.g., manifest says \"delete\" but existing SDK has \"deleteApiKey\").\n // Only accept when exactly one candidate matches — ambiguous matches are worse than no match.\n if (!methods) {\n const classMethods = surface.classes[className]?.methods ?? {};\n const prefix = resolvedMethodName.toLowerCase();\n const candidates: [string, ApiMethod[]][] = [];\n for (const [name, overloads] of Object.entries(classMethods)) {\n if (name.toLowerCase().startsWith(prefix) && name !== resolvedMethodName) {\n candidates.push([name, overloads]);\n }\n }\n if (candidates.length === 1) {\n methods = candidates[0][1];\n resolvedMethodName = candidates[0][0];\n } else if (candidates.length > 1) {\n // Disambiguate: prefer the candidate whose name is <prefix><pathSegment>\n // derived from the FIRST segment of the operation path. This avoids\n // mismatching when a class combines operations from multiple path groups\n // (e.g., /organizations and /organization_domains both in Organizations).\n const firstSegment =\n entry.path\n .split('/')\n .filter(Boolean)[0]\n ?.replace(/[{}_-]/g, '') ?? '';\n if (firstSegment) {\n const segLower = firstSegment.toLowerCase();\n // Try the path segment as-is and as singular\n const segSingular = segLower.endsWith('s') ? segLower.slice(0, -1) : segLower;\n const best = candidates.find(([name]) => {\n const lower = name.toLowerCase();\n return lower === prefix + segLower || lower === prefix + segSingular;\n });\n if (best) {\n methods = best[1];\n resolvedMethodName = best[0];\n }\n }\n\n // HTTP verb disambiguation: when path disambiguation fails, use the\n // HTTP method to prefer method names that match the verb semantics.\n // E.g., GET → list/get, POST → create, PUT → set/update, DELETE → delete/remove.\n if (!methods) {\n const verbMatch = disambiguateByHttpVerb(candidates, entry.httpMethod);\n if (verbMatch) {\n methods = verbMatch[1];\n resolvedMethodName = verbMatch[0];\n }\n }\n }\n }\n\n // Suffix match: the existing SDK may use a longer controller-prefixed\n // method name that ends with the transformed name.\n // (e.g., manifest says \"validate_api_key\" but existing SDK has\n // \"api_keys_controller_validate_api_key\").\n // Only accept when exactly one candidate matches — ambiguous matches are worse than no match.\n if (!methods) {\n const classMethods = surface.classes[className]?.methods ?? {};\n const suffix = resolvedMethodName.toLowerCase();\n const candidates: [string, ApiMethod[]][] = [];\n for (const [name, overloads] of Object.entries(classMethods)) {\n if (name.toLowerCase().endsWith(suffix) && name !== resolvedMethodName) {\n candidates.push([name, overloads]);\n }\n }\n if (candidates.length === 1) {\n methods = candidates[0][1];\n resolvedMethodName = candidates[0][0];\n }\n }\n\n // Word-part subsequence match: the surface method may have extra words\n // inserted into the manifest method name. For example:\n // \"disableFlag\" → \"disableFeatureFlag\" ([\"disable\",\"Flag\"] ⊂ [\"disable\",\"Feature\",\"Flag\"])\n // \"getByExternalId\" → \"getOrganizationByExternalId\"\n // Only accept when exactly one candidate matches, or use HTTP verb disambiguation.\n if (!methods) {\n const manifestWords = splitCamelCase(resolvedMethodName);\n if (manifestWords.length >= 2) {\n const classMethods = surface.classes[className]?.methods ?? {};\n const candidates: [string, ApiMethod[]][] = [];\n for (const [name, overloads] of Object.entries(classMethods)) {\n if (name === resolvedMethodName) continue;\n const surfaceWords = splitCamelCase(name);\n if (surfaceWords.length > manifestWords.length && isSubsequence(manifestWords, surfaceWords)) {\n candidates.push([name, overloads]);\n }\n }\n if (candidates.length === 1) {\n methods = candidates[0][1];\n resolvedMethodName = candidates[0][0];\n } else if (candidates.length > 1) {\n const verbMatch = disambiguateByHttpVerb(candidates, entry.httpMethod);\n if (verbMatch) {\n methods = verbMatch[1];\n resolvedMethodName = verbMatch[0];\n }\n }\n }\n }\n\n // Reverse prefix match: the manifest name may be LONGER than the surface\n // name (e.g., \"createResources\" → \"createResource\", \"removeRoleByCriteria\" → \"removeRole\").\n // Check if the manifest name starts with a surface name. Only accept unique matches.\n if (!methods) {\n const classMethods = surface.classes[className]?.methods ?? {};\n const manifestLower = resolvedMethodName.toLowerCase();\n const candidates: [string, ApiMethod[]][] = [];\n for (const [name, overloads] of Object.entries(classMethods)) {\n if (name === resolvedMethodName) continue;\n if (manifestLower.startsWith(name.toLowerCase()) && name.length >= 3) {\n candidates.push([name, overloads]);\n }\n }\n if (candidates.length === 1) {\n methods = candidates[0][1];\n resolvedMethodName = candidates[0][0];\n } else if (candidates.length > 1) {\n const verbMatch = disambiguateByHttpVerb(candidates, entry.httpMethod);\n if (verbMatch) {\n methods = verbMatch[1];\n resolvedMethodName = verbMatch[0];\n }\n }\n }\n\n const method = methods?.[0];\n if (method) {\n lookup.methodByOperation.set(key, {\n className,\n methodName: resolvedMethodName,\n params: method.params,\n returnType: method.returnType,\n });\n lookup.httpKeyByMethod.set(`${className}.${resolvedMethodName}`, key);\n }\n }\n }\n }\n\n // Map interface and type alias names\n for (const name of Object.keys(surface.interfaces)) {\n lookup.interfaceByName.set(name, name);\n }\n for (const name of Object.keys(surface.typeAliases)) {\n lookup.typeAliasByName.set(name, name);\n }\n\n // Map barrel exports\n for (const [path, symbols] of Object.entries(surface.exports)) {\n lookup.requiredExports.set(path, new Set(symbols));\n }\n\n // Populate fileBySymbol from enriched surface\n for (const record of [surface.classes, surface.interfaces, surface.typeAliases, surface.enums] as Record<\n string,\n { sourceFile?: string }\n >[]) {\n for (const [name, item] of Object.entries(record)) {\n if (item.sourceFile) lookup.fileBySymbol.set(name, item.sourceFile);\n }\n }\n\n // Auto-infer IR model name → SDK interface name mappings\n if (spec) {\n buildModelNameMap(surface, spec, lookup, resolvedHints, options);\n\n // Remap fileBySymbol so IR model names point to the SDK symbol's file\n for (const [irName, sdkName] of lookup.modelNameByIR) {\n const filePath = lookup.fileBySymbol.get(sdkName);\n if (filePath) {\n lookup.fileBySymbol.set(irName, filePath);\n }\n }\n }\n\n return lookup;\n}\n\n// ---------------------------------------------------------------------------\n// HTTP verb disambiguation\n// ---------------------------------------------------------------------------\n\n/** Map HTTP methods to preferred method name prefixes for disambiguation. */\nconst HTTP_VERB_PREFIXES: Record<string, string[]> = {\n GET: ['list', 'get', 'fetch', 'retrieve', 'find'],\n POST: ['create', 'add', 'insert', 'send'],\n PUT: ['set', 'update', 'replace', 'put'],\n PATCH: ['update', 'patch', 'modify'],\n DELETE: ['delete', 'remove', 'revoke'],\n};\n\n/**\n * Disambiguate multiple method candidates using HTTP verb semantics.\n * Returns the best match or undefined if no unique match is found.\n */\nfunction disambiguateByHttpVerb<T>(candidates: [string, T][], httpMethod: string): [string, T] | undefined {\n const prefixes = HTTP_VERB_PREFIXES[httpMethod.toUpperCase()];\n if (!prefixes) return undefined;\n\n const verbCandidates = candidates.filter(([name]) => {\n const lower = name.toLowerCase();\n return prefixes.some((p) => lower.startsWith(p));\n });\n\n if (verbCandidates.length === 1) return verbCandidates[0];\n return undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Word-part matching helpers\n// ---------------------------------------------------------------------------\n\n/** Split a camelCase identifier into its word parts (e.g., \"getByExternalId\" → [\"get\",\"By\",\"External\",\"Id\"]). */\nfunction splitCamelCase(name: string): string[] {\n const parts: string[] = [];\n let start = 0;\n for (let i = 1; i < name.length; i++) {\n if (name[i] >= 'A' && name[i] <= 'Z') {\n parts.push(name.slice(start, i));\n start = i;\n }\n }\n parts.push(name.slice(start));\n return parts;\n}\n\n/** Check if `needle` words form a subsequence of `haystack` words (case-insensitive). */\nfunction isSubsequence(needle: string[], haystack: string[]): boolean {\n let ni = 0;\n for (let hi = 0; hi < haystack.length && ni < needle.length; hi++) {\n if (needle[ni].toLowerCase() === haystack[hi].toLowerCase()) ni++;\n }\n return ni === needle.length;\n}\n\n// ---------------------------------------------------------------------------\n// Automatic model name inference\n// ---------------------------------------------------------------------------\n\n/**\n * Normalize a field name to a canonical form for comparison.\n * Handles camelCase → snake_case so \"createdAt\" and \"created_at\" match.\n */\nfunction normalizeFieldName(name: string): string {\n return toSnakeCase(name);\n}\n\n/**\n * Compute the Jaccard similarity between two sets of normalized field names.\n * Returns score (0–1) and raw intersection count.\n */\nfunction jaccardSimilarity(a: Set<string>, b: Set<string>): { score: number; intersection: number } {\n if (a.size === 0 && b.size === 0) return { score: 0, intersection: 0 };\n let intersection = 0;\n for (const item of a) {\n if (b.has(item)) intersection++;\n }\n const union = a.size + b.size - intersection;\n return { score: union === 0 ? 0 : intersection / union, intersection };\n}\n\n/**\n * Build a set of normalized field names from an IR model.\n */\nfunction irModelFieldSignature(model: Model): Set<string> {\n return new Set(model.fields.map((f) => normalizeFieldName(f.name)));\n}\n\n/**\n * Build a set of normalized field names from an SDK interface.\n */\nfunction sdkInterfaceFieldSignature(iface: ApiInterface): Set<string> {\n return new Set(Object.keys(iface.fields).map(normalizeFieldName));\n}\n\n/**\n * Populate the modelNameByIR map using two strategies:\n *\n * 1. Operation-based matching (high confidence):\n * When a manifest maps an HTTP operation to an SDK method, extract the\n * method's return type and parameter types. Match them against the IR\n * operation's response model and request body model.\n *\n * 2. Field-structure matching (fallback):\n * For IR models not matched by operations, compare their field names\n * against all SDK interfaces using Jaccard similarity. A match requires\n * ≥60% field overlap with ≥3 fields in common.\n */\nfunction buildModelNameMap(\n surface: ApiSurface,\n spec: ApiSpec,\n lookup: OverlayLookup,\n hints: LanguageHints,\n options?: { strictModelMatch?: boolean },\n): void {\n const mapped = new Set<string>(); // IR model names already mapped\n const usedSdkNames = new Set<string>(); // SDK names already claimed\n\n // --- Strategy 1: Operation-based matching ---\n if (lookup.methodByOperation.size > 0) {\n for (const service of spec.services) {\n for (const op of service.operations) {\n const httpKey = `${op.httpMethod.toUpperCase()} ${op.path}`;\n const methodOverlay = lookup.methodByOperation.get(httpKey);\n if (!methodOverlay) continue;\n\n // Match response model → SDK return type\n if (op.response.kind === 'model' && !mapped.has(op.response.name)) {\n const sdkTypeName = hints.extractReturnTypeName(methodOverlay.returnType);\n if (sdkTypeName && surface.interfaces[sdkTypeName]) {\n lookup.modelNameByIR.set(op.response.name, sdkTypeName);\n mapped.add(op.response.name);\n usedSdkNames.add(sdkTypeName);\n }\n }\n\n // Match request body model → SDK param type\n if (op.requestBody?.kind === 'model' && !mapped.has(op.requestBody.name)) {\n for (const param of methodOverlay.params) {\n const sdkTypeName = hints.extractParamTypeName(param.type);\n if (sdkTypeName && surface.interfaces[sdkTypeName]) {\n lookup.modelNameByIR.set(op.requestBody.name, sdkTypeName);\n mapped.add(op.requestBody.name);\n usedSdkNames.add(sdkTypeName);\n break;\n }\n }\n }\n }\n }\n }\n\n // --- Strategy 2: Field-structure matching ---\n // Pre-compute SDK interface field signatures\n const sdkSignatures: { name: string; fields: Set<string>; fieldCount: number }[] = [];\n for (const [name, iface] of Object.entries(surface.interfaces)) {\n if (usedSdkNames.has(name)) continue;\n const fields = sdkInterfaceFieldSignature(iface);\n if (fields.size >= 2) {\n sdkSignatures.push({ name, fields, fieldCount: fields.size });\n }\n }\n\n const sdkSignatureNames = new Set(sdkSignatures.map((s) => s.name));\n\n for (const model of spec.models) {\n if (mapped.has(model.name)) continue;\n if (model.fields.length < 2) continue;\n\n // Strategy 2a: Prefer exact name match — if the IR model name matches an SDK\n // interface name exactly, use it without Jaccard scoring. This prevents\n // false positives when a superset interface (e.g., DirectoryUserWithGroups)\n // scores higher than the exact match (DirectoryUser).\n if (sdkSignatureNames.has(model.name) && !usedSdkNames.has(model.name)) {\n lookup.modelNameByIR.set(model.name, model.name);\n mapped.add(model.name);\n usedSdkNames.add(model.name);\n continue;\n }\n\n // Strategy 2a+: Try derived model names before falling back to Jaccard\n const derivedNames = hints.derivedModelNames(model.name);\n for (const derived of derivedNames) {\n if (sdkSignatureNames.has(derived) && !usedSdkNames.has(derived)) {\n lookup.modelNameByIR.set(model.name, derived);\n mapped.add(model.name);\n usedSdkNames.add(derived);\n break;\n }\n }\n if (mapped.has(model.name)) continue;\n\n // In strict mode, skip Jaccard entirely\n if (options?.strictModelMatch) continue;\n\n // Strategy 2b: Fall back to Jaccard field-similarity matching\n const irFields = irModelFieldSignature(model);\n let bestMatch: string | null = null;\n let bestScore = 0;\n\n for (const sdk of sdkSignatures) {\n if (usedSdkNames.has(sdk.name)) continue;\n\n const { score, intersection } = jaccardSimilarity(irFields, sdk.fields);\n\n // Require ≥60% Jaccard AND enough fields in common (scaled by model size)\n const minIntersection = Math.max(3, Math.ceil(irFields.size * 0.5));\n if (score > bestScore && score >= 0.6 && intersection >= minIntersection) {\n bestScore = score;\n bestMatch = sdk.name;\n }\n }\n\n if (bestMatch) {\n lookup.modelNameByIR.set(model.name, bestMatch);\n mapped.add(model.name);\n usedSdkNames.add(bestMatch);\n }\n }\n}\n\n/** Categories that can be patched by the overlay retry loop. */\nconst PATCHABLE_CATEGORIES = new Set(['symbol_removed', 'symbol_renamed']);\n\n/** Check if a classified change is patchable by the overlay loop. */\nexport function isPatchableChange(change: ClassifiedChange): boolean {\n return PATCHABLE_CATEGORIES.has(change.category);\n}\n\n/**\n * Patch overlay with classified changes from a failed verification.\n * Adds explicit name mappings for symbols that were generated with wrong names.\n * Returns a new OverlayLookup (immutable).\n */\nexport function patchOverlay(overlay: OverlayLookup, changes: ClassifiedChange[], baseline: ApiSurface): OverlayLookup {\n const patched: OverlayLookup = {\n methodByOperation: new Map(overlay.methodByOperation),\n httpKeyByMethod: new Map(overlay.httpKeyByMethod),\n interfaceByName: new Map(overlay.interfaceByName),\n typeAliasByName: new Map(overlay.typeAliasByName),\n requiredExports: new Map(Array.from(overlay.requiredExports.entries()).map(([k, v]) => [k, new Set(v)])),\n modelNameByIR: new Map(overlay.modelNameByIR),\n fileBySymbol: new Map(overlay.fileBySymbol),\n };\n\n let warnedManifest = false;\n\n for (const c of changes) {\n if (!isPatchableChange(c)) continue;\n\n // symbol is the fqName, e.g. \"ClassName.methodName\" or \"ClassName\"\n const parts = c.symbol.split('.');\n if (parts.length === 2) {\n const [className, methodName] = parts;\n const baseClass = baseline.classes[className];\n if (baseClass && baseClass.methods[methodName]?.length > 0) {\n const httpKey = overlay.httpKeyByMethod.get(`${className}.${methodName}`);\n if (!httpKey && overlay.httpKeyByMethod.size === 0 && !warnedManifest) {\n console.warn(\n 'Warning: No operations map in .oagen-manifest.json. Method-level violations cannot be auto-patched. ' +\n 'Implement buildOperationsMap in your emitter for the self-correcting loop to resolve these.',\n );\n warnedManifest = true;\n }\n if (httpKey) {\n const method = baseClass.methods[methodName][0];\n patched.methodByOperation.set(httpKey, {\n className,\n methodName,\n params: method.params,\n returnType: method.returnType,\n });\n }\n }\n const baseIface = baseline.interfaces[className];\n if (baseIface) {\n patched.interfaceByName.set(className, className);\n }\n } else if (parts.length === 1) {\n const name = parts[0];\n if (baseline.interfaces[name]) {\n patched.interfaceByName.set(name, name);\n }\n if (baseline.typeAliases[name]) {\n patched.typeAliasByName.set(name, name);\n }\n }\n }\n\n return patched;\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tree-sitter-C6HB4OrC.mjs","names":[],"sources":["../src/ir/types.ts","../src/errors.ts","../src/utils/naming.ts","../src/utils/tree-sitter.ts"],"sourcesContent":["import type { SdkBehavior } from './sdk-behavior.js';\n\n/** Authentication scheme extracted from OpenAPI securitySchemes */\nexport type AuthScheme =\n | { kind: 'bearer' }\n | { kind: 'apiKey'; in: 'header' | 'query' | 'cookie'; name: string }\n | { kind: 'oauth2'; flows: Record<string, unknown> };\n\n/** Root IR node representing the full API surface */\n/** A server entry from the OpenAPI servers array */\nexport interface ServerEntry {\n url: string;\n description?: string;\n}\n\n/** Root IR node representing the full API surface */\nexport interface ApiSpec {\n name: string;\n version: string;\n description?: string;\n baseUrl: string;\n servers?: ServerEntry[];\n services: Service[];\n models: Model[];\n enums: Enum[];\n auth?: AuthScheme[];\n /** Language-agnostic runtime policies (retry, errors, telemetry, etc.). */\n sdk: SdkBehavior;\n}\n\n/** A service groups related operations (maps to an SDK resource class) */\nexport interface Service {\n name: string;\n description?: string;\n operations: Operation[];\n}\n\n/** A single API operation (maps to an SDK method) */\n/** Per-operation security requirement: scheme name → scope list. */\nexport interface SecurityRequirement {\n schemeName: string;\n scopes: string[];\n}\n\nexport interface Operation {\n name: string;\n description?: string;\n httpMethod: HttpMethod;\n path: string;\n pathParams: Parameter[];\n queryParams: Parameter[];\n headerParams: Parameter[];\n cookieParams?: Parameter[];\n requestBody?: TypeRef;\n requestBodyEncoding?: 'json' | 'form-data' | 'form-urlencoded' | 'binary' | 'text';\n response: TypeRef;\n successResponses?: SuccessResponse[];\n errors: ErrorResponse[];\n pagination?: PaginationMeta;\n injectIdempotencyKey: boolean;\n deprecated?: boolean;\n async?: boolean;\n /** Per-operation security overrides. When present, overrides the global spec-level security. */\n security?: SecurityRequirement[];\n /**\n * Mutually-exclusive parameter groups parsed from `x-mutually-exclusive-parameter-groups`.\n * Each group represents a logical choice the caller must (or may) make between\n * several subsets of query/path/header parameters. The grouped parameters remain\n * in their original arrays (queryParams, pathParams, etc.) for wire-format purposes;\n * this field adds the grouping metadata so emitters can render sum types.\n */\n parameterGroups?: ParameterGroup[];\n}\n\n/**\n * A mutually-exclusive parameter group. The caller must supply exactly one\n * variant (when `optional` is false) or may omit the group entirely (when true).\n */\nexport interface ParameterGroup {\n /** Group name from the extension (e.g. \"parent_resource\"). */\n name: string;\n /** True when the whole group may be omitted. */\n optional: boolean;\n /** Ordered variants (insertion order matches the spec). */\n variants: ParameterGroupVariant[];\n /**\n * Base name emitters must use for this group's generated wrapper type, in\n * place of `name`.\n *\n * Two operations commonly share one group name — create and update both\n * declare `protocol_options` — and emitters name the wrapper from the group\n * name alone, so both operations collapse onto one type. That is correct\n * only while their members agree. When they disagree (create's\n * `saml_options` is a `CreateConnectionSAMLOptions`, update's is a\n * `PatchConnectionSAMLOptions`) one wrapper silently forces one operation to\n * use the other operation's type.\n *\n * The parser therefore fingerprints each group's members across every\n * operation declaring it and qualifies this with the operation name\n * (`update_connection_protocol_options`) only where they genuinely diverge.\n * Groups that agree — including ones differing only by nullability, or by\n * duplicate inline enums carrying identical values — keep the bare group\n * name, so already-published wrapper types are never renamed.\n */\n wrapperName?: string;\n}\n\n/**\n * One variant within a mutually-exclusive parameter group.\n */\nexport interface ParameterGroupVariant {\n /** Variant name from the extension (e.g. \"by_id\", \"by_external_id\"). */\n name: string;\n /**\n * References to the actual parameter IR nodes. These are the same\n * objects that live in operation.queryParams / .pathParams / .headerParams --\n * shared by identity, not duplicated.\n */\n parameters: Parameter[];\n /**\n * Names of parameters that may be omitted when this variant is used —\n * optional modifiers of the variant's required fields, from the\n * extension's `optionalFields`. Absent means every parameter in the\n * variant is required with it.\n */\n optionalParameters?: string[];\n}\n\n/** Structured pagination metadata for auto-paging iterator generation */\nexport interface PaginationMeta {\n strategy: 'cursor' | 'offset' | 'link-header';\n param: string;\n limitParam?: string;\n dataPath?: string;\n itemType: TypeRef;\n}\n\nexport type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options' | 'trace';\n\nexport interface Parameter {\n name: string;\n type: TypeRef;\n required: boolean;\n description?: string;\n deprecated?: boolean;\n default?: unknown;\n example?: unknown;\n style?: 'form' | 'simple' | 'label' | 'matrix';\n explode?: boolean;\n}\n\n/** Type reference — the core type system of the IR */\nexport type TypeRef = PrimitiveType | ArrayType | ModelRef | EnumRef | UnionType | NullableType | LiteralType | MapType;\n\nexport interface PrimitiveType {\n kind: 'primitive';\n type: 'string' | 'integer' | 'number' | 'boolean' | 'unknown';\n format?: string;\n}\n\nexport interface ArrayType {\n kind: 'array';\n items: TypeRef;\n}\n\nexport interface ModelRef {\n kind: 'model';\n name: string;\n}\n\nexport interface EnumRef {\n kind: 'enum';\n name: string;\n values?: (string | number)[];\n}\n\nexport interface LiteralType {\n kind: 'literal';\n value: string | number | boolean | null;\n}\n\nexport interface UnionType {\n kind: 'union';\n variants: TypeRef[];\n discriminator?: { property: string; mapping: Record<string, string> };\n /** Which OAS composition keyword produced this union. Emitters can use this to\n * distinguish inheritance (allOf) from exclusive union (oneOf) from open union (anyOf). */\n compositionKind?: 'allOf' | 'oneOf' | 'anyOf';\n}\n\nexport interface NullableType {\n kind: 'nullable';\n inner: TypeRef;\n}\n\nexport interface MapType {\n kind: 'map';\n valueType: TypeRef;\n keyType?: TypeRef;\n}\n\n/**\n * A generic type parameter on a model.\n * Example: `DirectoryUser<TCustomAttributes = Record<string, unknown>>`\n * → `{ name: 'TCustomAttributes', default: { kind: 'map', valueType: { kind: 'primitive', type: 'unknown' } } }`\n */\nexport interface TypeParam {\n name: string;\n /** Default type when the param is not specified. */\n default?: TypeRef;\n}\n\n/** Model definition (maps to an SDK model/data class) */\nexport interface Model {\n name: string;\n description?: string;\n fields: Field[];\n /** Generic type parameters. Empty/undefined for non-generic models. */\n typeParams?: TypeParam[];\n /**\n * When set, this model is a discriminated union over allOf+oneOf variants.\n * Emitters should generate a dispatcher (factory) instead of a regular dataclass.\n * The `property` field is the discriminator key (e.g. \"event\"), and `mapping`\n * maps each discriminator value to the concrete variant model name.\n */\n discriminator?: {\n property: string;\n mapping: Record<string, string>;\n };\n}\n\nexport interface Field {\n name: string;\n /**\n * Optional domain-facing name override. When set, emitters derive the\n * domain-side identifier (in their own casing) from this instead of `name`,\n * while serialization still uses `name` for the wire key. Lets an SDK expose\n * a wire field under a friendlier name (e.g. `connection_type` → `type`)\n * without changing the API contract. Set via the `fieldHints` config and\n * honored by any emitter that reads it.\n */\n domainName?: string;\n type: TypeRef;\n required: boolean;\n description?: string;\n readOnly?: boolean;\n writeOnly?: boolean;\n deprecated?: boolean;\n default?: unknown;\n example?: unknown;\n}\n\n/** Enum definition */\nexport interface Enum {\n name: string;\n values: EnumValue[];\n /** Spec-level default value (the value of `default:` on the schema). Optional. */\n default?: string | number;\n}\n\nexport interface EnumValue {\n name: string;\n value: string | number;\n description?: string;\n deprecated?: boolean;\n}\n\n/**\n * Exhaustive check helper for TypeRef switches.\n * If a new kind is added to TypeRef, any switch that doesn't handle it\n * will fail to compile because `never` won't accept the unhandled variant.\n *\n * Usage:\n * switch (ref.kind) {\n * case 'primitive': ...\n * case 'array': ...\n * // If you forget 'literal', TypeScript errors here:\n * default: assertNever(ref);\n * }\n */\nexport function assertNever(x: never): never {\n // Inline to avoid importing from ../errors.js (ir/ is layer 0, must not import upward)\n const kind = (x as TypeRef).kind;\n const err = new Error(\n `Unexpected TypeRef kind: ${kind}\\nHint: If you added a new TypeRef variant, handle it in every switch/case that calls assertNever.`,\n );\n err.name = 'InternalError';\n throw err;\n}\n\n/**\n * Generic depth-first walker for TypeRef trees.\n * Handles recursion into array/nullable/union/map children and provides\n * an exhaustive `assertNever` check so callers don't need to repeat the\n * switch boilerplate. Supply callbacks only for the leaf kinds you care about.\n */\nexport function walkTypeRef(\n ref: TypeRef,\n visitor: {\n model?: (ref: ModelRef) => void;\n enum?: (ref: EnumRef) => void;\n primitive?: (ref: PrimitiveType) => void;\n literal?: (ref: LiteralType) => void;\n },\n): void {\n switch (ref.kind) {\n case 'model':\n visitor.model?.(ref);\n break;\n case 'enum':\n visitor.enum?.(ref);\n break;\n case 'array':\n walkTypeRef(ref.items, visitor);\n break;\n case 'nullable':\n walkTypeRef(ref.inner, visitor);\n break;\n case 'union':\n for (const v of ref.variants) walkTypeRef(v, visitor);\n break;\n case 'map':\n if (ref.keyType) walkTypeRef(ref.keyType, visitor);\n walkTypeRef(ref.valueType, visitor);\n break;\n case 'literal':\n visitor.literal?.(ref);\n break;\n case 'primitive':\n visitor.primitive?.(ref);\n break;\n default:\n assertNever(ref);\n }\n}\n\n/**\n * Generic depth-first mapper for TypeRef trees.\n * Like walkTypeRef but returns a transformed value instead of void.\n * Handles recursion into array/nullable/union/map children, passing\n * already-mapped child values to the parent callback.\n */\nexport function mapTypeRef<T>(\n ref: TypeRef,\n mapper: {\n primitive: (ref: PrimitiveType) => T;\n array: (ref: ArrayType, mappedItems: T) => T;\n model: (ref: ModelRef) => T;\n enum: (ref: EnumRef) => T;\n union: (ref: UnionType, mappedVariants: T[]) => T;\n nullable: (ref: NullableType, mappedInner: T) => T;\n literal: (ref: LiteralType) => T;\n map: (ref: MapType, mappedValue: T, mappedKey?: T) => T;\n },\n): T {\n switch (ref.kind) {\n case 'primitive':\n return mapper.primitive(ref);\n case 'array':\n return mapper.array(ref, mapTypeRef(ref.items, mapper));\n case 'model':\n return mapper.model(ref);\n case 'enum':\n return mapper.enum(ref);\n case 'union':\n return mapper.union(\n ref,\n ref.variants.map((v) => mapTypeRef(v, mapper)),\n );\n case 'nullable':\n return mapper.nullable(ref, mapTypeRef(ref.inner, mapper));\n case 'literal':\n return mapper.literal(ref);\n case 'map':\n return mapper.map(\n ref,\n mapTypeRef(ref.valueType, mapper),\n ref.keyType ? mapTypeRef(ref.keyType, mapper) : undefined,\n );\n default:\n return assertNever(ref);\n }\n}\n\n// --- IR traversal utilities ---\n\n/**\n * Collect all model names referenced (directly or transitively) by a TypeRef.\n */\nexport function collectModelRefs(ref: TypeRef): string[] {\n const names: string[] = [];\n walkTypeRef(ref, { model: (r) => names.push(r.name) });\n return names;\n}\n\n/**\n * Collect all enum names referenced by a TypeRef.\n */\nexport function collectEnumRefs(ref: TypeRef): string[] {\n const names: string[] = [];\n walkTypeRef(ref, { enum: (r) => names.push(r.name) });\n return names;\n}\n\n/**\n * Collect all TypeRef-referenced model and enum names from a model's fields.\n * Returns { models, enums } sets for generating import statements.\n */\nexport function collectFieldDependencies(model: Model): {\n models: Set<string>;\n enums: Set<string>;\n} {\n const models = new Set<string>();\n const enums = new Set<string>();\n\n for (const field of model.fields) {\n for (const name of collectModelRefs(field.type)) {\n if (name !== model.name) models.add(name);\n }\n for (const name of collectEnumRefs(field.type)) {\n enums.add(name);\n }\n }\n\n return { models, enums };\n}\n\n/**\n * Assign each model to the service that first references it.\n * Models referenced by multiple services are assigned to the first.\n * Models not referenced by any service are unassigned (absent from the map).\n *\n * @param hints - Optional pin overrides keyed by IR model name → IR service\n * name. Applied after the natural assignment loop. A hint only pins a model\n * present in THIS `models` slice; the target service is resolved by name\n * downstream, so a hint pointing at a service outside `services` still lands\n * the model in the right directory. Callers may pass a PARTIAL slice (e.g.\n * discriminated-union planning, per-service barrels, or a `--services`-scoped\n * run), so this function never rejects a hint — typo validation lives in\n * {@link validateModelHints}, which runs once against the full spec.\n */\nexport function assignModelsToServices(\n models: Model[],\n services: Service[],\n hints?: Record<string, string>,\n): Map<string, string> {\n const modelToService = new Map<string, string>();\n const modelNames = new Set(models.map((m) => m.name));\n\n for (const service of services) {\n const referencedModels = new Set<string>();\n\n for (const op of service.operations) {\n if (op.requestBody) {\n for (const name of collectModelRefs(op.requestBody)) {\n referencedModels.add(name);\n }\n }\n for (const name of collectModelRefs(op.response)) {\n referencedModels.add(name);\n }\n for (const param of [...op.pathParams, ...op.queryParams, ...op.headerParams, ...(op.cookieParams ?? [])]) {\n for (const name of collectModelRefs(param.type)) {\n referencedModels.add(name);\n }\n }\n if (op.pagination) {\n for (const name of collectModelRefs(op.pagination.itemType)) {\n referencedModels.add(name);\n }\n }\n }\n\n // Transitively collect models referenced by the directly-referenced models\n const toVisit = [...referencedModels];\n while (toVisit.length > 0) {\n const name = toVisit.pop()!;\n const model = models.find((m) => m.name === name);\n if (!model) continue;\n for (const field of model.fields) {\n for (const ref of collectModelRefs(field.type)) {\n if (!referencedModels.has(ref) && modelNames.has(ref)) {\n referencedModels.add(ref);\n toVisit.push(ref);\n }\n }\n }\n }\n\n for (const name of referencedModels) {\n if (!modelToService.has(name)) {\n modelToService.set(name, service.name);\n }\n }\n }\n\n if (hints) {\n for (const [modelName, serviceName] of Object.entries(hints)) {\n // Only pin models present in THIS slice; an out-of-slice hint is applied\n // where its own slice is processed. The target service resolves by name\n // downstream, so it need not appear in this slice's `services`. Genuine\n // typos are caught up front by validateModelHints against the full spec.\n if (!modelNames.has(modelName)) continue;\n modelToService.set(modelName, serviceName);\n }\n }\n\n return modelToService;\n}\n\n/**\n * Validate model-placement hints against the FULL spec. Run once at the start of\n * generation — where the complete model/service universe is known — so typos in\n * `modelHints` fail loud even though {@link assignModelsToServices} is\n * intentionally lenient about the partial slices it may be handed.\n */\nexport function validateModelHints(models: Model[], services: Service[], hints: Record<string, string>): void {\n const modelNames = new Set(models.map((m) => m.name));\n const serviceNames = new Set(services.map((s) => s.name));\n for (const [modelName, serviceName] of Object.entries(hints)) {\n if (!modelNames.has(modelName)) {\n const err = new Error(\n `modelHints: unknown model \"${modelName}\". Hint keys must match an IR model name (post-cleanSchemaName/schemaNameTransform).`,\n );\n err.name = 'ConfigError';\n throw err;\n }\n if (!serviceNames.has(serviceName)) {\n const err = new Error(\n `modelHints: unknown service \"${serviceName}\" for model \"${modelName}\". Hint values must match an IR service name (PascalCase, derived from the operation's first tag).`,\n );\n err.name = 'ConfigError';\n throw err;\n }\n }\n}\n\n/**\n * Collect all model names referenced as request bodies across all services.\n */\nexport function collectRequestBodyModels(services: Service[]): Set<string> {\n const result = new Set<string>();\n for (const service of services) {\n for (const op of service.operations) {\n if (op.requestBody) {\n for (const name of collectModelRefs(op.requestBody)) {\n result.add(name);\n }\n }\n }\n }\n return result;\n}\n\nexport interface ErrorResponse {\n statusCode: number;\n type?: TypeRef;\n}\n\n/** A successful response entry from a 2xx status code */\nexport interface SuccessResponse {\n statusCode: number;\n type: TypeRef;\n}\n","/**\n * Structured error hierarchy for oagen.\n *\n * Every error carries a human-readable `hint` that suggests a recovery action.\n * The hint is appended to the `message` so it appears in stack traces and logs.\n */\n\n/** Base class for all oagen errors. */\nexport class OagenError extends Error {\n readonly hint: string;\n\n constructor(message: string, hint: string) {\n const fullMessage = hint ? `${message}\\nHint: ${hint}` : message;\n super(fullMessage);\n this.name = 'OagenError';\n this.hint = hint;\n }\n}\n\n/** Thrown when a command should terminate with a specific exit code. */\nexport class CommandError extends OagenError {\n readonly exitCode: number;\n\n constructor(message: string, hint: string, exitCode: number) {\n super(message, hint);\n this.name = 'CommandError';\n this.exitCode = exitCode;\n }\n}\n\n/** Thrown when an OpenAPI spec cannot be parsed or has an unsupported version. */\nexport class SpecParseError extends OagenError {\n constructor(message: string, hint: string) {\n super(message, hint);\n this.name = 'SpecParseError';\n }\n}\n\n/** Thrown when configuration files (manifests, API surfaces, overlays) are missing or malformed. */\nexport class ConfigError extends OagenError {\n constructor(message: string, hint: string) {\n super(message, hint);\n this.name = 'ConfigError';\n }\n}\n\n/** Thrown when a config file exists but cannot be loaded or evaluated. */\nexport class ConfigLoadError extends ConfigError {\n constructor(message: string, hint: string) {\n super(message, hint);\n this.name = 'ConfigLoadError';\n }\n}\n\n/** Thrown when a config targets a different IR version than the installed package. */\nexport class ConfigVersionMismatchError extends ConfigError {\n constructor(message: string, hint: string) {\n super(message, hint);\n this.name = 'ConfigVersionMismatchError';\n }\n}\n\n/** Thrown when an API surface extractor encounters a problem. */\nexport class ExtractorError extends OagenError {\n constructor(message: string, hint: string) {\n super(message, hint);\n this.name = 'ExtractorError';\n }\n}\n\n/** Thrown when a requested language or extractor is not found in a registry. */\nexport class RegistryError extends OagenError {\n constructor(message: string, hint: string) {\n super(message, hint);\n this.name = 'RegistryError';\n }\n}\n\n/** Thrown for internal invariant violations that indicate a bug. */\nexport class InternalError extends OagenError {\n constructor(message: string, hint: string) {\n super(message, hint);\n this.name = 'InternalError';\n }\n}\n","/**\n * Known compound tokens that the regex-based splitter over-splits.\n * Each entry is [lowercase-word-sequence, canonical-form].\n * Sorted longest-first so greedy matching works correctly.\n */\nconst COMPOUND_WORDS: [string[], string][] = [\n [['m', '2', 'm'], 'M2M'],\n [['o', 'auth'], 'OAuth'],\n];\n\n/**\n * Recombine adjacent words that form a known compound token.\n */\nfunction recombineCompounds(words: string[]): string[] {\n const result: string[] = [];\n let i = 0;\n while (i < words.length) {\n let matched = false;\n for (const [pattern, canonical] of COMPOUND_WORDS) {\n if (i + pattern.length <= words.length) {\n const matches = pattern.every((p, j) => words[i + j].toLowerCase() === p);\n if (matches) {\n result.push(canonical);\n i += pattern.length;\n matched = true;\n break;\n }\n }\n }\n if (!matched) {\n result.push(words[i]);\n i++;\n }\n }\n return result;\n}\n\n/**\n * Split a string into words, handling:\n * - camelCase / PascalCase boundaries\n * - snake_case / kebab-case separators\n * - Consecutive capitals (e.g., \"HTTPClient\" → [\"HTTP\", \"Client\"])\n * - Numbers as word boundaries (e.g., \"OAuth2Token\" → [\"OAuth\", \"2\", \"Token\"])\n * - Known compounds are recombined (e.g., \"M2M\" stays as one word)\n */\nexport function splitWords(s: string): string[] {\n if (!s) return [];\n\n const words = s\n .replace(/[^a-zA-Z0-9_\\-\\s.]/g, '_') // replace non-alphanumeric chars with separator\n .replace(/([a-z])([A-Z])/g, '$1\\0$2') // camelCase boundary\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1\\0$2') // consecutive caps boundary\n .replace(/([a-zA-Z])(\\d)/g, '$1\\0$2') // letter to number\n .replace(/(\\d)([a-zA-Z])/g, '$1\\0$2') // number to letter\n .split(/[\\0_\\-\\s.]+/)\n .filter((w) => w.length > 0);\n\n return recombineCompounds(words);\n}\n\nexport const ACRONYM_SET = new Set(['SSO', 'FGA', 'SAML', 'SCIM', 'JWT', 'HMAC', 'M2M']);\n\nexport function toPascalCase(s: string, acronyms?: Set<string>): string {\n const merged = acronyms ? new Set([...ACRONYM_SET, ...acronyms]) : ACRONYM_SET;\n return splitWords(s)\n .map((w) => {\n const upper = w.toUpperCase();\n if (merged.has(upper)) return upper;\n // Special case: OAuth should stay as OAuth, not OAUTH\n if (upper === 'OAUTH') return 'OAuth';\n return w.charAt(0).toUpperCase() + w.slice(1).toLowerCase();\n })\n .join('');\n}\n\nexport function toCamelCase(s: string, acronyms?: Set<string>): string {\n const merged = acronyms ? new Set([...ACRONYM_SET, ...acronyms]) : ACRONYM_SET;\n const words = splitWords(s);\n if (words.length === 0) return '';\n return words\n .map((w, i) => {\n if (i === 0) return w.toLowerCase();\n const upper = w.toUpperCase();\n if (merged.has(upper)) return upper;\n if (upper === 'OAUTH') return 'OAuth';\n return w.charAt(0).toUpperCase() + w.slice(1).toLowerCase();\n })\n .join('');\n}\n\nexport function toSnakeCase(s: string): string {\n return splitWords(s)\n .map((w) => w.toLowerCase())\n .join('_');\n}\n\nexport function toKebabCase(s: string): string {\n return splitWords(s)\n .map((w) => w.toLowerCase())\n .join('-');\n}\n\nexport function toUpperSnakeCase(s: string): string {\n return splitWords(s)\n .map((w) => w.toUpperCase())\n .join('_');\n}\n\nconst BACKEND_SUFFIXES = ['Controller'];\n\nexport function stripBackendSuffixes(name: string): string {\n for (const suffix of BACKEND_SUFFIXES) {\n if (name.endsWith(suffix) && name.length > suffix.length) {\n return name.slice(0, -suffix.length);\n }\n }\n return name;\n}\n\nexport function stripBackendPrefixes(name: string): string {\n return name.replace(/Userland/g, '').replace(/Controller/g, '');\n}\n\n/**\n * Remove ListItem / ByExternalId / ByResourceId / ForResource markers from PascalCase names.\n * E.g. \"DirectoriesListItemState\" → \"DirectoriesState\"\n */\nexport function stripListItemMarkers(name: string): string {\n return name\n .replace(/ListItem/g, '')\n .replace(/ByExternalId/g, '')\n .replace(/ByResourceId/g, '')\n .replace(/ForResource/g, '');\n}\n\n/** Words that look plural but must NOT be singularized. */\nconst SINGULAR_SAFE_LIST = new Set([\n 'Status',\n 'Address',\n 'Access',\n 'Process',\n 'Progress',\n 'Success',\n 'Radius',\n 'Canvas',\n 'Alias',\n 'Basis',\n 'Bus',\n 'Species',\n 'Series',\n]);\n\n/**\n * Conservative singularize for the leading PascalCase word.\n * Only applied to the first word of a PascalCase name (the resource word).\n * - `ies` → `y` (e.g. Directories → Directory)\n * - trailing `s` for words >4 chars (e.g. Organizations → Organization)\n * Safe-listed words are never singularized.\n */\nexport function singularize(word: string): string {\n if (SINGULAR_SAFE_LIST.has(word)) return word;\n if (word.endsWith('ies') && word.length > 4) {\n return word.slice(0, -3) + 'y';\n }\n if (word.endsWith('ses') && word.length > 4) {\n // e.g. \"Processes\" — but \"Process\" is safe-listed, this handles non-safe ones\n return word.slice(0, -2);\n }\n if (word.endsWith('s') && !word.endsWith('ss') && word.length > 4) {\n return word.slice(0, -1);\n }\n return word;\n}\n\n/**\n * Compose all backend name cleaning transforms in order:\n * 1. Strip backend prefixes (Userland, Controller)\n * 2. Strip backend suffixes (Dto, DTO, Controller)\n * 3. Strip ListItem / ByExternalId markers\n * 4. Singularize leading resource word\n *\n * Must be idempotent: `cleanSchemaName(cleanSchemaName(x)) === cleanSchemaName(x)`\n */\n/** Strip `.js` extensions from import/export specifiers for dedup comparison. */\nexport function normalizeJsExtension(text: string): string {\n return text.replace(/\\.js(['\"])/g, '$1');\n}\n\nexport function cleanSchemaName(name: string): string {\n let result = stripBackendPrefixes(stripBackendSuffixes(name));\n result = stripListItemMarkers(result);\n\n // Singularize the leading PascalCase word\n const match = result.match(/^([A-Z][a-z]*)/);\n if (match) {\n const leadWord = match[1];\n const singular = singularize(leadWord);\n if (singular !== leadWord) {\n result = singular + result.slice(leadWord.length);\n }\n }\n\n return result;\n}\n","/**\n * Shared tree-sitter utilities.\n *\n * tree-sitter 0.21.x has a native binding bug: its internal UTF-16 buffer is\n * 32 768 uint16 units (32 768 characters for BMP text). When the JS input\n * callback returns a string >= 32 768 chars, `napi_get_value_string_utf16`\n * overflows and the C layer throws \"Invalid argument\". Work around this by\n * supplying a chunked callback for large sources instead of a raw string.\n */\n\nimport type Parser from 'tree-sitter';\n\nconst TS_SAFE_CHUNK = 32_767;\n\nexport function safeParse(parser: Parser, source: string): Parser.Tree {\n if (source.length < TS_SAFE_CHUNK) {\n return parser.parse(source);\n }\n return parser.parse((offset: number) => source.slice(offset, offset + TS_SAFE_CHUNK));\n}\n"],"mappings":"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"}
|