@workos/oagen 0.22.3 → 0.22.5
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/README.md +1 -1
- package/dist/cli/index.mjs +150 -2
- package/dist/cli/index.mjs.map +1 -1
- package/dist/{diff-DkeDowzz.mjs → diff-CQzcGuFJ.mjs} +151 -3
- package/dist/diff-CQzcGuFJ.mjs.map +1 -0
- package/dist/index.mjs +1 -1
- package/dist/verify/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/diff-DkeDowzz.mjs.map +0 -1
package/dist/cli/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["singularize","singularize","singularize","singularize","extractDeclarationName","declarationKey","path","path","path","defaultNodeHints","path","path","path","path"],"sources":["../../src/ir/sdk-behavior.ts","../../src/errors.ts","../../src/parser/refs.ts","../../src/ir/types.ts","../../src/utils/naming.ts","../../src/parser/inline-models.ts","../../src/parser/schemas.ts","../../src/parser/pagination.ts","../../src/parser/responses.ts","../../src/parser/operations.ts","../../src/parser/normalize-inline-models.ts","../../src/parser/collect-inline-enums.ts","../../src/parser/normalize-model-refs.ts","../../src/parser/parse.ts","../../src/cli/parse.ts","../../src/engine/merge-adapters/url-fingerprint.ts","../../src/engine/merge-adapters/dotnet.ts","../../src/engine/merge-adapters/elixir.ts","../../src/engine/merge-adapters/go.ts","../../src/engine/merge-adapters/kotlin.ts","../../src/engine/merge-adapters/node.ts","../../src/engine/merge-adapters/php.ts","../../src/engine/merge-adapters/python.ts","../../src/engine/merge-adapters/ruby.ts","../../src/engine/merge-adapters/rust.ts","../../src/engine/merge-adapters/index.ts","../../src/utils/tree-sitter.ts","../../src/engine/merger.ts","../../src/engine/json-merge.ts","../../src/engine/writer.ts","../../src/ir/operation-hints.ts","../../src/engine/generate-files.ts","../../src/engine/integrate.ts","../../src/engine/formatter.ts","../../src/engine/manifest.ts","../../src/engine/orchestrator.ts","../../src/engine/registry.ts","../../src/compat/language-hints.ts","../../src/compat/overlay.ts","../../src/compat/extractor-registry.ts","../../src/engine/manifest-reader.ts","../../src/cli/overlay-loader.ts","../../src/utils/expand-doc-urls.ts","../../src/cli/generate.ts","../../src/differ/classify.ts","../../src/differ/models.ts","../../src/differ/operations.ts","../../src/differ/services.ts","../../src/differ/diff.ts","../../src/cli/diff.ts","../../src/cli/extract.ts","../../src/compat/policy.ts","../../src/compat/schema.ts","../../src/compat/ir.ts","../../src/cli/compat-extract.ts","../../src/compat/config.ts","../../src/compat/classify.ts","../../src/compat/spec-filter.ts","../../src/compat/differ.ts","../../src/compat/concepts.ts","../../src/compat/report.ts","../../src/cli/compat-diff.ts","../../src/cli/compat-summary.ts","../../src/compat/approvals.ts","../../src/verify/run-compat-check.ts","../../src/verify/run-overlay-retry-loop.ts","../../src/compat/staleness.ts","../../src/verify/run-staleness-check.ts","../../src/verify/run-smoke-check.ts","../../src/verify/write-diagnostics.ts","../../src/cli/verify.ts","../../src/cli/templates/init.ts","../../src/cli/init.ts","../../src/cli/resolve.ts","../../src/cli/config-loader.ts","../../src/cli/plugin-loader.ts","../../src/cli/index.ts"],"sourcesContent":["/**\n * SDK Behavior IR — language-agnostic runtime policies for generated SDKs.\n *\n * These types capture the \"what\" of SDK behavior (retry, telemetry, errors, etc.)\n * while emitters provide the \"how\" (language-specific mechanism).\n *\n * Emitters access these via `ctx.spec.sdk` — always populated, never undefined.\n */\n\n// ── Retry ──────────────────────────────────────────────────────────\n\n/** Retry policy — when and how to retry failed requests. */\nexport interface RetryPolicy {\n /** HTTP status codes that trigger a retry. */\n retryableStatusCodes: number[];\n /** Maximum number of retry attempts (0 = no retries). */\n maxRetries: number;\n /** Whether to retry on connection errors (DNS failure, TCP reset). */\n retryOnConnectionError: boolean;\n /** Whether to retry on timeout errors. */\n retryOnTimeout: boolean;\n /** Backoff strategy between retries. */\n backoff: BackoffStrategy;\n}\n\n/** Exponential backoff configuration.\n *\n * Formula: `delay = min(initialDelay * multiplier^attempt, maxDelay)`\n * With jitter: `delay += delay * jitterFactor * random(0, 1)`\n */\nexport interface BackoffStrategy {\n /** Initial delay in seconds before the first retry. */\n initialDelay: number;\n /** Multiplier applied to the delay on each subsequent retry. */\n multiplier: number;\n /** Maximum delay in seconds (cap). */\n maxDelay: number;\n /** Jitter factor (0..1). 0.5 means up to 50% random jitter added. */\n jitterFactor: number;\n}\n\n// ── Errors ─────────────────────────────────────────────────────────\n\n/** Error mapping — status codes to named exception kinds. */\nexport interface ErrorPolicy {\n /** Map from HTTP status code to a logical error kind name (e.g. 400 → 'BadRequest').\n * Emitters append language-specific suffixes (e.g. 'BadRequestException'). */\n statusCodeMap: Record<number, string>;\n /** Catch-all error kind for 5xx status codes not in the map. */\n serverErrorKind: string;\n /** Catch-all error kind for unrecognized status codes. */\n clientErrorKind: string;\n /** URL template for error documentation. Use {code} as placeholder for the API error code.\n * Example: 'https://workos.com/docs/errors/{code}' */\n errorDocUrlTemplate?: string;\n}\n\n// ── Telemetry ──────────────────────────────────────────────────────\n\n/** Telemetry — what request metrics to track and send. */\nexport interface TelemetryPolicy {\n /** Whether telemetry is enabled by default. Users can opt out via constructor param. */\n enabledByDefault: boolean;\n /** Header name for client telemetry data (previous request's ID + latency). */\n headerName: string;\n /** Response header name for the request ID. */\n requestIdHeader: string;\n}\n\n// ── Pagination ─────────────────────────────────────────────────────\n\n/** Pagination behavior defaults. */\nexport interface PaginationPolicy {\n /** Delay in milliseconds between pages during auto-pagination. 0 = no delay. */\n autoPageDelayMs: number;\n}\n\n// ── Idempotency ────────────────────────────────────────────────────\n\n/** Idempotency auto-generation rules. */\nexport interface IdempotencyPolicy {\n /** Header name for the idempotency key. */\n headerName: string;\n /** Whether to auto-generate a UUID v4 idempotency key for POST requests when retries > 0. */\n autoGenerateForPost: boolean;\n}\n\n// ── Logging ────────────────────────────────────────────────────────\n\n/** Logging contract — what to log at which level. */\nexport interface LoggingPolicy {\n /** Whether structured logging hooks are generated. */\n enabled: boolean;\n /** Log events that the generated client emits. */\n events: LogEvent[];\n}\n\n/** A discrete loggable event in the request lifecycle. */\nexport type LogEvent =\n | 'request.start'\n | 'request.success'\n | 'request.retry'\n | 'request.rate_limited'\n | 'request.error'\n | 'request.connection_error';\n\n// ── User-Agent ─────────────────────────────────────────────────────\n\n/** User-Agent construction rules. */\nexport interface UserAgentPolicy {\n /** Template for the SDK identifier string.\n * Placeholders: {name} = spec name, {lang} = emitter language, {version} = SDK version.\n * Each emitter interpolates with its own language string and casing conventions.\n * Example: '{name} {lang}/{version}' → 'WorkOS PHP/4.32.0' */\n sdkIdentifierTemplate: string;\n /** Whether to append the runtime/language version (e.g. PHP 8.2, Python 3.12). */\n includeRuntimeVersion: boolean;\n /** Whether to allow app info enrichment via setAppInfo(name, version, url). */\n allowAppInfo: boolean;\n /** AI agent environment variable detection entries. */\n aiAgentEnvVars: AiAgentEnvVar[];\n}\n\n/** Maps an environment variable to an AI agent slug for User-Agent enrichment. */\nexport interface AiAgentEnvVar {\n /** Environment variable to check (e.g. 'CLAUDE_CODE'). */\n envVar: string;\n /** Agent name to append to User-Agent (e.g. 'ClaudeCode'). */\n agentName: string;\n}\n\n// ── Request Guards ─────────────────────────────────────────────────\n\n/** Guards that validate request params before sending. */\nexport interface RequestGuardPolicy {\n /** Keys that should be in RequestOptions, not in params.\n * If detected in the body or query params, the SDK throws an error. */\n optionKeys: string[];\n}\n\n// ── Timeouts ───────────────────────────────────────────────────────\n\n/** Timeout configuration. */\nexport interface TimeoutPolicy {\n /** Default HTTP request timeout in seconds. */\n defaultTimeoutSeconds: number;\n /** Environment variable name to override the timeout (e.g. 'WORKOS_REQUEST_TIMEOUT'). */\n timeoutEnvVar?: string;\n}\n\n// ── Root ───────────────────────────────────────────────────────────\n\n/** Language-agnostic runtime policies for generated SDKs.\n * Attached to `ApiSpec.sdk` and consumed by emitters via `ctx.spec.sdk`. */\nexport interface SdkBehavior {\n retry: RetryPolicy;\n errors: ErrorPolicy;\n telemetry: TelemetryPolicy;\n pagination: PaginationPolicy;\n idempotency: IdempotencyPolicy;\n logging: LoggingPolicy;\n userAgent: UserAgentPolicy;\n requestGuard: RequestGuardPolicy;\n timeout: TimeoutPolicy;\n}\n\n// ── Defaults ───────────────────────────────────────────────────────\n\n/**\n * Canonical SDK behavior defaults. These match the PHP emitter's current\n * implementation (the most complete). Per-language overrides can be applied\n * via `mergeSdkBehavior()` in each SDK's `oagen.config.ts`.\n *\n * - Retry: exponential backoff with jitter, retries on 429/5xx\n * - Errors: standard HTTP status → exception kind mapping\n * - Telemetry: enabled by default, tracks request ID + latency\n * - Pagination: no inter-page delay (Node overrides to 350ms)\n * - Idempotency: auto-generate UUID v4 for retryable POSTs\n * - Logging: all lifecycle events enabled\n * - User-Agent: SDK identifier + runtime version + app info + AI agent detection\n * - Request guards: detect misplaced RequestOptions keys in params\n * - Timeout: 60s default (Python overrides to 30s)\n */\nexport function defaultSdkBehavior(): SdkBehavior {\n return {\n retry: {\n retryableStatusCodes: [429, 500, 502, 503, 504],\n maxRetries: 3,\n retryOnConnectionError: true,\n retryOnTimeout: true,\n backoff: {\n initialDelay: 1.0,\n multiplier: 2.0,\n maxDelay: 30.0,\n jitterFactor: 0.5,\n },\n },\n errors: {\n statusCodeMap: {\n 400: 'BadRequest',\n 401: 'Authentication',\n 403: 'Authorization',\n 404: 'NotFound',\n 409: 'Conflict',\n 422: 'UnprocessableEntity',\n 429: 'RateLimitExceeded',\n },\n serverErrorKind: 'Server',\n clientErrorKind: 'Api',\n errorDocUrlTemplate: 'https://workos.com/docs/errors/{code}',\n },\n telemetry: {\n enabledByDefault: true,\n headerName: 'X-WorkOS-Client-Telemetry',\n requestIdHeader: 'X-Request-ID',\n },\n pagination: {\n autoPageDelayMs: 0,\n },\n idempotency: {\n headerName: 'Idempotency-Key',\n autoGenerateForPost: true,\n },\n logging: {\n enabled: true,\n events: [\n 'request.start',\n 'request.success',\n 'request.retry',\n 'request.rate_limited',\n 'request.error',\n 'request.connection_error',\n ],\n },\n userAgent: {\n sdkIdentifierTemplate: '{name} {lang}/{version}',\n includeRuntimeVersion: true,\n allowAppInfo: true,\n aiAgentEnvVars: [\n { envVar: 'CLAUDE_CODE', agentName: 'ClaudeCode' },\n { envVar: 'CURSOR_AGENT', agentName: 'Cursor' },\n { envVar: 'CLINE_ACTIVE', agentName: 'Cline' },\n { envVar: 'WINDSURF_ACTIVE', agentName: 'Windsurf' },\n { envVar: 'COPILOT_AGENT', agentName: 'Copilot' },\n ],\n },\n requestGuard: {\n optionKeys: [\n 'api_key',\n 'apiKey',\n 'idempotency_key',\n 'idempotencyKey',\n 'extra_headers',\n 'extraHeaders',\n 'max_retries',\n 'maxRetries',\n 'base_url',\n 'baseUrl',\n ],\n },\n timeout: {\n defaultTimeoutSeconds: 60,\n },\n };\n}\n\n// ── Merge ──────────────────────────────────────────────────────────\n\n/** Recursive partial type for deep overrides. */\nexport type DeepPartial<T> = {\n [K in keyof T]?: T[K] extends (infer U)[]\n ? U[] // Arrays replace entirely (don't concat)\n : T[K] extends object\n ? DeepPartial<T[K]>\n : T[K];\n};\n\n/**\n * Deep-merge partial overrides into the canonical defaults.\n * Arrays replace entirely (so `retryableStatusCodes: [429]` replaces the full list,\n * rather than appending). Object properties are merged recursively.\n */\nexport function mergeSdkBehavior(overrides: DeepPartial<SdkBehavior>): SdkBehavior {\n return deepMerge(\n defaultSdkBehavior() as unknown as Record<string, unknown>,\n overrides as unknown as Record<string, unknown>,\n ) as unknown as SdkBehavior;\n}\n\n/**\n * Self-contained deep merge (no external imports — ir/ is layer 0).\n * Arrays and primitives from `source` replace those in `target`.\n * Objects are merged recursively.\n */\nfunction deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = { ...target };\n for (const key of Object.keys(source)) {\n const sourceVal = source[key];\n const targetVal = target[key];\n if (sourceVal === undefined) continue;\n if (\n sourceVal !== null &&\n typeof sourceVal === 'object' &&\n !Array.isArray(sourceVal) &&\n targetVal !== null &&\n typeof targetVal === 'object' &&\n !Array.isArray(targetVal)\n ) {\n result[key] = deepMerge(targetVal as Record<string, unknown>, sourceVal as Record<string, unknown>);\n } else {\n result[key] = sourceVal;\n }\n }\n return result;\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","import { readFile } from 'node:fs/promises';\nimport { resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { makeDocumentFromString, bundleDocument, createConfig, BaseResolver, Oas3_1Types } from '@redocly/openapi-core';\nimport { SpecParseError } from '../errors.js';\n\nexport interface BundledSpec {\n parsed: Record<string, unknown>;\n specPath: string;\n}\n\nexport async function loadAndBundleSpec(specPath: string): Promise<BundledSpec> {\n const absolutePath = resolve(specPath);\n const content = await readFile(absolutePath, 'utf-8');\n const document = makeDocumentFromString(content, pathToFileURL(absolutePath).href);\n\n const config = await createConfig({});\n const resolver = new BaseResolver();\n\n const result = await bundleDocument({\n document,\n config,\n types: Oas3_1Types,\n externalRefResolver: resolver,\n dereference: false,\n });\n\n if (result.problems.some((p) => p.severity === 'error')) {\n const errors = result.problems\n .filter((p) => p.severity === 'error')\n .map((p) => p.message)\n .join('\\n');\n throw new SpecParseError(\n `Failed to parse spec: ${errors}`,\n `Check the OpenAPI spec at \"${absolutePath}\" for syntax errors. Run a linter such as \\`npx @redocly/cli lint ${specPath}\\` to identify issues.`,\n );\n }\n\n return {\n parsed: result.bundle.parsed as Record<string, unknown>,\n specPath: absolutePath,\n };\n}\n","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\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\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 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. Both names must exist in\n * the spec; unknown keys/values throw a config-style error so typos fail\n * loud at generation time.\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 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 modelToService.set(modelName, serviceName);\n }\n }\n\n return modelToService;\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 * 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","import type { Model, Field } from '../ir/types.js';\nimport { toPascalCase, stripListItemMarkers, singularize } from '../utils/naming.js';\nimport type { SchemaObject } from './schemas.js';\nimport { buildFieldFromSchema, resolveSchemaName } from './schemas.js';\n\n/**\n * Qualify an inline model name with the parent schema name.\n * If `parentName` is provided and the field name doesn't already start with\n * the parent, the result is `${parentName}${PascalField}` with the trailing\n * word singularized (e.g., Connection + Domains → ConnectionDomain).\n */\nexport function qualifyInlineModelName(baseName: string, parentName?: string): string {\n if (!parentName) return baseName;\n // Strip ListItem/ByExternalId markers from parent name so inline model names\n // are clean and match the names produced by qualifyNestedName() in responses.ts.\n // e.g., ConnectionListItem + Domains → Connection + Domain = ConnectionDomain\n const cleanParent = stripListItemMarkers(parentName);\n if (baseName.startsWith(cleanParent)) return baseName;\n // Singularize the trailing PascalCase word of the combined name.\n // Split baseName into leading words + trailing word, singularize trailing.\n const trailingMatch = baseName.match(/^(.*?)([A-Z][a-z]*)$/);\n if (trailingMatch) {\n const [, prefix, trailingWord] = trailingMatch;\n const singular = singularize(trailingWord);\n return `${cleanParent}${prefix}${singular}`;\n }\n return `${cleanParent}${baseName}`;\n}\n\n/**\n * Walk all component schemas and extract inline Model definitions for fields\n * that are objects with properties (or arrays of such objects).\n * These correspond to the ModelRef entries created by schemaToTypeRef.\n */\nexport function extractInlineModelsFromSchemas(schemas: Record<string, SchemaObject> | undefined): Model[] {\n if (!schemas) return [];\n\n const inlineModels: Model[] = [];\n\n for (const [schemaName, schema] of Object.entries(schemas)) {\n const parentName = resolveSchemaName(schemaName);\n extractInlineModelsFromProperties(schema, inlineModels, parentName);\n }\n\n return inlineModels;\n}\n\nfunction extractInlineModelsFromProperties(schema: SchemaObject, results: Model[], parentName?: string): void {\n const properties = schema.properties ?? {};\n const allOfSchemas = schema.allOf ?? [];\n\n for (const sub of allOfSchemas) {\n if (sub.properties) {\n extractInlineModelsFromProperties(sub, results, parentName);\n }\n }\n\n for (const [fieldName, fieldSchema] of Object.entries(properties)) {\n if (!fieldSchema) continue;\n // Direct inline object with properties (with or without explicit type: 'object')\n if (fieldSchema.properties && (fieldSchema.type === 'object' || !fieldSchema.type)) {\n const baseName = toPascalCase(fieldName);\n const modelName = qualifyInlineModelName(baseName, parentName);\n results.push(buildInlineModel(modelName, fieldSchema));\n extractInlineModelsFromProperties(fieldSchema, results, modelName);\n }\n\n // Array of inline objects\n if (fieldSchema.type === 'array' && fieldSchema.items) {\n const items = fieldSchema.items;\n if (items.properties && (items.type === 'object' || !items.type)) {\n const baseName = toPascalCase(fieldName);\n const modelName = qualifyInlineModelName(baseName, parentName);\n results.push(buildInlineModel(modelName, items));\n extractInlineModelsFromProperties(items, results, modelName);\n }\n }\n\n // oneOf containing objects — extract every inline object variant as a\n // model so each gets its own typed class. Variant 0 keeps the bare\n // qualified inline name (e.g. `ApiKeyCreatedDataOwner`); subsequent\n // variants are prefixed by their const-discriminator value via\n // `nameOneOfVariant` (e.g. `UserApiKeyCreatedDataOwner`). When the\n // oneOf doesn't have a const-discriminator (single object variant + null\n // for nullable, or single object variant only), only variant 0 is\n // extracted and the bare name pattern preserves backward compat.\n if (fieldSchema.oneOf) {\n const inlineObjectVariants = fieldSchema.oneOf.filter(\n (v) => !v.$ref && v.properties && (v.type === 'object' || !v.type),\n );\n if (inlineObjectVariants.length > 0) {\n const baseName = toPascalCase(fieldName);\n const modelName = qualifyInlineModelName(baseName, parentName);\n const existingNames = new Set(results.map((r) => r.name));\n const namingDiscProp = deriveOneOfNamingDiscriminator(inlineObjectVariants);\n const emittedNames: string[] = [];\n for (const variant of inlineObjectVariants) {\n const variantName = nameOneOfVariant(variant, modelName, emittedNames, namingDiscProp);\n emittedNames.push(variantName);\n if (!existingNames.has(variantName)) {\n existingNames.add(variantName);\n results.push(buildInlineModel(variantName, variant));\n extractInlineModelsFromProperties(variant, results, variantName);\n }\n }\n }\n }\n }\n}\n\n/** Find a single string-const-valued property shared by every variant whose\n * values are all distinct — the implicit discriminator. Returns null when no\n * such property exists. Mirrors `deriveConstNamingDiscriminator` in schemas.ts. */\nfunction deriveOneOfNamingDiscriminator(variants: SchemaObject[]): string | null {\n if (variants.length < 2) return null;\n const candidates = Object.keys(variants[0]?.properties ?? {});\n for (const propName of candidates) {\n const values = variants.map((v) => readConstString(v.properties?.[propName]));\n if (values.some((v) => v === null)) continue;\n if (new Set(values).size !== values.length) continue;\n return propName;\n }\n return null;\n}\n\nfunction readConstString(prop: SchemaObject | undefined): string | null {\n if (!prop) return null;\n if (typeof prop.const === 'string') return prop.const;\n if (Array.isArray(prop.enum) && prop.enum.length === 1 && typeof prop.enum[0] === 'string') {\n return prop.enum[0];\n }\n return null;\n}\n\n/** Produce a per-variant model name. Variant 0 keeps the bare parent name;\n * later variants are prefixed by the const-derived label. Mirrors\n * `nameVariantModel` in schemas.ts. Falls back to a numeric suffix when no\n * discriminator is available, the const value PascalCases to nothing, or\n * the derived candidate collides with the parent or an already-emitted name. */\nfunction nameOneOfVariant(\n variant: SchemaObject,\n parentName: string,\n alreadyEmitted: string[],\n discriminatorProperty: string | null,\n): string {\n if (alreadyEmitted.length === 0) return parentName;\n if (discriminatorProperty) {\n const constValue = readConstString(variant.properties?.[discriminatorProperty]);\n if (constValue) {\n const prefix = toPascalCase(constValue);\n if (prefix) {\n const candidate = parentName.startsWith(prefix) ? parentName : `${prefix}${parentName}`;\n const collision = candidate === parentName || alreadyEmitted.includes(candidate);\n if (!collision) return candidate;\n }\n }\n }\n return `${parentName}${alreadyEmitted.length + 1}`;\n}\n\nfunction buildInlineModel(name: string, schema: SchemaObject): Model {\n const requiredSet = new Set(schema.required ?? []);\n const fields: Field[] = [];\n\n for (const [fieldName, fieldSchema] of Object.entries(schema.properties ?? {})) {\n if (!fieldSchema) continue;\n fields.push(buildFieldFromSchema(fieldName, fieldSchema, name, requiredSet));\n }\n\n return { name, description: schema.description, fields };\n}\n","import type { Model, Enum, EnumValue, Field, TypeRef } from '../ir/types.js';\nimport { walkTypeRef } from '../ir/types.js';\nimport {\n toPascalCase,\n toUpperSnakeCase,\n cleanSchemaName,\n singularize,\n stripListItemMarkers,\n splitWords,\n} from '../utils/naming.js';\n\n/**\n * Module-level transform set during extractSchemas(). Used by schemaToTypeRef()\n * to apply the same name transform to $ref model/enum references.\n */\nlet activeSchemaNameTransform: ((name: string) => string) | null = null;\n\n/**\n * Module-level set of resolved schema names whose components/schemas entry is\n * an enum (i.e. has `enum:`). Populated by extractSchemas() so schemaToTypeRef()\n * can classify a `$ref` to a top-level enum schema as `kind: 'enum'` instead of\n * `kind: 'model'`. Without this, every `$ref` was naively returned as a model\n * ref, even when the target was a shared enum like `PaginationOrder`.\n */\nlet activeEnumSchemaNames: Set<string> = new Set();\n\n/** Apply cleanSchemaName + the active transform (if any) to a raw schema name. */\nexport function resolveSchemaName(rawName: string): string {\n let name = cleanSchemaName(toPascalCase(rawName));\n if (activeSchemaNameTransform) name = activeSchemaNameTransform(name);\n return name;\n}\n\nexport interface SchemaExtractionOptions {\n schemaNameTransform?: (name: string) => string;\n}\n\nexport interface SchemaObject {\n type?: string | string[];\n format?: string;\n description?: string;\n properties?: Record<string, SchemaObject | undefined>;\n required?: string[];\n items?: SchemaObject;\n enum?: (string | number)[];\n allOf?: SchemaObject[];\n oneOf?: SchemaObject[];\n anyOf?: SchemaObject[];\n discriminator?: { propertyName: string; mapping?: Record<string, string> };\n readOnly?: boolean;\n writeOnly?: boolean;\n nullable?: boolean;\n $ref?: string;\n additionalProperties?: boolean | SchemaObject;\n const?: unknown;\n patternProperties?: Record<string, SchemaObject>;\n deprecated?: boolean;\n default?: unknown;\n example?: unknown;\n [key: string]: unknown;\n}\n\nexport interface ExtractedSchemas {\n models: Model[];\n enums: Enum[];\n}\n\nexport function extractSchemas(\n schemas: Record<string, SchemaObject> | undefined,\n options?: SchemaExtractionOptions,\n): ExtractedSchemas {\n const enums: Enum[] = [];\n\n if (!schemas) return { models: [], enums };\n\n // Build collision-safe transform if provided\n if (options?.schemaNameTransform) {\n const transform = options.schemaNameTransform;\n const rawNames = Object.keys(schemas);\n const cleanedNames = rawNames.map((n) => cleanSchemaName(toPascalCase(n)));\n const transformedToOriginals = new Map<string, string[]>();\n for (const cleaned of cleanedNames) {\n const transformed = transform(cleaned);\n if (!transformedToOriginals.has(transformed)) transformedToOriginals.set(transformed, []);\n transformedToOriginals.get(transformed)!.push(cleaned);\n }\n const unsafeToTransform = new Set<string>();\n for (const [, originals] of transformedToOriginals) {\n if (originals.length > 1) {\n for (const n of originals) unsafeToTransform.add(n);\n }\n }\n activeSchemaNameTransform = (name: string) => (unsafeToTransform.has(name) ? name : transform(name));\n } else {\n activeSchemaNameTransform = null;\n }\n\n // Pre-compute the set of resolved names whose component schema is an enum so\n // schemaToTypeRef() can classify `$ref` targets correctly. Built in a separate\n // pass because the per-schema loop mutates models/enums and we want this map\n // available before any TypeRef is resolved (operations + nested fields both\n // call schemaToTypeRef during extraction).\n activeEnumSchemaNames = new Set();\n for (const [name, schema] of Object.entries(schemas)) {\n if (schema.enum) activeEnumSchemaNames.add(resolveSchemaName(name));\n }\n\n const modelsByCleanName = new Map<string, Model>();\n\n for (const [name, schema] of Object.entries(schemas)) {\n const pascalName = resolveSchemaName(name);\n\n if (schema.enum) {\n enums.push(extractEnum(pascalName, schema));\n } else {\n const model = extractModel(pascalName, schema, schemas);\n const existing = modelsByCleanName.get(pascalName);\n if (existing) {\n // Keep the model with more fields when names collide after cleaning\n if (model.fields.length > existing.fields.length) {\n modelsByCleanName.set(pascalName, model);\n }\n } else {\n modelsByCleanName.set(pascalName, model);\n }\n\n for (const inlineModel of extractDiscriminatedAllOfVariantModels(schema, pascalName)) {\n const existingInline = modelsByCleanName.get(inlineModel.name);\n if (existingInline) {\n if (inlineModel.fields.length > existingInline.fields.length) {\n modelsByCleanName.set(inlineModel.name, inlineModel);\n }\n } else {\n modelsByCleanName.set(inlineModel.name, inlineModel);\n }\n }\n }\n }\n\n const models = [...modelsByCleanName.values()];\n\n // Collect inline models from nested object/oneOf properties\n // that schemaToTypeRef created model refs for but weren't extracted\n const modelNames = new Set(models.map((m) => m.name));\n const inlineQueue: Model[] = [...models];\n while (inlineQueue.length > 0) {\n const model = inlineQueue.pop()!;\n for (const field of model.fields) {\n collectNestedInlineModels(field.type, field.name, model.name, schemas ?? {}, models, modelNames, inlineQueue);\n }\n }\n\n // Collect inline enums from model fields\n for (const model of models) {\n collectInlineEnums(model.fields, enums);\n }\n\n // NOTE: activeSchemaNameTransform is intentionally NOT cleared here.\n // extractOperations() calls schemaToTypeRef() for $ref resolution and\n // needs the same transform active. parseSpec() calls clearSchemaNameTransform()\n // after all extraction is complete.\n return { models, enums };\n}\n\n/** Clear the module-level schemaNameTransform. Called by parseSpec() after all extraction phases. */\nexport function clearSchemaNameTransform(): void {\n activeSchemaNameTransform = null;\n activeEnumSchemaNames = new Set();\n}\n\n/**\n * Walk a single TypeRef and extract inline enum refs as top-level enum definitions.\n * Shared by both schemas.ts (field-level) and parse.ts (model-level) collection passes.\n */\nexport function collectInlineEnumFromRef(ref: TypeRef, enums: Enum[], seen: Set<string>): void {\n walkTypeRef(ref, {\n enum: (r) => {\n if (r.values && !seen.has(r.name)) {\n seen.add(r.name);\n enums.push({\n name: r.name,\n values: r.values.map((v) => ({\n name: toUpperSnakeCase(String(v)),\n value: v,\n description: undefined,\n })),\n });\n }\n },\n });\n}\n\n/**\n * Walk model fields and extract inline enum refs as top-level enum definitions.\n * This ensures type alias files are generated for inline enums.\n */\nfunction collectInlineEnums(fields: Field[], enums: Enum[]): void {\n const seen = new Set(enums.map((e) => e.name));\n for (const field of fields) {\n collectInlineEnumFromRef(field.type, enums, seen);\n }\n}\n\n/**\n * Walk a TypeRef tree and extract inline models for any model refs that point\n * to schemas with inline object properties (not in components/schemas).\n * This handles nested objects like `totp: { oneOf: [{ type: object, properties: {...} }] }`\n * that schemaToTypeRef turns into model refs but aren't extracted from components.\n */\nfunction collectNestedInlineModels(\n ref: TypeRef,\n fieldName: string,\n parentModelName: string,\n schemas: Record<string, SchemaObject>,\n models: Model[],\n modelNames: Set<string>,\n queue: Model[],\n): void {\n walkTypeRef(ref, {\n model: (modelRef) => {\n if (modelNames.has(modelRef.name)) return; // already extracted\n // Check if this model name corresponds to a component schema\n // by checking all possible original names that would map to this PascalCase name\n const isComponent = Object.keys(schemas).some((k) => resolveSchemaName(k) === modelRef.name);\n if (isComponent) return; // will be extracted from components\n\n // This is a reference to a nested inline model that wasn't extracted.\n // Look up the field schema in the parent model's component schema to extract it.\n const parentSchema = findSchemaByName(parentModelName, schemas);\n if (!parentSchema) return;\n\n const fieldSchema = findNestedFieldSchema(fieldName, parentSchema, schemas);\n if (!fieldSchema) return;\n\n // Extract inline models from the field schema\n const extracted = extractNestedSchema(modelRef.name, fieldSchema);\n for (const m of extracted) {\n if (!modelNames.has(m.name)) {\n models.push(m);\n modelNames.add(m.name);\n queue.push(m); // re-scan for deeper nesting\n }\n }\n },\n });\n}\n\n/** Find a component schema by PascalCase name. */\nfunction findSchemaByName(pascalName: string, schemas: Record<string, SchemaObject>): SchemaObject | null {\n for (const [k, v] of Object.entries(schemas)) {\n if (resolveSchemaName(k) === pascalName) return v;\n }\n return null;\n}\n\n/** Walk into a schema to find a field's sub-schema, resolving allOf and oneOf/anyOf. */\nfunction findNestedFieldSchema(\n fieldName: string,\n parentSchema: SchemaObject,\n schemas: Record<string, SchemaObject>,\n): SchemaObject | null {\n if (parentSchema.properties?.[fieldName]) {\n return parentSchema.properties[fieldName]!;\n }\n if (parentSchema.allOf) {\n for (const sub of parentSchema.allOf) {\n let resolved = sub;\n if (sub.$ref) {\n const segments = sub.$ref.split('/');\n const refName = segments[segments.length - 1];\n if (refName && schemas[refName]) resolved = schemas[refName];\n }\n if (resolved.properties?.[fieldName]) {\n return resolved.properties[fieldName]!;\n }\n }\n }\n // Also check inside oneOf/anyOf variants (pure oneOf schemas flatten variant\n // properties into the model, so the field may live inside a variant).\n for (const variant of [...(parentSchema.oneOf ?? []), ...(parentSchema.anyOf ?? [])]) {\n let resolved = variant;\n if (variant.$ref) {\n const segments = variant.$ref.split('/');\n const refName = segments[segments.length - 1];\n if (refName && schemas[refName]) resolved = schemas[refName];\n }\n if (resolved.properties?.[fieldName]) {\n return resolved.properties[fieldName]!;\n }\n }\n return null;\n}\n\n/** Extract a model (and nested models) from an inline field schema. */\nfunction extractNestedSchema(name: string, schema: SchemaObject): Model[] {\n // Handle oneOf: extract each object variant as its own model\n if (schema.oneOf) {\n const models: Model[] = [];\n\n // Collect the inline object variants up front. When every variant pins\n // the same property to a const value, we can derive meaningful names\n // from the const (e.g. `UserApiKeyOwner` instead of `ApiKeyOwner2`)\n // — much friendlier for SDK consumers than numeric suffixes.\n const inlineObjectVariants: SchemaObject[] = schema.oneOf.filter(\n (v) => !v.$ref && v.properties && (v.type === 'object' || !v.type),\n );\n const constNamingDiscriminator = deriveConstNamingDiscriminator(inlineObjectVariants);\n\n for (const variant of schema.oneOf) {\n if (variant.$ref) continue;\n if (variant.properties && (variant.type === 'object' || !variant.type)) {\n const requiredSet = new Set(variant.required ?? []);\n const fields: Field[] = [];\n for (const [fn, fs] of Object.entries(variant.properties)) {\n if (!fs) continue;\n fields.push(buildFieldFromSchema(fn, fs, name, requiredSet));\n }\n const variantName = nameVariantModel(variant, name, models, constNamingDiscriminator);\n models.push({ name: variantName, description: variant.description, fields });\n }\n }\n return models;\n }\n\n // Handle direct object\n if (schema.properties && (schema.type === 'object' || !schema.type)) {\n const requiredSet = new Set(schema.required ?? []);\n const fields: Field[] = [];\n for (const [fn, fs] of Object.entries(schema.properties)) {\n if (!fs) continue;\n fields.push(buildFieldFromSchema(fn, fs, name, requiredSet));\n }\n return [{ name, description: schema.description, fields }];\n }\n\n // Handle array with inline items\n if (schema.type === 'array' && schema.items?.properties) {\n const requiredSet = new Set(schema.items.required ?? []);\n const fields: Field[] = [];\n for (const [fn, fs] of Object.entries(schema.items.properties)) {\n if (!fs) continue;\n fields.push(buildFieldFromSchema(fn, fs, name, requiredSet));\n }\n return [{ name, description: schema.items.description, fields }];\n }\n\n return [];\n}\n\n/**\n * Derive a meaningful name for a oneOf object variant past the first,\n * falling back to the numeric-suffix scheme (`Foo2`, `Foo3`) when no\n * better signal is available. The \"better signal\" is a const-valued\n * discriminator property that distinguishes one variant from the others.\n *\n * For a schema like `ApiKey.owner` whose oneOf has two variants — one\n * with `type: { const: \"organization\" }` and one with `type: { const:\n * \"user\" }` — this returns `ApiKeyOwner` for the first variant (the\n * baseline name that the union TypeRef will reference, so consumer-\n * visible typed fields stay backward-compatible) and `UserApiKeyOwner`\n * for the second instead of `ApiKeyOwner2`. SDK consumers reading the\n * generated types can tell the variants apart at a glance.\n *\n * The first variant always keeps the bare parent name because\n * `schemaToTypeRef` builds union variants whose model refs collapse to\n * `qualifyInlineModelName(field, parent)` — so the first model name\n * must match for the union's degenerate-collapse to land on a valid\n * type. Renaming variant 0 would orphan it.\n *\n * Falls back to numeric suffix when:\n * - The variant has no discriminator property (no shared const\n * property across all object variants), OR\n * - The const value PascalCases to an empty/whitespace name, OR\n * - The derived name collides with the parent name or an already-\n * emitted variant name (numeric keeps uniqueness).\n */\nfunction nameVariantModel(\n variant: SchemaObject,\n parentName: string,\n alreadyEmitted: Model[],\n discriminator: { property: string } | null,\n): string {\n // Variant 0 keeps the bare parent name so the union TypeRef's degenerate\n // collapse target exists in the model registry.\n if (alreadyEmitted.length === 0) return parentName;\n\n if (discriminator) {\n const constValue = getConstPropertyValue(variant, discriminator.property);\n if (constValue) {\n const prefix = toPascalCase(constValue);\n if (prefix) {\n const candidate = parentName.startsWith(prefix) ? parentName : `${prefix}${parentName}`;\n const collision = candidate === parentName || alreadyEmitted.some((m) => m.name === candidate);\n if (!collision) return candidate;\n }\n }\n }\n return `${parentName}${alreadyEmitted.length + 1}`;\n}\n\n/**\n * Returns a discriminator descriptor when every inline object variant in a\n * oneOf has a string-const value on the same property — the signature of a\n * discriminated union without an explicit `discriminator:` keyword. Used by\n * `nameVariantModel` to derive variant names from the const values.\n *\n * Distinct from `detectConstPropertyDiscriminator` (which requires every\n * variant to carry a `$ref` or `title` so a name mapping can be built):\n * this pass operates on inline anonymous variants, where naming is exactly\n * what we're trying to derive.\n */\nfunction deriveConstNamingDiscriminator(variants: SchemaObject[]): { property: string } | null {\n if (variants.length < 2) return null;\n const candidates = Object.keys(variants[0]?.properties ?? {});\n for (const propName of candidates) {\n const values = variants.map((v) => getConstPropertyValue(v, propName));\n if (values.some((v) => v === null)) continue;\n if (new Set(values).size !== values.length) continue; // collisions = no signal\n return { property: propName };\n }\n return null;\n}\n\n/** Build a single Field from a schema property entry. Shared across all extraction sites. */\nexport function buildFieldFromSchema(\n fieldName: string,\n fieldSchema: SchemaObject,\n contextName: string,\n requiredSet: Set<string>,\n): Field {\n return {\n name: fieldName,\n type: schemaToTypeRef(fieldSchema, fieldName, contextName),\n required: requiredSet.has(fieldName),\n description: fieldSchema.description,\n readOnly: fieldSchema.readOnly || undefined,\n writeOnly: fieldSchema.writeOnly || undefined,\n deprecated: fieldSchema.deprecated || undefined,\n default: fieldSchema.default,\n example: fieldSchema.example,\n };\n}\n\n/**\n * If every non-null oneOf/anyOf variant is a string-valued const, return the\n * list of those const values so the union can collapse into a single enum.\n * Returns null when any variant isn't a pure string-const (model ref,\n * number const, nullable, etc.).\n */\nfunction collectLiteralStringConsts(variants: SchemaObject[]): string[] | null {\n if (variants.length === 0) return null;\n const values: string[] = [];\n for (const v of variants) {\n // A single-element enum is semantically identical to const.\n if (typeof v.const === 'string') {\n values.push(v.const);\n continue;\n }\n if (Array.isArray(v.enum) && v.enum.length === 1 && typeof v.enum[0] === 'string') {\n values.push(v.enum[0]);\n continue;\n }\n return null;\n }\n return values;\n}\n\n/** Build an EnumRef the same way the regular enum path does for naming. */\nfunction buildSyntheticEnumRef(\n values: string[],\n contextName: string | undefined,\n parentModelName: string | undefined,\n): TypeRef {\n const baseName = toPascalCase(contextName ?? 'UnknownEnum');\n const cleanParent = parentModelName ? stripListItemMarkers(parentModelName) : undefined;\n const qualifiedName = cleanParent && !baseName.startsWith(cleanParent) ? `${cleanParent}${baseName}` : baseName;\n // Run the same `schemaNameTransform` we apply to component-schema names so\n // a project-level rename map (e.g. `RadarAction` → `RadarListAction` in\n // `oagen.config.ts`) catches inline parameter enums too.\n const finalName = activeSchemaNameTransform ? activeSchemaNameTransform(qualifiedName) : qualifiedName;\n return { kind: 'enum', name: finalName, values };\n}\n\n/**\n * Detect an implicit discriminator on an oneOf where every variant is an\n * object schema that pins the same property to a const value. Returns\n * { property, mapping } so the IR can represent the union as discriminated\n * without needing an explicit `discriminator:` key in the spec.\n *\n * Both shapes are supported:\n * { properties: { event: { const: \"x\" } }, required: [\"event\"] }\n * { properties: { event: { type: \"string\", enum: [\"x\"] } } }\n *\n * Returns null when any variant doesn't fit the pattern or when variants\n * disagree on which property carries the discriminator.\n */\nfunction detectConstPropertyDiscriminator(\n variants: SchemaObject[],\n): { property: string; mapping: Record<string, string> } | null {\n if (variants.length < 2) return null;\n\n // Find properties whose const value is present on every variant.\n let candidateProperty: string | null = null;\n const candidates = Object.keys(variants[0]?.properties ?? {});\n for (const propName of candidates) {\n if (variants.every((v) => getConstPropertyValue(v, propName) !== null)) {\n candidateProperty = propName;\n break;\n }\n }\n\n if (!candidateProperty) return null;\n\n const mapping: Record<string, string> = {};\n for (const v of variants) {\n const value = getConstPropertyValue(v, candidateProperty);\n if (value === null) return null;\n // Require a $ref or title so we have a concrete model name to map to.\n const variantName = resolveVariantModelName(v);\n if (!variantName) return null;\n mapping[value] = variantName;\n }\n\n return { property: candidateProperty, mapping };\n}\n\nfunction getConstPropertyValue(schema: SchemaObject, property: string): string | null {\n const prop = schema.properties?.[property];\n if (!prop) return null;\n if (typeof prop.const === 'string') return prop.const;\n if (Array.isArray(prop.enum) && prop.enum.length === 1 && typeof prop.enum[0] === 'string') {\n return prop.enum[0];\n }\n return null;\n}\n\nfunction resolveVariantModelName(schema: SchemaObject): string | null {\n if (schema.$ref) {\n return resolveSchemaName(schema.$ref.replace(/^#\\/components\\/schemas\\//, ''));\n }\n const title = typeof schema['title'] === 'string' ? (schema['title'] as string) : null;\n if (title) return resolveSchemaName(title);\n return null;\n}\n\n/** Look up the discriminator's mapped variant name for an inline object\n * variant by reading its const-valued discriminator property. Returns null\n * when the variant doesn't pin the property to a string const, or when\n * the value isn't in the mapping. */\nfunction mapVariantToDiscriminatorEntry(\n variant: SchemaObject,\n discriminator: { property: string; mapping: Record<string, string> },\n): string | null {\n const value = getConstPropertyValue(variant, discriminator.property);\n if (value === null) return null;\n return discriminator.mapping[value] ?? null;\n}\n\n/**\n * Derive a discriminator value → variant model name mapping for an inline-\n * variant `oneOf` whose explicit `discriminator:` has no `mapping:` clause.\n *\n * Each variant model name is reproduced via `nameVariantModel` so it matches\n * what `extractNestedSchema` registered when it walked the same `oneOf` to\n * pull variants out as named models. Variant 0 keeps the bare parent name\n * (e.g. `ApiKeyOwner`); subsequent variants get a const-derived prefix\n * (e.g. `UserApiKeyOwner` for the `type: const: user` variant).\n *\n * The \"parent name\" used here mirrors the one `collectNestedInlineModels`\n * passes to `extractNestedSchema`: it's the qualified inline model name\n * built from `contextName` (the field name) plus `parentModelName` (the\n * containing model). Returns null when any non-object variant is present\n * or when a variant lacks a const value on the discriminator property.\n */\nfunction deriveInlineVariantMapping(\n variants: SchemaObject[],\n discriminatorProperty: string,\n contextName: string | undefined,\n parentModelName: string | undefined,\n): Record<string, string> | null {\n if (variants.length === 0 || !contextName) return null;\n const inlineObjectVariants = variants.filter((v) => !v.$ref && v.properties && (v.type === 'object' || !v.type));\n if (inlineObjectVariants.length !== variants.length) return null;\n\n const baseInlineName = qualifyInlineModelName(toPascalCase(contextName), parentModelName);\n const namingDiscriminator = { property: discriminatorProperty };\n const mapping: Record<string, string> = {};\n const emittedSoFar: Model[] = [];\n for (const variant of inlineObjectVariants) {\n const constValue = getConstPropertyValue(variant, discriminatorProperty);\n if (constValue === null) return null;\n const variantName = nameVariantModel(variant, baseInlineName, emittedSoFar, namingDiscriminator);\n mapping[constValue] = variantName;\n emittedSoFar.push({ name: variantName, fields: [] });\n }\n return mapping;\n}\n\nfunction extractEnum(name: string, schema: SchemaObject): Enum {\n const values: EnumValue[] = (schema.enum ?? []).map((v) => ({\n name: toUpperSnakeCase(String(v)),\n value: typeof v === 'number' ? v : String(v),\n description: undefined,\n }));\n\n const rawDefault = schema.default;\n const def =\n rawDefault !== undefined && values.some((v) => v.value === rawDefault)\n ? (rawDefault as string | number)\n : undefined;\n\n return { name, values, default: def };\n}\nfunction extractModel(name: string, schema: SchemaObject, schemas?: Record<string, SchemaObject>): Model {\n if (schema.allOf) {\n return extractAllOfModel(name, schema, schemas);\n }\n\n const requiredSet = new Set(schema.required ?? []);\n const fields: Field[] = [];\n\n for (const [fieldName, fieldSchema] of Object.entries(schema.properties ?? {})) {\n if (!fieldSchema) continue;\n fields.push(buildFieldFromSchema(fieldName, fieldSchema, name, requiredSet));\n }\n\n // Pure oneOf/anyOf schemas (no allOf, no properties): merge variant fields\n // as optional. This handles schemas like UpdateOrganizationMembership which\n // is a oneOf with mutually exclusive field groups (role_slug vs role_slugs).\n if (fields.length === 0 && (schema.oneOf || schema.anyOf)) {\n const variants = schema.oneOf ?? schema.anyOf ?? [];\n const emptyRequired = new Set<string>();\n const seenFieldNames = new Set<string>();\n for (const variant of variants) {\n if (!variant.properties) continue;\n for (const [fieldName, fieldSchema] of Object.entries(variant.properties)) {\n if (!fieldSchema || seenFieldNames.has(fieldName)) continue;\n seenFieldNames.add(fieldName);\n fields.push(buildFieldFromSchema(fieldName, fieldSchema as SchemaObject, name, emptyRequired));\n }\n }\n }\n\n // When additionalProperties is an object schema alongside properties,\n // surface it as a catch-all map field so emitters can generate Map<string, T>.\n if (schema.additionalProperties && typeof schema.additionalProperties === 'object' && schema.properties) {\n const apKeys = Object.keys(schema.additionalProperties);\n if (apKeys.length > 0) {\n const valueType = schemaToTypeRef(schema.additionalProperties as SchemaObject, 'additionalProperties', name);\n fields.push({\n name: 'additionalProperties',\n type: { kind: 'map', valueType },\n required: false,\n description: 'Additional properties not captured by named fields',\n });\n }\n }\n\n return { name, description: schema.description, fields };\n}\n\nfunction extractAllOfModel(name: string, schema: SchemaObject, schemas?: Record<string, SchemaObject>): Model {\n const fields: Field[] = [];\n const requiredSet = new Set<string>();\n let resultDiscriminator: { property: string; mapping: Record<string, string> } | undefined;\n\n for (const subSchema of schema.allOf ?? []) {\n // Resolve $ref sub-schemas by looking up the referenced component schema\n let resolved = subSchema;\n if (subSchema.$ref && schemas) {\n const segments = subSchema.$ref.split('/');\n const refName = segments[segments.length - 1];\n if (refName && schemas[refName]) {\n resolved = schemas[refName];\n }\n }\n\n // If the resolved schema is itself an allOf, recursively extract its fields\n if (resolved.allOf) {\n const nested = extractAllOfModel(name, resolved, schemas);\n for (const f of nested.fields) {\n fields.push({ ...f, required: false }); // will be re-set below\n if (f.required) requiredSet.add(f.name);\n }\n } else if (resolved.oneOf || resolved.anyOf) {\n const variants = resolved.oneOf ?? resolved.anyOf ?? [];\n // Detect discriminated union: every variant pins the same property to a\n // distinct const value (e.g. EventSchema where each variant has event: const).\n // When detected, store the discriminator instead of flattening variant fields —\n // the base allOf schema already captures the common fields.\n const discriminatorInfo = detectAllOfVariantDiscriminator(variants, name);\n if (discriminatorInfo) {\n resultDiscriminator = discriminatorInfo;\n } else {\n // Flatten oneOf/anyOf variant fields into the parent model as optional\n // fields. This handles the common allOf + oneOf pattern where the spec\n // uses mutually exclusive variant groups (e.g. password vs password_hash).\n const emptyRequired = new Set<string>();\n const seenFieldNames = new Set(fields.map((f) => f.name));\n for (const variant of variants) {\n if (!variant.properties) continue;\n for (const [fieldName, fieldSchema] of Object.entries(variant.properties)) {\n if (!fieldSchema || seenFieldNames.has(fieldName)) continue;\n seenFieldNames.add(fieldName);\n fields.push(buildFieldFromSchema(fieldName, fieldSchema as SchemaObject, name, emptyRequired));\n }\n }\n // Do NOT add variant-level required to the requiredSet — these fields\n // are optional at the parent level because they come from mutually\n // exclusive branches.\n }\n } else {\n if (resolved.required) {\n for (const r of resolved.required) requiredSet.add(r);\n }\n if (resolved.properties) {\n // Use an empty requiredSet — required flags are set in the final pass below\n const emptyRequired = new Set<string>();\n for (const [fieldName, fieldSchema] of Object.entries(resolved.properties)) {\n if (!fieldSchema) continue;\n fields.push(buildFieldFromSchema(fieldName, fieldSchema, name, emptyRequired));\n }\n }\n }\n }\n\n // Also collect required from the outer schema\n if (schema.required) {\n for (const r of schema.required) requiredSet.add(r);\n }\n\n // Set required flags\n for (const f of fields) {\n f.required = requiredSet.has(f.name);\n }\n\n return {\n name,\n description: schema.description,\n fields,\n ...(resultDiscriminator ? { discriminator: resultDiscriminator } : {}),\n };\n}\n\n/**\n * Walk through `allOf` wrappers to collect the effective top-level properties\n * of a schema. Stops at `oneOf` / `anyOf` boundaries — those are different\n * variant axes, not part of the same flat object.\n *\n * Used by `detectAllOfVariantDiscriminator` and `deriveDiscriminatedVariantName`\n * so a oneOf variant of the form `{ allOf: [{ properties: { … } }, { oneOf: […] }] }`\n * still surfaces its top-level `properties` (in particular its discriminator\n * `const`) instead of being treated as having none.\n */\nfunction getEffectiveProperties(schema: SchemaObject): Record<string, SchemaObject> {\n const props: Record<string, SchemaObject> = {};\n const visit = (s: SchemaObject): void => {\n if (s.properties) {\n for (const [k, v] of Object.entries(s.properties)) {\n if (!(k in props) && v) props[k] = v;\n }\n }\n if (s.allOf) {\n for (const sub of s.allOf) visit(sub);\n }\n // Do NOT walk into oneOf / anyOf — those are alternatives, not\n // simultaneously-present properties.\n };\n visit(schema);\n return props;\n}\n\nfunction getEffectiveConstPropertyValue(schema: SchemaObject, property: string): string | null {\n const direct = getConstPropertyValue(schema, property);\n if (direct !== null) return direct;\n const effective = getEffectiveProperties(schema)[property];\n if (!effective) return null;\n if (typeof effective.const === 'string') return effective.const;\n if (Array.isArray(effective.enum) && effective.enum.length === 1 && typeof effective.enum[0] === 'string') {\n return effective.enum[0];\n }\n return null;\n}\n\n/**\n * Detect an implicit discriminator on an allOf+oneOf where every variant is an\n * object that pins the same property to a distinct const value. Unlike\n * detectConstPropertyDiscriminator (which requires $ref or title for variant\n * model names), this version derives model names from the const value itself\n * using deriveDiscriminatedVariantName — matching how extractDiscriminatedAllOfVariantModels\n * names those models.\n *\n * Walks through allOf wrappers on each variant so a oneOf branch like\n * { allOf: [{ properties: { type: { const: 'oauth' } } }, { oneOf: […] }] }\n * still surfaces `type` as a candidate discriminator.\n *\n * Returns null when no discriminator can be reliably detected.\n */\nfunction detectAllOfVariantDiscriminator(\n variants: SchemaObject[],\n fallbackName: string,\n): { property: string; mapping: Record<string, string> } | null {\n if (variants.length < 2) return null;\n\n // Find a property whose const value is present on every variant\n // (looking through allOf wrappers on each variant).\n const firstProps = getEffectiveProperties(variants[0] ?? {});\n let candidateProperty: string | null = null;\n for (const propName of Object.keys(firstProps)) {\n if (variants.every((v) => getEffectiveConstPropertyValue(v, propName) !== null)) {\n candidateProperty = propName;\n break;\n }\n }\n if (!candidateProperty) return null;\n\n const mapping: Record<string, string> = {};\n const seenModelNames = new Set<string>();\n for (const v of variants) {\n const value = getEffectiveConstPropertyValue(v, candidateProperty);\n if (value === null) return null;\n const modelName = deriveDiscriminatedVariantName(v, fallbackName);\n // If two variants map to the same model name, the discriminator is ambiguous\n if (seenModelNames.has(modelName)) return null;\n seenModelNames.add(modelName);\n mapping[value] = modelName;\n }\n\n return { property: candidateProperty, mapping };\n}\n\nfunction extractDiscriminatedAllOfVariantModels(schema: SchemaObject, fallbackName: string): Model[] {\n const models: Model[] = [];\n const seenNames = new Set<string>();\n\n // Collect base-object properties + required from the allOf wrapper so each\n // variant can be emitted as a complete, self-contained type. Schemas like\n // `EventSchema` repeat the base fields inside every variant in the spec\n // (so this merge is a no-op there), but `ConnectApplication`'s OAuth /\n // M2M variants don't — without this, dispatcher consumers would get a\n // variant that's missing the shared `id` / `name` / `object` etc.\n const baseProperties: Record<string, SchemaObject> = {};\n const baseRequired = new Set<string>();\n for (const subSchema of schema.allOf ?? []) {\n if (subSchema.oneOf) continue; // the variant axis, handled below\n const flat = subSchema.allOf ? flattenVariantForExtraction(subSchema) : subSchema;\n if (flat.properties) {\n for (const [k, v] of Object.entries(flat.properties)) {\n if (!(k in baseProperties) && v) baseProperties[k] = v;\n }\n }\n if (flat.required) for (const r of flat.required) baseRequired.add(r);\n }\n\n for (const subSchema of schema.allOf ?? []) {\n for (const variant of subSchema.oneOf ?? []) {\n // Flatten any allOf wrapper on the variant (e.g. `ConnectApplication`'s\n // OAuth branch is `allOf: [{ properties: {…} }, { oneOf: [first-party\n // sub-variants] }]`). The flattened object has merged properties and\n // an inlined sub-variant `oneOf` so `extractInlineModelDeep` can pull\n // out a complete variant model.\n const flat = flattenVariantForExtraction(variant);\n if (!flat.properties || (flat.type !== undefined && flat.type !== 'object')) continue;\n\n // Merge base fields into the variant. Variant-specific properties win\n // on name collisions because the spec may pin a base field to a more\n // specific shape inside a variant.\n const mergedProperties: Record<string, SchemaObject> = { ...baseProperties };\n for (const [k, v] of Object.entries(flat.properties)) {\n if (v) mergedProperties[k] = v;\n }\n const mergedRequired = new Set<string>([...baseRequired, ...(flat.required ?? [])]);\n const merged: SchemaObject = {\n type: 'object',\n properties: mergedProperties,\n required: [...mergedRequired],\n };\n\n const variantName = deriveDiscriminatedVariantName(variant, fallbackName);\n for (const model of extractInlineModelDeep(variantName, merged)) {\n if (seenNames.has(model.name)) continue;\n seenNames.add(model.name);\n models.push(model);\n }\n }\n }\n\n return models;\n}\n\n/**\n * Flatten a oneOf variant schema into a single object-shaped schema for\n * variant-model extraction. Recursively merges `allOf` members and folds\n * any nested `oneOf` into an inline-oneOf field group whose properties are\n * the union across sub-branches (required only when present in every\n * sub-branch). Returns the schema unchanged when no flattening is needed.\n */\nfunction flattenVariantForExtraction(variant: SchemaObject): SchemaObject {\n if (!variant.allOf) return variant;\n\n const mergedProperties: Record<string, SchemaObject> = {};\n const mergedRequired = new Set<string>();\n const nestedOneOfs: SchemaObject[][] = [];\n\n const collect = (s: SchemaObject): void => {\n if (s.properties) {\n for (const [k, v] of Object.entries(s.properties)) {\n if (!(k in mergedProperties) && v) mergedProperties[k] = v;\n }\n }\n if (s.required) {\n for (const r of s.required) mergedRequired.add(r);\n }\n if (s.allOf) {\n for (const sub of s.allOf) collect(sub);\n }\n if (s.oneOf) nestedOneOfs.push(s.oneOf);\n };\n collect(variant);\n\n // Fold each nested oneOf into the merged shape: any field appearing in any\n // sub-branch is included as optional (or required iff present-and-required\n // in every sub-branch). Conflicting literal types widen to their primitive\n // base. This handles the `is_first_party: true | false` widening on the\n // OAuth variant's first-party sub-oneOf.\n for (const branches of nestedOneOfs) {\n const flatBranches = branches.map(flattenVariantForExtraction);\n const branchKeys = new Set<string>();\n for (const b of flatBranches) {\n for (const k of Object.keys(b.properties ?? {})) branchKeys.add(k);\n }\n for (const key of branchKeys) {\n const schemas: SchemaObject[] = [];\n for (const b of flatBranches) {\n const s = b.properties?.[key];\n if (s) schemas.push(s);\n }\n const merged = mergeBranchPropertySchemas(schemas);\n if (!(key in mergedProperties)) mergedProperties[key] = merged;\n const inAllBranches = flatBranches.every((b) => b.properties && key in b.properties);\n const requiredInAll = inAllBranches && flatBranches.every((b) => (b.required ?? []).includes(key));\n if (requiredInAll) mergedRequired.add(key);\n }\n }\n\n return {\n type: 'object',\n properties: mergedProperties,\n required: [...mergedRequired],\n };\n}\n\n/**\n * Merge same-named property schemas from across sub-variants. If every\n * occurrence is a boolean const, widen to plain boolean; if every occurrence\n * is a distinct string const, widen to plain string. Otherwise return the\n * first occurrence — emitters that build their own widened types (e.g. the\n * Node discriminated-models module) re-derive from the raw spec.\n */\nfunction mergeBranchPropertySchemas(schemas: SchemaObject[]): SchemaObject {\n if (schemas.length === 0) return {};\n if (schemas.length === 1) return schemas[0];\n\n const allBoolConst = schemas.every((s) => s.type === 'boolean' && typeof s.const === 'boolean');\n if (allBoolConst) {\n return { type: 'boolean', description: schemas[0].description };\n }\n const allStringConst = schemas.every((s) => s.type === 'string' && typeof s.const === 'string');\n if (allStringConst) {\n const values = schemas.map((s) => s.const as string);\n if (new Set(values).size === 1) return schemas[0];\n return { type: 'string', description: schemas[0].description };\n }\n return schemas[0];\n}\n\nfunction deriveDiscriminatedVariantName(schema: SchemaObject, fallbackName: string): string {\n // Walk through allOf wrappers so a variant of the form\n // `{ allOf: [{ properties: { type: const: 'oauth' } }, { oneOf: […] }] }`\n // still surfaces its discriminator const value for naming.\n const effective = getEffectiveProperties(schema);\n if (Object.keys(effective).length === 0) return fallbackName;\n\n const pickConst = (name: string): string | null => {\n const field = effective[name];\n if (!field) return null;\n if (typeof field.const === 'string') return field.const;\n if (field.enum && field.enum.length === 1 && typeof field.enum[0] === 'string') {\n return field.enum[0];\n }\n return null;\n };\n\n let constValue: string | null = null;\n for (const preferred of ['event', 'type', 'object']) {\n constValue = pickConst(preferred);\n if (constValue) break;\n }\n if (constValue === null) {\n for (const name of Object.keys(effective)) {\n constValue = pickConst(name);\n if (constValue) break;\n }\n }\n if (constValue === null) return fallbackName;\n\n const pascal = toPascalCase(constValue);\n if (!pascal) return fallbackName;\n\n // A single-word const like `oauth` or `m2m` is too generic to stand alone\n // as a top-level model name — it would collide with unrelated schemas. Pair\n // it with the parent name so the variant resolves to e.g. `ConnectApplicationOAuth`\n // / `ConnectApplicationM2M`. Multi-word consts like `action.authentication.denied`\n // are already specific enough on their own, matching the established\n // EventSchema variant naming.\n const wordCount = splitWords(constValue).length;\n if (wordCount >= 2) return pascal;\n if (pascal === fallbackName) return pascal;\n if (fallbackName.startsWith(pascal)) return fallbackName;\n if (pascal.endsWith(fallbackName)) return pascal;\n return `${fallbackName}${pascal}`;\n}\n\nfunction extractInlineModelDeep(name: string, schema: SchemaObject): Model[] {\n const requiredSet = new Set(schema.required ?? []);\n const fields: Field[] = [];\n const properties = schema.properties ?? {};\n const nestedModels: Model[] = [];\n\n for (const [fieldName, fieldSchema] of Object.entries(properties)) {\n if (!fieldSchema) continue;\n fields.push(buildFieldFromSchema(fieldName, fieldSchema, name, requiredSet));\n\n if (fieldSchema.type === 'object' && fieldSchema.properties) {\n nestedModels.push(...extractInlineModelDeep(qualifyNestedInlineName(name, fieldName), fieldSchema));\n }\n\n if (fieldSchema.type === 'array' && fieldSchema.items?.properties) {\n nestedModels.push(...extractInlineModelDeep(qualifyNestedInlineName(name, fieldName), fieldSchema.items));\n }\n\n if (fieldSchema.allOf) {\n const mergedProperties: Record<string, SchemaObject | undefined> = {};\n const mergedRequired: string[] = [];\n for (const sub of fieldSchema.allOf) {\n if (sub.properties) Object.assign(mergedProperties, sub.properties);\n if (sub.required) mergedRequired.push(...sub.required);\n }\n if (Object.keys(mergedProperties).length > 0) {\n nestedModels.push(\n ...extractInlineModelDeep(qualifyNestedInlineName(name, fieldName), {\n type: 'object',\n properties: mergedProperties,\n required: mergedRequired,\n }),\n );\n }\n }\n\n if (fieldSchema.oneOf) {\n const inlineObjectVariants = fieldSchema.oneOf.filter(\n (v) => !v.$ref && v.properties && (v.type === 'object' || !v.type),\n );\n if (inlineObjectVariants.length > 0) {\n const baseQualified = qualifyNestedInlineName(name, fieldName);\n const namingDisc = deriveConstNamingDiscriminator(inlineObjectVariants);\n const emitted: Model[] = [];\n for (const variant of inlineObjectVariants) {\n const variantName = nameVariantModel(variant, baseQualified, emitted, namingDisc);\n emitted.push({ name: variantName, fields: [] });\n nestedModels.push(...extractInlineModelDeep(variantName, variant));\n }\n }\n }\n }\n\n return [{ name, description: schema.description, fields }, ...nestedModels];\n}\n\nfunction qualifyNestedInlineName(parentName: string, fieldName: string): string {\n const pascalField = toPascalCase(fieldName);\n if (pascalField.startsWith(parentName)) return pascalField;\n\n const cleanParent = stripListItemMarkers(parentName);\n const qualified = `${cleanParent}${pascalField}`;\n const match = qualified.match(/^(.+?)([A-Z][a-z]+s?)$/);\n if (match && match[2]) {\n return match[1] + singularize(match[2]);\n }\n return qualified;\n}\n\nexport function schemaToTypeRef(schema: SchemaObject, contextName?: string, parentModelName?: string): TypeRef {\n // Handle $ref → ModelRef or EnumRef.\n // A `$ref` to a top-level component schema needs to preserve whether the\n // target is a model or an enum, because emitters route imports differently\n // for the two kinds (e.g. com.workos.models.X vs com.workos.types.X). The\n // set of enum names is precomputed by extractSchemas() in a first pass so\n // it's available even when called recursively for nested $refs.\n if (schema.$ref) {\n const segments = schema.$ref.split('/');\n const rawName = segments[segments.length - 1];\n const resolved = resolveSchemaName(rawName);\n if (activeEnumSchemaNames.has(resolved)) {\n return { kind: 'enum', name: resolved };\n }\n return { kind: 'model', name: resolved };\n }\n\n // Handle OAS 3.1 nullable type arrays: type: [string, null]\n if (Array.isArray(schema.type)) {\n const nonNullTypes = schema.type.filter((t: string) => t !== 'null');\n // type: ['null'] — only null, no real type\n if (nonNullTypes.length === 0) {\n return { kind: 'nullable', inner: { kind: 'primitive', type: 'unknown' } };\n }\n if (schema.type.includes('null') && nonNullTypes.length === 1) {\n return {\n kind: 'nullable',\n inner: schemaToTypeRef({ ...schema, type: nonNullTypes[0], nullable: false }, contextName),\n };\n }\n // Multiple non-null types → union\n if (nonNullTypes.length > 1) {\n const variants = nonNullTypes.map((t: string) => schemaToTypeRef({ ...schema, type: t }, contextName));\n const ref: TypeRef = { kind: 'union', variants };\n if (schema.type.includes('null')) {\n return { kind: 'nullable', inner: ref };\n }\n return ref;\n }\n }\n\n // Handle OAS 3.0 nullable flag\n if (schema.nullable && schema.type) {\n return {\n kind: 'nullable',\n inner: schemaToTypeRef({ ...schema, nullable: false }, contextName),\n };\n }\n\n // Handle allOf — merge properties from all sub-schemas.\n // This handles patterns like: allOf: [{ type: object, properties: {...} }, { oneOf: [...] }]\n // which are valid OAS 3.1 but weren't handled for field-level schemas.\n if (schema.allOf) {\n // If allOf contains a $ref, prefer the ref (it's a named type)\n const refItem = schema.allOf.find((s: SchemaObject) => s.$ref);\n if (refItem) {\n // If allOf has $ref AND siblings with properties, return a merged model ref\n // to avoid losing the augmentation properties\n const hasAugmentation = schema.allOf.some((s: SchemaObject) => !s.$ref && (s.properties || s.type === 'object'));\n if (hasAugmentation) {\n const baseName = toPascalCase(contextName ?? 'UnknownModel');\n return { kind: 'model', name: qualifyInlineModelName(baseName, parentModelName) };\n }\n return schemaToTypeRef(refItem, contextName, parentModelName);\n }\n // If allOf has a single item, unwrap it\n if (schema.allOf.length === 1) {\n return schemaToTypeRef(schema.allOf[0], contextName, parentModelName);\n }\n // If allOf items all have properties, treat as a merged model\n const hasProperties = schema.allOf.some((s: SchemaObject) => s.properties);\n if (hasProperties) {\n const baseName = toPascalCase(contextName ?? 'UnknownModel');\n return {\n kind: 'model',\n name: qualifyInlineModelName(baseName, parentModelName),\n };\n }\n // Fall through to other checks\n }\n\n // Handle oneOf / anyOf → Union or Nullable\n // Valid OAS 3.1: properties can have { oneOf: [{ type: object }, { type: 'null' }] }\n // without a wrapping `type` field.\n if (schema.oneOf || schema.anyOf) {\n const compositionKind: 'oneOf' | 'anyOf' = schema.oneOf ? 'oneOf' : 'anyOf';\n const rawVariants: SchemaObject[] = schema.oneOf ?? schema.anyOf ?? [];\n\n // Check for nullable pattern: oneOf: [realType, { type: 'null' }]\n const nullVariant = rawVariants.find(\n (v: SchemaObject) => v.type === 'null' || (Array.isArray(v.type) && v.type.length === 1 && v.type[0] === 'null'),\n );\n const nonNullVariants = rawVariants.filter((v) => v !== nullVariant);\n\n if (nullVariant && nonNullVariants.length === 1) {\n // Nullable single type — unwrap as nullable\n return {\n kind: 'nullable',\n inner: schemaToTypeRef(nonNullVariants[0], contextName, parentModelName),\n };\n }\n\n // Collapse an oneOf/anyOf whose non-null variants are all string-const\n // schemas into a single enum. This turns patterns like\n // provider: { oneOf: [{ const: \"AppleOAuth\" }, { const: \"GitHubOAuth\" }, ...] }\n // into a proper enum type with one member per variant instead of a\n // structurally-opaque union of literal refs.\n const literalStrings = collectLiteralStringConsts(nonNullVariants);\n if (literalStrings !== null && literalStrings.length >= 2) {\n const enumRef = buildSyntheticEnumRef(literalStrings, contextName, parentModelName);\n return nullVariant ? { kind: 'nullable', inner: enumRef } : enumRef;\n }\n\n // Resolve the discriminator. Three sources, in order:\n // 1. Explicit `discriminator:` with explicit `mapping:` — trust the spec.\n // 2. Explicit `discriminator:` with no `mapping:` — derive mapping from\n // variants' const values on the discriminator property, pairing each\n // to its inline-extracted variant model name (built the same way\n // `extractNestedSchema` names them via `nameVariantModel`). This\n // covers `ApiKey.owner`-shaped schemas where the spec uses\n // `discriminator: { propertyName: type }` but lists inline anonymous\n // `oneOf` variants instead of `$ref` links.\n // 3. No explicit discriminator but every variant pins the same const-\n // valued property AND the variants are nameable via $ref/title —\n // `detectConstPropertyDiscriminator` covers this.\n // 4. As a last resort, when (3) doesn't apply because variants are\n // inline anonymous objects, derive the same const → variant-model-\n // name mapping using `nameVariantModel`. This covers\n // `ApiKeyCreatedData.owner`-shaped schemas (oneOf with inline\n // const-discriminating variants but no `discriminator:` keyword).\n let resolvedDiscriminator: { property: string; mapping: Record<string, string> } | undefined;\n if (schema.discriminator) {\n const property = schema.discriminator.propertyName;\n const explicitMapping = schema.discriminator.mapping ?? {};\n let mapping: Record<string, string> = Object.fromEntries(\n Object.entries(explicitMapping).map(([k, v]) => [k, v.replace(/^#\\/components\\/schemas\\//, '')]),\n );\n if (Object.keys(mapping).length === 0) {\n const inlineMapping = deriveInlineVariantMapping(nonNullVariants, property, contextName, parentModelName);\n if (inlineMapping) mapping = inlineMapping;\n }\n resolvedDiscriminator = { property, mapping };\n } else if (compositionKind === 'oneOf') {\n const synthetic = detectConstPropertyDiscriminator(nonNullVariants);\n if (synthetic) {\n resolvedDiscriminator = synthetic;\n } else {\n const namingDisc = deriveConstNamingDiscriminator(nonNullVariants);\n if (namingDisc) {\n const inlineMapping = deriveInlineVariantMapping(\n nonNullVariants,\n namingDisc.property,\n contextName,\n parentModelName,\n );\n if (inlineMapping) {\n resolvedDiscriminator = { property: namingDisc.property, mapping: inlineMapping };\n }\n }\n }\n }\n\n // Build variants. When we have a discriminator with a known mapping and\n // every non-null variant is an inline object that pins the discriminator\n // property to a const, route each variant's TypeRef through that mapping.\n // This avoids the degenerate case where `qualifyInlineModelName` would\n // assign the same parent-derived name (e.g. `ApiKeyOwner`) to every\n // inline variant, collapsing the union to a single repeated model ref.\n const variants: TypeRef[] = [];\n for (const v of rawVariants) {\n if (v === nullVariant) continue;\n const inlineMappingName =\n resolvedDiscriminator && !v.$ref && v.properties && (v.type === 'object' || !v.type)\n ? mapVariantToDiscriminatorEntry(v, resolvedDiscriminator)\n : null;\n if (inlineMappingName) {\n variants.push({ kind: 'model', name: inlineMappingName });\n } else {\n variants.push(schemaToTypeRef(v, contextName, parentModelName));\n }\n }\n const hasNull = !!nullVariant;\n\n const union: TypeRef = {\n kind: 'union',\n variants,\n compositionKind,\n ...(resolvedDiscriminator ? { discriminator: resolvedDiscriminator } : {}),\n };\n return hasNull ? { kind: 'nullable', inner: union } : union;\n }\n\n // Handle const → LiteralType (supports string, number, boolean)\n if (schema.const !== undefined) {\n if (typeof schema.const === 'string' || typeof schema.const === 'number' || typeof schema.const === 'boolean') {\n return { kind: 'literal', value: schema.const };\n }\n // null const → nullable unknown\n if (schema.const === null) {\n return { kind: 'nullable', inner: { kind: 'primitive', type: 'unknown' } };\n }\n // const of object/array → map or array with unknown values\n if (typeof schema.const === 'object') {\n if (Array.isArray(schema.const)) {\n return { kind: 'array', items: { kind: 'primitive', type: 'unknown' } };\n }\n return { kind: 'map', valueType: { kind: 'primitive', type: 'unknown' } };\n }\n }\n if (schema.enum && schema.enum.length === 1) {\n const v = schema.enum[0];\n return { kind: 'literal', value: typeof v === 'number' ? v : String(v) };\n }\n\n // Handle enum\n if (schema.enum) {\n const baseName = toPascalCase(contextName ?? 'UnknownEnum');\n // Strip ListItem/ByExternalId markers from parent name so enum names are clean:\n // e.g., DirectoryListItem + State → Directory + State = DirectoryState\n const cleanParent = parentModelName ? stripListItemMarkers(parentModelName) : undefined;\n // Avoid redundant prefix: Connection + ConnectionType → ConnectionType\n const qualifiedName = cleanParent && !baseName.startsWith(cleanParent) ? `${cleanParent}${baseName}` : baseName;\n // Run `schemaNameTransform` so project-level rename maps in\n // `oagen.config.ts` reach inline parameter/field enums too — without\n // this, `RadarAction` (built from path param `action` on the Radar\n // service) couldn't be redirected to `RadarListAction` from config.\n const finalName = activeSchemaNameTransform ? activeSchemaNameTransform(qualifiedName) : qualifiedName;\n return {\n kind: 'enum',\n name: finalName,\n values: schema.enum.map((v) => (typeof v === 'number' ? v : String(v))),\n };\n }\n\n // Handle array — pass parentModelName through to qualify inline items\n if (schema.type === 'array' && schema.items) {\n return {\n kind: 'array',\n items: schemaToTypeRef(schema.items, contextName, parentModelName),\n };\n }\n // Handle array without explicit type but with items (valid OAS 3.1)\n if (!schema.type && schema.items) {\n return {\n kind: 'array',\n items: schemaToTypeRef(schema.items, contextName, parentModelName),\n };\n }\n\n // Handle object → ModelRef (if it has properties, it's a named model reference)\n // When additionalProperties is also present, we still return a ModelRef so the\n // named properties are preserved. The extractModel path will pick up the extra\n // properties as a catch-all map field named `additionalProperties`.\n if (schema.type === 'object' && schema.properties) {\n const baseName = toPascalCase(contextName ?? 'UnknownModel');\n return {\n kind: 'model',\n name: qualifyInlineModelName(baseName, parentModelName),\n };\n }\n\n // Handle freeform object with additionalProperties or patternProperties → Map<string, T>\n if (schema.type === 'object' && !schema.properties) {\n let valueType: TypeRef = { kind: 'primitive', type: 'unknown' };\n if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {\n // Empty additionalProperties ({}) means \"any value\" — keep as unknown\n const apKeys = Object.keys(schema.additionalProperties);\n if (apKeys.length > 0) {\n valueType = schemaToTypeRef(schema.additionalProperties as SchemaObject, contextName);\n }\n } else if (schema.patternProperties) {\n // patternProperties: { \"pattern\": schema } → use the first pattern's schema as value type\n const patterns = Object.values(schema.patternProperties);\n if (patterns.length > 0) {\n valueType = schemaToTypeRef(patterns[0], contextName);\n }\n }\n return {\n kind: 'map',\n valueType,\n };\n }\n\n // Handle primitives\n const primitiveMap: Record<string, 'string' | 'integer' | 'number' | 'boolean'> = {\n string: 'string',\n integer: 'integer',\n number: 'number',\n boolean: 'boolean',\n };\n\n const typeStr = Array.isArray(schema.type) ? schema.type[0] : schema.type;\n if (typeStr && primitiveMap[typeStr]) {\n return {\n kind: 'primitive',\n type: primitiveMap[typeStr],\n ...(schema.format ? { format: schema.format } : {}),\n };\n }\n\n // Handle schemas with no type — if it has properties, treat as model\n if (!schema.type && schema.properties) {\n const baseName = toPascalCase(contextName ?? 'UnknownModel');\n return {\n kind: 'model',\n name: qualifyInlineModelName(baseName, parentModelName),\n };\n }\n\n // Empty schema {} → unknown\n if (\n !schema.type &&\n !schema.$ref &&\n !schema.oneOf &&\n !schema.anyOf &&\n !schema.allOf &&\n !schema.enum &&\n !schema.properties &&\n !schema.items\n ) {\n return { kind: 'primitive', type: 'unknown' };\n }\n\n // Fallback: treat unknown schemas as unknown\n if (contextName) {\n console.warn(`[oagen] Warning: Unknown schema shape treated as unknown (context: ${contextName})`);\n }\n return { kind: 'primitive', type: 'unknown' };\n}\n\nimport { qualifyInlineModelName } from './inline-models.js';\n\nexport { qualifyInlineModelName, extractInlineModelsFromSchemas } from './inline-models.js';\n","import type { TypeRef, Parameter, PaginationMeta } from '../ir/types.js';\n\nconst CURSOR_PARAMS = ['cursor', 'after', 'before', 'starting_after', 'ending_before', 'page_token', 'next_token'];\n\nconst OFFSET_PARAMS = ['offset', 'page', 'page_number', 'skip'];\nconst LIMIT_PARAMS = ['limit', 'page_size', 'per_page', 'size', 'count'];\n\n/**\n * Detect if an operation uses pagination and return structured metadata\n * for auto-paging iterator generation.\n *\n * Supports two strategies:\n * 1. **Cursor-based**: query params include a cursor-like parameter\n * 2. **Offset-based**: query params include both an offset-like and limit-like parameter\n *\n * Returns null if no pagination pattern is detected.\n */\nexport function detectPagination(\n response: TypeRef,\n queryParams: Parameter[],\n dataPath?: string,\n): PaginationMeta | null {\n // Try cursor-based first (preferred). Scan in CURSOR_PARAMS priority order\n // rather than queryParams order so that an endpoint exposing both `before`\n // and `after` reports `after` (forward iteration) — matches the wire\n // convention where `after` advances through pages.\n const cursorParam = CURSOR_PARAMS.map((name) => queryParams.find((p) => p.name === name)).find(\n (p): p is Parameter => p !== undefined,\n );\n\n if (cursorParam) {\n const itemType: TypeRef = response.kind === 'array' ? response.items : response;\n return {\n strategy: 'cursor',\n param: cursorParam.name,\n dataPath: dataPath,\n itemType,\n };\n }\n\n // Try offset-based pagination\n const offsetParam = queryParams.find((p) => OFFSET_PARAMS.includes(p.name));\n const limitParam = queryParams.find((p) => LIMIT_PARAMS.includes(p.name));\n\n if (offsetParam && limitParam) {\n const itemType: TypeRef = response.kind === 'array' ? response.items : response;\n return {\n strategy: 'offset',\n param: offsetParam.name,\n limitParam: limitParam.name,\n dataPath: dataPath,\n itemType,\n };\n }\n\n return null;\n}\n","import type { TypeRef, Model, Field } from '../ir/types.js';\nimport { toPascalCase, singularize, stripListItemMarkers } from '../utils/naming.js';\nimport type { SchemaObject } from './schemas.js';\nimport { schemaToTypeRef, buildFieldFromSchema } from './schemas.js';\n\nexport interface ResponseExtractionResult {\n /** The TypeRef to use as the operation's response type */\n response: TypeRef;\n /** Any inline models discovered during extraction (to merge into ir.models) */\n inlineModels: Model[];\n /** Whether this response indicates a paginated list */\n isPaginated: boolean;\n /** Path to the data array within the response envelope (e.g., 'data') */\n dataPath?: string;\n /** TypeRef of individual items in a paginated list */\n itemType?: TypeRef;\n}\n\nexport function classifyAndExtractResponse(schema: SchemaObject, contextName: string): ResponseExtractionResult {\n // 1. If schema is a $ref, resolve to model name (Phase 1)\n if (schema.$ref) {\n return { response: schemaToTypeRef(schema, contextName), inlineModels: [], isPaginated: false };\n }\n\n // 2. Check for list envelope (structural detection: array prop + non-array companion)\n const envelope = detectListEnvelope(schema);\n if (envelope.isEnvelope) {\n return extractListResponse(schema, contextName, envelope.dataPath!);\n }\n\n // 3. Check for single-resource wrapper ({ resource_name: { object: \"...\", ... } })\n if (isSingleResourceWrapper(schema)) {\n return extractWrappedResource(schema, contextName);\n }\n\n // 4. Direct resource or plain inline object\n return extractDirectResource(schema, contextName);\n}\n\ninterface ListEnvelopeResult {\n isEnvelope: boolean;\n dataPath: string | null;\n}\n\nconst KNOWN_DATA_PATHS = new Set(['data', 'items', 'results', 'records', 'entries', 'values', 'nodes', 'edges']);\n\nconst PAGINATION_METADATA_PATTERNS = [\n 'meta',\n 'metadata',\n 'pagination',\n 'cursor',\n 'has_more',\n 'page_info',\n 'total',\n 'next_page',\n 'previous_page',\n 'offset',\n];\n\nfunction detectListEnvelope(schema: SchemaObject): ListEnvelopeResult {\n // Collect all property sources (allOf sub-schemas or flat schema)\n const propSources: Record<string, SchemaObject | undefined>[] = [];\n if (schema.allOf) {\n for (const sub of schema.allOf) {\n if (sub.properties) propSources.push(sub.properties);\n }\n }\n if (schema.properties) {\n propSources.push(schema.properties);\n }\n\n if (propSources.length === 0) return { isEnvelope: false, dataPath: null };\n\n // Merge all properties into a single view\n const mergedProps: Record<string, SchemaObject | undefined> = {};\n for (const source of propSources) {\n Object.assign(mergedProps, source);\n }\n\n // Find array-typed properties and non-array companion properties\n const arrayProps: string[] = [];\n const nonArrayKeys: string[] = [];\n\n for (const [key, propSchema] of Object.entries(mergedProps)) {\n if (!propSchema) continue;\n if (propSchema.type === 'array') {\n arrayProps.push(key);\n } else {\n nonArrayKeys.push(key);\n }\n }\n\n // List envelope heuristic: exactly one array property + at least one non-array companion\n // that looks like pagination metadata. A `data` array alone (e.g. with only an\n // `object` discriminant companion) is NOT sufficient — the companion must indicate\n // actual pagination (cursor, metadata, total, etc.).\n if (arrayProps.length === 1 && nonArrayKeys.length >= 1) {\n const arrayPropName = arrayProps[0];\n\n const hasPaginationCompanion = nonArrayKeys.some((key) =>\n PAGINATION_METADATA_PATTERNS.some((pattern) => key.toLowerCase().includes(pattern)),\n );\n\n if (KNOWN_DATA_PATHS.has(arrayPropName) && hasPaginationCompanion) {\n return { isEnvelope: true, dataPath: arrayPropName };\n }\n\n // Non-standard array property name — still treat as envelope if pagination companion exists\n if (hasPaginationCompanion) {\n return { isEnvelope: true, dataPath: arrayPropName };\n }\n }\n\n return { isEnvelope: false, dataPath: null };\n}\n\nfunction extractListResponse(schema: SchemaObject, contextName: string, dataPath: string): ResponseExtractionResult {\n let itemTypeRef: TypeRef = { kind: 'primitive', type: 'string' };\n const inlineModels: Model[] = [];\n\n // Collect all property sources (allOf sub-schemas or flat schema)\n const propSources: Record<string, SchemaObject | undefined>[] = [];\n if (schema.allOf) {\n for (const sub of schema.allOf) {\n if (sub.properties) propSources.push(sub.properties);\n }\n }\n if (schema.properties) {\n propSources.push(schema.properties);\n }\n\n for (const props of propSources) {\n const dataProp = props[dataPath];\n if (!dataProp) continue;\n\n if (dataProp.type === 'array' && dataProp.items) {\n const items = dataProp.items;\n if (items.$ref) {\n itemTypeRef = schemaToTypeRef(items, contextName);\n } else if (items.type === 'object' && items.properties) {\n const itemName = contextName.replace(/Response$/, '') + 'Item';\n itemTypeRef = { kind: 'model', name: itemName };\n inlineModels.push(...extractInlineModel(itemName, items));\n }\n }\n }\n\n return {\n response: { kind: 'array', items: itemTypeRef },\n inlineModels,\n isPaginated: true,\n dataPath,\n itemType: itemTypeRef,\n };\n}\n\nfunction hasDiscriminantConstField(schema: SchemaObject): { property: string; value: string } | null {\n if (!schema.properties) return null;\n\n // Prefer well-known discriminant properties for backward compatibility\n const preferred = ['object', 'type'];\n for (const name of preferred) {\n const field = schema.properties[name];\n if (!field) continue;\n if (field.const !== undefined && typeof field.const === 'string') {\n return { property: name, value: field.const };\n }\n if (field.enum && field.enum.length === 1 && typeof field.enum[0] === 'string') {\n return { property: name, value: field.enum[0] };\n }\n }\n\n // Fall back to any property with a const or single-value enum\n for (const [name, field] of Object.entries(schema.properties)) {\n if (!field) continue;\n if (field.const !== undefined && typeof field.const === 'string') {\n return { property: name, value: field.const };\n }\n if (field.enum && field.enum.length === 1 && typeof field.enum[0] === 'string') {\n return { property: name, value: field.enum[0] };\n }\n }\n\n return null;\n}\n\nfunction isSingleResourceWrapper(schema: SchemaObject): boolean {\n if (schema.type !== 'object') return false;\n if (!schema.properties) return false;\n\n // Find the wrapper property: use required[0] if available, or the single property key\n let wrapperKey: string | undefined;\n if (schema.required && schema.required.length === 1) {\n wrapperKey = schema.required[0];\n } else {\n const propKeys = Object.keys(schema.properties);\n if (propKeys.length === 1) {\n wrapperKey = propKeys[0];\n }\n }\n if (!wrapperKey) return false;\n\n const propSchema = schema.properties[wrapperKey];\n if (!propSchema) return false;\n\n // Direct object with a discriminant const field\n if (propSchema.type === 'object' && hasDiscriminantConstField(propSchema) !== null) return true;\n\n // oneOf with object + null (nullable resource)\n if (propSchema.oneOf) {\n return propSchema.oneOf.some((v) => v.type === 'object' && hasDiscriminantConstField(v) !== null);\n }\n\n return false;\n}\n\nfunction extractWrappedResource(schema: SchemaObject, contextName: string): ResponseExtractionResult {\n const props = schema.properties!;\n const wrapperKey = schema.required && schema.required.length === 1 ? schema.required[0] : Object.keys(props)[0];\n const propSchema = props[wrapperKey]!;\n const inlineModels: Model[] = [];\n\n // Derive model name from the object const value or wrapper property name\n const resourceName = contextName.replace(/Response$/, '');\n\n if (propSchema.oneOf) {\n const objectVariant = propSchema.oneOf.find((v) => v.type === 'object' && hasDiscriminantConstField(v) !== null);\n\n if (objectVariant) {\n const modelName = deriveModelName(objectVariant, resourceName);\n inlineModels.push(...extractInlineModel(modelName, objectVariant));\n\n const hasNullVariant = propSchema.oneOf.some(\n (v) => v.type === 'null' || (Array.isArray(v.type) && v.type.includes('null')),\n );\n\n const modelRef: TypeRef = { kind: 'model', name: modelName };\n return {\n response: hasNullVariant ? { kind: 'nullable', inner: modelRef } : modelRef,\n inlineModels,\n isPaginated: false,\n };\n }\n }\n\n // Direct object\n const modelName = deriveModelName(propSchema, resourceName);\n inlineModels.push(...extractInlineModel(modelName, propSchema));\n\n return {\n response: { kind: 'model', name: modelName },\n inlineModels,\n isPaginated: false,\n };\n}\n\nfunction extractDirectResource(schema: SchemaObject, contextName: string): ResponseExtractionResult {\n const inlineModels: Model[] = [];\n\n // Direct object with properties (with or without explicit type: 'object')\n if (schema.properties && (schema.type === 'object' || !schema.type)) {\n const modelName = deriveModelName(schema, contextName);\n inlineModels.push(...extractInlineModel(modelName, schema));\n return {\n response: { kind: 'model', name: modelName },\n inlineModels,\n isPaginated: false,\n };\n }\n\n // allOf with properties — merge into a single model\n if (schema.allOf) {\n const mergedProperties: Record<string, SchemaObject | undefined> = {};\n const mergedRequired: string[] = [];\n for (const sub of schema.allOf) {\n if (sub.properties) {\n Object.assign(mergedProperties, sub.properties);\n }\n if (sub.required) {\n mergedRequired.push(...sub.required);\n }\n }\n if (Object.keys(mergedProperties).length > 0) {\n const merged: SchemaObject = { type: 'object', properties: mergedProperties, required: mergedRequired };\n const modelName = deriveModelName(merged, contextName);\n inlineModels.push(...extractInlineModel(modelName, merged));\n return {\n response: { kind: 'model', name: modelName },\n inlineModels,\n isPaginated: false,\n };\n }\n }\n\n // oneOf — delegate to schemaToTypeRef (returns union) but also extract inline models\n // from object variants so the model refs resolve\n if (schema.oneOf) {\n for (const variant of schema.oneOf) {\n if (variant.properties && (variant.type === 'object' || !variant.type)) {\n const modelName = deriveModelName(variant, contextName);\n const existingNames = new Set(inlineModels.map((m) => m.name));\n if (!existingNames.has(modelName)) {\n inlineModels.push(...extractInlineModel(modelName, variant));\n }\n }\n }\n }\n\n // Array with inline object items — extract the item model\n if (schema.type === 'array' && schema.items) {\n const items = schema.items;\n if (items.$ref) {\n return {\n response: { kind: 'array', items: schemaToTypeRef(items, contextName) },\n inlineModels,\n isPaginated: false,\n };\n }\n if (items.properties && (items.type === 'object' || !items.type)) {\n const itemName = contextName.replace(/Response$/, '') + 'Item';\n inlineModels.push(...extractInlineModel(itemName, items));\n return {\n response: { kind: 'array', items: { kind: 'model', name: itemName } },\n inlineModels,\n isPaginated: false,\n };\n }\n }\n\n // Non-object schema (primitive, union, etc.) — delegate to schemaToTypeRef\n return {\n response: schemaToTypeRef(schema, contextName),\n inlineModels,\n isPaginated: false,\n };\n}\n\nfunction deriveModelName(schema: SchemaObject, fallback: string): string {\n if (!schema.properties) return toPascalCase(fallback);\n\n // Prefer well-known discriminant properties for backward compatibility\n const preferred = ['object', 'type'];\n for (const name of preferred) {\n const field = schema.properties[name];\n if (field && field.const && typeof field.const === 'string') {\n return toPascalCase(field.const);\n }\n }\n\n // Fall back to any property with a const string value\n for (const [, field] of Object.entries(schema.properties)) {\n if (field && field.const && typeof field.const === 'string') {\n return toPascalCase(field.const);\n }\n }\n\n return toPascalCase(fallback);\n}\n\n/**\n * Qualify a nested inline model name with its parent to avoid generic names.\n * e.g., parent=\"Connection\" + field=\"domains\" → \"ConnectionDomain\" (singularized)\n * Only qualifies when the field name alone would be too generic.\n */\nfunction qualifyNestedName(parentName: string, fieldName: string): string {\n const pascalField = toPascalCase(fieldName);\n // If the field name already starts with the parent name, don't double-prefix\n if (pascalField.startsWith(parentName)) return pascalField;\n // Qualify with parent and singularize:\n // Connection + Domains → ConnectionDomains → singularize lead word → ConnectionDomain\n const cleanParent = stripListItemMarkers(parentName);\n const qualified = `${cleanParent}${pascalField}`;\n // Singularize the trailing word: ConnectionDomains → ConnectionDomain\n const match = qualified.match(/^(.+?)([A-Z][a-z]+s?)$/);\n if (match && match[2]) {\n const trailing = singularize(match[2]);\n return match[1] + trailing;\n }\n return qualified;\n}\n\nfunction extractInlineModel(name: string, schema: SchemaObject): Model[] {\n const requiredSet = new Set(schema.required ?? []);\n const fields: Field[] = [];\n const properties = schema.properties ?? {};\n const nestedModels: Model[] = [];\n\n for (const [fieldName, fieldSchema] of Object.entries(properties)) {\n if (!fieldSchema) continue;\n fields.push(buildFieldFromSchema(fieldName, fieldSchema, name, requiredSet));\n\n // Recursively extract nested inline objects — qualify with parent name\n // to avoid generic names like \"Domains\" when multiple parents have a \"domains\" field\n if (fieldSchema.type === 'object' && fieldSchema.properties) {\n const nestedName = qualifyNestedName(name, fieldName);\n nestedModels.push(...extractInlineModel(nestedName, fieldSchema));\n }\n if (fieldSchema.type === 'array' && fieldSchema.items) {\n const items = fieldSchema.items;\n if (items.type === 'object' && items.properties) {\n const nestedName = qualifyNestedName(name, fieldName);\n nestedModels.push(...extractInlineModel(nestedName, items));\n }\n }\n // Handle allOf with inline object properties — merge into a single nested model\n if (fieldSchema.allOf) {\n const mergedProperties: Record<string, SchemaObject | undefined> = {};\n const mergedRequired: string[] = [];\n for (const sub of fieldSchema.allOf) {\n if (sub.properties) Object.assign(mergedProperties, sub.properties);\n if (sub.required) mergedRequired.push(...sub.required);\n }\n if (Object.keys(mergedProperties).length > 0) {\n const nestedName = qualifyNestedName(name, fieldName);\n const merged: SchemaObject = { type: 'object', properties: mergedProperties, required: mergedRequired };\n const existingNames = new Set(nestedModels.map((m) => m.name));\n if (!existingNames.has(nestedName)) {\n nestedModels.push(...extractInlineModel(nestedName, merged));\n }\n }\n }\n // Handle oneOf containing inline objects — extract the first non-null object variant\n if (fieldSchema.oneOf) {\n const objectVariant = fieldSchema.oneOf.find((v) => v.properties && (v.type === 'object' || !v.type));\n if (objectVariant) {\n const nestedName = qualifyNestedName(name, fieldName);\n const existingNames = new Set(nestedModels.map((m) => m.name));\n if (!existingNames.has(nestedName)) {\n nestedModels.push(...extractInlineModel(nestedName, objectVariant));\n }\n }\n }\n }\n\n return [{ name, description: schema.description, fields }, ...nestedModels];\n}\n","import type {\n Service,\n Operation,\n HttpMethod,\n Parameter,\n ParameterGroup,\n TypeRef,\n ErrorResponse,\n SuccessResponse,\n SecurityRequirement,\n Model,\n Field,\n PaginationMeta,\n} from '../ir/types.js';\nimport { toPascalCase, toCamelCase, cleanSchemaName } from '../utils/naming.js';\nimport type { SchemaObject } from './schemas.js';\nimport { schemaToTypeRef, buildFieldFromSchema } from './schemas.js';\nimport { detectPagination } from './pagination.js';\nimport { classifyAndExtractResponse } from './responses.js';\n\ninterface PathItem {\n get?: OperationObject;\n post?: OperationObject;\n put?: OperationObject;\n patch?: OperationObject;\n delete?: OperationObject;\n head?: OperationObject;\n options?: OperationObject;\n trace?: OperationObject;\n parameters?: ParameterObject[];\n}\n\ninterface ParameterGroupExtension {\n optional: boolean;\n variants: Record<string, string[]>;\n}\n\ninterface OperationObject {\n operationId?: string;\n summary?: string;\n description?: string;\n tags?: string[];\n parameters?: ParameterObject[];\n requestBody?: RequestBodyObject;\n responses?: Record<string, ResponseObject>;\n deprecated?: boolean;\n 'x-oagen-async'?: boolean;\n security?: Array<Record<string, string[]>>;\n 'x-mutually-exclusive-parameter-groups'?: Record<string, ParameterGroupExtension>;\n 'x-mutually-exclusive-body-groups'?: Record<string, ParameterGroupExtension>;\n}\n\ninterface ParameterObject {\n name: string;\n in: 'path' | 'query' | 'header' | 'cookie';\n required?: boolean;\n description?: string;\n schema?: SchemaObject;\n deprecated?: boolean;\n example?: unknown;\n style?: string;\n explode?: boolean;\n}\n\ninterface RequestBodyObject {\n required?: boolean;\n content?: Record<string, { schema?: SchemaObject }>;\n}\n\ninterface ResponseObject {\n description?: string;\n content?: Record<string, { schema?: SchemaObject }>;\n}\n\nconst HTTP_METHODS: HttpMethod[] = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'];\n\nexport interface OperationExtractionResult {\n services: Service[];\n inlineModels: Model[];\n}\n\nexport function extractOperations(\n paths: Record<string, PathItem> | undefined,\n operationIdTransform?: (id: string) => string,\n componentSchemas?: Record<string, SchemaObject>,\n): OperationExtractionResult {\n if (!paths) return { services: [], inlineModels: [] };\n\n const serviceMap = new Map<string, Operation[]>();\n const inlineModels: Model[] = [];\n\n for (const [path, pathItem] of Object.entries(paths)) {\n const pathLevelParams = pathItem.parameters ?? [];\n\n for (const method of HTTP_METHODS) {\n const op = pathItem[method];\n if (!op) continue;\n\n const serviceName = inferServiceName(path, op.tags?.[0]);\n\n const { operation, inlineModels: opModels } = buildOperation(\n method,\n path,\n op,\n pathLevelParams,\n operationIdTransform,\n serviceName,\n componentSchemas,\n );\n inlineModels.push(...opModels);\n const ops = serviceMap.get(serviceName) ?? [];\n ops.push(operation);\n serviceMap.set(serviceName, ops);\n }\n }\n\n // Split services when a single tag groups operations from multiple path prefixes.\n // Example: /organizations and /organization_domains both tagged \"organizations\"\n // should become separate services based on their first path segment.\n for (const [serviceName, operations] of serviceMap) {\n const pathGroups = new Map<string, Operation[]>();\n for (const op of operations) {\n const firstSeg = op.path.split('/').filter(Boolean)[0] ?? '';\n const groupKey = firstSeg.startsWith('{') ? serviceName : toPascalCase(firstSeg);\n const group = pathGroups.get(groupKey) ?? [];\n group.push(op);\n pathGroups.set(groupKey, group);\n }\n // Only split if there are multiple distinct path-prefix groups AND\n // at least one group name differs from the current service name\n if (pathGroups.size > 1) {\n const needsSplit = [...pathGroups.keys()].some((k) => k !== serviceName);\n if (needsSplit) {\n serviceMap.delete(serviceName);\n for (const [groupName, groupOps] of pathGroups) {\n const existing = serviceMap.get(groupName) ?? [];\n existing.push(...groupOps);\n serviceMap.set(groupName, existing);\n }\n }\n }\n }\n\n // Disambiguate operation names within each service.\n // Multiple operations can get the same name (e.g., several \"list\" endpoints\n // in UserManagement for users, invitations, auth factors, etc.).\n for (const [, operations] of serviceMap) {\n disambiguateOperationNames(operations);\n }\n\n const services = Array.from(serviceMap.entries()).map(([name, operations]) => ({\n name,\n operations,\n }));\n\n return { services, inlineModels };\n}\n\nfunction inferServiceName(path: string, tag?: string): string {\n // Prefer OpenAPI tag when available — tags represent the logical grouping\n // (e.g., \"multi-factor-auth\" for /auth/factors/* endpoints).\n if (tag) {\n return toPascalCase(tag);\n }\n // Fallback: extract first meaningful path segment: /widgets/{id}/sub → \"Widgets\"\n const segments = path.split('/').filter(Boolean);\n const first = segments[0] ?? 'Default';\n // Skip path params\n if (first.startsWith('{')) return 'Default';\n return toPascalCase(first);\n}\n\n/**\n * Strip overload indices (e.g. NestJS emits `Foo_bar[0]` when a controller\n * method handles multiple routes) from an operationId so derived names never\n * leak the bracketed digit. Without this, `authenticate[0]` would surface as\n * `authenticate0` in method names and `Authenticate0Request` in body model\n * names. Brackets at the end (or with trailing whitespace) are common in\n * NestJS-style backends; this regex is intentionally narrow to avoid eating\n * legitimate digits like `oauth2`.\n */\nfunction normalizeOperationIdForNaming(operationId: string): string {\n return operationId.replace(/\\[\\d+\\]\\s*$/, '');\n}\n\nfunction inferOperationName(\n method: HttpMethod,\n path: string,\n operationId?: string,\n operationIdTransform?: (id: string) => string,\n): string {\n if (operationId) {\n const normalized = normalizeOperationIdForNaming(operationId);\n if (operationIdTransform) {\n return operationIdTransform(normalized);\n }\n return toCamelCase(normalized);\n }\n\n // Fallback when no operationId is available — use method + path to build\n // a descriptive name like \"listUsers\", \"getOrganization\", \"deleteAuthFactor\"\n const verb = inferVerb(method, path);\n const resource = inferResourceFromPath(path);\n return resource ? toCamelCase(`${verb}_${resource}`) : verb;\n}\n\n/**\n * Infer the CRUD verb from HTTP method and path shape.\n */\nfunction inferVerb(method: HttpMethod, path: string): string {\n const segments = path.split('/').filter(Boolean);\n const hasTrailingParam = segments.length > 0 && segments[segments.length - 1].startsWith('{');\n\n switch (method) {\n case 'get':\n return hasTrailingParam ? 'get' : 'list';\n case 'post':\n return 'create';\n case 'put':\n case 'patch':\n return 'update';\n case 'delete':\n return 'delete';\n case 'head':\n return 'check';\n case 'options':\n return 'options';\n case 'trace':\n return 'trace';\n default:\n return method;\n }\n}\n\n/**\n * Extract a resource noun from the path for operation naming.\n * Uses the last non-param segment (the resource being operated on).\n *\n * Examples:\n * /user_management/users → \"Users\"\n * /user_management/users/{id} → \"User\" (singular for item operations)\n * /user_management/users/{id}/auth_factors → \"AuthFactors\"\n * /organizations/{id}/api_keys → \"ApiKeys\"\n * /sso/authorize → \"Authorize\" (action endpoint)\n */\nfunction inferResourceFromPath(path: string): string | null {\n const segments = path.split('/').filter(Boolean);\n if (segments.length <= 1) return null;\n\n // Find the last meaningful (non-param) segment\n let resourceSegment: string | null = null;\n for (let i = segments.length - 1; i >= 0; i--) {\n if (!segments[i].startsWith('{')) {\n resourceSegment = segments[i];\n break;\n }\n }\n\n if (!resourceSegment) return null;\n // Skip the service name (first segment) — it would be redundant\n if (resourceSegment === segments[0]) return null;\n\n return toPascalCase(resourceSegment);\n}\n\n/**\n * Detect and resolve name collisions within a service's operations.\n *\n * When multiple operations share the same name (e.g., several \"list\" from\n * different sub-resources), disambiguate by appending the resource noun\n * from the path. Only renames operations on DIFFERENT paths — same-name\n * operations on the same path (e.g., PUT + PATCH both \"update\") are left as-is\n * since they represent the same logical resource.\n */\nfunction disambiguateOperationNames(operations: Operation[]): void {\n // Group by name\n const byName = new Map<string, Operation[]>();\n for (const op of operations) {\n const group = byName.get(op.name) ?? [];\n group.push(op);\n byName.set(op.name, group);\n }\n\n for (const [name, group] of byName) {\n if (group.length <= 1) continue;\n\n // Check if these are genuinely different resources (different paths)\n // vs the same resource with different methods (PUT + PATCH)\n const uniquePaths = new Set(group.map((op) => op.path));\n if (uniquePaths.size <= 1) continue; // same path, different methods — no disambiguation needed\n\n for (const op of group) {\n const resource = inferResourceFromPath(op.path);\n if (resource) {\n const newName = toCamelCase(`${name}_${resource}`);\n (op as { name: string }).name = newName;\n }\n }\n\n // If disambiguation still left collisions (same sub-resource),\n // use the full distinguishing path segment chain\n const renamed = new Map<string, Operation[]>();\n for (const op of group) {\n const rGroup = renamed.get(op.name) ?? [];\n rGroup.push(op);\n renamed.set(op.name, rGroup);\n }\n for (const [, rGroup] of renamed) {\n if (rGroup.length <= 1) continue;\n // Still colliding — different paths map to same resource name.\n // Use deeper path context to disambiguate.\n for (const op of rGroup) {\n const deeper = inferDeeperContext(op.path);\n if (deeper) {\n (op as { name: string }).name = toCamelCase(`${op.name}_${deeper}`);\n }\n }\n }\n }\n}\n\n/**\n * Extract a deeper disambiguation context from the path when the last\n * segment isn't unique enough. Uses the second-to-last non-param segment.\n *\n * /users/{id}/auth_factors → already captured as \"AuthFactors\"\n * /users/external_id/{external_id} → \"ExternalId\" (special path, not a sub-resource)\n */\nfunction inferDeeperContext(path: string): string | null {\n const segments = path.split('/').filter(Boolean);\n const nonParams = segments.filter((s) => !s.startsWith('{'));\n // Skip first (service) and last (already used) — use the middle ones\n if (nonParams.length >= 3) {\n return toPascalCase(nonParams.slice(1, -1).join('_'));\n }\n return null;\n}\n\n/**\n * Extract mutually-exclusive parameter groups from the `x-mutually-exclusive-parameter-groups`\n * operation extension. Cross-references grouped parameter names against the already-extracted\n * IR parameter arrays so emitters get object-identity references.\n */\nfunction extractParameterGroups(\n op: OperationObject,\n allIRParams: Parameter[],\n operationContext: string,\n): ParameterGroup[] | undefined {\n const raw = op['x-mutually-exclusive-parameter-groups'];\n if (!raw || typeof raw !== 'object') return undefined;\n\n const paramByName = new Map<string, Parameter>();\n for (const p of allIRParams) {\n paramByName.set(p.name, p);\n }\n\n const groups: ParameterGroup[] = [];\n\n for (const [groupName, groupDef] of Object.entries(raw)) {\n if (!groupDef || typeof groupDef !== 'object') {\n throw new Error(\n `Malformed x-mutually-exclusive-parameter-groups.${groupName} in ${operationContext}: expected an object with \"optional\" and \"variants\".`,\n );\n }\n\n if (typeof groupDef.optional !== 'boolean') {\n throw new Error(\n `Malformed x-mutually-exclusive-parameter-groups.${groupName}.optional in ${operationContext}: expected a boolean.`,\n );\n }\n\n if (!groupDef.variants || typeof groupDef.variants !== 'object') {\n throw new Error(\n `Malformed x-mutually-exclusive-parameter-groups.${groupName}.variants in ${operationContext}: expected an object mapping variant names to parameter name arrays.`,\n );\n }\n\n if (Object.keys(groupDef.variants).length === 0) {\n throw new Error(\n `Malformed x-mutually-exclusive-parameter-groups.${groupName} in ${operationContext}: group has zero variants.`,\n );\n }\n\n const variants = Object.entries(groupDef.variants).map(([variantName, paramNames]) => {\n if (!Array.isArray(paramNames) || paramNames.length === 0) {\n throw new Error(\n `Malformed x-mutually-exclusive-parameter-groups.${groupName}.variants.${variantName} in ${operationContext}: expected a non-empty array of parameter names.`,\n );\n }\n const parameters: Parameter[] = paramNames.map((pName) => {\n const irParam = paramByName.get(pName);\n if (!irParam) {\n throw new Error(\n `x-mutually-exclusive-parameter-groups.${groupName}.variants.${variantName} references parameter \"${pName}\" which does not exist in the operation's parameters[] (${operationContext}).`,\n );\n }\n return irParam;\n });\n return { name: variantName, parameters };\n });\n\n groups.push({\n name: groupName,\n optional: groupDef.optional,\n variants,\n });\n }\n\n return groups.length > 0 ? groups : undefined;\n}\n\n/**\n * Extract mutually-exclusive body parameter groups from the\n * `x-mutually-exclusive-body-groups` operation extension. Unlike query\n * parameter groups (whose parameters live in operation.queryParams), body\n * group parameters are synthetic — built from the oneOf variant schemas in\n * the request body. Emitters use the group's presence to generate sum-type\n * interfaces and custom JSON marshalling instead of flat optional fields.\n */\nfunction extractBodyParameterGroups(op: OperationObject, operationContext: string): ParameterGroup[] | undefined {\n const raw = op['x-mutually-exclusive-body-groups'];\n if (!raw || typeof raw !== 'object') return undefined;\n\n // Collect the body schema's oneOf variant fields so we can resolve types.\n // The body schema has been structurally rewritten to allOf: [base, { oneOf: [...] }]\n // by the spec generator; the variant properties live inside oneOf branches.\n const bodySchema = op.requestBody?.content?.['application/json']?.schema;\n const variantFieldSchemas = new Map<string, SchemaObject>();\n\n if (bodySchema) {\n // Walk allOf → oneOf → variant.properties to find all variant fields\n for (const sub of bodySchema.allOf ?? []) {\n for (const variant of sub.oneOf ?? []) {\n if (variant.properties) {\n for (const [name, fieldSchema] of Object.entries(variant.properties)) {\n if (fieldSchema) variantFieldSchemas.set(name, fieldSchema);\n }\n }\n }\n }\n // Also check top-level oneOf (for inline schemas that aren't wrapped in allOf)\n for (const variant of bodySchema.oneOf ?? []) {\n if (variant.properties) {\n for (const [name, fieldSchema] of Object.entries(variant.properties)) {\n if (fieldSchema) variantFieldSchemas.set(name, fieldSchema);\n }\n }\n }\n }\n\n const groups: ParameterGroup[] = [];\n\n for (const [groupName, groupDef] of Object.entries(raw)) {\n if (!groupDef || typeof groupDef !== 'object') continue;\n if (typeof groupDef.optional !== 'boolean') continue;\n if (!groupDef.variants || typeof groupDef.variants !== 'object') continue;\n if (Object.keys(groupDef.variants).length === 0) continue;\n\n const variants = Object.entries(groupDef.variants).map(([variantName, paramNames]) => {\n if (!Array.isArray(paramNames) || paramNames.length === 0) {\n throw new Error(\n `Malformed x-mutually-exclusive-body-groups.${groupName}.variants.${variantName} in ${operationContext}: expected a non-empty array of parameter names.`,\n );\n }\n const parameters: Parameter[] = paramNames.map((pName) => {\n const fieldSchema = variantFieldSchemas.get(pName);\n const fieldType: TypeRef = fieldSchema\n ? schemaToTypeRef(fieldSchema, toPascalCase(pName))\n : { kind: 'primitive', type: 'string' };\n return {\n name: pName,\n type: fieldType,\n required: false, // group variant fields are always optional at the struct level\n description: fieldSchema?.description,\n };\n });\n return { name: variantName, parameters };\n });\n\n groups.push({\n name: groupName,\n optional: groupDef.optional,\n variants,\n });\n }\n\n return groups.length > 0 ? groups : undefined;\n}\n\nfunction buildOperation(\n method: HttpMethod,\n path: string,\n op: OperationObject,\n pathLevelParams: ParameterObject[],\n operationIdTransform?: (id: string) => string,\n serviceName?: string,\n componentSchemas?: Record<string, SchemaObject>,\n): { operation: Operation; inlineModels: Model[] } {\n const allParams = [...pathLevelParams, ...(op.parameters ?? [])];\n\n const hasIdempotencyHeader = allParams.some((p) => p.in === 'header' && p.name.toLowerCase() === 'idempotency-key');\n\n // Use the service name as context so inline parameter enums get qualified\n // names. e.g., service \"SSO\" + param \"provider\" → \"SSOProvider\".\n const opContext = serviceName;\n const pathParams = extractParams(allParams, 'path', opContext, componentSchemas);\n const queryParams = extractParams(allParams, 'query', opContext, componentSchemas);\n const headerParams = extractParams(allParams, 'header', opContext, componentSchemas).filter(\n (p) => p.name.toLowerCase() !== 'idempotency-key',\n );\n const cookieParams = extractParams(allParams, 'cookie', opContext, componentSchemas);\n\n const reqBodyModels: Model[] = [];\n const { body: requestBody, encoding: requestBodyEncoding } = extractRequestBody(op.requestBody, op, reqBodyModels);\n const {\n response,\n successResponses,\n errors,\n inlineModels,\n isPaginated,\n dataPath: responseDataPath,\n itemType: responseItemType,\n } = extractResponses(op.responses, op, path, method);\n inlineModels.push(...reqBodyModels);\n\n // Build structured pagination metadata from response classification and query param detection\n const paginationFromParams = detectPagination(response, queryParams, responseDataPath);\n let pagination: PaginationMeta | undefined;\n if (isPaginated) {\n const itemType = responseItemType ?? (response.kind === 'array' ? response.items : response);\n pagination = {\n strategy: paginationFromParams?.strategy ?? 'cursor',\n param: paginationFromParams?.param ?? 'after',\n limitParam: paginationFromParams?.limitParam,\n dataPath: responseDataPath ?? paginationFromParams?.dataPath,\n itemType,\n };\n } else if (paginationFromParams) {\n pagination = paginationFromParams;\n }\n\n // Extract per-operation security overrides\n const security = extractOperationSecurity(op.security);\n\n // Extract mutually-exclusive parameter groups (query/path/header/cookie)\n const allIRParams = [...pathParams, ...queryParams, ...headerParams, ...cookieParams];\n const opLabel = op.operationId ?? `${method.toUpperCase()} ${path}`;\n const queryParamGroups = extractParameterGroups(op, allIRParams, opLabel);\n\n // Extract mutually-exclusive body parameter groups\n const bodyParamGroups = extractBodyParameterGroups(op, opLabel);\n\n // Merge both sources into a single parameterGroups array\n const parameterGroups =\n queryParamGroups || bodyParamGroups ? [...(queryParamGroups ?? []), ...(bodyParamGroups ?? [])] : undefined;\n\n return {\n operation: {\n name: inferOperationName(method, path, op.operationId, operationIdTransform),\n description: buildDescription(op.summary, op.description),\n httpMethod: method,\n path,\n pathParams,\n queryParams,\n headerParams,\n cookieParams: cookieParams.length > 0 ? cookieParams : undefined,\n requestBody,\n requestBodyEncoding,\n response,\n successResponses,\n errors,\n pagination,\n injectIdempotencyKey: hasIdempotencyHeader,\n deprecated: op.deprecated || undefined,\n async: op['x-oagen-async'],\n security,\n parameterGroups,\n },\n inlineModels,\n };\n}\n\n/**\n * Extract per-operation security requirements from an OpenAPI security directive.\n * Returns undefined when the operation uses the spec-level default security.\n *\n * OpenAPI security format: `security: [{ schemeName: [scope1, scope2] }]`\n */\nfunction extractOperationSecurity(\n security: Array<Record<string, string[]>> | undefined,\n): SecurityRequirement[] | undefined {\n if (!security || security.length === 0) return undefined;\n\n const requirements: SecurityRequirement[] = [];\n for (const entry of security) {\n for (const [schemeName, scopes] of Object.entries(entry)) {\n requirements.push({ schemeName, scopes: scopes ?? [] });\n }\n }\n return requirements.length > 0 ? requirements : undefined;\n}\n\nfunction buildDescription(summary: string | undefined, description: string | undefined): string | undefined {\n if (summary && description && summary !== description) {\n return `${summary}\\n\\n${description}`;\n }\n return description ?? summary;\n}\n\nfunction extractParams(\n params: ParameterObject[],\n location: 'path' | 'query' | 'header' | 'cookie',\n operationContext?: string,\n componentSchemas?: Record<string, SchemaObject>,\n): Parameter[] {\n return params\n .filter((p) => p.in === location)\n .map((p) => {\n const refTarget = resolveParamSchemaRef(p.schema, componentSchemas);\n return {\n name: p.name,\n type: p.schema\n ? schemaToTypeRef(p.schema, p.name, operationContext ? toPascalCase(operationContext) : undefined)\n : ({ kind: 'primitive', type: 'string' } as TypeRef),\n required: p.required ?? false,\n description: p.description,\n deprecated: p.deprecated || p.schema?.deprecated || refTarget?.deprecated || undefined,\n default: p.schema?.default ?? refTarget?.default,\n example: p.example ?? p.schema?.example ?? refTarget?.example,\n style: p.style as Parameter['style'],\n explode: p.explode,\n };\n });\n}\n\n/**\n * If a parameter's schema is a `$ref` to `#/components/schemas/X`, return the\n * referenced component schema. Used to surface schema-level metadata (default,\n * example, deprecated) that wouldn't otherwise be visible at the param level.\n *\n * Refs are not pre-resolved by the bundler (`dereference: false` in refs.ts),\n * so without this, a param like `schema: { $ref: '.../PaginationOrder' }`\n * silently loses the target's `default: desc` and the SDK stops emitting the\n * spec-mandated default value in generated method signatures.\n */\nfunction resolveParamSchemaRef(\n schema: SchemaObject | undefined,\n componentSchemas: Record<string, SchemaObject> | undefined,\n): SchemaObject | undefined {\n if (!schema || !componentSchemas) return undefined;\n const ref = (schema as { $ref?: string }).$ref;\n if (!ref) return undefined;\n const match = /^#\\/components\\/schemas\\/(.+)$/.exec(ref);\n if (!match) return undefined;\n return componentSchemas[match[1]];\n}\n\nfunction extractRequestBody(\n body: RequestBodyObject | undefined,\n op: OperationObject | undefined,\n inlineModels: Model[],\n): { body?: TypeRef; encoding?: 'json' | 'form-data' | 'form-urlencoded' | 'binary' | 'text' } {\n if (!body?.content) return {};\n\n // Detect encoding and find schema from content type in priority order\n let encoding: 'json' | 'form-data' | 'form-urlencoded' | 'binary' | 'text' = 'json';\n let schema: SchemaObject | undefined;\n\n if (body.content['application/json']?.schema) {\n encoding = 'json';\n schema = body.content['application/json']!.schema;\n } else if (body.content['multipart/form-data']?.schema) {\n encoding = 'form-data';\n schema = body.content['multipart/form-data']!.schema;\n } else if (body.content['application/x-www-form-urlencoded']?.schema) {\n encoding = 'form-urlencoded';\n schema = body.content['application/x-www-form-urlencoded']!.schema;\n } else if (body.content['application/octet-stream']) {\n encoding = 'binary';\n schema = body.content['application/octet-stream']!.schema;\n } else if (body.content['text/plain']) {\n encoding = 'text';\n schema = body.content['text/plain']!.schema;\n }\n\n if (!schema) {\n // For binary/text, a schema is optional — produce a primitive TypeRef\n if (encoding === 'binary') {\n return { body: { kind: 'primitive', type: 'string', format: 'binary' }, encoding };\n }\n if (encoding === 'text') {\n return { body: { kind: 'primitive', type: 'string' }, encoding };\n }\n return {};\n }\n\n const rawName = op?.operationId\n ? toPascalCase(normalizeOperationIdForNaming(op.operationId)) + 'Request'\n : 'RequestBody';\n const contextName = cleanSchemaName(rawName);\n\n // If the request body is an inline object with properties, extract it as a model\n if (schema.properties && (schema.type === 'object' || !schema.type)) {\n const requiredSet = new Set(schema.required ?? []);\n const fields: Field[] = [];\n for (const [fieldName, fieldSchema] of Object.entries(schema.properties)) {\n if (!fieldSchema) continue;\n fields.push(buildFieldFromSchema(fieldName, fieldSchema, contextName, requiredSet));\n }\n inlineModels.push({ name: contextName, description: undefined, fields });\n return { body: { kind: 'model', name: contextName }, encoding };\n }\n\n // If the request body is a oneOf, extract each variant as an inline model\n // and build a union type pointing to them by name.\n if (schema.oneOf) {\n const variants: TypeRef[] = [];\n\n for (const variant of schema.oneOf) {\n if (variant.$ref) {\n const ref = schemaToTypeRef(variant, contextName);\n variants.push(ref);\n } else if (variant.type === 'null') {\n // skip null variant in union, handle separately\n } else if (variant.properties && (variant.type === 'object' || !variant.type)) {\n const variantName = deriveOneOfVariantName(variant, contextName, inlineModels);\n const requiredSet = new Set(variant.required ?? []);\n const fields: Field[] = [];\n for (const [fieldName, fieldSchema] of Object.entries(variant.properties)) {\n if (!fieldSchema) continue;\n fields.push(buildFieldFromSchema(fieldName, fieldSchema, variantName, requiredSet));\n }\n inlineModels.push({ name: variantName, description: variant.description, fields });\n variants.push({ kind: 'model', name: variantName });\n } else {\n variants.push(schemaToTypeRef(variant, contextName));\n }\n }\n\n const hasNull = schema.oneOf.some(\n (v: SchemaObject) => v.type === 'null' || (Array.isArray(v.type) && v.type.includes('null')),\n );\n const union: TypeRef = {\n kind: 'union',\n variants,\n ...(schema.discriminator\n ? {\n discriminator: { property: schema.discriminator.propertyName, mapping: schema.discriminator.mapping ?? {} },\n }\n : {}),\n };\n const body = hasNull ? ({ kind: 'nullable', inner: union } as TypeRef) : union;\n return { body, encoding };\n }\n\n return { body: schemaToTypeRef(schema, contextName), encoding };\n}\n\n/** Derive a unique variant name for a oneOf inline model. */\nfunction deriveOneOfVariantName(variant: SchemaObject, baseName: string, existingModels: Model[]): string {\n // Try to use a distinguishing property (e.g., \"grant_type\" field's const/enum value)\n if (variant.properties) {\n for (const [, propSchema] of Object.entries(variant.properties)) {\n if (propSchema?.const && typeof propSchema.const === 'string') {\n return toPascalCase(propSchema.const) + baseName.replace(/Request$/, '') + 'Request';\n }\n }\n }\n // Fallback: append a numeric suffix\n const existingNames = new Set(existingModels.map((m) => m.name));\n let name = baseName;\n let suffix = 2;\n while (existingNames.has(name)) {\n name = `${baseName}${suffix}`;\n suffix++;\n }\n return name;\n}\n\nfunction deriveResponseName(op: OperationObject | undefined, path: string, method: HttpMethod): string {\n if (op?.operationId) {\n return cleanSchemaName(toPascalCase(normalizeOperationIdForNaming(op.operationId)) + 'Response');\n }\n const segments = path.split('/').filter(Boolean);\n const resource = segments[0] ?? 'Unknown';\n return toPascalCase(resource) + toPascalCase(method) + 'Response';\n}\n\nfunction extractResponses(\n responses?: Record<string, ResponseObject>,\n op?: OperationObject,\n path?: string,\n method?: HttpMethod,\n): {\n response: TypeRef;\n successResponses?: SuccessResponse[];\n errors: ErrorResponse[];\n inlineModels: Model[];\n isPaginated: boolean;\n dataPath?: string;\n itemType?: TypeRef;\n} {\n const errors: ErrorResponse[] = [];\n let response: TypeRef = { kind: 'primitive', type: 'string' };\n let inlineModels: Model[] = [];\n let isPaginated = false;\n let dataPath: string | undefined;\n let itemType: TypeRef | undefined;\n\n if (!responses) return { response, errors, inlineModels, isPaginated };\n\n const allSuccessResponses: SuccessResponse[] = [];\n\n for (const [statusCode, resp] of Object.entries(responses)) {\n const code = parseInt(statusCode, 10);\n\n if (code >= 200 && code < 300) {\n let extractedType: TypeRef = { kind: 'primitive', type: 'unknown' };\n const jsonContent = resp.content?.['application/json'];\n if (jsonContent?.schema) {\n const contextName = deriveResponseName(op, path ?? '/', method ?? 'get');\n const result = classifyAndExtractResponse(jsonContent.schema, contextName);\n extractedType = result.response;\n // Keep track of inline models and pagination from the latest 2xx with a schema\n inlineModels = result.inlineModels;\n isPaginated = result.isPaginated;\n dataPath = result.dataPath;\n itemType = result.itemType;\n } else if (resp.content) {\n // Handle non-JSON response content types (text/plain, binary, XML, etc.)\n if (resp.content['application/octet-stream'] || resp.content['application/pdf']) {\n extractedType = { kind: 'primitive', type: 'string', format: 'binary' };\n } else if (\n resp.content['text/plain'] ||\n resp.content['text/html'] ||\n resp.content['text/xml'] ||\n resp.content['application/xml']\n ) {\n extractedType = { kind: 'primitive', type: 'string' };\n } else {\n // Try the first available content type's schema\n const firstKey = Object.keys(resp.content)[0];\n if (firstKey) {\n const firstContent = resp.content[firstKey];\n if (firstContent?.schema) {\n extractedType = schemaToTypeRef(\n firstContent.schema,\n deriveResponseName(op, path ?? '/', method ?? 'get'),\n );\n }\n }\n }\n }\n allSuccessResponses.push({ statusCode: code, type: extractedType });\n } else if (code >= 300 && code < 400) {\n // 3xx redirects — include so emitter can detect redirect endpoints\n allSuccessResponses.push({ statusCode: code, type: { kind: 'primitive', type: 'unknown' } });\n } else if (code >= 400) {\n const jsonContent = resp.content?.['application/json'];\n const type = jsonContent?.schema ? schemaToTypeRef(jsonContent.schema, `Error${code}`) : undefined;\n errors.push({ statusCode: code, type });\n }\n }\n\n // Primary response = lowest 2xx with a body schema, falling back to first 2xx\n if (allSuccessResponses.length > 0) {\n const sorted = [...allSuccessResponses].sort((a, b) => a.statusCode - b.statusCode);\n const primary =\n sorted.find((r) => r.type.kind !== 'primitive' || (r.type as { type: string }).type !== 'unknown') ?? sorted[0];\n response = primary.type;\n }\n\n const successResponses = allSuccessResponses.length > 1 ? allSuccessResponses : undefined;\n\n return { response, successResponses, errors, inlineModels, isPaginated, dataPath, itemType };\n}\n","import type { Model, Service, TypeRef } from '../ir/types.js';\nimport { walkTypeRef } from '../ir/types.js';\n\nfunction keepLargestByName(models: Model[]): Model[] {\n const byName = new Map<string, Model>();\n for (const model of models) {\n const existing = byName.get(model.name);\n if (!existing || model.fields.length > existing.fields.length) {\n byName.set(model.name, model);\n }\n }\n return [...byName.values()];\n}\n\nfunction rewriteModelRef(ref: TypeRef, oldName: string, newName: string): void {\n walkTypeRef(ref, {\n model: (r) => {\n if (r.name === oldName) (r as { name: string }).name = newName;\n },\n });\n}\n\nfunction rewriteModelRefs(models: Model[], services: Service[], oldName: string, newName: string): void {\n for (const model of models) {\n for (const field of model.fields) {\n rewriteModelRef(field.type, oldName, newName);\n }\n }\n for (const service of services) {\n for (const op of service.operations) {\n rewriteModelRef(op.response, oldName, newName);\n if (op.requestBody) {\n rewriteModelRef(op.requestBody, oldName, newName);\n }\n }\n }\n}\n\nexport function mergeInlineResponseModels(schemaModels: Model[], inlineModels: Model[]): Model[] {\n const mergedSchemaModels = [...schemaModels];\n const schemaModelNames = new Set(mergedSchemaModels.map((m) => m.name));\n const schemaModelsByName = new Map(mergedSchemaModels.map((m) => [m.name, m]));\n\n const deduplicatedInlineModels = inlineModels.filter((model) => {\n if (!schemaModelNames.has(model.name)) return true;\n\n const existing = schemaModelsByName.get(model.name)!;\n const existingFieldNames = new Set(existing.fields.map((f) => f.name));\n const inlineFieldNames = new Set(model.fields.map((f) => f.name));\n const hasDifference =\n model.fields.some((f) => !existingFieldNames.has(f.name)) ||\n existing.fields.some((f) => !inlineFieldNames.has(f.name));\n\n if (hasDifference && model.fields.length > existing.fields.length) {\n const idx = mergedSchemaModels.indexOf(existing);\n if (idx !== -1) mergedSchemaModels[idx] = model;\n schemaModelsByName.set(model.name, model);\n console.warn(\n `[oagen] Warning: Inline model \"${model.name}\" has more fields than component schema (${model.fields.length} vs ${existing.fields.length}) — using inline response model`,\n );\n } else if (hasDifference) {\n console.warn(\n `[oagen] Warning: Inline model \"${model.name}\" has different fields than component schema — using component schema`,\n );\n }\n\n return false;\n });\n\n return [...mergedSchemaModels, ...keepLargestByName(deduplicatedInlineModels)];\n}\n\nexport function mergeFieldInlineModels(existingModels: Model[], fieldInlineModels: Model[]): Model[] {\n const modelNames = new Set(existingModels.map((m) => m.name));\n const modelsByName = new Map(existingModels.map((m) => [m.name, m]));\n\n const deduplicatedFieldModels = fieldInlineModels.filter((model) => {\n if (!modelNames.has(model.name)) return true;\n\n const existing = modelsByName.get(model.name)!;\n const existingFieldNames = new Set(existing.fields.map((f) => f.name));\n const inlineFieldNames = new Set(model.fields.map((f) => f.name));\n const hasDifference =\n model.fields.some((f) => !existingFieldNames.has(f.name)) ||\n existing.fields.some((f) => !inlineFieldNames.has(f.name));\n\n if (hasDifference) {\n console.warn(\n `[oagen] Warning: Inline model \"${model.name}\" has different fields than component schema — using component schema`,\n );\n }\n\n return false;\n });\n\n return [...existingModels, ...keepLargestByName(deduplicatedFieldModels)];\n}\n\nfunction hasModelConstDiscriminant(model: Model): boolean {\n return model.fields.some(\n (f) => (f.name === 'object' || f.name === 'type') && f.type.kind === 'literal' && typeof f.type.value === 'string',\n );\n}\n\nfunction isModelReferencedByOthers(name: string, models: Model[], excludeNames: Set<string>): boolean {\n for (const model of models) {\n if (excludeNames.has(model.name)) continue;\n for (const field of model.fields) {\n let found = false;\n walkTypeRef(field.type, {\n model: (r) => {\n if (r.name === name) found = true;\n },\n });\n if (found) return true;\n }\n }\n return false;\n}\n\nexport function collapseJsonSuffixModels(models: Model[], services: Service[]): Model[] {\n const normalizedModels = [...models];\n const byName = new Map(normalizedModels.map((m) => [m.name, m]));\n\n // Pass 1: collect merge candidates\n const mergeCandidates: Array<{ jsonModel: Model; baseModel: Model }> = [];\n for (const model of normalizedModels) {\n if (!model.name.endsWith('Json')) continue;\n\n const baseName = model.name.slice(0, -4);\n const baseModel = byName.get(baseName);\n if (!baseModel || model.fields.length <= baseModel.fields.length) continue;\n\n const isSuperset = baseModel.fields.every((f) => model.fields.some((mf) => mf.name === f.name));\n if (!isSuperset) continue;\n\n // Guard: both models have a const discriminant — they are distinct entities\n if (hasModelConstDiscriminant(model) && hasModelConstDiscriminant(baseModel)) continue;\n\n // Guard: a third model explicitly references the Json-suffix model\n if (isModelReferencedByOthers(model.name, normalizedModels, new Set([model.name, baseName]))) continue;\n\n mergeCandidates.push({ jsonModel: model, baseModel });\n }\n\n // Pass 2: apply merges\n const toRemove = new Set<string>();\n for (const { jsonModel, baseModel } of mergeCandidates) {\n baseModel.fields = jsonModel.fields;\n toRemove.add(jsonModel.name);\n rewriteModelRefs(normalizedModels, services, jsonModel.name, baseModel.name);\n console.warn(\n `[oagen] Merged \"${jsonModel.name}\" into \"${baseModel.name}\" (${jsonModel.fields.length} fields, superset)`,\n );\n }\n\n // Pass 3: cascade renames to inline children of collapsed Json-suffix models.\n // e.g. when AuditLogSchemaJson → AuditLogSchema, also rename\n // AuditLogSchemaJsonTarget → AuditLogSchemaTarget.\n for (const { jsonModel, baseModel } of mergeCandidates) {\n const jsonPrefix = jsonModel.name;\n const basePrefix = baseModel.name;\n\n for (const model of normalizedModels) {\n if (toRemove.has(model.name)) continue;\n if (model.name.length <= jsonPrefix.length) continue;\n if (!model.name.startsWith(jsonPrefix)) continue;\n\n const newName = basePrefix + model.name.slice(jsonPrefix.length);\n const existing = byName.get(newName);\n\n if (existing && !toRemove.has(existing.name)) {\n toRemove.add(model.name);\n rewriteModelRefs(normalizedModels, services, model.name, newName);\n console.warn(`[oagen] Collapsed child \"${model.name}\" into existing \"${newName}\"`);\n } else {\n rewriteModelRefs(normalizedModels, services, model.name, newName);\n model.name = newName;\n byName.set(newName, model);\n console.warn(`[oagen] Renamed child \"${jsonPrefix}…\" → \"${newName}\"`);\n }\n }\n }\n\n return normalizedModels.filter((m) => !toRemove.has(m.name));\n}\n","import type { Enum, Model, Service } from '../ir/types.js';\nimport { collectInlineEnumFromRef } from './schemas.js';\n\nexport function collectInlineEnumsFromModels(models: Model[], enums: Enum[]): void {\n const enumNames = new Set(enums.map((e) => e.name));\n for (const model of models) {\n for (const field of model.fields) {\n collectInlineEnumFromRef(field.type, enums, enumNames);\n }\n }\n}\n\n/**\n * Collect inline enum definitions from operation parameters (query, path, header)\n * and promote them to top-level enums so emitters can generate typed enum files.\n */\nexport function collectInlineEnumsFromOperations(services: Service[], enums: Enum[]): void {\n const enumNames = new Set(enums.map((e) => e.name));\n for (const service of services) {\n for (const op of service.operations) {\n for (const param of [...op.pathParams, ...op.queryParams, ...op.headerParams, ...(op.cookieParams ?? [])]) {\n collectInlineEnumFromRef(param.type, enums, enumNames);\n }\n }\n }\n}\n","import type { ApiSpec, TypeRef } from '../ir/types.js';\nimport { walkTypeRef } from '../ir/types.js';\n\nexport function validateModelRefs(spec: ApiSpec): void {\n const knownNames = new Set<string>();\n for (const m of spec.models) knownNames.add(m.name);\n for (const e of spec.enums) knownNames.add(e.name);\n\n function walkRef(ref: TypeRef, context: string): void {\n walkTypeRef(ref, {\n model: (r) => {\n if (!knownNames.has(r.name)) {\n console.warn(`[oagen] Warning: Unresolved model reference \"${r.name}\" (context: ${context})`);\n }\n },\n });\n }\n\n for (const model of spec.models) {\n for (const field of model.fields) {\n walkRef(field.type, `${model.name}.${field.name}`);\n }\n }\n\n for (const service of spec.services) {\n for (const op of service.operations) {\n for (const p of [...op.pathParams, ...op.queryParams, ...op.headerParams]) {\n walkRef(p.type, `${service.name}.${op.name}.${p.name}`);\n }\n if (op.requestBody) walkRef(op.requestBody, `${service.name}.${op.name}.requestBody`);\n walkRef(op.response, `${service.name}.${op.name}.response`);\n }\n }\n}\n","import type { ApiSpec, AuthScheme, ServerEntry } from '../ir/types.js';\nimport { defaultSdkBehavior } from '../ir/sdk-behavior.js';\nimport { SpecParseError } from '../errors.js';\nimport { loadAndBundleSpec } from './refs.js';\nimport { extractSchemas, extractInlineModelsFromSchemas, clearSchemaNameTransform } from './schemas.js';\nimport { extractOperations } from './operations.js';\nimport {\n mergeInlineResponseModels,\n collapseJsonSuffixModels,\n mergeFieldInlineModels,\n} from './normalize-inline-models.js';\nimport { collectInlineEnumsFromModels, collectInlineEnumsFromOperations } from './collect-inline-enums.js';\nimport { validateModelRefs } from './normalize-model-refs.js';\n\n/**\n * A bundled OpenAPI document, post-`$ref` resolution but pre-IR extraction.\n *\n * This is the shape the spec author wrote, with external refs inlined and\n * internal refs left intact. It is intentionally loose (`Record<string,\n * unknown>`) so `transformSpec` can reach arbitrary spec extensions without\n * fighting types — narrow with `as` at use sites.\n */\nexport type OpenApiDocument = Record<string, unknown>;\n\nexport interface ParseOptions {\n operationIdTransform?: (id: string) => string;\n schemaNameTransform?: (name: string) => string;\n /**\n * Pre-IR overlay applied to the bundled OpenAPI document before any IR\n * extraction runs. Use this when the upstream spec can't be changed but you\n * need to patch around a spec quirk that would otherwise emit a breaking SDK\n * change — e.g. rewriting a path's response `$ref` back to its prior schema,\n * merging the new fields onto the prior schema, and dropping the fork.\n *\n * The function may mutate the document in place and return it, or return a\n * new object; the returned value is what the rest of oagen sees.\n *\n * Runs once, after `$ref` bundling and before schema/operation extraction.\n * If you need to inspect the resulting IR instead, post-process the\n * `ApiSpec` returned by `parseSpec`.\n */\n transformSpec?: (spec: OpenApiDocument) => OpenApiDocument;\n}\n\nexport async function parseSpec(specPath: string, options?: ParseOptions): Promise<ApiSpec> {\n const { parsed } = await loadAndBundleSpec(specPath);\n const transformed = options?.transformSpec ? options.transformSpec(parsed) : parsed;\n\n const spec = transformed as {\n openapi?: string;\n info?: { title?: string; version?: string; description?: string };\n servers?: Array<{ url?: string; description?: string }>;\n paths?: Record<string, unknown>;\n components?: {\n schemas?: Record<string, unknown>;\n securitySchemes?: Record<\n string,\n { type: string; scheme?: string; in?: string; name?: string; flows?: Record<string, unknown> }\n >;\n };\n };\n\n // Validate OpenAPI version\n const version = spec.openapi ?? '';\n if (!version.startsWith('3.')) {\n throw new SpecParseError(\n `Unsupported OpenAPI version: ${version}. oagen requires OpenAPI 3.x`,\n `Update the spec to OpenAPI 3.0 or 3.1. If you are using Swagger 2.x, convert it first with \\`npx swagger2openapi ${specPath}\\`.`,\n );\n }\n\n const { models, enums } = extractSchemas(\n spec.components?.schemas as Record<string, Record<string, unknown>> | undefined,\n { schemaNameTransform: options?.schemaNameTransform },\n );\n\n const { services, inlineModels } = extractOperations(\n spec.paths as Record<string, Record<string, unknown>> | undefined,\n options?.operationIdTransform,\n spec.components?.schemas as Record<string, Record<string, unknown>> | undefined,\n );\n\n const responseNormalizedModels = mergeInlineResponseModels(models, inlineModels);\n\n // Extract inline models from model field definitions (objects/arrays with properties).\n // schemaNameTransform is kept active so inline child names use the\n // transformed parent name (e.g. AuditLogSchemaJson→AuditLogSchema yields\n // AuditLogSchemaTarget, not AuditLogSchemaJsonTarget).\n const fieldInlineModels = extractInlineModelsFromSchemas(\n spec.components?.schemas as Record<string, Record<string, unknown>> | undefined,\n );\n clearSchemaNameTransform();\n const fieldMergedModels = mergeFieldInlineModels(responseNormalizedModels, fieldInlineModels);\n const finalModels = collapseJsonSuffixModels(fieldMergedModels, services);\n collectInlineEnumsFromModels(finalModels, enums);\n collectInlineEnumsFromOperations(services, enums);\n\n const auth = extractAuthSchemes(spec.components?.securitySchemes);\n\n const serverEntries: ServerEntry[] = (spec.servers ?? [])\n .map((s) => ({ url: s.url ?? '', description: s.description }))\n .filter((s) => s.url);\n\n const result: ApiSpec = {\n name: spec.info?.title ?? 'Unknown API',\n version: spec.info?.version ?? '0.0.0',\n description: spec.info?.description,\n baseUrl: serverEntries[0]?.url ?? '',\n servers: serverEntries.length > 0 ? serverEntries : undefined,\n services,\n models: finalModels,\n enums,\n auth,\n sdk: defaultSdkBehavior(),\n };\n\n validateModelRefs(result);\n\n return result;\n}\n/** Extract authentication schemes from OpenAPI securitySchemes. */\nfunction extractAuthSchemes(\n securitySchemes?: Record<\n string,\n { type: string; scheme?: string; in?: string; name?: string; flows?: Record<string, unknown> }\n >,\n): AuthScheme[] | undefined {\n if (!securitySchemes) return undefined;\n const schemes: AuthScheme[] = [];\n for (const [, scheme] of Object.entries(securitySchemes)) {\n if (scheme.type === 'http' && scheme.scheme === 'bearer') {\n schemes.push({ kind: 'bearer' });\n } else if (scheme.type === 'apiKey' && scheme.in && scheme.name) {\n schemes.push({ kind: 'apiKey', in: scheme.in as 'header' | 'query' | 'cookie', name: scheme.name });\n } else if (scheme.type === 'oauth2' && scheme.flows) {\n schemes.push({ kind: 'oauth2', flows: scheme.flows });\n }\n }\n return schemes.length > 0 ? schemes : undefined;\n}\n","import { parseSpec, type OpenApiDocument } from '../parser/parse.js';\n\nexport async function parseCommand(opts: {\n spec: string;\n operationIdTransform?: (id: string) => string;\n schemaNameTransform?: (name: string) => string;\n transformSpec?: (spec: OpenApiDocument) => OpenApiDocument;\n}): Promise<void> {\n const ir = await parseSpec(opts.spec, {\n operationIdTransform: opts.operationIdTransform,\n schemaNameTransform: opts.schemaNameTransform,\n transformSpec: opts.transformSpec,\n });\n console.log(JSON.stringify(ir, null, 2));\n}\n","import type Parser from 'tree-sitter';\nimport type { UrlFingerprintConfig } from './types.js';\n\n/**\n * Extract a URL path fingerprint from a method body using tree-sitter AST traversal.\n *\n * Walks the AST subtree of the member node looking for the first string literal\n * that starts with '/'. Normalizes interpolation expressions to '{}' and format\n * specifiers (%s, %d, etc.) to '{}' for cross-language comparison.\n *\n * @returns A normalized URL fingerprint like \"/organizations/{}\" or undefined if none found.\n */\nexport function extractUrlFingerprint(memberNode: Parser.SyntaxNode, config: UrlFingerprintConfig): string | undefined {\n const stringTypes = new Set(config.stringNodeTypes);\n const contentTypes = new Set(config.contentNodeTypes);\n const interpolationTypes = new Set(config.interpolationNodeTypes);\n const formatFns = config.formatFunctionNames ? new Set(config.formatFunctionNames) : null;\n\n // Iterative DFS through the method's AST subtree\n const stack: Parser.SyntaxNode[] = [memberNode];\n\n while (stack.length > 0) {\n const node = stack.pop()!;\n\n if (stringTypes.has(node.type)) {\n const fp = resolveFingerprint(node, contentTypes, interpolationTypes);\n if (fp?.startsWith('/')) return fp;\n }\n\n // For format functions (Go's Sprintf, Rust's format!): check if this call\n // matches and extract the first string argument.\n if (formatFns && isFormatCall(node, formatFns)) {\n const fp = extractFromFormatCall(node, stringTypes, contentTypes, interpolationTypes);\n if (fp?.startsWith('/')) return fp;\n }\n\n // Push children in reverse order so leftmost child is processed first\n for (let i = node.childCount - 1; i >= 0; i--) {\n const child = node.child(i);\n if (child) stack.push(child);\n }\n }\n\n return undefined;\n}\n\n/**\n * Resolve the text content of a string node, normalizing interpolations to '{}'.\n */\nfunction resolveFingerprint(\n stringNode: Parser.SyntaxNode,\n contentTypes: Set<string>,\n interpolationTypes: Set<string>,\n): string | undefined {\n // Leaf string node (no children besides quotes) — strip quotes\n if (stringNode.namedChildCount === 0) {\n return normalizeFormatSpecifiers(stripQuotes(stringNode.text));\n }\n\n // Composite string (has content fragments + interpolation children)\n let result = '';\n for (let i = 0; i < stringNode.childCount; i++) {\n const child = stringNode.child(i)!;\n if (contentTypes.has(child.type)) {\n result += child.text;\n } else if (interpolationTypes.has(child.type)) {\n result += '{}';\n }\n // Skip quote delimiters, interpolation markers, etc.\n }\n\n return result ? normalizeFormatSpecifiers(result) : normalizeFormatSpecifiers(stripQuotes(stringNode.text));\n}\n\n/** Check if a node is a call to one of the format functions (e.g., fmt.Sprintf, format!). */\nfunction isFormatCall(node: Parser.SyntaxNode, formatFns: Set<string>): boolean {\n // Rust macro: format!(...) — tree-sitter may parse as macro_invocation\n if (node.type === 'macro_invocation') {\n const macroName = node.childForFieldName('macro')?.text;\n return !!(macroName && formatFns.has(macroName.replace(/!$/, '')));\n }\n\n if (node.type !== 'call_expression') return false;\n const fnNode = node.childForFieldName('function');\n if (!fnNode) return false;\n\n // Direct call: Sprintf(...) or format!(...)\n if (formatFns.has(fnNode.text)) return true;\n\n // Member call: fmt.Sprintf(...)\n if (fnNode.type === 'selector_expression' || fnNode.type === 'member_expression') {\n const prop = fnNode.childForFieldName('field') ?? fnNode.childForFieldName('property');\n if (prop && formatFns.has(prop.text)) return true;\n }\n return false;\n}\n\n/** Extract the first string argument from a format function call. */\nfunction extractFromFormatCall(\n callNode: Parser.SyntaxNode,\n stringTypes: Set<string>,\n contentTypes: Set<string>,\n interpolationTypes: Set<string>,\n): string | undefined {\n const args = callNode.childForFieldName('arguments');\n if (!args) return undefined;\n\n for (let i = 0; i < args.childCount; i++) {\n const arg = args.child(i)!;\n if (stringTypes.has(arg.type)) {\n return resolveFingerprint(arg, contentTypes, interpolationTypes);\n }\n }\n return undefined;\n}\n\n/** Strip surrounding quote characters from a string literal. */\nfunction stripQuotes(text: string): string {\n // Handle various quote styles: \"...\", '...', `...`, f\"...\", $\"...\", @\"...\"\n const match = text.match(/^(?:f|r|b|@|\\$)?(?:\"\"\"([\\s\\S]*)\"\"\"|'''([\\s\\S]*)'''|\"(.*)\"|'(.*)'|`(.*)`)$/s);\n if (match) return match[1] ?? match[2] ?? match[3] ?? match[4] ?? match[5] ?? text;\n return text;\n}\n\n/** Replace printf-style format specifiers (%s, %d, %v, %f) with {}. */\nfunction normalizeFormatSpecifiers(s: string): string {\n return s.replace(/%[sdvf]/g, '{}');\n}\n","import type Parser from 'tree-sitter';\nimport type {\n MergeAdapter,\n MergeStatement,\n MergeImport,\n DocstringInfo,\n SymbolDocstrings,\n MemberDocstrings,\n} from './types.js';\nimport { extractUrlFingerprint } from './url-fingerprint.js';\n\nconst DOTNET_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['string_literal', 'interpolated_string_expression'],\n contentNodeTypes: ['string_content', 'string_literal_content'],\n interpolationNodeTypes: ['interpolation'],\n};\n\nconst DECLARATION_TYPES = new Set([\n 'class_declaration',\n 'struct_declaration',\n 'interface_declaration',\n 'enum_declaration',\n 'record_declaration',\n]);\n\nfunction extractDeclarationName(node: Parser.SyntaxNode): string | null {\n if (DECLARATION_TYPES.has(node.type)) {\n const nameNode = node.childForFieldName('name') ?? node.children.find((c) => c.type === 'identifier');\n return nameNode?.text ?? null;\n }\n if (node.type === 'namespace_declaration' || node.type === 'file_scoped_namespace_declaration') {\n const nameNode =\n node.children.find((c) => c.type === 'qualified_name') ?? node.children.find((c) => c.type === 'identifier');\n return nameNode ? `__namespace:${nameNode.text}` : null;\n }\n return null;\n}\n\nfunction collectPrecedingXmlDocComments(\n children: Parser.SyntaxNode[],\n index: number,\n source: string,\n): DocstringInfo | null {\n let lastIdx = -1;\n let firstIdx = -1;\n for (let k = index - 1; k >= 0; k--) {\n const prev = children[k];\n if (prev.type === 'comment') {\n const text = source.slice(prev.startIndex, prev.endIndex);\n if (text.startsWith('///')) {\n if (lastIdx === -1) lastIdx = k;\n firstIdx = k;\n } else {\n break;\n }\n } else {\n break;\n }\n }\n if (firstIdx === -1) return null;\n const first = children[firstIdx];\n const last = children[lastIdx];\n return { text: source.slice(first.startIndex, last.endIndex), startIndex: first.startIndex, endIndex: last.endIndex };\n}\n\n/**\n * Collect declarations from a list of sibling nodes (root level or namespace body).\n */\nfunction collectDeclarations(\n children: Parser.SyntaxNode[],\n source: string,\n statements: MergeStatement[],\n imports: MergeImport[],\n importAnchors: string[],\n importInsertionAnchor: { value?: string },\n): void {\n for (const child of children) {\n if (child.type === 'comment') continue;\n\n if (child.type === 'using_directive') {\n const text = source.slice(child.startIndex, child.endIndex);\n imports.push({ key: text.trim(), text });\n importAnchors.push(text);\n continue;\n }\n\n if (child.type === 'file_scoped_namespace_declaration') {\n importInsertionAnchor.value = source.slice(child.startIndex, child.endIndex);\n // File-scoped namespace: subsequent declarations are siblings at root\n continue;\n }\n\n if (child.type === 'namespace_declaration') {\n importInsertionAnchor.value = source.slice(child.startIndex, child.endIndex);\n // Block namespace: recurse into declaration_list\n const body = child.children.find((c) => c.type === 'declaration_list');\n if (body) {\n collectDeclarations(body.namedChildren, source, statements, imports, importAnchors, importInsertionAnchor);\n }\n continue;\n }\n\n const name = extractDeclarationName(child);\n statements.push({\n key: name,\n kind: name ? 'declaration' : 'other',\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n}\n\nexport const dotnetMergeAdapter: MergeAdapter = {\n language: 'dotnet',\n grammarModule: 'tree-sitter-c-sharp',\n testFilePatterns: [/Tests?\\.cs$/],\n urlFingerprintConfig: DOTNET_URL_FINGERPRINT_CONFIG,\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n const statements: MergeStatement[] = [];\n const importInsertionAnchor: { value?: string } = {};\n\n collectDeclarations(tree.rootNode.children, source, statements, imports, importAnchors, importInsertionAnchor);\n\n return {\n imports,\n importAnchors,\n importInsertionAnchor: importInsertionAnchor.value,\n statements,\n };\n },\n renderImports(imports) {\n return imports.map((entry) => entry.text);\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n\n function processChildren(children: Parser.SyntaxNode[]): void {\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n\n // Recurse into namespaces\n if (child.type === 'namespace_declaration') {\n const body = child.children.find((c) => c.type === 'declaration_list');\n if (body) processChildren(body.children);\n continue;\n }\n\n const name = extractDeclarationName(child);\n if (!name || name.startsWith('__namespace:')) continue;\n\n const docstring = collectPrecedingXmlDocComments(children, i, source);\n const members = new Map<string, MemberDocstrings>();\n\n // Extract member docstrings\n const body = child.children.find((c) => c.type === 'declaration_list');\n if (body) {\n const bodyChildren = body.children;\n for (let j = 0; j < bodyChildren.length; j++) {\n const member = bodyChildren[j];\n if (member.type !== 'method_declaration' && member.type !== 'property_declaration') continue;\n // For methods, the second identifier is the name (first is return type)\n const identifiers = member.children.filter((c) => c.type === 'identifier');\n const memberName =\n member.type === 'method_declaration'\n ? identifiers.length >= 2\n ? identifiers[1]!.text\n : identifiers[0]?.text\n : identifiers[0]?.text;\n if (!memberName) continue;\n const memberDoc = collectPrecedingXmlDocComments(bodyChildren, j, source);\n members.set(memberName, {\n docstring: memberDoc,\n declStartIndex: member.startIndex,\n declColumn: member.startPosition.column,\n urlFingerprint: extractUrlFingerprint(member, DOTNET_URL_FINGERPRINT_CONFIG),\n });\n }\n }\n\n result.set(name, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members,\n });\n }\n }\n\n processChildren(tree.rootNode.children);\n return result;\n },\n};\n","import type Parser from 'tree-sitter';\nimport type {\n MergeAdapter,\n MergeStatement,\n MergeImport,\n DocstringInfo,\n SymbolDocstrings,\n MemberDocstrings,\n} from './types.js';\nimport { extractUrlFingerprint } from './url-fingerprint.js';\n\nconst ELIXIR_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['string'],\n contentNodeTypes: ['quoted_content'],\n interpolationNodeTypes: ['interpolation'],\n};\n\nfunction isDefmodule(node: Parser.SyntaxNode): boolean {\n return node.type === 'call' && node.children[0]?.text === 'defmodule';\n}\n\nfunction getModuleName(node: Parser.SyntaxNode): string | null {\n if (!isDefmodule(node)) return null;\n const args = node.children.find((c) => c.type === 'arguments');\n if (!args) return null;\n const alias = args.children.find((c) => c.type === 'alias');\n return alias?.text ?? null;\n}\n\nfunction getDoBlock(node: Parser.SyntaxNode): Parser.SyntaxNode | null {\n return node.children.find((c) => c.type === 'do_block') ?? null;\n}\n\n/** Check if a node is an @moduledoc or @doc attribute. */\nfunction isDocAttribute(node: Parser.SyntaxNode): string | null {\n if (node.type !== 'unary_operator') return null;\n const call = node.children.find((c) => c.type === 'call');\n if (!call) return null;\n const id = call.children.find((c) => c.type === 'identifier');\n if (id?.text === 'moduledoc' || id?.text === 'doc') return id.text;\n return null;\n}\n\n/** Check if a node is a def/defp call. */\nfunction getDefName(node: Parser.SyntaxNode): string | null {\n if (node.type !== 'call') return null;\n const id = node.children[0];\n if (!id || (id.text !== 'def' && id.text !== 'defp')) return null;\n const args = node.children.find((c) => c.type === 'arguments');\n if (!args) return null;\n // The function name is either a simple identifier or a call (for functions with params)\n for (const arg of args.namedChildren) {\n if (arg.type === 'identifier') return arg.text;\n if (arg.type === 'call') {\n const nameNode = arg.children.find((c) => c.type === 'identifier');\n return nameNode?.text ?? null;\n }\n }\n return null;\n}\n\n/** Check if a node is an alias/import/require/use call. */\nfunction isImportLike(node: Parser.SyntaxNode): boolean {\n if (node.type !== 'call') return false;\n const id = node.children[0];\n return id?.type === 'identifier' && ['alias', 'import', 'require', 'use'].includes(id.text);\n}\n\nexport const elixirMergeAdapter: MergeAdapter = {\n language: 'elixir',\n grammarModule: 'tree-sitter-elixir',\n testFilePatterns: [/_test\\.exs$/],\n urlFingerprintConfig: ELIXIR_URL_FINGERPRINT_CONFIG,\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n const statements: MergeStatement[] = [];\n\n for (const child of tree.rootNode.children) {\n if (child.type === 'comment') continue;\n\n // Top-level alias/import/require/use (rare but possible outside modules)\n if (isImportLike(child)) {\n const text = source.slice(child.startIndex, child.endIndex);\n imports.push({ key: text.trim(), text });\n importAnchors.push(text);\n continue;\n }\n\n const moduleName = getModuleName(child);\n statements.push({\n key: moduleName,\n kind: moduleName ? 'declaration' : 'other',\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n\n return { imports, importAnchors, statements };\n },\n renderImports(imports) {\n return imports.map((entry) => entry.text);\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n const rootChildren = tree.rootNode.children;\n\n for (let i = 0; i < rootChildren.length; i++) {\n const child = rootChildren[i];\n const moduleName = getModuleName(child);\n if (!moduleName) continue;\n\n // Look for @moduledoc inside the do_block\n let docstring: DocstringInfo | null = null;\n const doBlock = getDoBlock(child);\n const members = new Map<string, MemberDocstrings>();\n\n if (doBlock) {\n const bodyChildren = doBlock.children;\n\n // Find @moduledoc\n for (const bodyChild of bodyChildren) {\n if (isDocAttribute(bodyChild) === 'moduledoc') {\n docstring = {\n text: source.slice(bodyChild.startIndex, bodyChild.endIndex),\n startIndex: bodyChild.startIndex,\n endIndex: bodyChild.endIndex,\n };\n break;\n }\n }\n\n // Find @doc + def pairs for member docstrings\n for (let j = 0; j < bodyChildren.length; j++) {\n const bodyChild = bodyChildren[j];\n const defName = getDefName(bodyChild);\n if (!defName) continue;\n\n // Look for preceding @doc attribute\n let memberDoc: DocstringInfo | null = null;\n for (let k = j - 1; k >= 0; k--) {\n const prev = bodyChildren[k];\n if (isDocAttribute(prev) === 'doc') {\n memberDoc = {\n text: source.slice(prev.startIndex, prev.endIndex),\n startIndex: prev.startIndex,\n endIndex: prev.endIndex,\n };\n break;\n }\n if (prev.type === 'comment') continue;\n break;\n }\n\n members.set(defName, {\n docstring: memberDoc,\n declStartIndex: bodyChild.startIndex,\n declColumn: bodyChild.startPosition.column,\n urlFingerprint: extractUrlFingerprint(bodyChild, ELIXIR_URL_FINGERPRINT_CONFIG),\n });\n }\n }\n\n result.set(moduleName, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members,\n });\n }\n\n return result;\n },\n};\n","import type Parser from 'tree-sitter';\nimport type { MergeAdapter, MergeStatement, MergeImport, DocstringInfo, SymbolDocstrings } from './types.js';\n\nconst GO_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['interpreted_string_literal'],\n contentNodeTypes: ['interpreted_string_literal_content'],\n interpolationNodeTypes: [],\n formatFunctionNames: ['Sprintf'],\n};\n\nfunction lastIdentifier(text: string): string | null {\n const matches = [...text.matchAll(/[A-Za-z_][A-Za-z0-9_]*/g)];\n return matches.length > 0 ? matches[matches.length - 1]![0] : null;\n}\n\nfunction receiverKey(node: Parser.SyntaxNode): string | null {\n const receiver = node.childForFieldName('receiver');\n if (!receiver) return null;\n return lastIdentifier(receiver.text);\n}\n\nfunction declarationKey(node: Parser.SyntaxNode): string | null {\n switch (node.type) {\n case 'package_clause': {\n const pkg = lastIdentifier(node.text);\n return pkg ? `__package:${pkg}` : '__package:';\n }\n case 'type_declaration': {\n const spec = node.firstNamedChild?.type === 'type_spec' ? node.firstNamedChild : node.namedChildren[0];\n const nameNode = spec?.childForFieldName('name');\n return nameNode?.text ?? null;\n }\n case 'function_declaration': {\n return node.childForFieldName('name')?.text ?? null;\n }\n case 'method_declaration': {\n const name = node.childForFieldName('name')?.text ?? null;\n const receiver = receiverKey(node);\n return name && receiver ? `method:${receiver}.${name}` : name;\n }\n case 'const_declaration':\n case 'var_declaration': {\n return node.text.split(/\\s+/).slice(0, 3).join(' ');\n }\n default:\n return null;\n }\n}\n\nfunction importEntries(node: Parser.SyntaxNode, source: string): MergeImport[] {\n const entries: MergeImport[] = [];\n\n const collect = (spec: Parser.SyntaxNode): void => {\n const path = spec.childForFieldName('path')?.text ?? spec.text;\n const name = spec.childForFieldName('name')?.text ?? '';\n const text = source.slice(spec.startIndex, spec.endIndex);\n entries.push({\n key: `${name}:${path.replace(/^\"|\"$/g, '')}`,\n text,\n });\n };\n\n for (const child of node.namedChildren) {\n if (child.type === 'import_spec') {\n collect(child);\n continue;\n }\n if (child.type === 'import_spec_list') {\n for (const spec of child.namedChildren) {\n if (spec.type === 'import_spec') collect(spec);\n }\n }\n }\n\n return entries;\n}\n\nfunction collectPrecedingGoComments(\n children: Parser.SyntaxNode[],\n index: number,\n source: string,\n): DocstringInfo | null {\n let lastIdx = -1;\n let firstIdx = -1;\n for (let k = index - 1; k >= 0; k--) {\n const prev = children[k];\n if (prev.type === 'comment') {\n const text = source.slice(prev.startIndex, prev.endIndex);\n if (text.startsWith('//')) {\n if (lastIdx === -1) lastIdx = k;\n firstIdx = k;\n } else {\n break;\n }\n } else {\n break;\n }\n }\n if (firstIdx === -1) return null;\n const first = children[firstIdx];\n const last = children[lastIdx];\n return { text: source.slice(first.startIndex, last.endIndex), startIndex: first.startIndex, endIndex: last.endIndex };\n}\n\nexport const goMergeAdapter: MergeAdapter = {\n language: 'go',\n grammarModule: 'tree-sitter-go',\n testFilePatterns: [/_test\\.go$/],\n urlFingerprintConfig: GO_URL_FINGERPRINT_CONFIG,\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n let importInsertionAnchor: string | undefined;\n const statements: MergeStatement[] = [];\n\n for (const child of tree.rootNode.children) {\n if (child.type === 'comment') continue;\n\n if (child.type === 'package_clause') {\n importInsertionAnchor = source.slice(child.startIndex, child.endIndex);\n }\n\n if (child.type === 'import_declaration') {\n imports.push(...importEntries(child, source));\n importAnchors.push(source.slice(child.startIndex, child.endIndex));\n continue;\n }\n\n const key = declarationKey(child);\n statements.push({\n key,\n kind: key ? 'declaration' : 'other',\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n\n return { imports, importAnchors, importInsertionAnchor, statements };\n },\n renderImports(imports) {\n if (imports.length === 0) return [];\n if (imports.length === 1) return [`import ${imports[0]!.text}`];\n return [`import (\\n${imports.map((entry) => ` ${entry.text}`).join('\\n')}\\n)`];\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n const rootChildren = tree.rootNode.children;\n\n for (let i = 0; i < rootChildren.length; i++) {\n const child = rootChildren[i];\n const key = declarationKey(child);\n if (!key || key.startsWith('__package:')) continue;\n\n const docstring = collectPrecedingGoComments(rootChildren, i, source);\n result.set(key, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members: new Map(),\n });\n }\n\n return result;\n },\n};\n","import type Parser from 'tree-sitter';\nimport type {\n MergeAdapter,\n MergeStatement,\n MergeImport,\n MergeMember,\n DeepMergeSymbol,\n DocstringInfo,\n SymbolDocstrings,\n MemberDocstrings,\n} from './types.js';\nimport { extractUrlFingerprint } from './url-fingerprint.js';\n\nconst KOTLIN_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['string_literal'],\n contentNodeTypes: ['string_content'],\n interpolationNodeTypes: ['interpolated_expression'],\n};\n\nfunction extractDeclarationName(node: Parser.SyntaxNode): string | null {\n if (node.type === 'class_declaration') {\n // Handles class, data class, enum class, etc.\n const nameNode = node.children.find((c) => c.type === 'type_identifier');\n return nameNode?.text ?? null;\n }\n if (node.type === 'function_declaration') {\n const nameNode = node.children.find((c) => c.type === 'simple_identifier');\n return nameNode?.text ?? null;\n }\n if (node.type === 'object_declaration') {\n const nameNode = node.children.find((c) => c.type === 'type_identifier');\n return nameNode?.text ?? null;\n }\n if (node.type === 'type_alias') {\n const nameNode = node.children.find((c) => c.type === 'type_identifier');\n return nameNode?.text ?? null;\n }\n if (node.type === 'property_declaration') {\n const nameNode = node.children.find((c) => c.type === 'variable_declaration');\n if (nameNode) {\n const id = nameNode.children.find((c) => c.type === 'simple_identifier');\n return id?.text ?? null;\n }\n }\n return null;\n}\n\nfunction findPrecedingKdoc(children: Parser.SyntaxNode[], index: number, source: string): DocstringInfo | null {\n for (let k = index - 1; k >= 0; k--) {\n const prev = children[k];\n if (prev.type === 'multiline_comment') {\n const text = source.slice(prev.startIndex, prev.endIndex);\n if (text.startsWith('/**')) {\n return { text, startIndex: prev.startIndex, endIndex: prev.endIndex };\n }\n return null;\n }\n if (prev.type === 'line_comment') continue;\n return null;\n }\n return null;\n}\n\nfunction extractKotlinClassMembers(classBody: Parser.SyntaxNode, source: string): MergeMember[] {\n const members: MergeMember[] = [];\n const children = classBody.namedChildren;\n\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n let memberName: string | null = null;\n\n if (child.type === 'property_declaration') {\n const varDecl = child.children.find((c) => c.type === 'variable_declaration');\n memberName = varDecl?.children.find((c) => c.type === 'simple_identifier')?.text ?? null;\n } else if (child.type === 'function_declaration') {\n memberName = child.children.find((c) => c.type === 'simple_identifier')?.text ?? null;\n } else if (child.type === 'companion_object') {\n memberName = 'companion';\n }\n\n if (!memberName) continue;\n\n // Fold trailing getter/setter into the property's text span\n let endIdx = child.endIndex;\n if (child.type === 'property_declaration') {\n while (i + 1 < children.length) {\n const next = children[i + 1];\n if (next.type === 'getter' || next.type === 'setter') {\n endIdx = next.endIndex;\n i++;\n } else {\n break;\n }\n }\n }\n\n // Include preceding KDoc comment in the text span so deep merge\n // inserts the member with its documentation intact.\n let startIdx = child.startIndex;\n for (let k = i - 1; k >= 0; k--) {\n const prev = children[k];\n if (prev.type === 'multiline_comment') {\n const text = source.slice(prev.startIndex, prev.endIndex);\n if (text.startsWith('/**')) startIdx = prev.startIndex;\n break;\n }\n if (prev.type === 'line_comment') continue;\n break;\n }\n\n members.push({ key: memberName, text: source.slice(startIdx, endIdx), startIndex: startIdx, endIndex: endIdx });\n }\n\n return members;\n}\n\n/**\n * KDoc signature that identifies a generator-emitted service accessor inside\n * the WorkOS class. The Kotlin client emitter writes every accessor with this\n * exact doc preamble — when the existing file carries a member with this doc\n * but the regenerated content omits it, the member is stale (its mount target\n * was remapped or removed) and gets pruned.\n */\nconst KOTLIN_MANAGED_ACCESSOR_DOC =\n /\\/\\*\\*[\\s\\S]*?Lazily-constructed \\[[^\\]]+\\] accessor for this \\[WorkOS\\] client\\.[\\s\\S]*?\\*\\//;\n\nexport const kotlinMergeAdapter: MergeAdapter = {\n language: 'kotlin',\n grammarModule: 'tree-sitter-kotlin',\n testFilePatterns: [/Test\\.kt$/],\n urlFingerprintConfig: KOTLIN_URL_FINGERPRINT_CONFIG,\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n const statements: MergeStatement[] = [];\n\n for (const child of tree.rootNode.children) {\n if (child.type === 'multiline_comment' || child.type === 'line_comment') continue;\n\n if (child.type === 'import_list') {\n const fullText = source.slice(child.startIndex, child.endIndex);\n importAnchors.push(fullText);\n for (const imp of child.namedChildren) {\n if (imp.type === 'import_header') {\n const text = source.slice(imp.startIndex, imp.endIndex).trim();\n // Key on the full import path\n const idNode = imp.children.find((c) => c.type === 'identifier');\n const key = idNode?.text ?? text;\n imports.push({ key, text });\n }\n }\n continue;\n }\n\n const name = extractDeclarationName(child);\n statements.push({\n key: name,\n kind: name ? 'declaration' : 'other',\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n\n return { imports, importAnchors, statements };\n },\n renderImports(imports) {\n return imports.map((entry) => entry.text);\n },\n isManagedMember(member) {\n return KOTLIN_MANAGED_ACCESSOR_DOC.test(member.text);\n },\n shouldSkipDeepMerge(_symbolName, existingMemberKeys, newMembers) {\n // Skip if new members reference instance properties that don't exist in the target\n const newText = newMembers.map((m) => m.text).join('\\n');\n for (const match of newText.matchAll(/this\\.(\\w+)/g)) {\n const propName = match[1];\n if (propName && !existingMemberKeys.has(propName)) return true;\n }\n return false;\n },\n extractMembers(tree, source) {\n const result = new Map<string, DeepMergeSymbol>();\n\n for (const child of tree.rootNode.children) {\n if (child.type !== 'class_declaration') continue;\n const nameNode = child.children.find((c) => c.type === 'type_identifier');\n if (!nameNode) continue;\n const body = child.children.find((c) => c.type === 'class_body');\n if (!body) continue;\n\n const members = extractKotlinClassMembers(body, source);\n const firstMember = body.firstNamedChild;\n const memberIndent = firstMember ? ' '.repeat(firstMember.startPosition.column) : undefined;\n result.set(nameNode.text, { members, bodyEndLine: body.endPosition.row, memberIndent });\n }\n\n return result;\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n const rootChildren = tree.rootNode.children;\n\n for (let i = 0; i < rootChildren.length; i++) {\n const child = rootChildren[i];\n const name = extractDeclarationName(child);\n if (!name) continue;\n\n const docstring = findPrecedingKdoc(rootChildren, i, source);\n const members = new Map<string, MemberDocstrings>();\n\n // Extract member docstrings for classes\n if (child.type === 'class_declaration') {\n const body = child.children.find((c) => c.type === 'class_body' || c.type === 'enum_class_body');\n if (body) {\n const bodyChildren = body.children;\n for (let j = 0; j < bodyChildren.length; j++) {\n const member = bodyChildren[j];\n const memberName = extractDeclarationName(member);\n if (!memberName) continue;\n const memberDoc = findPrecedingKdoc(bodyChildren, j, source);\n members.set(memberName, {\n docstring: memberDoc,\n declStartIndex: member.startIndex,\n declColumn: member.startPosition.column,\n urlFingerprint: extractUrlFingerprint(member, KOTLIN_URL_FINGERPRINT_CONFIG),\n });\n }\n }\n }\n\n result.set(name, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members,\n });\n }\n\n return result;\n },\n};\n","import type Parser from 'tree-sitter';\nimport { normalizeJsExtension } from '../../utils/naming.js';\nimport type {\n MergeAdapter,\n MergeStatement,\n MergeImport,\n DeepMergeSymbol,\n MergeMember,\n DocstringInfo,\n SymbolDocstrings,\n} from './types.js';\nimport { extractUrlFingerprint } from './url-fingerprint.js';\n\nconst REEXPORT_PREFIX = '__export:';\n\nfunction extractDeclName(node: Parser.SyntaxNode): string | null {\n const nameNode = node.childForFieldName('name');\n if (nameNode) return nameNode.text;\n\n if (node.type === 'lexical_declaration') {\n const declarator = node.firstNamedChild;\n if (declarator?.type === 'variable_declarator') {\n const name = declarator.childForFieldName('name');\n if (name) return name.text;\n }\n }\n\n return null;\n}\n\nfunction extractNodeKey(node: Parser.SyntaxNode): { key: string | null; kind: MergeStatement['kind'] } {\n if (node.type === 'export_statement') {\n const decl = node.childForFieldName('declaration');\n if (decl) {\n return { key: extractDeclName(decl), kind: 'declaration' };\n }\n\n const source = node.childForFieldName('source');\n if (source) {\n return { key: `${REEXPORT_PREFIX}${normalizeJsExtension(source.text)}`, kind: 'reexport' };\n }\n\n return { key: null, kind: 'other' };\n }\n return { key: extractDeclName(node), kind: extractDeclName(node) ? 'declaration' : 'other' };\n}\n\nfunction extractClassMembers(classBody: Parser.SyntaxNode, source: string): MergeMember[] {\n const members: MergeMember[] = [];\n for (const child of classBody.namedChildren) {\n if (child.type === 'method_definition') {\n const nameNode = child.childForFieldName('name');\n if (nameNode && nameNode.text !== 'constructor') {\n members.push({ key: nameNode.text, text: source.slice(child.startIndex, child.endIndex) });\n }\n } else if (child.type === 'public_field_definition') {\n const nameNode = child.childForFieldName('name');\n if (nameNode) {\n // tree-sitter may exclude the trailing semicolon from\n // public_field_definition nodes — include it if present\n let endIdx = child.endIndex;\n if (source[endIdx] === ';') {\n endIdx += 1;\n }\n members.push({ key: nameNode.text, text: source.slice(child.startIndex, endIdx) });\n }\n }\n }\n return members;\n}\n\nfunction extractInterfaceMembers(body: Parser.SyntaxNode, source: string): MergeMember[] {\n const members: MergeMember[] = [];\n for (const child of body.namedChildren) {\n if (child.type === 'property_signature' || child.type === 'method_signature') {\n const nameNode = child.childForFieldName('name');\n if (nameNode) {\n members.push({ key: nameNode.text, text: source.slice(child.startIndex, child.endIndex) });\n }\n }\n }\n return members;\n}\n\nfunction extractEnumMembers(body: Parser.SyntaxNode, source: string): MergeMember[] {\n const members: MergeMember[] = [];\n for (const child of body.namedChildren) {\n if (child.type === 'enum_assignment') {\n const nameNode = child.childForFieldName('name');\n if (nameNode) {\n members.push({ key: nameNode.text, text: source.slice(child.startIndex, child.endIndex) });\n }\n } else if (child.type === 'property_identifier') {\n members.push({ key: child.text, text: source.slice(child.startIndex, child.endIndex) });\n }\n }\n return members;\n}\n\nfunction isCommentNode(node: Parser.SyntaxNode): boolean {\n // tree-sitter extras (comments) may report the parent node's type\n // instead of 'comment' — check grammarType as fallback\n return node.type === 'comment' || (node as any).grammarType === 'comment';\n}\n\nfunction findPrecedingDocstring(children: Parser.SyntaxNode[], index: number, source: string): DocstringInfo | null {\n for (let k = index - 1; k >= 0; k--) {\n const prev = children[k];\n if (isCommentNode(prev)) {\n const text = source.slice(prev.startIndex, prev.endIndex);\n if (text.startsWith('/**')) {\n return { text, startIndex: prev.startIndex, endIndex: prev.endIndex };\n }\n return null;\n }\n if (prev.type === ',' || prev.type === ';' || prev.type === '{') continue;\n return null;\n }\n return null;\n}\n\nconst CLASS_MEMBER_TYPES = new Set(['method_definition', 'public_field_definition']);\nconst INTERFACE_MEMBER_TYPES = new Set(['property_signature', 'method_signature']);\nconst ENUM_MEMBER_TYPES = new Set(['enum_assignment', 'property_identifier']);\n\nconst NODE_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['string', 'template_string'],\n contentNodeTypes: ['string_fragment'],\n interpolationNodeTypes: ['template_substitution'],\n};\n\nfunction extractBodyMemberDocstrings(\n body: Parser.SyntaxNode,\n source: string,\n memberTypes: Set<string>,\n): Map<\n string,\n { docstring: DocstringInfo | null; declStartIndex: number; declColumn: number; urlFingerprint?: string }\n> {\n const result = new Map<\n string,\n { docstring: DocstringInfo | null; declStartIndex: number; declColumn: number; urlFingerprint?: string }\n >();\n const allChildren = body.children;\n for (let i = 0; i < allChildren.length; i++) {\n const child = allChildren[i];\n if (!memberTypes.has(child.type)) continue;\n let memberName: string | null = null;\n if (child.type === 'property_identifier') {\n memberName = child.text;\n } else {\n const nameNode = child.childForFieldName('name');\n if (nameNode) memberName = nameNode.text;\n }\n if (!memberName || memberName === 'constructor') continue;\n const docstring = findPrecedingDocstring(allChildren, i, source);\n const fp = extractUrlFingerprint(child, NODE_URL_FINGERPRINT_CONFIG);\n result.set(memberName, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n urlFingerprint: fp,\n });\n }\n return result;\n}\n\nexport const nodeMergeAdapter: MergeAdapter = {\n language: 'node',\n grammarModule: 'tree-sitter-typescript/bindings/node/typescript.js',\n normalizeReexport: normalizeJsExtension,\n testFilePatterns: [/\\.(spec|test)\\.[jt]sx?$/],\n urlFingerprintConfig: NODE_URL_FINGERPRINT_CONFIG,\n shouldSkipDeepMerge(_symbolName, existingMemberKeys, newMembers) {\n // If new members reference instance properties (this.X) that don't exist\n // in the target class, the merged code would be broken.\n // Exception: `this.workos` is always valid — it's the constructor-injected\n // WorkOS client instance that every generated resource class uses.\n const newText = newMembers.map((m) => m.text).join('\\n');\n for (const match of newText.matchAll(/this\\.(\\w+)/g)) {\n const propName = match[1];\n if (propName === 'workos') continue;\n if (propName && !existingMemberKeys.has(propName)) {\n return true;\n }\n }\n return false;\n },\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n const statements: MergeStatement[] = [];\n\n for (const child of tree.rootNode.children) {\n if (child.type === 'comment') continue;\n\n if (child.type === 'import_statement') {\n const text = source.slice(child.startIndex, child.endIndex);\n // Key on module path so `import { X }` and `import type { X }` from\n // the same module are treated as duplicates\n const sourceNode = child.childForFieldName('source');\n const modulePath = sourceNode ? normalizeJsExtension(sourceNode.text) : normalizeJsExtension(text.trim());\n imports.push({ key: modulePath, text });\n importAnchors.push(text);\n continue;\n }\n\n const { key, kind } = extractNodeKey(child);\n statements.push({\n key,\n kind,\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n\n return { imports, importAnchors, statements };\n },\n renderImports(imports) {\n return imports.map((entry) => entry.text);\n },\n extractMembers(tree, source) {\n const result = new Map<string, DeepMergeSymbol>();\n\n for (const child of tree.rootNode.children) {\n if (child.type !== 'export_statement') continue;\n const decl = child.childForFieldName('declaration');\n if (!decl) continue;\n\n const nameNode = decl.childForFieldName('name');\n if (!nameNode) continue;\n const symbolName = nameNode.text;\n\n if (decl.type === 'class_declaration') {\n const body = decl.childForFieldName('body');\n if (!body) continue;\n const members = extractClassMembers(body, source);\n const firstMember = body.firstNamedChild;\n const memberIndent = firstMember ? ' '.repeat(firstMember.startPosition.column) : undefined;\n result.set(symbolName, { members, bodyEndLine: body.endPosition.row, memberIndent });\n } else if (decl.type === 'interface_declaration') {\n const body = decl.childForFieldName('body');\n if (!body) continue;\n const members = extractInterfaceMembers(body, source);\n const firstMember = body.firstNamedChild;\n const memberIndent = firstMember ? ' '.repeat(firstMember.startPosition.column) : undefined;\n result.set(symbolName, { members, bodyEndLine: body.endPosition.row, memberIndent });\n } else if (decl.type === 'enum_declaration') {\n const body = decl.childForFieldName('body');\n if (!body) continue;\n const members = extractEnumMembers(body, source);\n const firstMember = body.firstNamedChild;\n const memberIndent = firstMember ? ' '.repeat(firstMember.startPosition.column) : undefined;\n result.set(symbolName, { members, bodyEndLine: body.endPosition.row, memberIndent });\n }\n }\n\n return result;\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n const rootChildren = tree.rootNode.children;\n\n for (let i = 0; i < rootChildren.length; i++) {\n const child = rootChildren[i];\n if (child.type !== 'export_statement') continue;\n const decl = child.childForFieldName('declaration');\n if (!decl) continue;\n const nameNode = decl.childForFieldName('name');\n if (!nameNode) continue;\n\n // Find preceding JSDoc for this top-level symbol\n const docstring = findPrecedingDocstring(rootChildren, i, source);\n\n // Extract member-level docstrings\n let members = new Map<string, { docstring: DocstringInfo | null; declStartIndex: number; declColumn: number }>();\n const body = decl.childForFieldName('body');\n if (body) {\n if (decl.type === 'class_declaration') {\n members = extractBodyMemberDocstrings(body, source, CLASS_MEMBER_TYPES);\n } else if (decl.type === 'interface_declaration') {\n members = extractBodyMemberDocstrings(body, source, INTERFACE_MEMBER_TYPES);\n } else if (decl.type === 'enum_declaration') {\n members = extractBodyMemberDocstrings(body, source, ENUM_MEMBER_TYPES);\n }\n }\n\n result.set(nameNode.text, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members,\n });\n }\n\n return result;\n },\n};\n","import type Parser from 'tree-sitter';\nimport type {\n MergeAdapter,\n MergeStatement,\n MergeImport,\n DocstringInfo,\n SymbolDocstrings,\n MemberDocstrings,\n} from './types.js';\nimport { extractUrlFingerprint } from './url-fingerprint.js';\n\nconst PHP_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['encapsed_string', 'string'],\n contentNodeTypes: ['string_content'],\n interpolationNodeTypes: ['variable_name'],\n};\n\nfunction extractPhpDeclarationName(node: Parser.SyntaxNode): string | null {\n switch (node.type) {\n case 'class_declaration':\n case 'interface_declaration':\n case 'trait_declaration':\n case 'enum_declaration':\n case 'function_definition': {\n const nameNode = node.childForFieldName('name');\n return nameNode?.text ?? null;\n }\n case 'namespace_definition': {\n const nameNode = node.childForFieldName('name');\n return nameNode ? `__namespace:${nameNode.text}` : '__namespace:';\n }\n default:\n return null;\n }\n}\n\nfunction findPhpDocstring(children: Parser.SyntaxNode[], index: number, source: string): DocstringInfo | null {\n for (let k = index - 1; k >= 0; k--) {\n const prev = children[k];\n if (prev.type === 'comment') {\n const text = source.slice(prev.startIndex, prev.endIndex);\n if (text.startsWith('/**')) {\n return { text, startIndex: prev.startIndex, endIndex: prev.endIndex };\n }\n return null;\n }\n if (prev.type === ';' || prev.type === '{') continue;\n return null;\n }\n return null;\n}\n\nexport const phpMergeAdapter: MergeAdapter = {\n language: 'php',\n grammarModule: 'tree-sitter-php',\n testFilePatterns: [/Test\\.php$/],\n urlFingerprintConfig: PHP_URL_FINGERPRINT_CONFIG,\n resolveGrammar: (mod) => {\n // ESM import wraps in { default: { php, php_only } }\n const m = (mod as Record<string, unknown>)?.default ?? mod;\n if (typeof m === 'object' && m !== null && 'php' in (m as Record<string, unknown>))\n return (m as { php: unknown }).php;\n return m;\n },\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n let importInsertionAnchor: string | undefined;\n const statements: MergeStatement[] = [];\n\n for (const child of tree.rootNode.children) {\n if (child.type === 'comment') continue;\n\n if (child.type === 'namespace_definition') {\n importInsertionAnchor = source.slice(child.startIndex, child.endIndex);\n }\n\n if (child.type === 'namespace_use_declaration') {\n const text = source.slice(child.startIndex, child.endIndex);\n imports.push({ key: text.trim(), text });\n importAnchors.push(text);\n continue;\n }\n\n const declarationName = extractPhpDeclarationName(child);\n const kind: MergeStatement['kind'] = declarationName ? 'declaration' : 'other';\n\n statements.push({\n key: declarationName,\n kind,\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n\n return { imports, importAnchors, importInsertionAnchor, statements };\n },\n renderImports(imports) {\n return imports.map((entry) => entry.text);\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n const rootChildren = tree.rootNode.children;\n\n for (let i = 0; i < rootChildren.length; i++) {\n const child = rootChildren[i];\n const name = extractPhpDeclarationName(child);\n if (!name || name.startsWith('__namespace:')) continue;\n\n const docstring = findPhpDocstring(rootChildren, i, source);\n const members = new Map<string, MemberDocstrings>();\n\n const body = child.childForFieldName('body');\n if (body) {\n const bodyChildren = body.children;\n for (let j = 0; j < bodyChildren.length; j++) {\n const member = bodyChildren[j];\n if (member.type !== 'method_declaration') continue;\n const memberName = member.childForFieldName('name')?.text;\n if (!memberName) continue;\n const memberDoc = findPhpDocstring(bodyChildren, j, source);\n members.set(memberName, {\n docstring: memberDoc,\n declStartIndex: member.startIndex,\n declColumn: member.startPosition.column,\n urlFingerprint: extractUrlFingerprint(member, PHP_URL_FINGERPRINT_CONFIG),\n });\n }\n }\n\n result.set(name, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members,\n });\n }\n\n return result;\n },\n};\n","import type Parser from 'tree-sitter';\nimport type {\n MergeAdapter,\n MergeStatement,\n MergeImport,\n DocstringInfo,\n SymbolDocstrings,\n MemberDocstrings,\n} from './types.js';\nimport { extractUrlFingerprint } from './url-fingerprint.js';\n\nconst PYTHON_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['string'],\n contentNodeTypes: ['string_content'],\n interpolationNodeTypes: ['interpolation'],\n};\n\nfunction extractPythonDeclarationName(node: Parser.SyntaxNode): string | null {\n if (node.type === 'class_definition' || node.type === 'function_definition') {\n const nameNode = node.childForFieldName('name');\n return nameNode?.text ?? null;\n }\n\n // Detect `__all__ = [...]` assignments so they get a key and can be deduplicated\n if (node.type === 'expression_statement') {\n const firstChild = node.firstNamedChild;\n if (firstChild?.type === 'assignment') {\n const left = firstChild.childForFieldName('left');\n if (left?.type === 'identifier' && left.text === '__all__') {\n return '__all__';\n }\n }\n }\n\n return null;\n}\n\nfunction extractPythonDocstring(bodyNode: Parser.SyntaxNode, source: string): DocstringInfo | null {\n // Python docstrings are the first expression_statement in a body block\n // where the expression is a string literal\n for (const child of bodyNode.namedChildren) {\n if (child.type === 'expression_statement') {\n const expr = child.firstNamedChild;\n if (expr?.type === 'string') {\n const text = source.slice(child.startIndex, child.endIndex);\n return { text, startIndex: child.startIndex, endIndex: child.endIndex };\n }\n }\n // Only the FIRST statement can be a docstring\n break;\n }\n return null;\n}\n\nfunction collectPrecedingPythonComments(\n children: Parser.SyntaxNode[],\n index: number,\n source: string,\n): DocstringInfo | null {\n let lastIdx = -1;\n let firstIdx = -1;\n for (let k = index - 1; k >= 0; k--) {\n const prev = children[k];\n if (prev.type === 'comment') {\n if (lastIdx === -1) lastIdx = k;\n firstIdx = k;\n } else {\n break;\n }\n }\n if (firstIdx === -1) return null;\n const first = children[firstIdx];\n const last = children[lastIdx];\n return { text: source.slice(first.startIndex, last.endIndex), startIndex: first.startIndex, endIndex: last.endIndex };\n}\n\nexport const pythonMergeAdapter: MergeAdapter = {\n language: 'python',\n grammarModule: 'tree-sitter-python',\n testFilePatterns: [/(?:^|\\/)test_.*\\.py$/, /_test\\.py$/],\n urlFingerprintConfig: PYTHON_URL_FINGERPRINT_CONFIG,\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n const statements: MergeStatement[] = [];\n\n for (const child of tree.rootNode.children) {\n if (child.type === 'comment') continue;\n\n if (child.type === 'import_statement' || child.type === 'import_from_statement') {\n const text = source.slice(child.startIndex, child.endIndex);\n imports.push({ key: text.trim(), text });\n importAnchors.push(text);\n continue;\n }\n\n const declarationName = extractPythonDeclarationName(child);\n const kind: MergeStatement['kind'] = declarationName ? 'declaration' : 'other';\n\n statements.push({\n key: declarationName,\n kind,\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n\n return { imports, importAnchors, statements };\n },\n renderImports(imports) {\n return imports.map((entry) => entry.text);\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n const rootChildren = tree.rootNode.children;\n\n for (let i = 0; i < rootChildren.length; i++) {\n const child = rootChildren[i];\n const name = extractPythonDeclarationName(child);\n if (!name) continue;\n\n // Python: class/function docstrings are inside the body, OR use # comments before\n let docstring: DocstringInfo | null = null;\n const body = child.childForFieldName('body');\n if (body) {\n docstring = extractPythonDocstring(body, source);\n }\n // Fallback: check for # comments before the declaration\n if (!docstring) {\n docstring = collectPrecedingPythonComments(rootChildren, i, source);\n }\n\n const members = new Map<string, MemberDocstrings>();\n\n // Extract method docstrings for classes\n if (child.type === 'class_definition' && body) {\n for (const member of body.namedChildren) {\n if (member.type !== 'function_definition') continue;\n const memberName = member.childForFieldName('name')?.text;\n if (!memberName) continue;\n\n let memberDoc: DocstringInfo | null = null;\n const memberBody = member.childForFieldName('body');\n if (memberBody) {\n memberDoc = extractPythonDocstring(memberBody, source);\n }\n\n members.set(memberName, {\n docstring: memberDoc,\n declStartIndex: member.startIndex,\n declColumn: member.startPosition.column,\n urlFingerprint: extractUrlFingerprint(member, PYTHON_URL_FINGERPRINT_CONFIG),\n });\n }\n }\n\n result.set(name, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members,\n });\n }\n\n return result;\n },\n};\n","import type Parser from 'tree-sitter';\nimport type {\n MergeAdapter,\n MergeStatement,\n MergeImport,\n DocstringInfo,\n SymbolDocstrings,\n MemberDocstrings,\n} from './types.js';\nimport { extractUrlFingerprint } from './url-fingerprint.js';\n\nconst RUBY_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['string'],\n contentNodeTypes: ['string_content'],\n interpolationNodeTypes: ['interpolation'],\n};\n\nfunction isRequireCall(node: Parser.SyntaxNode): boolean {\n if (node.type !== 'call') return false;\n const method = node.childForFieldName('method');\n if (!method) return false;\n return method.text === 'require' || method.text === 'require_relative';\n}\n\nfunction extractRubyDeclarationName(node: Parser.SyntaxNode): string | null {\n if (node.type !== 'class' && node.type !== 'module') return null;\n const nameNode = node.childForFieldName('name');\n return nameNode?.text ?? null;\n}\n\nfunction collectPrecedingRubyComments(\n children: Parser.SyntaxNode[],\n index: number,\n source: string,\n): DocstringInfo | null {\n let lastIdx = -1;\n let firstIdx = -1;\n for (let k = index - 1; k >= 0; k--) {\n const prev = children[k];\n const nodeType = (prev as any).grammarType ?? prev.type;\n if (nodeType === 'comment') {\n const text = source.slice(prev.startIndex, prev.endIndex);\n if (text.startsWith('#')) {\n if (lastIdx === -1) lastIdx = k;\n firstIdx = k;\n } else {\n break;\n }\n } else {\n break;\n }\n }\n if (firstIdx === -1) return null;\n const first = children[firstIdx];\n const last = children[lastIdx];\n return { text: source.slice(first.startIndex, last.endIndex), startIndex: first.startIndex, endIndex: last.endIndex };\n}\n\nexport const rubyMergeAdapter: MergeAdapter = {\n language: 'ruby',\n grammarModule: 'tree-sitter-ruby',\n testFilePatterns: [/_test\\.rb$/, /_spec\\.rb$/],\n urlFingerprintConfig: RUBY_URL_FINGERPRINT_CONFIG,\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n const statements: MergeStatement[] = [];\n\n for (const child of tree.rootNode.children) {\n if (child.type === 'comment') continue;\n\n const declarationName = extractRubyDeclarationName(child);\n if (isRequireCall(child)) {\n const text = source.slice(child.startIndex, child.endIndex);\n imports.push({ key: text.trim(), text });\n importAnchors.push(text);\n continue;\n }\n\n const kind: MergeStatement['kind'] = declarationName ? 'declaration' : 'other';\n\n statements.push({\n key: declarationName,\n kind,\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n\n return { imports, importAnchors, statements };\n },\n renderImports(imports) {\n return imports.map((entry) => entry.text);\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n const rootChildren = tree.rootNode.children;\n\n for (let i = 0; i < rootChildren.length; i++) {\n const child = rootChildren[i];\n const name = extractRubyDeclarationName(child);\n if (!name) continue;\n\n const docstring = collectPrecedingRubyComments(rootChildren, i, source);\n const members = new Map<string, MemberDocstrings>();\n\n // Ruby class/module bodies: comments may appear in class children\n // (before body_statement) or in body_statement children (between methods)\n if (child.type === 'class' || child.type === 'module') {\n const allClassChildren = child.children;\n const body = child.childForFieldName('body');\n\n // Check for comment before body_statement in class children\n // (docstring for the first method)\n let firstMethodDocFromClass: DocstringInfo | null = null;\n for (let j = 0; j < allClassChildren.length; j++) {\n if (allClassChildren[j] === body || allClassChildren[j].type === 'body_statement') {\n firstMethodDocFromClass = collectPrecedingRubyComments(allClassChildren, j, source);\n break;\n }\n }\n\n if (body) {\n const bodyChildren = body.children;\n let firstMethodHandled = false;\n for (let j = 0; j < bodyChildren.length; j++) {\n const member = bodyChildren[j];\n if (member.type !== 'method') continue;\n const memberName = member.childForFieldName('name')?.text;\n if (!memberName) continue;\n\n let memberDoc: DocstringInfo | null;\n if (!firstMethodHandled && firstMethodDocFromClass) {\n memberDoc = firstMethodDocFromClass;\n firstMethodHandled = true;\n } else {\n memberDoc = collectPrecedingRubyComments(bodyChildren, j, source);\n firstMethodHandled = true;\n }\n\n members.set(memberName, {\n docstring: memberDoc,\n declStartIndex: member.startIndex,\n declColumn: member.startPosition.column,\n urlFingerprint: extractUrlFingerprint(member, RUBY_URL_FINGERPRINT_CONFIG),\n });\n }\n }\n }\n\n result.set(name, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members,\n });\n }\n\n return result;\n },\n};\n","import type Parser from 'tree-sitter';\nimport type { MergeAdapter, MergeStatement, MergeImport, DocstringInfo, SymbolDocstrings } from './types.js';\n\nconst RUST_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['string_literal'],\n contentNodeTypes: ['string_content'],\n interpolationNodeTypes: [],\n};\n\nfunction declarationKey(node: Parser.SyntaxNode): string | null {\n switch (node.type) {\n case 'struct_item':\n case 'enum_item':\n case 'function_item':\n case 'trait_item':\n case 'type_item':\n case 'const_item': {\n return node.childForFieldName('name')?.text ?? null;\n }\n case 'impl_item': {\n const typeName = node.childForFieldName('type')?.text ?? 'unknown';\n const traitName = node.childForFieldName('trait')?.text;\n return traitName ? `impl:${traitName}->${typeName}` : `impl:${typeName}`;\n }\n default:\n return null;\n }\n}\n\nfunction collectPrecedingRustDocComments(\n children: Parser.SyntaxNode[],\n index: number,\n source: string,\n): DocstringInfo | null {\n let lastIdx = -1;\n let firstIdx = -1;\n for (let k = index - 1; k >= 0; k--) {\n const prev = children[k];\n if (prev.type === 'line_comment') {\n const text = source.slice(prev.startIndex, prev.endIndex);\n if (text.startsWith('///')) {\n if (lastIdx === -1) lastIdx = k;\n firstIdx = k;\n } else {\n break;\n }\n } else {\n break;\n }\n }\n if (firstIdx === -1) return null;\n const first = children[firstIdx];\n const last = children[lastIdx];\n return { text: source.slice(first.startIndex, last.endIndex), startIndex: first.startIndex, endIndex: last.endIndex };\n}\n\nexport const rustMergeAdapter: MergeAdapter = {\n language: 'rust',\n grammarModule: 'tree-sitter-rust',\n testFilePatterns: [/_test\\.rs$/, /(?:^|\\/)tests\\/.*\\.rs$/],\n urlFingerprintConfig: RUST_URL_FINGERPRINT_CONFIG,\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n const statements: MergeStatement[] = [];\n\n for (const child of tree.rootNode.children) {\n if (child.type === 'comment') continue;\n\n if (child.type === 'use_declaration') {\n const text = source.slice(child.startIndex, child.endIndex);\n imports.push({ key: text.trim(), text });\n importAnchors.push(text);\n continue;\n }\n\n const key = declarationKey(child);\n statements.push({\n key,\n kind: key ? 'declaration' : 'other',\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n\n return { imports, importAnchors, statements };\n },\n renderImports(imports) {\n return imports.map((entry) => entry.text);\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n const rootChildren = tree.rootNode.children;\n\n for (let i = 0; i < rootChildren.length; i++) {\n const child = rootChildren[i];\n const key = declarationKey(child);\n if (!key) continue;\n\n const docstring = collectPrecedingRustDocComments(rootChildren, i, source);\n result.set(key, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members: new Map(),\n });\n }\n\n return result;\n },\n};\n","import type { MergeAdapter } from './types.js';\nimport { dotnetMergeAdapter } from './dotnet.js';\nimport { elixirMergeAdapter } from './elixir.js';\nimport { goMergeAdapter } from './go.js';\nimport { kotlinMergeAdapter } from './kotlin.js';\nimport { nodeMergeAdapter } from './node.js';\nimport { phpMergeAdapter } from './php.js';\nimport { pythonMergeAdapter } from './python.js';\nimport { rubyMergeAdapter } from './ruby.js';\nimport { rustMergeAdapter } from './rust.js';\n\nconst adapters = new Map<string, MergeAdapter>([\n ['dotnet', dotnetMergeAdapter],\n ['elixir', elixirMergeAdapter],\n ['go', goMergeAdapter],\n ['kotlin', kotlinMergeAdapter],\n ['node', nodeMergeAdapter],\n ['php', phpMergeAdapter],\n ['python', pythonMergeAdapter],\n ['ruby', rubyMergeAdapter],\n ['rust', rustMergeAdapter],\n]);\n\nexport function getMergeAdapter(language: string): MergeAdapter | undefined {\n return adapters.get(language);\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","/**\n * AST-level file merger using tree-sitter.\n *\n * When generating into a directory that already contains files, the merger\n * parses both the existing and generated content, detects top-level symbols,\n * and only appends symbols that don't already exist. Hand-written code is\n * never modified or removed.\n *\n * Supports any language with a tree-sitter grammar package.\n */\n\nimport Parser from 'tree-sitter';\nimport { getMergeAdapter } from './merge-adapters/index.js';\nimport type { MergeImport, ParsedMergeFile, SymbolDocstrings } from './merge-adapters/types.js';\n\n// Cache parser instances per language\nconst parserCache = new Map<string, Parser>();\n\nimport { safeParse } from '../utils/tree-sitter.js';\n\n// --- @deprecated preservation ---\n\n/**\n * When replacing an existing docstring with a generated one, carry over any\n * `@deprecated` lines from the existing doc that aren't present in the\n * generated doc. This prevents hand-written deprecation notices from being\n * silently dropped during docstring refresh.\n */\nfunction preserveDeprecatedTags(existingDoc: string, generatedDoc: string): string {\n // Check if the existing docstring contains @deprecated anywhere\n if (!existingDoc.includes('@deprecated')) return generatedDoc;\n\n // If generated doc already has @deprecated, no need to merge\n if (generatedDoc.includes('@deprecated')) return generatedDoc;\n\n // Extract the @deprecated content from the existing doc.\n // Handle both multi-line (`* @deprecated ...`) and one-liner (`/** @deprecated ... */`) formats.\n const deprecatedParts: string[] = [];\n for (const line of existingDoc.split('\\n')) {\n if (/@deprecated\\b/.test(line)) {\n // Normalize to JSDoc member format: ` * @deprecated ...`\n const match = line.match(/@deprecated\\b.*/);\n if (match) {\n // Strip trailing */ and whitespace (from one-liner JSDoc like `/** @deprecated ... */`)\n const cleaned = match[0].replace(/\\s*\\*\\/\\s*$/, '');\n deprecatedParts.push(` * ${cleaned}`);\n }\n }\n }\n if (deprecatedParts.length === 0) return generatedDoc;\n\n // Insert @deprecated lines before the closing */ of the generated doc\n const closingIdx = generatedDoc.lastIndexOf('*/');\n if (closingIdx === -1) return generatedDoc;\n const before = generatedDoc.slice(0, closingIdx);\n const after = generatedDoc.slice(closingIdx);\n return before + deprecatedParts.join('\\n') + '\\n ' + after;\n}\n\n// --- @oagen-ignore region helpers ---\n\ninterface IgnoredRegion {\n startIndex: number;\n endIndex: number;\n}\n\nfunction findIgnoredRegions(source: string): IgnoredRegion[] {\n const regions: IgnoredRegion[] = [];\n const startTag = '@oagen-ignore-start';\n const endTag = '@oagen-ignore-end';\n let searchFrom = 0;\n\n while (true) {\n const startIdx = source.indexOf(startTag, searchFrom);\n if (startIdx === -1) break;\n const endIdx = source.indexOf(endTag, startIdx + startTag.length);\n if (endIdx === -1) break; // Unclosed — silently ignore\n regions.push({ startIndex: startIdx, endIndex: endIdx + endTag.length });\n searchFrom = endIdx + endTag.length;\n }\n\n return regions;\n}\n\nfunction buildIgnoredSymbolNames(docstrings: Map<string, SymbolDocstrings>, regions: IgnoredRegion[]): Set<string> {\n if (regions.length === 0) return new Set();\n const ignored = new Set<string>();\n for (const [name, info] of docstrings) {\n if (regions.some((r) => info.declStartIndex >= r.startIndex && info.declStartIndex <= r.endIndex)) {\n ignored.add(name);\n }\n }\n return ignored;\n}\n\nfunction clampIndex(value: number, contentLength: number): number {\n if (!Number.isFinite(value)) return 0;\n if (value < 0) return 0;\n if (value > contentLength) return contentLength;\n return value;\n}\n\n/**\n * Resolve the declaration line start for insertion using the current content,\n * instead of relying on parser column arithmetic. This avoids misplaced inserts\n * when parser columns/offsets drift.\n */\nfunction declarationLineStart(content: string, declStartIndex: number): number {\n const idx = clampIndex(declStartIndex, content.length);\n const prevNewline = content.lastIndexOf('\\n', Math.max(0, idx - 1));\n return prevNewline === -1 ? 0 : prevNewline + 1;\n}\n\n/**\n * Resolve a docstring range by searching for the nearest matching text before\n * the declaration start. Falls back to parser-provided offsets when search fails.\n */\nfunction resolveDocRange(\n content: string,\n docText: string,\n declStartIndex: number,\n fallbackStart: number,\n fallbackEnd: number,\n): { start: number; end: number } {\n const safeDecl = clampIndex(declStartIndex, content.length);\n const safeFallbackStart = clampIndex(fallbackStart, content.length);\n const safeFallbackEnd = clampIndex(fallbackEnd, content.length);\n const found = content.lastIndexOf(docText, safeDecl);\n if (found !== -1) {\n return { start: found, end: found + docText.length };\n }\n return { start: safeFallbackStart, end: safeFallbackEnd };\n}\n\n/**\n * Check if a tree-sitter grammar is configured for the given language.\n */\nexport function hasGrammar(language: string): boolean {\n return getMergeAdapter(language) !== undefined;\n}\n\nasync function getParser(language: string): Promise<Parser> {\n const cached = parserCache.get(language);\n if (cached) return cached;\n\n const adapter = getMergeAdapter(language);\n if (!adapter) {\n throw new Error(\n `No tree-sitter grammar configured for language \"${language}\". ` +\n `Add a merge adapter and install the corresponding tree-sitter grammar package.`,\n );\n }\n\n const mod = await import(adapter.grammarModule);\n const exported = adapter.resolveGrammar ? adapter.resolveGrammar(mod) : mod;\n const grammar = (exported as { default?: unknown }).default ?? exported;\n const parser = new Parser();\n parser.setLanguage(grammar);\n parserCache.set(language, parser);\n return parser;\n}\n\ninterface ParsedSymbols {\n names: Set<string>;\n /** Trimmed text of unnamed top-level statements (for text-based dedup) */\n unnamedTexts: Set<string>;\n}\n\n/**\n * Extract all top-level symbol names (and unnamed statement texts) from source code.\n */\nexport async function extractTopLevelSymbols(source: string, language: string): Promise<ParsedSymbols> {\n const parser = await getParser(language);\n const adapter = getMergeAdapter(language);\n if (!adapter) {\n throw new Error(`No merge adapter configured for language \"${language}\"`);\n }\n if (typeof source !== 'string') {\n throw new Error(`extractTopLevelSymbols: expected string source, got ${typeof source}`);\n }\n const tree = safeParse(parser, source);\n const names = new Set<string>();\n const unnamedTexts = new Set<string>();\n const parsed = adapter.parseStatements(tree, source);\n\n for (const imp of parsed.imports) {\n names.add(imp.key);\n }\n for (const statement of parsed.statements) {\n if (statement.key) {\n names.add(statement.key);\n } else {\n unnamedTexts.add(statement.text.trim());\n }\n }\n\n return { names, unnamedTexts };\n}\n\n/** Convenience wrapper that returns only the name set. */\nexport async function extractTopLevelNames(source: string, language: string): Promise<Set<string>> {\n return (await extractTopLevelSymbols(source, language)).names;\n}\n\n/**\n * Extract top-level statements from generated source with their names\n * and exact text span.\n */\nexport async function extractStatements(source: string, language: string): Promise<ParsedMergeFile> {\n const parser = await getParser(language);\n const adapter = getMergeAdapter(language);\n if (!adapter) {\n throw new Error(`No merge adapter configured for language \"${language}\"`);\n }\n const tree = safeParse(parser, source);\n return adapter.parseStatements(tree, source);\n}\n\n/**\n * Return a map of top-level class name → { bodyEndLine, bodyEndCol } using\n * tree-sitter. `bodyEndLine` is 0-based. For brace-delimited classes the\n * end points at the closing brace line; for indentation-delimited classes\n * it points one past the last line of the class body.\n */\nexport async function extractClassEndLines(\n source: string,\n language: string,\n): Promise<Map<string, { bodyEndLine: number }>> {\n const parser = await getParser(language);\n const tree = safeParse(parser, source);\n const map = new Map<string, { bodyEndLine: number }>();\n\n function processClassNode(node: Parser.SyntaxNode): void {\n const nameNode =\n node.childForFieldName('name') ??\n node.children.find((c) => c.type === 'type_identifier' || c.type === 'identifier');\n if (!nameNode) return;\n const name = nameNode.text;\n\n const body =\n node.childForFieldName('body') ?? node.children.find((c) => c.type === 'class_body' || c.type === 'body');\n const endRow = body ? body.endPosition.row : node.endPosition.row;\n const lastChar = source[body ? body.endIndex - 1 : node.endIndex - 1];\n\n if (lastChar === '}') {\n map.set(name, { bodyEndLine: endRow });\n } else {\n map.set(name, { bodyEndLine: endRow + 1 });\n }\n }\n\n // Walk the tree recursively. Ruby (and Python) often nest target classes\n // inside `module Foo` / `class Outer:` containers, so a flat iteration over\n // root children would miss them.\n function walk(node: Parser.SyntaxNode): void {\n if (node.type === 'class' || node.type === 'class_definition' || node.type === 'class_declaration') {\n processClassNode(node);\n }\n if (node.type === 'decorated_definition') {\n for (const inner of node.namedChildren) {\n if (inner.type === 'class_definition') processClassNode(inner);\n }\n }\n if (node.type === 'export_statement') {\n for (const inner of node.namedChildren) {\n if (inner.type === 'class_declaration') processClassNode(inner);\n }\n }\n for (const child of node.namedChildren) walk(child);\n }\n for (const child of tree.rootNode.children) {\n walk(child);\n }\n\n return map;\n}\n\nexport interface MergeResult {\n content: string;\n added: number;\n preserved: number;\n changed: boolean;\n}\n\n/**\n * Merge generated content into an existing file.\n *\n * - Parses both files with tree-sitter\n * - Detects which top-level symbols already exist\n * - Appends only new symbols\n * - Never modifies or removes existing code\n * - Adds auto-generated header if not present\n */\nexport async function mergeIntoExisting(\n existingContent: string,\n generatedContent: string,\n language: string,\n header: string,\n): Promise<MergeResult> {\n const adapter = getMergeAdapter(language);\n if (!adapter) {\n throw new Error(`No merge adapter configured for language \"${language}\"`);\n }\n\n // Parse existing file once — extract both symbols and statements from the same AST pass\n const existingStatements = await extractStatements(existingContent, language);\n const generatedStatements = await extractStatements(generatedContent, language);\n\n const existingKeys = new Set<string>();\n const existingUnnamedTexts = new Set<string>();\n const existingImportKeys = new Set<string>();\n const existingReexports = new Set<string>();\n let lastImportEndIndex = -1;\n\n // Collect import keys AND imported identifiers (to prevent adding declarations\n // that clash with already-imported names)\n const existingImportedNames = new Set<string>();\n for (const imp of existingStatements.imports) {\n existingImportKeys.add(imp.key);\n // Extract identifiers from import text: import { Foo, Bar } from '...'\n const braceMatch = imp.text.match(/\\{([^}]+)\\}/);\n if (braceMatch) {\n for (const name of braceMatch[1].split(',')) {\n const trimmed = name.replace(/\\btype\\b/, '').trim();\n if (trimmed) existingImportedNames.add(trimmed);\n }\n }\n }\n for (const anchor of existingStatements.importAnchors) {\n const linesBefore = existingContent.slice(0, existingContent.indexOf(anchor)).split('\\n').length - 1;\n const stmtLines = anchor.split('\\n').length;\n lastImportEndIndex = linesBefore + stmtLines - 1;\n }\n if (lastImportEndIndex === -1 && existingStatements.importInsertionAnchor) {\n const linesBefore =\n existingContent.slice(0, existingContent.indexOf(existingStatements.importInsertionAnchor)).split('\\n').length -\n 1;\n const stmtLines = existingStatements.importInsertionAnchor.split('\\n').length;\n lastImportEndIndex = linesBefore + stmtLines - 1;\n }\n\n // Track all names exported by existing statements (both direct exports and\n // re-export aliases like `export { X as Y }`). Used to prevent the merger\n // from appending a re-export that introduces a duplicate exported name.\n const existingExportedNames = new Set<string>();\n\n for (const stmt of existingStatements.statements) {\n if (stmt.kind === 'reexport') {\n existingReexports.add(adapter.normalizeReexport ? adapter.normalizeReexport(stmt.text.trim()) : stmt.text.trim());\n // Collect aliased export names from re-exports\n const braceMatch = stmt.text.match(/\\{([^}]+)\\}/);\n if (braceMatch) {\n for (const part of braceMatch[1].split(',')) {\n const segments = part.trim().split(/\\s+as\\s+/);\n const exportedName = (segments[1] ?? segments[0]).trim();\n if (exportedName) existingExportedNames.add(exportedName);\n }\n }\n }\n if (stmt.key) {\n existingKeys.add(stmt.key);\n existingExportedNames.add(stmt.key);\n } else {\n existingUnnamedTexts.add(stmt.text.trim());\n }\n }\n\n const headerLine = header.trim();\n\n const newImports: MergeImport[] = [];\n const toAppend: string[] = [];\n let preserved = 0;\n\n for (const imp of generatedStatements.imports) {\n if (imp.text.trim() === headerLine) continue;\n if (existingImportKeys.has(imp.key)) {\n // The existing file already imports from this module path.\n // Check if the generated import adds identifiers not present in\n // the existing import — if so, create a supplemental import with\n // only the new identifiers. The supplemental participates in the\n // usage-based filter (below) so unused identifiers are dropped.\n const braceMatch = imp.text.match(/\\{([^}]+)\\}/);\n if (braceMatch) {\n const names = braceMatch[1]\n .split(',')\n .map((n) => n.replace(/\\btype\\b/, '').trim())\n .filter(Boolean);\n const newNames = names.filter((n) => !existingImportedNames.has(n) && !existingKeys.has(n));\n if (newNames.length > 0) {\n const isTypeImport = imp.text.trimStart().startsWith('import type');\n const prefix = isTypeImport ? 'import type' : 'import';\n const sourceMatch = imp.text.match(/from\\s+(['\"][^'\"]+['\"]);?/);\n if (sourceMatch) {\n newImports.push({\n key: imp.key + '#supplemental',\n text: `${prefix} { ${newNames.join(', ')} } from ${sourceMatch[1]};`,\n });\n }\n }\n }\n preserved++;\n continue;\n }\n // Strip out identifiers that are already imported from another path.\n // This prevents duplicates when the generated file uses a specific path\n // (e.g., '../interfaces/organization.interface') while the existing file\n // imports the same names from a barrel (e.g., '../interfaces').\n const braceMatch = imp.text.match(/\\{([^}]+)\\}/);\n if (braceMatch) {\n const names = braceMatch[1]\n .split(',')\n .map((n) => n.replace(/\\btype\\b/, '').trim())\n .filter(Boolean);\n // Check against both existing imports AND existing top-level declarations\n const isAlreadyDefined = (n: string) => existingImportedNames.has(n) || existingKeys.has(n);\n if (names.length > 0 && names.every(isAlreadyDefined)) {\n preserved++;\n continue;\n }\n // If only SOME identifiers are already defined, strip them out and keep only new ones\n if (names.some(isAlreadyDefined)) {\n const newNames = names.filter((n) => !isAlreadyDefined(n));\n if (newNames.length === 0) {\n preserved++;\n continue;\n }\n // Rebuild the import with only new identifiers\n const isTypeImport = imp.text.trimStart().startsWith('import type');\n const prefix = isTypeImport ? 'import type' : 'import';\n const sourceMatch = imp.text.match(/from\\s+(['\"][^'\"]+['\"]);?/);\n if (sourceMatch) {\n const newText = `${prefix} { ${newNames.join(', ')} } from ${sourceMatch[1]};`;\n newImports.push({ key: imp.key, text: newText });\n continue;\n }\n }\n }\n newImports.push(imp);\n }\n\n for (const stmt of generatedStatements.statements) {\n // Skip the header comment\n if (stmt.text.trim() === headerLine) continue;\n\n // Skip re-export statements that duplicate existing re-exports\n // (e.g., generated uses .js extension but existing doesn't).\n // Allow genuinely new re-exports through.\n if (stmt.kind === 'reexport') {\n const normalizedText = adapter.normalizeReexport ? adapter.normalizeReexport(stmt.text.trim()) : stmt.text.trim();\n if (existingReexports.has(normalizedText) || (stmt.key !== null && existingKeys.has(stmt.key))) {\n preserved++;\n continue;\n }\n // Also skip re-exports whose aliased names are already defined as\n // top-level exports in the existing file (e.g., generated file has\n // `export { X as deserializeFoo } from '...'` but existing file\n // already has `export const deserializeFoo = ...`).\n const braceMatch = stmt.text.match(/\\{([^}]+)\\}/);\n if (braceMatch) {\n const exportedNames = braceMatch[1]\n .split(',')\n .map((n) => {\n const parts = n.trim().split(/\\s+as\\s+/);\n return (parts[1] ?? parts[0]).trim();\n })\n .filter(Boolean);\n if (exportedNames.length > 0 && exportedNames.every((n) => existingExportedNames.has(n))) {\n preserved++;\n continue;\n }\n }\n }\n\n if (stmt.key && (existingKeys.has(stmt.key) || existingImportedNames.has(stmt.key))) {\n preserved++;\n continue;\n }\n\n if (!stmt.key) {\n if (existingUnnamedTexts.has(stmt.text.trim())) {\n preserved++;\n continue;\n }\n }\n\n toAppend.push(stmt.text);\n }\n\n if (newImports.length === 0 && toAppend.length === 0) {\n // No top-level changes — check for deep merge before returning\n if (!adapter.extractMembers) {\n // Still need to check docstring refresh below\n }\n }\n\n let result = existingContent;\n\n // Append new top-level symbols first (so deep merge can see them)\n if (toAppend.length > 0) {\n result = result.trimEnd() + '\\n\\n' + toAppend.join('\\n\\n') + '\\n';\n }\n\n // Deep merge pass: add new members to existing symbols\n // Runs after import/symbol merge so line numbers are based on the updated content\n let deepAdded = 0;\n let deepPruned = 0;\n const insertions: { line: number; text: string }[] = [];\n if (adapter.extractMembers) {\n const parser = await getParser(language);\n const resultTree = safeParse(parser, result);\n const generatedTree = safeParse(parser, generatedContent);\n const resultSymbols = adapter.extractMembers(resultTree, result);\n const generatedSymbols = adapter.extractMembers(generatedTree, generatedContent);\n\n // Build ignored symbol set from @oagen-ignore-start/@oagen-ignore-end regions\n const existingTree = safeParse(parser, existingContent);\n const existingDocs = adapter.extractDocstrings(existingTree, existingContent);\n const deepIgnoredRegions = findIgnoredRegions(existingContent);\n const deepIgnoredSymbols = buildIgnoredSymbolNames(existingDocs, deepIgnoredRegions);\n\n // Pass 1: prune stale \"managed\" members (existing members the adapter\n // recognizes as generator-owned but that no longer appear in the\n // regenerated content — e.g. accessors whose mount target was remapped).\n // Done as byte-range deletes before line-based insertions so insertion\n // line numbers stay valid for the post-prune result.\n if (adapter.isManagedMember) {\n const pruneEdits: { start: number; end: number }[] = [];\n for (const [symbolName, genSymbol] of generatedSymbols) {\n if (deepIgnoredSymbols.has(symbolName)) continue;\n const existSymbol = resultSymbols.get(symbolName);\n if (!existSymbol) continue;\n const genMemberKeys = new Set(genSymbol.members.map((m) => m.key));\n for (const existMember of existSymbol.members) {\n if (genMemberKeys.has(existMember.key)) continue;\n if (existMember.startIndex === undefined || existMember.endIndex === undefined) continue;\n if (!adapter.isManagedMember(existMember)) continue;\n pruneEdits.push({ start: existMember.startIndex, end: existMember.endIndex });\n }\n }\n if (pruneEdits.length > 0) {\n pruneEdits.sort((a, b) => b.start - a.start);\n for (const edit of pruneEdits) {\n let end = edit.end;\n while (end < result.length && (result[end] === ' ' || result[end] === '\\t')) end++;\n if (result[end] === '\\n') end++;\n result = result.slice(0, edit.start) + result.slice(end);\n }\n deepPruned = pruneEdits.length;\n // Re-extract since byte offsets and line numbers shifted.\n const reTree = safeParse(parser, result);\n resultSymbols.clear();\n for (const [k, v] of adapter.extractMembers(reTree, result)) resultSymbols.set(k, v);\n }\n }\n\n // Pass 2: append new members the regenerated content adds.\n for (const [symbolName, genSymbol] of generatedSymbols) {\n if (deepIgnoredSymbols.has(symbolName)) continue;\n const existSymbol = resultSymbols.get(symbolName);\n if (!existSymbol) continue; // New symbol — handled by top-level append\n\n const existingMemberKeys = new Set(existSymbol.members.map((m) => m.key));\n const newMembers = genSymbol.members.filter((m) => !existingMemberKeys.has(m.key));\n\n if (newMembers.length > 0) {\n // Let the adapter decide whether to skip deep merge (e.g., when new members\n // reference dependencies the existing symbol doesn't provide)\n if (adapter.shouldSkipDeepMerge?.(symbolName, existingMemberKeys, newMembers)) {\n continue;\n }\n\n const indent = existSymbol.memberIndent ?? ' ';\n const insertText = newMembers.map((m) => indent + m.text).join('\\n\\n');\n // Leading blank line separates inserted members from existing ones.\n insertions.push({ line: existSymbol.bodyEndLine, text: '\\n' + insertText });\n deepAdded += newMembers.length;\n }\n }\n\n if (insertions.length > 0) {\n // Apply bottom-up to avoid offset shifting\n insertions.sort((a, b) => b.line - a.line);\n const resultLines = result.split('\\n');\n for (const ins of insertions) {\n resultLines.splice(ins.line, 0, ins.text);\n }\n result = resultLines.join('\\n');\n }\n }\n\n // Insert new imports only when new symbols or members were actually added.\n // This prevents orphaned imports for generated code that wasn't merged in.\n // Additionally, filter imports to only include identifiers actually used in the\n // appended/inserted code — prevents orphaned imports for generated code that\n // referenced types used in other (non-appended) generated functions.\n if (newImports.length > 0 && (toAppend.length > 0 || deepAdded > 0)) {\n // Build text of all new code that was actually added (appended + deep-merged members)\n const addedParts: string[] = [...toAppend];\n if (insertions) {\n for (const ins of insertions) {\n addedParts.push(ins.text);\n }\n }\n const addedCodeText = addedParts.join('\\n');\n\n // Filter imports to only identifiers that appear in the added code.\n // Strip individual unused identifiers from each import rather than\n // keeping/dropping the entire import — prevents orphaned imports when\n // a generated import line contains both used and unused identifiers\n // (e.g., `import { deserializeFoo, serializeFoo }` where only\n // serializeFoo is used in the appended code).\n const filteredImports: MergeImport[] = [];\n for (const imp of newImports) {\n const braceMatch = imp.text.match(/\\{([^}]+)\\}/);\n if (!braceMatch) {\n // Non-destructured import (e.g., default import) — keep as-is\n filteredImports.push(imp);\n continue;\n }\n const names = braceMatch[1]\n .split(',')\n .map((n) => n.replace(/\\btype\\b/, '').trim())\n .filter(Boolean);\n const usedNames = names.filter((name) => addedCodeText.includes(name));\n if (usedNames.length === 0) continue; // Drop entirely\n if (usedNames.length === names.length) {\n // All identifiers used — keep original import\n filteredImports.push(imp);\n } else {\n // Rebuild import with only used identifiers\n const isTypeImport = imp.text.trimStart().startsWith('import type');\n const prefix = isTypeImport ? 'import type' : 'import';\n const sourceMatch = imp.text.match(/from\\s+(['\"][^'\"]+['\"]);?/);\n if (sourceMatch) {\n filteredImports.push({\n key: imp.key,\n text: `${prefix} { ${usedNames.join(', ')} } from ${sourceMatch[1]};`,\n });\n } else {\n filteredImports.push(imp);\n }\n }\n }\n\n if (filteredImports.length > 0) {\n const renderedImports = adapter.renderImports\n ? adapter.renderImports(filteredImports)\n : filteredImports.map((entry) => entry.text);\n const lines = result.split('\\n');\n const insertIdx = lastImportEndIndex + 1;\n lines.splice(insertIdx, 0, ...renderedImports);\n result = lines.join('\\n');\n }\n }\n\n // Docstring refresh pass: update existing docstrings to match generated content\n let docstringUpdates = 0;\n {\n const parser = await getParser(language);\n const resultTree = safeParse(parser, result);\n const generatedTree = safeParse(parser, generatedContent);\n const resultDocs = adapter.extractDocstrings(resultTree, result);\n const generatedDocs = adapter.extractDocstrings(generatedTree, generatedContent);\n const docIgnoredRegions = findIgnoredRegions(result);\n const docIgnoredSymbols = buildIgnoredSymbolNames(resultDocs, docIgnoredRegions);\n\n const edits: { start: number; end: number; newText: string }[] = [];\n\n for (const [symbolName, genInfo] of generatedDocs) {\n const existInfo = resultDocs.get(symbolName);\n if (!existInfo) continue;\n if (docIgnoredSymbols.has(symbolName)) continue;\n\n // Skip header comments being treated as docstrings\n const genDoc = genInfo.docstring && genInfo.docstring.text.trim() !== headerLine ? genInfo.docstring : null;\n\n // Top-level docstring\n if (genDoc) {\n if (existInfo.docstring) {\n const isPreserved = existInfo.docstring.text.includes('@oagen-ignore');\n if (!isPreserved && existInfo.docstring.text !== genDoc.text) {\n const newText = preserveDeprecatedTags(existInfo.docstring.text, genDoc.text);\n const range = resolveDocRange(\n result,\n existInfo.docstring.text,\n existInfo.declStartIndex,\n existInfo.docstring.startIndex,\n existInfo.docstring.endIndex,\n );\n edits.push({\n start: range.start,\n end: range.end,\n newText,\n });\n docstringUpdates++;\n }\n } else {\n const lineStart = declarationLineStart(result, existInfo.declStartIndex);\n const indent = ' '.repeat(existInfo.declColumn);\n edits.push({\n start: lineStart,\n end: lineStart,\n newText: indent + genDoc.text + '\\n',\n });\n docstringUpdates++;\n }\n }\n\n // Member-level docstrings — first pass: match by name\n const matchedExistMembers = new Set<string>();\n for (const [memberName, genMember] of genInfo.members) {\n const existMember = existInfo.members.get(memberName);\n if (!existMember) continue;\n matchedExistMembers.add(memberName);\n if (!genMember.docstring) continue;\n\n if (existMember.docstring) {\n const isPreserved = existMember.docstring.text.includes('@oagen-ignore');\n if (!isPreserved && existMember.docstring.text !== genMember.docstring.text) {\n const newText = preserveDeprecatedTags(existMember.docstring.text, genMember.docstring.text);\n const range = resolveDocRange(\n result,\n existMember.docstring.text,\n existMember.declStartIndex,\n existMember.docstring.startIndex,\n existMember.docstring.endIndex,\n );\n edits.push({\n start: range.start,\n end: range.end,\n newText,\n });\n docstringUpdates++;\n }\n } else {\n const lineStart = declarationLineStart(result, existMember.declStartIndex);\n const indent = ' '.repeat(existMember.declColumn);\n edits.push({\n start: lineStart,\n end: lineStart,\n newText: indent + genMember.docstring.text + '\\n',\n });\n docstringUpdates++;\n }\n }\n\n // Member-level docstrings — second pass: URL fingerprint fallback\n // Match generated members to existing members by URL pattern when\n // name-based matching fails (e.g., generated \"find\" vs existing \"getOrganization\"\n // both call this.workos.get('/organizations/${id}')).\n //\n // Safety: only attempt fingerprint matching when there is exactly ONE\n // unmatched generated member and ONE unmatched existing member for a\n // given fingerprint. When multiple members share the same URL path\n // (e.g., POST and GET on /authorization/roles), fingerprint matching\n // is ambiguous and would swap docstrings between methods.\n const unmatchedGenByFp = new Map<\n string,\n { name: string; member: typeof genInfo.members extends Map<string, infer V> ? V : never }[]\n >();\n for (const [genName, genMember] of genInfo.members) {\n if (matchedExistMembers.has(genName)) continue; // name-matched in pass 1 (as an exist member) — skip\n if (!genMember.docstring || !genMember.urlFingerprint) continue;\n // Skip if this generated member was already name-matched\n if (existInfo.members.has(genName)) continue;\n const bucket = unmatchedGenByFp.get(genMember.urlFingerprint) ?? [];\n bucket.push({ name: genName, member: genMember });\n unmatchedGenByFp.set(genMember.urlFingerprint, bucket);\n }\n const unmatchedExistByFp = new Map<\n string,\n { name: string; member: typeof existInfo.members extends Map<string, infer V> ? V : never }[]\n >();\n for (const [existName, existMember] of existInfo.members) {\n if (matchedExistMembers.has(existName)) continue;\n if (!existMember.urlFingerprint) continue;\n const bucket = unmatchedExistByFp.get(existMember.urlFingerprint) ?? [];\n bucket.push({ name: existName, member: existMember });\n unmatchedExistByFp.set(existMember.urlFingerprint, bucket);\n }\n for (const [fp, genBucket] of unmatchedGenByFp) {\n if (genBucket.length !== 1) continue; // ambiguous — skip\n const existBucket = unmatchedExistByFp.get(fp);\n if (!existBucket || existBucket.length !== 1) continue; // ambiguous — skip\n const genMember = genBucket[0].member;\n const existEntry = existBucket[0];\n const existMember = existEntry.member;\n if (!genMember.docstring) continue;\n\n if (existMember.docstring) {\n const isPreserved = existMember.docstring.text.includes('@oagen-ignore');\n if (isPreserved) continue;\n if (existMember.docstring.text !== genMember.docstring.text) {\n const newText = preserveDeprecatedTags(existMember.docstring.text, genMember.docstring.text);\n const range = resolveDocRange(\n result,\n existMember.docstring.text,\n existMember.declStartIndex,\n existMember.docstring.startIndex,\n existMember.docstring.endIndex,\n );\n edits.push({\n start: range.start,\n end: range.end,\n newText,\n });\n docstringUpdates++;\n }\n } else {\n const lineStart = declarationLineStart(result, existMember.declStartIndex);\n const indent = ' '.repeat(existMember.declColumn);\n edits.push({\n start: lineStart,\n end: lineStart,\n newText: indent + genMember.docstring.text + '\\n',\n });\n docstringUpdates++;\n }\n matchedExistMembers.add(existEntry.name);\n }\n }\n\n if (edits.length > 0) {\n edits.sort((a, b) => b.start - a.start);\n for (const edit of edits) {\n result = result.slice(0, edit.start) + edit.newText + result.slice(edit.end);\n }\n }\n }\n\n const importsActuallyAdded =\n toAppend.length > 0 || deepAdded > 0\n ? adapter.renderImports\n ? adapter.renderImports(newImports).length\n : newImports.length\n : 0;\n const topLevelAdded = importsActuallyAdded + toAppend.length;\n const totalAdded = topLevelAdded + deepAdded;\n\n if (totalAdded === 0 && docstringUpdates === 0 && deepPruned === 0) {\n return { content: existingContent, added: 0, preserved, changed: false };\n }\n\n return {\n content: result,\n added: totalAdded,\n preserved,\n changed: true,\n };\n}\n","/**\n * Deep merge two parsed JSON values.\n *\n * - Objects: recursively merge, preserving existing keys not in generated\n * - Arrays: generated replaces existing entirely (generated owns array contents)\n * - Primitives: generated wins\n */\nexport function deepMergeJson(existing: unknown, generated: unknown): unknown {\n if (\n typeof existing === 'object' &&\n existing !== null &&\n !Array.isArray(existing) &&\n typeof generated === 'object' &&\n generated !== null &&\n !Array.isArray(generated)\n ) {\n const merged: Record<string, unknown> = { ...(existing as Record<string, unknown>) };\n for (const [key, value] of Object.entries(generated as Record<string, unknown>)) {\n if (key in merged) {\n merged[key] = deepMergeJson(merged[key], value);\n } else {\n merged[key] = value;\n }\n }\n return merged;\n }\n\n // Arrays and primitives: generated wins\n return generated;\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { GeneratedFile } from './types.js';\nimport { mergeIntoExisting, hasGrammar, extractClassEndLines } from './merger.js';\nimport { deepMergeJson } from './json-merge.js';\nimport { getMergeAdapter } from './merge-adapters/index.js';\n\nexport interface WriteOptions {\n /** The emitter language (e.g., \"node\", \"ruby\"). Used to select the\n * tree-sitter grammar for AST-level merging. */\n language?: string;\n /** The auto-generated file header string. */\n header?: string;\n}\n\nexport interface WriteResult {\n written: string[];\n merged: string[];\n skipped: string[];\n identical: string[];\n ignored: string[];\n}\n\n/**\n * Write generated files to disk with AST-level merging.\n *\n * When a file already exists:\n * - skipIfExists → leave it alone entirely\n * - AST merge available → parse both, append only new symbols\n * - No grammar → skip (never clobber hand-written code)\n *\n * New files are always written in full.\n */\nexport async function writeFiles(\n files: GeneratedFile[],\n outputDir: string,\n options?: WriteOptions,\n): Promise<WriteResult> {\n const result: WriteResult = {\n written: [],\n merged: [],\n skipped: [],\n identical: [],\n ignored: [],\n };\n const sorted = [...files].sort((a, b) => a.path.localeCompare(b.path));\n const language = options?.language;\n const header = options?.header ?? '';\n\n for (const file of sorted) {\n const fullPath = path.join(outputDir, file.path);\n\n // Repair on-disk casing when an emitter renames a generated file in a\n // case-only way (e.g. `AuthenticationMfaFailed.kt` → `AuthenticationMFAFailed.kt`\n // after adding `MFA` to an acronym list). On case-insensitive filesystems\n // (APFS, NTFS) `writeFile` would otherwise reuse the existing inode and\n // preserve the stale casing — surfacing later as ktlint/eslint errors.\n await renameMismatchedCasing(fullPath);\n\n // Check if file already exists\n let existingContent: string | null = null;\n try {\n existingContent = await fs.readFile(fullPath, 'utf-8');\n } catch {\n // File doesn't exist\n }\n\n // New file → write in full\n if (existingContent === null) {\n await fs.mkdir(path.dirname(fullPath), { recursive: true });\n await fs.writeFile(fullPath, file.content, 'utf-8');\n result.written.push(file.path);\n continue;\n }\n\n // skipIfExists → hard skip, no merge (but ensure header is present).\n // JSON files are skipped from header injection because a leading `//`\n // comment makes the file invalid JSON.\n if (file.skipIfExists) {\n if (header && !existingContent.startsWith(header) && !file.path.endsWith('.json')) {\n await fs.writeFile(fullPath, header + '\\n\\n' + existingContent, 'utf-8');\n }\n result.skipped.push(file.path);\n continue;\n }\n\n // @oagen-ignore-file → skip entirely (existing file opts out of all generation)\n if (existingContent.includes('@oagen-ignore-file')) {\n result.ignored.push(file.path);\n continue;\n }\n\n // Don't merge test files into hand-written test files — generated tests are\n // designed for the standalone generated SDK and will have wrong\n // signatures/fixtures when merged into hand-written tests.\n // However, if the existing test file is itself auto-generated (has the oagen\n // header), allow overwriteExisting to take effect so new methods get coverage.\n const adapter = language ? getMergeAdapter(language) : undefined;\n const isTestFile = adapter?.testFilePatterns\n ? adapter.testFilePatterns.some((p) => p.test(file.path))\n : isDefaultTestFile(file.path);\n if (isTestFile) {\n const isExistingAutoGenerated = header && existingContent.startsWith(header);\n if (!isExistingAutoGenerated && !file.overwriteExisting) {\n result.skipped.push(file.path);\n continue;\n }\n // Auto-generated test file or overwriteExisting — fall through to overwriteExisting / identical checks\n }\n\n // Identical content → no-op\n if (existingContent === file.content) {\n result.identical.push(file.path);\n continue;\n }\n\n // Force overwrite — but preserve any @oagen-ignore regions from existing content\n if (file.overwriteExisting) {\n const content =\n existingContent.includes('@oagen-ignore-start') && language && hasGrammar(language)\n ? await overwriteWithPreservedRegions(existingContent, file.content, language)\n : file.content;\n await fs.writeFile(fullPath, content, 'utf-8');\n result.written.push(file.path);\n continue;\n }\n\n // JSON files → deep merge preserving existing keys\n if (file.path.endsWith('.json')) {\n try {\n const existingJson = JSON.parse(existingContent);\n const generatedJson = JSON.parse(file.content);\n const merged = deepMergeJson(existingJson, generatedJson);\n const mergedContent = JSON.stringify(merged, null, 2) + '\\n';\n if (mergedContent === existingContent) {\n result.identical.push(file.path);\n } else {\n await fs.writeFile(fullPath, mergedContent, 'utf-8');\n result.merged.push(file.path);\n }\n } catch {\n // Parse failed — fall back to overwrite\n await fs.writeFile(fullPath, file.content, 'utf-8');\n result.written.push(file.path);\n }\n continue;\n }\n\n // Source files with grammar → AST-level merge\n if (language && hasGrammar(language)) {\n try {\n const mergeResult = await mergeIntoExisting(existingContent, file.content, language, header);\n\n // Ensure header is present on merged content\n let finalContent = mergeResult.content;\n if (header && !finalContent.startsWith(header)) {\n finalContent = header + '\\n\\n' + finalContent;\n }\n\n if (!mergeResult.changed && finalContent === existingContent) {\n result.identical.push(file.path);\n continue;\n }\n\n await fs.writeFile(fullPath, finalContent, 'utf-8');\n result.merged.push(file.path);\n continue;\n } catch (err) {\n // AST merge failed (e.g. tree-sitter grammar ABI issue) — fall back to overwrite\n console.warn(\n `[oagen] AST merge failed for ${file.path}, falling back to overwrite.${err instanceof Error ? ` ${err.message}` : ''}`,\n );\n await fs.writeFile(fullPath, file.content, 'utf-8');\n result.written.push(file.path);\n continue;\n }\n }\n\n // No grammar available → skip to avoid clobbering\n result.skipped.push(file.path);\n }\n\n return result;\n}\n\n/**\n * If a sibling exists with the same name except for letter case, rename it to\n * the requested casing. Uses a two-step rename via a temporary unique name so\n * case-insensitive filesystems (APFS on macOS, NTFS on Windows) actually\n * update the entry — `rename('Foo', 'FOO')` is a no-op on those systems.\n */\nasync function renameMismatchedCasing(fullPath: string): Promise<void> {\n const dir = path.dirname(fullPath);\n const target = path.basename(fullPath);\n let entries: string[];\n try {\n entries = await fs.readdir(dir);\n } catch {\n return;\n }\n if (entries.includes(target)) return;\n const targetLower = target.toLowerCase();\n const mismatch = entries.find((e) => e.toLowerCase() === targetLower);\n if (!mismatch) return;\n const oldPath = path.join(dir, mismatch);\n const tempPath = path.join(dir, `.oagen-case-${process.pid}-${Date.now()}-${target}`);\n await fs.rename(oldPath, tempPath);\n await fs.rename(tempPath, fullPath);\n}\n\n/** Comprehensive fallback when no adapter is available. */\nfunction isDefaultTestFile(filePath: string): boolean {\n return (\n /\\.(spec|test)\\.[jt]sx?$/.test(filePath) ||\n filePath.endsWith('_test.go') ||\n filePath.endsWith('_test.rb') ||\n filePath.endsWith('_spec.rb') ||\n /(?:^|\\/)test_.*\\.py$/.test(filePath) ||\n filePath.endsWith('_test.py') ||\n filePath.endsWith('Test.php') ||\n filePath.endsWith('_test.rs') ||\n /(?:^|\\/)tests\\/.*\\.rs$/.test(filePath)\n );\n}\n\n// --- @oagen-ignore region preservation for overwriteExisting ---\n\n/**\n * Overwrite a file with generated content while preserving\n * `@oagen-ignore-start` / `@oagen-ignore-end` regions (and their\n * required imports) from the existing file.\n *\n * Uses tree-sitter via `extractClassEndLines` to find accurate class\n * boundaries so ignore blocks are inserted at the correct position even\n * when docstrings contain unindented text.\n */\nexport async function overwriteWithPreservedRegions(\n existingContent: string,\n generatedContent: string,\n language: string,\n): Promise<string> {\n const existingLines = existingContent.split('\\n');\n const generatedLines = generatedContent.split('\\n');\n\n // 1. Extract ignore blocks, their containing class, and the anchor line\n // (first non-blank line after the block in the existing file).\n const blocks: { containingClass: string; containingScope: string; lines: string[]; anchor: string }[] = [];\n for (let i = 0; i < existingLines.length; i++) {\n if (!existingLines[i].includes('@oagen-ignore-start')) continue;\n const startIdx = i;\n while (i < existingLines.length && !existingLines[i].includes('@oagen-ignore-end')) i++;\n let anchor = '';\n for (let a = i + 1; a < existingLines.length; a++) {\n if (existingLines[a].trim()) {\n anchor = existingLines[a].trimStart();\n break;\n }\n }\n blocks.push({\n containingClass: findContainingClass(existingLines, startIdx),\n containingScope: findContainingDescribeScope(existingLines, startIdx),\n lines: existingLines.slice(startIdx, i + 1),\n anchor,\n });\n }\n if (blocks.length === 0) return generatedContent;\n\n // 2. Splice extra imports from existing into generated.\n // First strip any `@oagen-ignore-start`..`@oagen-ignore-end` regions the\n // generator itself emitted: we are about to re-insert the on-disk versions,\n // and if we left the generator's seed blocks in place we'd end up with two\n // copies of every ignore block per regeneration (monotonically growing).\n const result = stripIgnoreRegions(generatedLines);\n spliceExtraImports(existingLines, result);\n\n // 3. Build class-end map from the generated content (after import splicing)\n // via tree-sitter for accurate boundary detection.\n const genSource = result.join('\\n');\n const classEndLines = await extractClassEndLines(genSource, language);\n\n // 4. Group ignore blocks by class and determine insertion points\n const blocksByClass = new Map<string, Array<{ containingScope: string; lines: string[]; anchor: string }>>();\n for (const b of blocks) {\n if (!blocksByClass.has(b.containingClass)) blocksByClass.set(b.containingClass, []);\n blocksByClass.get(b.containingClass)!.push({\n containingScope: b.containingScope,\n lines: b.lines,\n anchor: b.anchor,\n });\n }\n\n // 4a. Handle replacement blocks: ignore blocks that redefine their\n // containing class replace the generated class entirely.\n // Also handles top-level blocks (no containing class) that define\n // a class matching one in the generated content.\n const replacedClasses = new Set<string>();\n const handledBlockKeys = new Set<string>();\n const replacements: {\n startLine: number;\n endLine: number;\n content: string[];\n }[] = [];\n for (const [className, classBlocks] of blocksByClass) {\n // Determine the target class for replacement. When the block has a\n // containing class, we check if the block redefines that class. When\n // there is no containing class (top-level ignore block), we look for a\n // class definition inside the block that matches a generated class.\n let targetClass = className;\n if (!targetClass) {\n for (const entry of classBlocks) {\n for (const l of entry.lines) {\n const m = l.match(/^(?:export\\s+)?class\\s+(\\w+)/);\n if (m && classEndLines.has(m[1])) {\n targetClass = m[1];\n break;\n }\n }\n if (targetClass) break;\n }\n }\n if (!targetClass) continue;\n const isReplacement = classBlocks.some((entry) =>\n entry.lines.some((l) => {\n const m = l.match(/^(?:export\\s+)?class\\s+(\\w+)/);\n return m?.[1] === targetClass;\n }),\n );\n if (!isReplacement) continue;\n const info = classEndLines.get(targetClass);\n if (!info) continue;\n const startLine = findClassDeclarationStart(result, targetClass, info.bodyEndLine);\n if (startLine < 0) continue;\n const content: string[] = [];\n for (const entry of classBlocks) {\n content.push('');\n content.push(...entry.lines);\n }\n replacements.push({ startLine, endLine: info.bodyEndLine, content });\n replacedClasses.add(targetClass);\n handledBlockKeys.add(className);\n }\n // Apply replacements bottom-up to preserve line indices\n replacements.sort((a, b) => b.startLine - a.startLine);\n for (const rep of replacements) {\n result.splice(rep.startLine, rep.endLine - rep.startLine, ...rep.content);\n }\n\n // 4b. Standard insertions for non-replacement blocks\n // Rebuild class end lines if replacements shifted line numbers.\n let effectiveClassEndLines = classEndLines;\n if (replacedClasses.size > 0) {\n effectiveClassEndLines = await extractClassEndLines(result.join('\\n'), language);\n }\n\n const insertions: { line: number; order: number; content: string[] }[] = [];\n let insertionOrder = 0;\n for (const [className, classBlocks] of blocksByClass) {\n if (handledBlockKeys.has(className) || replacedClasses.has(className)) continue;\n const info = className ? effectiveClassEndLines.get(className) : undefined;\n\n // Insert each block individually so each can use its own anchor.\n for (const entry of classBlocks) {\n let insertLine: number | undefined;\n\n // Try anchor-based positioning: find the first line in the generated\n // file whose trimmed-start content matches the anchor (the first\n // non-blank line that followed this block in the existing file).\n // Skip anchors that are just punctuation (braces, etc.) since they\n // match too many locations. Accept doc comment starters (/** /// #)\n // as valid anchors since they're structurally meaningful.\n // Also skip bare language keywords (`end`, `end;`, `end)`) that appear\n // on many lines and would match the wrong location (e.g. nesting the\n // block inside a Ruby method body instead of at class level).\n const isAmbiguousAnchor = /^end[;)\\s]*$/.test(entry.anchor);\n if (\n entry.anchor &&\n !entry.anchor.includes('@oagen-ignore') &&\n !isAmbiguousAnchor &&\n /[a-zA-Z]|^\\/\\*|^\\/\\//.test(entry.anchor)\n ) {\n for (let li = 0; li < result.length; li++) {\n if (result[li].trimStart() === entry.anchor) {\n insertLine = li;\n break;\n }\n }\n }\n\n // Fallback: class body end, or for top-level import blocks, after the\n // last import line (so they stay near the top of the file, not at the\n // bottom where they'd trigger E402 lint errors).\n if (insertLine === undefined) {\n if (info) {\n insertLine = info.bodyEndLine;\n } else {\n const scopeEndLine = entry.containingScope\n ? findDescribeScopeEndLine(result, entry.containingScope)\n : undefined;\n const blockHasImportsFallback = entry.lines.some((l: string) => /^\\s*(import|from)\\s/.test(l));\n if (scopeEndLine !== undefined) {\n insertLine = scopeEndLine;\n } else if (blockHasImportsFallback || hasTopLevelDeclaration(entry.lines)) {\n let lastImportLine = 0;\n for (let li = 0; li < result.length; li++) {\n const trimmed = result[li].trimStart();\n if (/^(import|from)\\s/.test(trimmed)) lastImportLine = li + 1;\n }\n insertLine = lastImportLine;\n } else {\n insertLine = result.length;\n }\n }\n }\n\n // When inserting an import-containing ignore block, move up past\n // blank separator lines so the block sits flush with surrounding\n // imports (e.g., Kotlin's ktlint forbids blank lines within import\n // blocks).\n const blockHasImports = entry.lines.some((l: string) => /^\\s*import\\s/.test(l));\n if (blockHasImports) {\n while (\n insertLine >= 2 &&\n result[insertLine - 1]?.trim() === '' &&\n /^\\s*(import|using|from)\\s/.test(result[insertLine - 2] ?? '')\n ) {\n insertLine--;\n }\n }\n\n // Skip the leading blank line when the block is adjacent to imports\n // or already preceded by a blank line (avoids double-blank-line gaps).\n const prevLine = insertLine > 0 ? (result[insertLine - 1]?.trimStart() ?? '') : '';\n const prevIsImport = /^import\\s/.test(prevLine) || /^using\\s/.test(prevLine) || /^from\\s/.test(prevLine);\n const prevIsBlank = insertLine > 0 && prevLine === '';\n const blockContent = prevIsImport || prevIsBlank ? [...entry.lines] : ['', ...entry.lines];\n // Add a trailing blank line when the next line is a doc comment\n // (C# SA1514 requires a blank line before `///` doc headers).\n const nextLine = result[insertLine]?.trimStart() ?? '';\n if (nextLine.startsWith('///')) {\n blockContent.push('');\n }\n insertions.push({ line: insertLine, order: insertionOrder++, content: blockContent });\n }\n }\n\n // Apply bottom-up to preserve line indices. Blocks with the same insertion\n // line must be applied in reverse discovery order because each splice inserts\n // at the same index; otherwise repeated generation flips their order.\n insertions.sort((a, b) => b.line - a.line || b.order - a.order);\n for (const ins of insertions) {\n result.splice(ins.line, 0, ...ins.content);\n }\n\n removeDuplicateImportsCoveredByIgnoreBlocks(result);\n\n return result.join('\\n');\n}\n\n/**\n * Remove every `@oagen-ignore-start`..`@oagen-ignore-end` region from the\n * supplied lines, collapsing stretches of blank lines that get left behind.\n * Used to drop generator-emitted seed blocks before splicing the on-disk\n * versions back in — otherwise every regen doubles up.\n */\nfunction stripIgnoreRegions(lines: string[]): string[] {\n const out: string[] = [];\n let skipping = false;\n for (const line of lines) {\n if (!skipping && line.includes('@oagen-ignore-start')) {\n skipping = true;\n // Drop a preceding blank line if we have one queued up — otherwise\n // regen leaves a stray blank line above the spliced-in block.\n while (out.length > 0 && out[out.length - 1].trim() === '') out.pop();\n continue;\n }\n if (skipping) {\n if (line.includes('@oagen-ignore-end')) skipping = false;\n continue;\n }\n out.push(line);\n }\n return out;\n}\n\n/** Scan backwards from `lineIdx` to find the nearest class declaration name. */\nfunction findContainingClass(lines: string[], lineIdx: number): string {\n if (/^\\S/.test(lines[lineIdx] ?? '')) return '';\n // Allow leading whitespace and language-specific modifiers before `class`.\n // Covers: `public class Foo` (C#/Java), `export class Foo` (TS),\n // `class Foo` (Python/Ruby), `internal sealed class Foo` (C#), etc.\n for (let j = lineIdx - 1; j >= 0; j--) {\n const m = lines[j].match(\n /^\\s*(?:(?:export|public|private|protected|internal|abstract|sealed|static|partial)\\s+)*class\\s+(\\w+)/,\n );\n if (m) return m[1];\n }\n return '';\n}\n\nfunction findContainingDescribeScope(lines: string[], lineIdx: number): string {\n const markerLine = lines[lineIdx] ?? '';\n if (/^\\S/.test(markerLine)) return '';\n const markerIndent = leadingSpaces(markerLine);\n for (let j = lineIdx - 1; j >= 0; j--) {\n const line = lines[j];\n const indent = leadingSpaces(line);\n if (indent >= markerIndent) continue;\n const match = line.match(/^\\s*describe\\((['\"`])(.+?)\\1\\s*,/);\n if (match) return match[2];\n if (/^\\s*(?:export\\s+)?class\\s+\\w+/.test(line)) return '';\n }\n return '';\n}\n\nfunction findDescribeScopeEndLine(lines: string[], scopeName: string): number | undefined {\n for (let i = 0; i < lines.length; i++) {\n const match = lines[i].match(/^\\s*describe\\((['\"`])(.+?)\\1\\s*,/);\n if (!match || match[2] !== scopeName) continue;\n\n let depth = 0;\n for (let j = i; j < lines.length; j++) {\n depth += countChar(lines[j], '{');\n depth -= countChar(lines[j], '}');\n if (j > i && depth <= 0) return j;\n }\n }\n return undefined;\n}\n\nfunction leadingSpaces(line: string): number {\n return line.match(/^\\s*/)?.[0].length ?? 0;\n}\n\nfunction countChar(line: string, char: string): number {\n return [...line].filter((c) => c === char).length;\n}\n\nfunction hasTopLevelDeclaration(lines: string[]): boolean {\n return lines.some((line) =>\n /^(?:export\\s+)?(?:interface|type|class|function|const|let|var|enum)\\s+\\w+/.test(line.trim()),\n );\n}\n\n/**\n * Find the start line of a class declaration (including decorators above it)\n * by scanning backwards from `beforeLine`.\n */\nfunction findClassDeclarationStart(lines: string[], className: string, beforeLine: number): number {\n // Match optional indentation so Ruby/Python nested classes are found.\n const classPattern = new RegExp(`^\\\\s*(?:export\\\\s+)?class\\\\s+${className}\\\\b`);\n for (let i = beforeLine - 1; i >= 0; i--) {\n if (!classPattern.test(lines[i])) continue;\n // Scan backward past decorators\n let start = i;\n while (start > 0 && /^\\s*@\\w+/.test(lines[start - 1])) {\n start--;\n }\n return start;\n }\n return -1;\n}\n\n/**\n * Collect `from X import Y, Z` identifiers grouped by module, handling\n * both single-line and multiline (parenthesized) forms.\n */\nfunction collectFromImports(lines: string[]): Map<string, Set<string>> {\n const byModule = new Map<string, Set<string>>();\n for (let i = 0; i < lines.length; i++) {\n if (!/^from\\s+/.test(lines[i])) continue;\n\n let fullText = lines[i];\n if (fullText.includes('(') && !fullText.includes(')')) {\n while (i + 1 < lines.length) {\n i++;\n fullText += ' ' + lines[i].trim();\n if (lines[i].includes(')')) break;\n }\n }\n\n const normalized = fullText.replace(/[()]/g, '').replace(/\\s+/g, ' ').trim();\n const match = normalized.match(/^from\\s+(\\S+)\\s+import\\s+(.+)$/);\n if (!match) continue;\n\n const mod = match[1];\n if (!byModule.has(mod)) byModule.set(mod, new Set());\n for (const id of match[2]\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)) {\n byModule.get(mod)!.add(id);\n }\n }\n return byModule;\n}\n\n/**\n * Collected TypeScript imports grouped by form. Each map keys on the module\n * specifier (e.g. `./foo`, `node:fs`).\n */\ninterface TsImports {\n /** `import { X, Y } from 'module'` — module → identifier names. */\n named: Map<string, Set<string>>;\n /** `import type { X } from 'module'` — module → identifier names. */\n typeOnly: Map<string, Set<string>>;\n /** `import X from 'module'` or `import type X from 'module'` — module → name. */\n defaults: Map<string, string>;\n /** `import * as X from 'module'` — module → namespace alias name. */\n namespaces: Map<string, string>;\n /** `import 'module'` — modules imported for side effects only. */\n sideEffects: Set<string>;\n}\n\n/**\n * Collect TypeScript imports, grouped by form. Handles single-line and\n * multi-line `{ … }` named imports. Disjoint from Python's `from X import Y`\n * syntax so this can be called in parallel with `collectFromImports`.\n */\nfunction collectTsImports(lines: string[]): TsImports {\n const out: TsImports = {\n named: new Map(),\n typeOnly: new Map(),\n defaults: new Map(),\n namespaces: new Map(),\n sideEffects: new Set(),\n };\n\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i].trim();\n if (!/^import(\\s|$)/.test(trimmed)) continue;\n\n // Accumulate multi-line `{ … }` imports.\n let fullText = lines[i];\n if (fullText.includes('{') && !fullText.includes('}')) {\n while (i + 1 < lines.length) {\n i++;\n fullText += ' ' + lines[i].trim();\n if (lines[i].includes('}')) break;\n }\n }\n\n const normalized = fullText.replace(/\\s+/g, ' ').trim().replace(/;\\s*$/, '');\n\n // `import 'module'`\n let m = normalized.match(/^import\\s+['\"]([^'\"]+)['\"]$/);\n if (m) {\n out.sideEffects.add(m[1]);\n continue;\n }\n\n // `import * as X from 'module'`\n m = normalized.match(/^import\\s+\\*\\s+as\\s+(\\w+)\\s+from\\s+['\"]([^'\"]+)['\"]$/);\n if (m) {\n out.namespaces.set(m[2], m[1]);\n continue;\n }\n\n // `import [Default,] { X, Y as Z } from 'module'` or `import type { X } from 'module'`\n m = normalized.match(/^import\\s+(type\\s+)?(?:(\\w+)\\s*,\\s*)?\\{\\s*([^}]*)\\s*\\}\\s+from\\s+['\"]([^'\"]+)['\"]$/);\n if (m) {\n const isTypeOnly = !!m[1];\n const defaultName = m[2];\n const namesRaw = m[3];\n const mod = m[4];\n if (defaultName) out.defaults.set(mod, defaultName);\n const names = namesRaw\n .split(',')\n .map((s) => s.trim().replace(/\\s+as\\s+\\w+$/, ''))\n .filter(Boolean);\n for (const rawName of names) {\n const isInlineTypeOnly = rawName.startsWith('type ');\n const name = rawName.replace(/^type\\s+/, '');\n const target = isTypeOnly || isInlineTypeOnly ? out.typeOnly : out.named;\n if (!target.has(mod)) target.set(mod, new Set());\n target.get(mod)!.add(name);\n }\n continue;\n }\n\n // `import X from 'module'` or `import type X from 'module'`\n m = normalized.match(/^import\\s+(?:type\\s+)?(\\w+)\\s+from\\s+['\"]([^'\"]+)['\"]$/);\n if (m) {\n out.defaults.set(m[2], m[1]);\n continue;\n }\n }\n\n return out;\n}\n\n/**\n * Add imports from the existing file that are absent from the generated\n * result. Handles:\n *\n * - Python: `import X` and `from X import Y`\n * - TypeScript: `import { X } from 'module'`, `import type { X } from 'module'`,\n * `import X from 'module'`, `import * as X from 'module'`, `import 'module'`\n * - PHP: `use Foo\\Bar;` and `use Foo\\Bar as Baz;` (namespace-qualified only)\n * - Ruby: `require '…'` and `require_relative '…'`\n *\n * Mutates `resultLines` in place.\n */\nfunction filterOutIgnoreRegions(lines: string[]): string[] {\n const out: string[] = [];\n let skipping = false;\n for (const line of lines) {\n if (!skipping && line.includes('@oagen-ignore-start')) {\n skipping = true;\n continue;\n }\n if (skipping) {\n if (line.includes('@oagen-ignore-end')) skipping = false;\n continue;\n }\n out.push(line);\n }\n return out;\n}\n\nfunction collectIgnoreRegionUsageText(lines: string[]): string {\n const out: string[] = [];\n let skipping = false;\n for (const line of lines) {\n if (!skipping && line.includes('@oagen-ignore-start')) {\n skipping = true;\n continue;\n }\n if (!skipping) continue;\n if (/^\\s*(import|from)\\s/.test(line)) continue;\n out.push(line);\n if (line.includes('@oagen-ignore-end')) skipping = false;\n }\n return out.join('\\n');\n}\n\nfunction removeDuplicateImportsCoveredByIgnoreBlocks(lines: string[]): void {\n const ignoredImports = new Set<string>();\n const importStatements = collectImportStatements(lines);\n for (const stmt of importStatements) {\n if (stmt.inIgnore) ignoredImports.add(normalizeImportStatement(stmt.lines));\n }\n if (ignoredImports.size === 0) return;\n\n for (const stmt of [...importStatements].reverse()) {\n if (stmt.inIgnore) continue;\n if (ignoredImports.has(normalizeImportStatement(stmt.lines))) {\n lines.splice(stmt.start, stmt.end - stmt.start + 1);\n }\n }\n}\n\nfunction collectImportStatements(\n lines: string[],\n): Array<{ start: number; end: number; lines: string[]; inIgnore: boolean }> {\n const statements: Array<{ start: number; end: number; lines: string[]; inIgnore: boolean }> = [];\n let inIgnore = false;\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (!inIgnore && line.includes('@oagen-ignore-start')) {\n inIgnore = true;\n continue;\n }\n if (inIgnore && line.includes('@oagen-ignore-end')) {\n inIgnore = false;\n continue;\n }\n if (!isImportLine(line)) continue;\n\n const start = i;\n let end = i;\n const statementLines = [line];\n const opens = (line.match(/[({]/g) ?? []).length;\n const closes = (line.match(/[)}]/g) ?? []).length;\n if (opens > closes) {\n while (end + 1 < lines.length) {\n end++;\n statementLines.push(lines[end]);\n if ((lines[end].match(/[)}]/g) ?? []).length > 0 && /\\bfrom\\b/.test(lines[end])) break;\n }\n i = end;\n }\n statements.push({ start, end, lines: statementLines, inIgnore });\n }\n return statements;\n}\n\nfunction normalizeImportStatement(lines: string[]): string {\n return lines.join('\\n').replace(/,\\s*}/g, ' }').replace(/\\s+/g, ' ').trim();\n}\n\nfunction isImportLine(line: string): boolean {\n const trimmed = line.trim();\n return (\n /^import(\\s|$)/.test(trimmed) ||\n /^from\\s+/.test(trimmed) ||\n /^use\\s+[\\w\\\\]/.test(trimmed) ||\n /^require(_relative)?\\s+['\"]/.test(trimmed)\n );\n}\n\nfunction identifierUsed(source: string, identifier: string): boolean {\n return new RegExp(`\\\\b${identifier.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\\b`).test(source);\n}\n\nfunction spliceExtraImports(existingLines: string[], resultLines: string[]): void {\n // Imports inside @oagen-ignore regions are converted into normal imports\n // only when non-import ignore content still references them. This prevents\n // stale import-only ignore blocks from creating duplicate or unused imports.\n const existingOutsideIgnore = filterOutIgnoreRegions(existingLines);\n const ignoreRegionText = collectIgnoreRegionUsageText(existingLines);\n\n // Python-style `import hashlib`. Excludes TS forms like `import X from '…'`\n // (have a `from` clause) and TS multi-line type imports whose first line is\n // `import type {` (have a brace) — both are handled by the TS collector\n // below.\n const isPythonSimpleImport = (l: string) => /^import\\s+\\w/.test(l) && !/\\sfrom\\s/.test(l) && !/[{}]/.test(l);\n\n // Simple imports (import hashlib, import json, …)\n const existingSimple = new Set(existingOutsideIgnore.filter(isPythonSimpleImport).map((l) => l.trim()));\n const generatedSimple = new Set(resultLines.filter(isPythonSimpleImport).map((l) => l.trim()));\n const extraSimple = [...existingSimple].filter((l) => !generatedSimple.has(l));\n\n // From-imports — compare by module and find extra identifiers\n const existingFrom = collectFromImports(existingOutsideIgnore);\n const generatedFrom = collectFromImports(resultLines);\n\n // Build a set of all identifiers imported by the generated file (across all modules)\n // so we can detect when an existing barrel import's identifiers are covered by\n // more-specific generated imports (e.g., `from x.y import Z` covers `from x import Z`).\n const allGeneratedIds = new Set<string>();\n for (const ids of generatedFrom.values()) {\n for (const id of ids) allGeneratedIds.add(id);\n }\n\n const extraFromLines: string[] = [];\n for (const [mod, existIds] of existingFrom) {\n const genIds = generatedFrom.get(mod);\n if (!genIds) {\n // The exact module isn't in the generated file — but check whether every\n // identifier is already imported from a different (e.g., more-specific) module.\n const extra = [...existIds].filter((id) => !allGeneratedIds.has(id));\n if (extra.length > 0) {\n extraFromLines.push(`from ${mod} import ${extra.join(', ')}`);\n }\n } else {\n const extra = [...existIds].filter((id) => !genIds.has(id) && !allGeneratedIds.has(id));\n if (extra.length > 0) {\n extraFromLines.push(`from ${mod} import ${extra.join(', ')}`);\n }\n }\n }\n\n // TypeScript imports.\n const existingTs = collectTsImports(existingOutsideIgnore);\n const generatedTs = collectTsImports(resultLines);\n const extraTsLines: string[] = [];\n\n for (const mod of existingTs.sideEffects) {\n if (!generatedTs.sideEffects.has(mod)) extraTsLines.push(`import '${mod}';`);\n }\n for (const [mod, name] of existingTs.defaults) {\n if (generatedTs.defaults.has(mod)) continue;\n if (!identifierUsed(ignoreRegionText, name)) continue;\n extraTsLines.push(`import ${name} from '${mod}';`);\n }\n for (const [mod, name] of existingTs.namespaces) {\n if (!identifierUsed(ignoreRegionText, name)) continue;\n if (!generatedTs.namespaces.has(mod)) extraTsLines.push(`import * as ${name} from '${mod}';`);\n }\n for (const [mod, existIds] of existingTs.named) {\n const genIds = generatedTs.named.get(mod) ?? new Set<string>();\n const genTypeIds = generatedTs.typeOnly.get(mod) ?? new Set<string>();\n const extra = [...existIds].filter(\n (id) => !genIds.has(id) && !genTypeIds.has(id) && identifierUsed(ignoreRegionText, id),\n );\n if (extra.length > 0) extraTsLines.push(`import { ${extra.join(', ')} } from '${mod}';`);\n }\n for (const [mod, existIds] of existingTs.typeOnly) {\n const genIds = generatedTs.typeOnly.get(mod) ?? new Set<string>();\n const genNamedIds = generatedTs.named.get(mod) ?? new Set<string>();\n const extra = [...existIds].filter(\n (id) => !genIds.has(id) && !genNamedIds.has(id) && identifierUsed(ignoreRegionText, id),\n );\n if (extra.length > 0) extraTsLines.push(`import type { ${extra.join(', ')} } from '${mod}';`);\n }\n\n // PHP `use Foo\\Bar;` and `use Foo\\Bar as Baz;` — namespace-qualified only\n // (a backslash anywhere in the path) so this doesn't mistakenly hoist\n // single-segment in-class trait references like `use TraitName;`.\n const isPhpUseImport = (l: string) => /^use\\s+[\\w\\\\]+\\\\[\\w\\\\]*(\\s+as\\s+\\w+)?\\s*;?$/.test(l);\n const existingPhpUse = new Set(existingOutsideIgnore.filter(isPhpUseImport).map((l) => l.trim()));\n const generatedPhpUse = new Set(resultLines.filter(isPhpUseImport).map((l) => l.trim()));\n const extraPhpUse = [...existingPhpUse].filter((l) => !generatedPhpUse.has(l));\n\n // Ruby `require '...'` and `require_relative '...'`. Dedupe by (kind, path)\n // so quote style differs without producing duplicates — e.g. when the\n // emitter writes `require 'json'` but a Ruby formatter has rewritten the\n // on-disk copy to `require \"json\"`.\n const rubyRequireRe = /^(require(?:_relative)?)\\s+['\"]([^'\"]+)['\"]\\s*$/;\n const rubyRequireKey = (l: string): string | undefined => {\n const m = l.trim().match(rubyRequireRe);\n return m ? `${m[1]}\\t${m[2]}` : undefined;\n };\n const generatedRubyRequireKeys = new Set<string>();\n for (const l of resultLines) {\n const key = rubyRequireKey(l);\n if (key) generatedRubyRequireKeys.add(key);\n }\n const seenExistingKeys = new Set<string>();\n const extraRubyRequire: string[] = [];\n for (const l of existingOutsideIgnore) {\n const key = rubyRequireKey(l);\n if (!key) continue;\n if (generatedRubyRequireKeys.has(key)) continue;\n if (seenExistingKeys.has(key)) continue;\n seenExistingKeys.add(key);\n extraRubyRequire.push(l.trim());\n }\n\n const allExtra = [...extraSimple, ...extraFromLines, ...extraTsLines, ...extraPhpUse, ...extraRubyRequire];\n if (allExtra.length === 0) return;\n\n // Find last import line in resultLines (accounting for multiline imports).\n // Recognizes Python (`from X import Y`, `import X`), TS (`import …`), PHP\n // (`use …`), and Ruby (`require`, `require_relative`).\n const isImportStart = (l: string) =>\n /^\\s*import(\\s|$)/.test(l) ||\n /^from\\s+/.test(l) ||\n /^\\s*use\\s+[\\w\\\\]/.test(l) ||\n /^\\s*require(_relative)?\\s+['\"]/.test(l);\n let lastImportIdx = -1;\n for (let i = 0; i < resultLines.length; i++) {\n if (!isImportStart(resultLines[i])) continue;\n lastImportIdx = i;\n const opens = (resultLines[i].match(/[({]/g) ?? []).length;\n const closes = (resultLines[i].match(/[)}]/g) ?? []).length;\n if (opens > closes) {\n while (i + 1 < resultLines.length) {\n i++;\n lastImportIdx = i;\n if ((resultLines[i].match(/[)}]/g) ?? []).length > 0) break;\n }\n }\n }\n\n if (lastImportIdx >= 0) {\n resultLines.splice(lastImportIdx + 1, 0, ...allExtra);\n }\n}\n","import type { ApiSpec, Service, Operation, HttpMethod } from './types.js';\n\n/** Minimal snake_case converter for path segments (avoids cross-layer import). */\nfunction toSnake(s: string): string {\n return s\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/[-\\s.]+/g, '_')\n .toLowerCase();\n}\n\n// ---------------------------------------------------------------------------\n// Hint types — consumer-provided overrides for operation resolution\n// ---------------------------------------------------------------------------\n\n/** Per-operation override keyed by \"METHOD /path\" (e.g. \"POST /sso/token\"). */\nexport interface OperationHint {\n /** Override the algorithm-derived method name. */\n name?: string;\n /** Remount this operation to a different service/namespace (PascalCase). */\n mountOn?: string;\n /** Split a union-body operation into N typed wrapper methods. */\n split?: SplitHint[];\n /** Inject constant body defaults (e.g. { grant_type: 'password' }). */\n defaults?: Record<string, string | number | boolean>;\n /** Fields the SDK reads from client config at runtime (e.g. ['client_id']). */\n inferFromClient?: string[];\n /**\n * Marks this operation as a URL builder rather than a real HTTP call. Emitters\n * should generate a method that returns the constructed URL (typically as a\n * string) without performing any I/O. Used for OAuth-style redirect endpoints\n * such as /sso/authorize and /user_management/sessions/logout.\n */\n urlBuilder?: boolean;\n}\n\nexport interface SplitHint {\n /** Wrapper method name (snake_case). */\n name: string;\n /** The discriminated union variant model name (e.g. 'PasswordSessionAuthenticateRequest'). */\n targetVariant: string;\n /** Constant body fields injected by the wrapper. */\n defaults?: Record<string, string | number | boolean>;\n /** Fields the SDK reads from client config at runtime. */\n inferFromClient?: string[];\n /** Only these body fields are exposed as method params. If omitted, all non-default/non-inferred fields are exposed. */\n exposedParams?: string[];\n /**\n * Subset of exposedParams that should be emitted as optional even when the\n * variant model would otherwise mark them required (or when the variant has\n * no addressable model, as happens for inline oneOf branches).\n */\n optionalParams?: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Resolved output — consumed by emitters\n// ---------------------------------------------------------------------------\n\nexport interface ResolvedOperation {\n /** The original IR operation (preserves description, params, types, etc.). */\n operation: Operation;\n /** The original IR service that owns this operation. */\n service: Service;\n /** Resolved snake_case method name (emitters convert to their convention). */\n methodName: string;\n /** Resolved target service/namespace (PascalCase). */\n mountOn: string;\n /** For split operations: one wrapper per union variant. */\n wrappers?: ResolvedWrapper[];\n /** Constant defaults injected into query/body at runtime (from operation-level hint). */\n defaults: Record<string, string | number | boolean>;\n /** Fields the SDK reads from client config at runtime (from operation-level hint). */\n inferFromClient: string[];\n /** Marks this operation as a URL builder; emitters should not generate an HTTP call. */\n urlBuilder: boolean;\n}\n\nexport interface ResolvedWrapper {\n /** Wrapper method name (snake_case). */\n name: string;\n /** The discriminated union variant model name. */\n targetVariant: string;\n /** Constant body defaults injected by the wrapper. */\n defaults: Record<string, string | number | boolean>;\n /** Fields read from client config at runtime. */\n inferFromClient: string[];\n /** Body fields exposed as method params. */\n exposedParams: string[];\n /** Optional body fields (not required in the variant). */\n optionalParams: string[];\n /** Response model name (if any). */\n responseModelName: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// Algorithm\n// ---------------------------------------------------------------------------\n\n/**\n * Action verbs recognised at the terminal path segment.\n * When a path ends with one of these, we use it as the verb instead of\n * deriving a CRUD verb from the HTTP method.\n */\nconst ACTION_VERBS = new Set([\n 'accept',\n 'activate',\n 'authorize',\n 'challenge',\n 'check',\n 'complete',\n 'confirm',\n 'deactivate',\n 'disable',\n 'enable',\n 'enroll',\n 'generate',\n 'reactivate',\n 'resend',\n 'revoke',\n 'send',\n 'verify',\n]);\n\n/** Map HTTP method → default CRUD verb. */\nconst CRUD_VERB: Record<HttpMethod, string> = {\n get: 'list',\n post: 'create',\n put: 'update',\n patch: 'update',\n delete: 'delete',\n head: 'get',\n options: 'list',\n trace: 'list',\n};\n\n/**\n * Naive singularization: strips trailing \"s\" with common-sense exceptions.\n * Good enough for API resource nouns; not a general-purpose English stemmer.\n */\nfunction singularize(word: string): string {\n if (word.length <= 2) return word;\n if (word.endsWith('ies')) return word.slice(0, -3) + 'y';\n if (\n word.endsWith('ses') ||\n word.endsWith('zes') ||\n word.endsWith('xes') ||\n word.endsWith('ches') ||\n word.endsWith('shes')\n ) {\n return word.slice(0, -2);\n }\n if (word.endsWith('ss') || word.endsWith('us') || word.endsWith('is')) return word;\n if (word.endsWith('s')) return word.slice(0, -1);\n return word;\n}\n\n/**\n * Derive a snake_case method name from an operation's HTTP method and path.\n *\n * Rules:\n * 1. Strip path-param segments (`{id}`, `{slug}`, etc.)\n * 2. If the terminal segment is an action verb, use it as the verb\n * 3. Otherwise, use the CRUD verb for the HTTP method\n * 4. For GET on a collection (no trailing {id}), use \"list\"; with {id}, use \"get\"\n * 5. For POST on a resource path, if only one path param, use \"create\" singular\n * 6. Singularize the resource noun for single-resource operations\n */\nexport function deriveMethodName(op: Operation, _service: Service): string {\n const segments = op.path.split('/').filter(Boolean);\n\n // Separate static segments from param segments\n const staticSegments: string[] = [];\n let trailingParam = false;\n for (const seg of segments) {\n if (seg.startsWith('{') && seg.endsWith('}')) {\n trailingParam = true;\n } else {\n staticSegments.push(seg);\n trailingParam = false;\n }\n }\n\n if (staticSegments.length === 0) {\n return `${CRUD_VERB[op.httpMethod] ?? 'get'}_root`;\n }\n\n const terminal = toSnake(staticSegments[staticSegments.length - 1]);\n\n // Check if terminal is an action verb\n if (ACTION_VERBS.has(terminal)) {\n // Resource context from preceding segments\n const context = staticSegments.slice(0, -1).filter((s) => !s.startsWith('{'));\n const resource = context.length > 0 ? toSnake(singularize(context[context.length - 1])) : '';\n if (resource) {\n return `${terminal}_${resource}`;\n }\n return terminal;\n }\n\n // Determine verb from HTTP method\n let verb = CRUD_VERB[op.httpMethod] ?? 'get';\n\n // GET with trailing {id} → \"get\" instead of \"list\"\n if (op.httpMethod === 'get' && trailingParam) {\n verb = 'get';\n }\n\n // Build resource name from static segments.\n // When path params separate static segments, include the penultimate static\n // segment (singularized) as a parent-context prefix to disambiguate nested paths.\n // e.g. /authorization/organizations/{id}/roles → \"organization_roles\"\n let resource = toSnake(terminal);\n if (staticSegments.length >= 2) {\n const penultimate = staticSegments[staticSegments.length - 2];\n // Check if a path param appears between the penultimate and terminal segments\n // in the original path by finding both positions and looking for {…} between them.\n const penIdx = segments.lastIndexOf(penultimate);\n const termIdx = segments.lastIndexOf(staticSegments[staticSegments.length - 1]);\n const hasParamBetween = segments.slice(penIdx + 1, termIdx).some((s) => s.startsWith('{'));\n if (hasParamBetween) {\n const prefix = toSnake(singularize(penultimate));\n resource = `${prefix}_${resource}`;\n }\n }\n\n // Singularize when:\n // * there's a trailing path param (single-resource read/update/delete), or\n // * the verb itself implies a single-resource operation (e.g. POST → create\n // always creates one item even when posted to a collection endpoint).\n const isSingleResource = trailingParam || verb === 'create';\n const noun = isSingleResource ? singularize(resource) : resource;\n\n // For \"list\" verb, keep plural\n const finalNoun = verb === 'list' ? resource : noun;\n\n return `${verb}_${finalNoun}`;\n}\n\n/**\n * Resolve all operations in the spec, applying hints and mount rules.\n *\n * @param spec - The parsed API spec\n * @param hints - Per-operation overrides keyed by \"METHOD /path\"\n * @param mountRules - Service name → target service mappings\n * @returns Resolved operations ready for emitter consumption\n */\nexport function resolveOperations(\n spec: ApiSpec,\n hints?: Record<string, OperationHint>,\n mountRules?: Record<string, string>,\n): ResolvedOperation[] {\n const resolved: ResolvedOperation[] = [];\n const hintMap = hints ?? {};\n const mounts = mountRules ?? {};\n\n for (const service of spec.services) {\n for (const op of service.operations) {\n const key = `${op.httpMethod.toUpperCase()} ${op.path}`;\n const hint = hintMap[key];\n\n // Resolve method name: hint > algorithm\n const methodName = hint?.name ?? deriveMethodName(op, service);\n\n // Resolve mount target: per-op hint > service mount rule > original service\n const mountOn = hint?.mountOn ?? mounts[service.name] ?? service.name;\n\n // Build wrappers for split operations\n let wrappers: ResolvedWrapper[] | undefined;\n if (hint?.split) {\n wrappers = hint.split.map((sh) => ({\n name: sh.name,\n targetVariant: sh.targetVariant,\n defaults: sh.defaults ?? {},\n inferFromClient: sh.inferFromClient ?? [],\n exposedParams: sh.exposedParams ?? [],\n optionalParams: sh.optionalParams ?? [],\n responseModelName: resolveResponseModelName(op),\n }));\n }\n\n resolved.push({\n operation: op,\n service,\n methodName,\n mountOn,\n wrappers,\n defaults: hint?.defaults ?? {},\n inferFromClient: hint?.inferFromClient ?? [],\n urlBuilder: hint?.urlBuilder ?? false,\n });\n }\n }\n\n return resolved;\n}\n\n/** Extract the response model name from an operation (for wrapper metadata). */\nfunction resolveResponseModelName(op: Operation): string | null {\n if (op.httpMethod === 'delete') return null;\n const ref = op.response;\n if (ref.kind === 'model') return ref.name;\n if (ref.kind === 'nullable' && ref.inner.kind === 'model') return ref.inner.name;\n return null;\n}\n","import type { ApiSpec, Model, TypeRef, Service } from '../ir/types.js';\nimport { walkTypeRef } from '../ir/types.js';\nimport type { OperationHint } from '../ir/operation-hints.js';\nimport { resolveOperations } from '../ir/operation-hints.js';\nimport type { Emitter, EmitterContext, GeneratedFile, OperationsMap } from './types.js';\nimport type { ApiSurface, OverlayLookup } from '../compat/types.js';\nimport { toSnakeCase } from '../utils/naming.js';\n\nexport function buildEmitterContext(\n spec: ApiSpec,\n options: {\n namespace: string;\n outputDir: string;\n apiSurface?: ApiSurface;\n overlayLookup?: OverlayLookup;\n operationHints?: Record<string, OperationHint>;\n mountRules?: Record<string, string>;\n modelHints?: Record<string, string>;\n emitterOptions?: Record<string, unknown>;\n target?: string;\n priorTargetManifestPaths?: Set<string>;\n },\n): EmitterContext {\n return {\n namespace: toSnakeCase(options.namespace),\n namespacePascal: options.namespace,\n spec,\n outputDir: options.outputDir,\n apiSurface: options.apiSurface,\n overlayLookup: options.overlayLookup,\n resolvedOperations: resolveOperations(spec, options.operationHints, options.mountRules),\n modelHints: options.modelHints,\n emitterOptions: options.emitterOptions,\n targetDir: options.target,\n priorTargetManifestPaths: options.priorTargetManifestPaths,\n };\n}\n\n/**\n * Collect model and enum names transitively referenced by service operations.\n * Walks operation parameters, request bodies, responses, and pagination item\n * types, then chases model field references until the set stabilizes.\n */\nexport function collectReferencedNames(\n services: Service[],\n models: Model[],\n): { models: Set<string>; enums: Set<string> } {\n const referencedModels = new Set<string>();\n const referencedEnums = new Set<string>();\n\n const collectFromTypeRef = (ref: TypeRef): void => {\n walkTypeRef(ref, {\n model: (r) => referencedModels.add(r.name),\n enum: (r) => referencedEnums.add(r.name),\n });\n };\n\n // Seed: walk every operation's params, request body, response, errors, and pagination\n for (const service of services) {\n for (const op of service.operations) {\n for (const p of [...op.pathParams, ...op.queryParams, ...op.headerParams, ...(op.cookieParams ?? [])]) {\n collectFromTypeRef(p.type);\n }\n if (op.requestBody) collectFromTypeRef(op.requestBody);\n collectFromTypeRef(op.response);\n if (op.pagination) collectFromTypeRef(op.pagination.itemType);\n for (const err of op.errors) {\n if (err.type) collectFromTypeRef(err.type);\n }\n if (op.successResponses) {\n for (const sr of op.successResponses) {\n collectFromTypeRef(sr.type);\n }\n }\n }\n }\n\n // Preserve discriminated models as public SDK types even when no operation\n // returns them directly. This matters for event/webhook unions where the base\n // operation references a generic envelope but the variant structs are still\n // useful public surface.\n //\n // Also preserve the variants mapped from an `allOf [base, oneOf […]]` base\n // (carried as `Model.discriminator.mapping`). The base model is reached\n // through the operation; without explicitly chasing its mapping, the\n // variant structs would be unreachable and the dispatcher would dangle\n // imports.\n for (const model of models) {\n if (isDiscriminatedModel(model)) {\n referencedModels.add(model.name);\n }\n const disc = model.discriminator;\n if (disc?.mapping) {\n for (const variantName of Object.values(disc.mapping)) {\n referencedModels.add(variantName);\n }\n }\n }\n\n // Chase: transitively resolve model field references until stable\n const modelsByName = new Map(models.map((m) => [m.name, m]));\n const visited = new Set<string>();\n const queue = [...referencedModels];\n while (queue.length > 0) {\n const name = queue.pop()!;\n if (visited.has(name)) continue;\n visited.add(name);\n const model = modelsByName.get(name);\n if (!model) continue;\n for (const field of model.fields) {\n collectFromTypeRef(field.type);\n // If new models were discovered, enqueue them\n for (const m of referencedModels) {\n if (!visited.has(m)) queue.push(m);\n }\n }\n }\n\n return { models: referencedModels, enums: referencedEnums };\n}\n\nfunction isDiscriminatedModel(model: Model): boolean {\n return model.fields.some(\n (field) =>\n (field.name === 'event' || field.name === 'type' || field.name === 'object') && field.type.kind === 'literal',\n );\n}\n\n/** Collect all generated files from an emitter (no headers, no path prefixes). */\nexport function generateAllFiles(spec: ApiSpec, emitter: Emitter, ctx: EmitterContext): GeneratedFile[] {\n const referenced = collectReferencedNames(spec.services, spec.models);\n const reachableModels = spec.models.filter((m) => referenced.models.has(m.name));\n const reachableEnums = spec.enums.filter((e) => referenced.enums.has(e.name));\n const reachableSpec: ApiSpec = { ...spec, models: reachableModels, enums: reachableEnums };\n\n return [\n ...emitter.generateModels(reachableModels, ctx),\n ...emitter.generateEnums(reachableEnums, ctx),\n ...emitter.generateResources(spec.services, ctx),\n ...emitter.generateClient(spec, ctx),\n ...emitter.generateErrors(ctx),\n ...(emitter.generateTypeSignatures?.(reachableSpec, ctx) ?? []),\n ...emitter.generateTests(reachableSpec, ctx),\n ];\n}\n\n/** Apply file header to generated files, respecting headerPlacement and JSON files. */\nexport function applyFileHeaders(files: GeneratedFile[], header: string): GeneratedFile[] {\n return files.map((f) => ({\n ...f,\n content:\n !header || f.path.endsWith('.json') || f.headerPlacement === 'skip' ? f.content : header + '\\n\\n' + f.content,\n skipIfExists: f.skipIfExists ?? false,\n }));\n}\n\nexport function generateFiles(\n spec: ApiSpec,\n emitter: Emitter,\n options: {\n namespace: string;\n outputDir: string;\n apiSurface?: ApiSurface;\n overlayLookup?: OverlayLookup;\n operationHints?: Record<string, OperationHint>;\n mountRules?: Record<string, string>;\n modelHints?: Record<string, string>;\n emitterOptions?: Record<string, unknown>;\n target?: string;\n priorTargetManifestPaths?: Set<string>;\n },\n): { files: GeneratedFile[]; ctx: EmitterContext; header: string; operations?: OperationsMap } {\n const ctx = buildEmitterContext(spec, options);\n const files = generateAllFiles(spec, emitter, ctx);\n const operations = emitter.buildOperationsMap?.(spec, ctx);\n const header = emitter.fileHeader();\n return { files: applyFileHeaders(files, header), ctx, header, operations };\n}\n","import * as fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { GeneratedFile } from './types.js';\nimport { writeFiles, type WriteResult } from './writer.js';\nimport { extractStatements } from './merger.js';\nimport { hasGrammar } from './merger.js';\n\n/**\n * Resolve a relative import path against a source file path to get the\n * target file path. Handles implicit .ts extensions and /index.ts.\n */\nfunction resolveImportPath(\n fromFilePath: string,\n importModulePath: string,\n knownPaths: Set<string>,\n): string | undefined {\n // Strip quotes from module path key (tree-sitter keeps them)\n const cleaned = importModulePath.replace(/^['\"]|['\"]$/g, '');\n // Skip non-relative imports (node_modules, bare specifiers)\n if (!cleaned.startsWith('.')) return undefined;\n\n const dir = path.dirname(fromFilePath);\n const resolved = path.normalize(path.join(dir, cleaned));\n\n // Try exact match, .ts, /index.ts\n for (const candidate of [resolved, `${resolved}.ts`, `${resolved}/index.ts`]) {\n if (knownPaths.has(candidate)) return candidate;\n }\n return undefined;\n}\n\n/**\n * Determine whether a generated file is a \"root\" — a file that should always\n * be integrated into the target. Roots are entry points from which we trace\n * the import graph. Everything else must be reachable from a root.\n *\n * Roots: resource classes, client, config, errors, enums, barrel index files.\n * Non-roots: serializers, fixtures, standalone interfaces, test files.\n */\nfunction isRootFile(filePath: string): boolean {\n // Fixtures are never roots (and should be filtered by integrateTarget already)\n if (filePath.includes('/fixtures/')) return false;\n // Test files are roots — they are standalone entry points that belong in the\n // target repo even though nothing imports them.\n if (filePath.endsWith('.spec.ts') || filePath.endsWith('.test.ts')) return true;\n // Serializer files\n if (filePath.includes('/serializers/')) return false;\n // Standalone interface files (not barrel/index)\n if (filePath.includes('/interfaces/') && !filePath.endsWith('/index.ts')) return false;\n // Everything else is a root: resource classes, client, config, errors, enums, barrel files\n return true;\n}\n\n/**\n * Build a file-level dependency graph from generated files and return only\n * files reachable from root entry points. Uses tree-sitter to parse imports.\n */\nexport async function treeShakeFiles(files: GeneratedFile[], language: string): Promise<GeneratedFile[]> {\n if (!hasGrammar(language)) return files;\n\n const knownPaths = new Set(files.map((f) => f.path));\n\n // Build dependency graph: file → set of files it imports\n const deps = new Map<string, Set<string>>();\n for (const file of files) {\n // Only parse .ts/.js files (skip JSON, etc.)\n if (!file.path.endsWith('.ts') && !file.path.endsWith('.js')) {\n deps.set(file.path, new Set());\n continue;\n }\n const parsed = await extractStatements(file.content, language);\n const fileDeps = new Set<string>();\n for (const imp of parsed.imports) {\n const resolved = resolveImportPath(file.path, imp.key, knownPaths);\n if (resolved) fileDeps.add(resolved);\n }\n // Also check re-export statements (export * from './foo')\n for (const stmt of parsed.statements) {\n if (stmt.kind === 'reexport') {\n // Extract module path from \"export * from './foo'\" or \"export { X } from './foo'\"\n const match = stmt.text.match(/from\\s+['\"]([^'\"]+)['\"]/);\n if (match) {\n const resolved = resolveImportPath(file.path, match[1], knownPaths);\n if (resolved) fileDeps.add(resolved);\n }\n }\n }\n deps.set(file.path, fileDeps);\n }\n\n // Determine which file extensions are source code for this language\n const codeExtensions = new Set([\n '.ts',\n '.js',\n '.tsx',\n '.jsx',\n '.py',\n '.rb',\n '.go',\n '.rs',\n '.kt',\n '.cs',\n '.ex',\n '.exs',\n '.php',\n ]);\n\n // BFS from roots\n const reachable = new Set<string>();\n const queue: string[] = [];\n for (const file of files) {\n const ext = file.path.slice(file.path.lastIndexOf('.'));\n // Non-code files (JSON, etc.) are always reachable — they can't participate\n // in the import graph and are loaded at runtime (e.g. test fixtures).\n if (!codeExtensions.has(ext)) {\n reachable.add(file.path);\n continue;\n }\n if (isRootFile(file.path)) {\n reachable.add(file.path);\n queue.push(file.path);\n }\n }\n while (queue.length > 0) {\n const current = queue.pop()!;\n const fileDeps = deps.get(current);\n if (!fileDeps) continue;\n for (const dep of fileDeps) {\n if (!reachable.has(dep)) {\n reachable.add(dep);\n queue.push(dep);\n }\n }\n }\n\n return files.filter((f) => reachable.has(f.path));\n}\n\nexport function mapFilesForTargetIntegration(files: GeneratedFile[], language: string): GeneratedFile[] {\n const langPrefix = `${language}/`;\n return files\n .filter((f) => f.integrateTarget !== false) // integrateTarget: false files are standalone-only\n .map((f) => {\n const stripped = f.path.startsWith(langPrefix) ? f.path.replace(langPrefix, '') : f.path;\n return {\n ...f,\n skipIfExists: false, // Always merge in target — never hard-skip\n path: stripped,\n };\n });\n}\n\n/**\n * Resolve file-to-directory conflicts in the target.\n *\n * When a generated file creates a package directory (e.g., `api_keys/__init__.py`)\n * that would shadow an existing module file (e.g., `api_keys.py`), move the\n * module file's content into `_compat.py` inside the package and add a\n * re-export from `__init__.py`. This preserves backward-compatible imports\n * (e.g., `from workos.api_keys import ApiKeysModule`) while the package directory\n * provides the generated models and resource classes.\n */\nasync function resolveFileToDirectoryConflicts(\n files: GeneratedFile[],\n targetDir: string,\n): Promise<{ files: GeneratedFile[]; removals: string[] }> {\n const result = [...files];\n const removals: string[] = [];\n\n for (let i = 0; i < result.length; i++) {\n const file = result[i];\n // Match package init files: e.g., src/workos/api_keys/__init__.py\n const match = file.path.match(/^(.+)\\/__init__\\.py$/);\n if (!match) continue;\n\n const dirPath = match[1]; // e.g., src/workos/api_keys\n const moduleFilePath = `${dirPath}.py`; // e.g., src/workos/api_keys.py\n const fullModulePath = path.join(targetDir, moduleFilePath);\n\n let moduleContent: string;\n try {\n moduleContent = await fs.readFile(fullModulePath, 'utf-8');\n } catch {\n continue; // Module file doesn't exist — no conflict\n }\n\n // Create a compat shim inside the package with the old module's content\n const compatPath = `${dirPath}/_compat.py`;\n result.push({\n path: compatPath,\n content: moduleContent,\n overwriteExisting: true,\n });\n\n // Append re-export from _compat to __init__.py so existing imports work.\n // Compat must come AFTER generated models so hand-written types take\n // precedence over generated types with the same name.\n const compatImport = 'from ._compat import * # noqa: F401,F403 # pyright: ignore[reportUnusedImport]';\n const existingContent = file.content.endsWith('\\n') ? file.content : file.content + '\\n';\n result[i] = {\n ...file,\n content: existingContent + compatImport + '\\n',\n };\n\n // Schedule the shadowed module file for removal\n removals.push(fullModulePath);\n }\n\n return { files: result, removals };\n}\n\nexport interface IntegrateResult extends WriteResult {\n /** Final set of paths this run claims ownership of in the target (post tree-shake + conflict resolution). */\n emittedPaths: string[];\n}\n\nexport async function integrateGeneratedFiles(opts: {\n files: GeneratedFile[];\n language: string;\n targetDir: string;\n header: string;\n}): Promise<IntegrateResult> {\n const mapped = mapFilesForTargetIntegration(opts.files, opts.language);\n const shaken = await treeShakeFiles(mapped, opts.language);\n\n // Handle file-to-directory conflicts before writing\n const { files: resolved, removals } = await resolveFileToDirectoryConflicts(shaken, opts.targetDir);\n\n const result = await writeFiles(resolved, opts.targetDir, {\n language: opts.language,\n header: opts.header,\n });\n\n // Remove shadowed module files after integration\n for (const filePath of removals) {\n try {\n await fs.unlink(filePath);\n } catch {\n // File may already be gone\n }\n }\n\n // The manifest tracks ALL files oagen owns, including tree-shaken ones.\n // Tree-shaking decides what to write, but shaken files are still oagen-managed\n // and must not be pruned from the target on subsequent runs.\n return { ...result, emittedPaths: mapped.map((f) => f.path) };\n}\n","/**\n * Post-integration formatter.\n *\n * After generating and merging files into a target directory, runs the\n * emitter-provided format command on all written/merged files so that\n * generated code matches the target project's style conventions.\n */\n\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport * as path from 'node:path';\nimport type { Emitter } from './types.js';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Run the emitter's format command on the given target files.\n * Silently skips if the emitter has no formatCommand or returns null.\n */\nexport async function formatTargetFiles(emitter: Emitter, targetDir: string, filePaths: string[]): Promise<void> {\n if (filePaths.length === 0) return;\n if (!emitter.formatCommand) return;\n\n const formatCmd = emitter.formatCommand(targetDir);\n if (!formatCmd) return;\n\n const absolutePaths = filePaths.map((f) => path.resolve(targetDir, f));\n const batchSize = formatCmd.batchSize ?? 100;\n\n process.stderr.write(\n `[oagen] formatting ${absolutePaths.length} file(s) with ${formatCmd.cmd} (batch ${batchSize})\\n`,\n );\n\n for (let i = 0; i < absolutePaths.length; i += batchSize) {\n const batch = absolutePaths.slice(i, i + batchSize);\n try {\n await execFileAsync(formatCmd.cmd, [...formatCmd.args, ...batch], {\n cwd: targetDir,\n maxBuffer: 10 * 1024 * 1024,\n timeout: 120_000,\n });\n } catch (err) {\n // Formatter failed on this batch — continue with remaining batches.\n // Surface the failure on stderr so misconfigured commands don't silently\n // leave generated code unformatted every regen.\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[oagen] formatter batch failed: ${msg}\\n`);\n }\n }\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\n/**\n * Prune-manifest support for `oagen generate`.\n *\n * The manifest records every auto-generated file emitted on the previous run,\n * relative to the directory it lives in (either the `--output` standalone dir\n * or the `--target` integration dir). On the next run we diff the previous\n * list against the current emission set and delete anything that's no longer\n * produced — preventing stale-file accumulation across regens.\n *\n * Design notes:\n * - The manifest is versioned so future format changes can be handled safely.\n * - Paths are stored sorted for deterministic diffs in git.\n * - Deletion is gated on a header guard when one is available: we only remove\n * files whose contents start with the auto-generated header. This protects\n * a hand-maintained file that happens to share a name with a previously\n * generated one (extremely rare, but worth catching).\n * - On first adoption (no previous manifest), pruning is skipped and a\n * one-line notice is printed — no surprise deletions.\n */\n\nexport const MANIFEST_FILENAME = '.oagen-manifest.json';\nconst MANIFEST_VERSION = 2;\n\nexport interface Manifest {\n /** Schema version. Bump when the format changes incompatibly. */\n version: number;\n /** Emitter language (e.g. \"python\"). Used only as a consistency hint. */\n language: string;\n /** Human-readable or package-level SDK identity (e.g. \"workos-php\"). */\n sdkName?: string;\n /** ISO-8601 timestamp of the run that produced the current manifest contents. */\n generatedAt: string;\n /** SHA-256 hash of the source OpenAPI spec used for generation. */\n specSha?: string;\n /** Path or reference to the source spec. */\n specPath?: string;\n /** Git SHA or version of the emitter code used. */\n emitterSha?: string;\n /** Emitter version string if available. */\n emitterVersion?: string;\n /** SHA-256 hash of the effective oagen.config.ts after resolution. */\n configSha?: string;\n /** Version of the compat snapshot/report schema expected by this generation. */\n compatSchemaVersion?: string;\n /** Sorted list of paths, relative to the manifest's containing directory. */\n files: string[];\n /** Maps \"METHOD /path\" to SDK method + service property name. */\n operations?: Record<string, unknown>;\n}\n\nexport interface PruneResult {\n /** Paths actually deleted. */\n pruned: string[];\n /** Paths skipped because the header guard didn't match (preserved). */\n preserved: string[];\n /** Paths already absent on disk (nothing to do). */\n missing: string[];\n}\n\n/** Read `.oagen-manifest.json` from a directory. Returns null if absent or malformed. */\nexport async function readManifest(dir: string): Promise<Manifest | null> {\n const manifestPath = path.join(dir, MANIFEST_FILENAME);\n let raw: string;\n try {\n raw = await fs.readFile(manifestPath, 'utf-8');\n } catch {\n return null;\n }\n try {\n const parsed = JSON.parse(raw) as Partial<Manifest>;\n if (\n typeof parsed.version !== 'number' ||\n typeof parsed.language !== 'string' ||\n typeof parsed.generatedAt !== 'string' ||\n !Array.isArray(parsed.files) ||\n !parsed.files.every((p): p is string => typeof p === 'string')\n ) {\n return null;\n }\n if (parsed.version > MANIFEST_VERSION) {\n console.warn(\n `[oagen] ${MANIFEST_FILENAME} schema version ${parsed.version} is newer than supported (${MANIFEST_VERSION}); ignoring for pruning.`,\n );\n return null;\n }\n // v1 manifests are forward-compatible — new fields are simply absent\n return parsed as Manifest;\n } catch {\n return null;\n }\n}\n\n/** Options for writing a manifest. */\nexport interface WriteManifestOpts {\n language: string;\n files: Iterable<string>;\n sdkName?: string;\n specSha?: string;\n specPath?: string;\n emitterSha?: string;\n emitterVersion?: string;\n configSha?: string;\n compatSchemaVersion?: string;\n operations?: Record<string, unknown>;\n}\n\n/** Write `.oagen-manifest.json` to a directory with sorted paths. */\nexport async function writeManifest(dir: string, opts: WriteManifestOpts): Promise<void> {\n const manifestPath = path.join(dir, MANIFEST_FILENAME);\n const manifest: Manifest = {\n version: MANIFEST_VERSION,\n language: opts.language,\n ...(opts.sdkName !== undefined ? { sdkName: opts.sdkName } : {}),\n generatedAt: new Date().toISOString(),\n ...(opts.specSha !== undefined ? { specSha: opts.specSha } : {}),\n ...(opts.specPath !== undefined ? { specPath: opts.specPath } : {}),\n ...(opts.emitterSha !== undefined ? { emitterSha: opts.emitterSha } : {}),\n ...(opts.emitterVersion !== undefined ? { emitterVersion: opts.emitterVersion } : {}),\n ...(opts.configSha !== undefined ? { configSha: opts.configSha } : {}),\n ...(opts.compatSchemaVersion !== undefined ? { compatSchemaVersion: opts.compatSchemaVersion } : {}),\n files: [...new Set(opts.files)].sort(),\n ...(opts.operations !== undefined ? { operations: opts.operations } : {}),\n };\n const previous = await readManifest(dir);\n if (previous && sameManifestExceptGeneratedAt(previous, manifest)) {\n manifest.generatedAt = previous.generatedAt;\n }\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\\n', 'utf-8');\n}\n\nfunction sameManifestExceptGeneratedAt(a: Manifest, b: Manifest): boolean {\n const { generatedAt: _aGeneratedAt, ...aComparable } = a;\n const { generatedAt: _bGeneratedAt, ...bComparable } = b;\n return JSON.stringify(aComparable) === JSON.stringify(bComparable);\n}\n\n/** Return the set of previous paths no longer present in the current emission. */\nexport function computeStalePaths(prev: Manifest, currentPaths: Iterable<string>): string[] {\n const current = new Set(currentPaths);\n return prev.files.filter((p) => !current.has(p)).sort();\n}\n\n/**\n * Delete stale files from `dir`.\n *\n * When `header` is provided, a file is only deleted if its contents start with\n * that header — so hand-maintained files that somehow collide with a previously\n * generated path can't be clobbered. When `header` is omitted, the guard is\n * skipped (useful for non-source artifacts like fixture JSON).\n *\n * Returns lists for reporting. Empty parent directories are removed after\n * deletion, up to (but not including) `dir` itself.\n */\nexport async function pruneStaleFiles(\n dir: string,\n paths: string[],\n opts: { header?: string } = {},\n): Promise<PruneResult> {\n const pruned: string[] = [];\n const preserved: string[] = [];\n const missing: string[] = [];\n\n for (const relPath of paths) {\n const fullPath = path.join(dir, relPath);\n let content: string;\n try {\n content = await fs.readFile(fullPath, 'utf-8');\n } catch {\n missing.push(relPath);\n continue;\n }\n if (opts.header && !content.startsWith(opts.header)) {\n preserved.push(relPath);\n continue;\n }\n try {\n await fs.unlink(fullPath);\n pruned.push(relPath);\n } catch {\n // Racing deletion or permission issue — treat as missing rather than fatal.\n missing.push(relPath);\n continue;\n }\n await removeEmptyParents(path.dirname(fullPath), dir);\n }\n\n return { pruned, preserved, missing };\n}\n\n/**\n * Walk up from `startDir` removing empty directories until we hit `stopDir`\n * (exclusive) or a non-empty directory. Silently ignores errors.\n */\nasync function removeEmptyParents(startDir: string, stopDir: string): Promise<void> {\n let current = path.resolve(startDir);\n const stop = path.resolve(stopDir);\n while (current.startsWith(stop + path.sep) && current !== stop) {\n let entries: string[];\n try {\n entries = await fs.readdir(current);\n } catch {\n return;\n }\n if (entries.length > 0) return;\n try {\n await fs.rmdir(current);\n } catch {\n return;\n }\n current = path.dirname(current);\n }\n}\n","import type { ApiSpec } from '../ir/types.js';\nimport type { OperationHint } from '../ir/operation-hints.js';\nimport type { Emitter, GeneratedFile } from './types.js';\nimport type { ApiSurface, OverlayLookup } from '../compat/types.js';\nimport { writeFiles } from './writer.js';\nimport { generateFiles } from './generate-files.js';\nimport { integrateGeneratedFiles } from './integrate.js';\nimport { formatTargetFiles } from './formatter.js';\nimport { computeStalePaths, MANIFEST_FILENAME, pruneStaleFiles, readManifest, writeManifest } from './manifest.js';\n\nexport async function generate(\n spec: ApiSpec,\n emitter: Emitter,\n options: {\n namespace: string;\n dryRun?: boolean;\n outputDir: string;\n target?: string;\n apiSurface?: ApiSurface;\n overlayLookup?: OverlayLookup;\n operationHints?: Record<string, OperationHint>;\n mountRules?: Record<string, string>;\n modelHints?: Record<string, string>;\n emitterOptions?: Record<string, unknown>;\n /** When true, skip deletion of files recorded in the previous manifest but not in the current emission. */\n noPrune?: boolean;\n },\n): Promise<GeneratedFile[]> {\n // Read previous manifests up front so emitters can mark files the prior run\n // wrote as safe-to-overwrite (vs files a human hand-maintains). Skipped\n // when --no-prune is set so users opting out of lifecycle tracking also opt\n // out of overwrite-on-regen behavior.\n const outputPrevManifestForCtx = options.noPrune ? null : await readManifest(options.outputDir);\n const targetManifestForCtx = options.target && !options.noPrune ? await readManifest(options.target) : null;\n const priorTargetManifestPaths = targetManifestForCtx\n ? new Set(targetManifestForCtx.files)\n : outputPrevManifestForCtx\n ? new Set(outputPrevManifestForCtx.files)\n : undefined;\n\n const {\n files: withHeaders,\n header,\n operations,\n } = generateFiles(spec, emitter, {\n ...options,\n priorTargetManifestPaths,\n });\n\n if (options.dryRun) {\n if (options.target) {\n console.log(`\\nTarget integration (${options.target}):`);\n for (const f of withHeaders) {\n console.log(` ${f.path}`);\n }\n }\n return withHeaders;\n }\n\n // Reuse the manifest read before generation; nothing above writes it.\n const outputPrevManifest = outputPrevManifestForCtx;\n\n const writeResult = await writeFiles(withHeaders, options.outputDir, {\n language: emitter.language,\n header,\n });\n\n if (writeResult.merged.length > 0) {\n console.log(`Merged into ${writeResult.merged.length} existing files (additive only)`);\n }\n if (writeResult.ignored.length > 0) {\n console.log(`Ignored ${writeResult.ignored.length} files (@oagen-ignore-file)`);\n }\n\n const outputEmittedPaths = withHeaders.map((f) => f.path);\n await applyManifestPrune({\n dir: options.outputDir,\n label: 'Output',\n prevManifest: outputPrevManifest,\n currentPaths: outputEmittedPaths,\n language: emitter.language,\n header,\n noPrune: options.noPrune,\n operations,\n });\n\n // Format output files so the emitter's formatter runs even without --target.\n const allOutputFiles = [...writeResult.written, ...writeResult.merged];\n if (allOutputFiles.length > 0) {\n await formatTargetFiles(emitter, options.outputDir, allOutputFiles);\n }\n\n // Target integration pass\n if (options.target) {\n // Reuse the manifest we already read to build the emitter context. This\n // is correct because nothing between the two reads writes the manifest.\n const targetPrevManifest = targetManifestForCtx;\n\n const targetResult = await integrateGeneratedFiles({\n files: withHeaders,\n language: emitter.language,\n targetDir: options.target,\n header,\n });\n\n if (targetResult.written.length > 0) {\n console.log(`Target: created ${targetResult.written.length} new files`);\n }\n if (targetResult.merged.length > 0) {\n console.log(`Target: merged into ${targetResult.merged.length} existing files (additive only)`);\n }\n if (targetResult.skipped.length > 0) {\n console.log(`Target: skipped ${targetResult.skipped.length} files (excluded or no grammar)`);\n }\n\n await applyManifestPrune({\n dir: options.target,\n label: 'Target',\n prevManifest: targetPrevManifest,\n currentPaths: targetResult.emittedPaths,\n language: emitter.language,\n header,\n noPrune: options.noPrune,\n operations,\n });\n\n // Run the emitter's formatter on all written/merged/identical files\n const allTargetFiles = [...targetResult.written, ...targetResult.merged, ...targetResult.identical];\n if (allTargetFiles.length > 0) {\n await formatTargetFiles(emitter, options.target, allTargetFiles);\n }\n }\n\n return withHeaders;\n}\n\n/**\n * Prune files recorded in the previous manifest but absent from the current emission,\n * then write the fresh manifest. Safe on first adoption (no previous manifest).\n */\nasync function applyManifestPrune(opts: {\n dir: string;\n label: string;\n prevManifest: Awaited<ReturnType<typeof readManifest>>;\n currentPaths: string[];\n language: string;\n header: string;\n noPrune?: boolean;\n operations?: Record<string, unknown>;\n}): Promise<void> {\n const manifestOpts = { language: opts.language, files: opts.currentPaths, operations: opts.operations };\n if (opts.noPrune) {\n // Still refresh the manifest so future runs with pruning enabled have a baseline.\n await writeManifest(opts.dir, manifestOpts);\n return;\n }\n\n if (!opts.prevManifest) {\n console.log(\n `${opts.label}: no ${MANIFEST_FILENAME} found — skipping prune (this baseline manifest will be written now).`,\n );\n await writeManifest(opts.dir, manifestOpts);\n return;\n }\n\n const stale = computeStalePaths(opts.prevManifest, opts.currentPaths);\n if (stale.length > 0) {\n const { pruned, preserved } = await pruneStaleFiles(opts.dir, stale, { header: opts.header });\n if (pruned.length > 0) {\n console.log(`${opts.label}: pruned ${pruned.length} stale file${pruned.length === 1 ? '' : 's'}`);\n }\n if (preserved.length > 0) {\n console.log(\n `${opts.label}: preserved ${preserved.length} file${preserved.length === 1 ? '' : 's'} in previous manifest but lacking the auto-generated header (possibly hand-edited).`,\n );\n for (const p of preserved) console.log(` ${p}`);\n }\n }\n\n await writeManifest(opts.dir, manifestOpts);\n}\n","import { RegistryError } from '../errors.js';\nimport type { Emitter } from './types.js';\n\nconst emitters = new Map<string, Emitter>();\n\nexport function registerEmitter(emitter: Emitter): void {\n emitters.set(emitter.language, emitter);\n}\n\nexport function getEmitter(language: string): Emitter {\n const emitter = emitters.get(language);\n if (!emitter) {\n const available = [...emitters.keys()].join(', ') || '(none)';\n throw new RegistryError(\n `Unknown language: ${language}. Available: ${available}`,\n `Register an emitter for \"${language}\" via registerEmitter() or check your oagen.config.ts plugin configuration.`,\n );\n }\n return emitter;\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 { 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., WorkOS) 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","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 { readFileSync, existsSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { MANIFEST_FILENAME } from './manifest.js';\n\n/** Minimal shape matching compat/overlay.ts ManifestEntry for cross-layer use. */\ninterface 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 * Read the operations map from `.oagen-manifest.json` in the given directory\n * and convert it to `ManifestEntry[]` for the overlay builder.\n *\n * Returns undefined if the manifest is absent or has no operations field.\n */\nexport function readManifestSync(dir: string): ManifestEntry[] | undefined {\n const manifestPath = path.join(dir, MANIFEST_FILENAME);\n if (!existsSync(manifestPath)) return undefined;\n try {\n const parsed = JSON.parse(readFileSync(manifestPath, 'utf-8'));\n const operations = parsed?.operations;\n if (!operations || typeof operations !== 'object') return undefined;\n return convertOperationsToManifestEntries(operations);\n } catch {\n return undefined;\n }\n}\n\n/** Convert the operations map from .oagen-manifest.json into ManifestEntry[]. */\nfunction convertOperationsToManifestEntries(operations: Record<string, unknown>): ManifestEntry[] {\n const entries: ManifestEntry[] = [];\n for (const [httpKey, value] of Object.entries(operations)) {\n const spaceIdx = httpKey.indexOf(' ');\n const httpMethod = httpKey.slice(0, spaceIdx);\n const httpPath = httpKey.slice(spaceIdx + 1);\n\n const values = Array.isArray(value) ? value : [value];\n for (const v of values) {\n const entry = v as { sdkMethod?: string; service?: string };\n entries.push({\n operationId: '',\n sdkResourceProperty: entry.service ?? '',\n sdkMethodName: entry.sdkMethod ?? '',\n httpMethod,\n path: httpPath,\n pathParams: [],\n bodyFields: [],\n queryFields: [],\n });\n }\n }\n return entries;\n}\n","import { readFileSync } from 'node:fs';\nimport { ConfigError } from '../errors.js';\nimport { buildOverlayLookup } from '../compat/overlay.js';\nimport type { ApiSurface, LanguageHints, OverlayLookup } from '../compat/types.js';\nimport type { ApiSpec } from '../ir/types.js';\nimport { nodeHints } from '../compat/language-hints.js';\nimport { getExtractor } from '../compat/extractor-registry.js';\nimport { readManifestSync } from '../engine/manifest-reader.js';\n\nexport interface OverlayContext {\n apiSurface: ApiSurface;\n overlayLookup: OverlayLookup;\n}\n\n/**\n * Load an API surface from disk, discover/load the manifest, resolve\n * language hints, and build the overlay lookup. Shared by diff and generate.\n */\nexport function loadOverlayContext(opts: {\n apiSurfacePath: string;\n outputDir: string;\n lang: string;\n spec?: ApiSpec;\n}): OverlayContext {\n let raw: string;\n try {\n raw = readFileSync(opts.apiSurfacePath, 'utf-8');\n } catch {\n throw new ConfigError(\n `API surface file not found: ${opts.apiSurfacePath}. Run \\`oagen extract\\` first.`,\n `Generate the API surface file by running \\`oagen extract --lang ${opts.lang} --sdk-path <path-to-sdk>\\` before running this command.`,\n );\n }\n let apiSurface: ApiSurface;\n try {\n apiSurface = JSON.parse(raw) as ApiSurface;\n } catch (err) {\n throw new ConfigError(\n `Failed to parse API surface JSON: ${err instanceof Error ? err.message : String(err)}`,\n `Ensure \"${opts.apiSurfacePath}\" contains valid JSON. Re-run \\`oagen extract\\` to regenerate it.`,\n );\n }\n\n // Load operations from .oagen-manifest.json in output directory\n const manifest = readManifestSync(opts.outputDir);\n\n let hints: LanguageHints = nodeHints;\n try {\n hints = getExtractor(opts.lang).hints;\n } catch {\n // no extractor registered — use nodeHints fallback\n }\n\n const overlayLookup = buildOverlayLookup(apiSurface, manifest, opts.spec, hints);\n return { apiSurface, overlayLookup };\n}\n","import type { ApiSpec } from '../ir/types.js';\n\n/**\n * Walk all description fields in the IR and expand relative URL paths\n * (e.g. `/reference/authkit/user`) into full URLs using the given base.\n *\n * Matches markdown-style links: `[text](/path)` → `[text](https://example.com/path)`\n * and bare parenthetical refs: `(/path)` → `(https://example.com/path)`\n */\nexport function expandDocUrls(spec: ApiSpec, docUrl: string): ApiSpec {\n // Normalize: strip trailing slash so joins are clean\n const base = docUrl.replace(/\\/+$/, '');\n\n function expand(description: string | undefined): string | undefined {\n if (!description) return description;\n // Match markdown links and bare parenthetical paths with a leading slash\n return description.replace(/\\(\\/([^)]*)\\)/g, `(${base}/$1)`);\n }\n\n return {\n ...spec,\n description: expand(spec.description),\n services: spec.services.map((service) => ({\n ...service,\n description: expand(service.description),\n operations: service.operations.map((op) => ({\n ...op,\n description: expand(op.description),\n pathParams: op.pathParams.map((p) => ({ ...p, description: expand(p.description) })),\n queryParams: op.queryParams.map((p) => ({ ...p, description: expand(p.description) })),\n headerParams: op.headerParams.map((p) => ({ ...p, description: expand(p.description) })),\n })),\n })),\n models: spec.models.map((model) => ({\n ...model,\n description: expand(model.description),\n fields: model.fields.map((f) => ({ ...f, description: expand(f.description) })),\n })),\n enums: spec.enums.map((e) => ({\n ...e,\n values: e.values.map((v) => ({ ...v, description: expand(v.description) })),\n })),\n };\n}\n","import { parseSpec, type OpenApiDocument } from '../parser/parse.js';\nimport { generate } from '../engine/orchestrator.js';\nimport { getEmitter } from '../engine/registry.js';\nimport { loadOverlayContext } from './overlay-loader.js';\nimport { expandDocUrls } from '../utils/expand-doc-urls.js';\nimport type { OperationHint } from '../ir/operation-hints.js';\n\nexport async function generateCommand(opts: {\n spec: string;\n lang: string;\n output: string;\n target?: string;\n namespace?: string;\n dryRun?: boolean;\n apiSurface?: string;\n compatCheck?: boolean;\n /** From `--no-prune`. When false, manifest-driven stale-file pruning is skipped. */\n prune?: boolean;\n operationIdTransform?: (id: string) => string;\n schemaNameTransform?: (name: string) => string;\n transformSpec?: (spec: OpenApiDocument) => OpenApiDocument;\n docUrl?: string;\n operationHints?: Record<string, OperationHint>;\n mountRules?: Record<string, string>;\n modelHints?: Record<string, string>;\n emitterOptions?: Record<string, unknown>;\n}): Promise<void> {\n let ir = await parseSpec(opts.spec, {\n operationIdTransform: opts.operationIdTransform,\n schemaNameTransform: opts.schemaNameTransform,\n transformSpec: opts.transformSpec,\n });\n if (opts.docUrl) {\n ir = expandDocUrls(ir, opts.docUrl);\n }\n const emitter = getEmitter(opts.lang);\n const namespace = opts.namespace ?? ir.name;\n\n // Build overlay from API surface if provided and not disabled\n let apiSurface;\n let overlayLookup;\n if (opts.apiSurface && opts.compatCheck !== false) {\n const ctx = loadOverlayContext({\n apiSurfacePath: opts.apiSurface,\n outputDir: opts.output,\n lang: opts.lang,\n spec: ir,\n });\n apiSurface = ctx.apiSurface;\n overlayLookup = ctx.overlayLookup;\n }\n\n const files = await generate(ir, emitter, {\n namespace,\n dryRun: opts.dryRun,\n outputDir: opts.output,\n target: opts.target,\n apiSurface,\n overlayLookup,\n operationHints: opts.operationHints,\n mountRules: opts.mountRules,\n modelHints: opts.modelHints,\n emitterOptions: opts.emitterOptions,\n noPrune: opts.prune === false,\n });\n\n if (opts.dryRun) {\n for (const f of files) {\n console.log(f.path);\n }\n } else {\n console.log(`Generated ${files.length} files in ${opts.output}`);\n if (opts.target) {\n console.log(`Integrated into ${opts.target}`);\n }\n }\n}\n","import type { FieldChange, ParamChange } from './types.js';\n\nexport function classifyFieldChange(kind: FieldChange['kind'], fieldName: string, isRequired?: boolean): FieldChange {\n switch (kind) {\n case 'field-added':\n return {\n kind,\n fieldName,\n classification: isRequired ? 'breaking' : 'additive',\n };\n case 'field-removed':\n return { kind, fieldName, classification: 'breaking' };\n case 'field-type-changed':\n return { kind, fieldName, classification: 'breaking' };\n case 'field-format-changed':\n // A primitive's `format` changing (e.g., string → string format=email)\n // is classified additive at the IR level: the wire-format base type is\n // unchanged, so callers' deserialization keeps working. Per-emitter\n // compat checks catch any source-level break a specific language layers\n // on top (e.g., a typed Email value object in TypeScript).\n return { kind, fieldName, classification: 'additive' };\n case 'field-required-changed':\n return {\n kind,\n fieldName,\n classification: isRequired ? 'breaking' : 'additive',\n details: isRequired ? 'optional → required' : 'required → optional',\n };\n case 'field-access-changed':\n return { kind, fieldName, classification: 'breaking' };\n }\n}\n\nexport function classifyParamChange(kind: ParamChange['kind'], paramName: string, isRequired?: boolean): ParamChange {\n switch (kind) {\n case 'param-added':\n return {\n kind,\n paramName,\n classification: isRequired ? 'breaking' : 'additive',\n };\n case 'param-removed':\n return { kind, paramName, classification: 'breaking' };\n case 'param-type-changed':\n return { kind, paramName, classification: 'breaking' };\n case 'param-format-changed':\n // See `field-format-changed`: format-only diffs are additive at the IR\n // layer.\n return { kind, paramName, classification: 'additive' };\n case 'param-required-changed':\n return {\n kind,\n paramName,\n classification: isRequired ? 'breaking' : 'additive',\n };\n case 'param-default-changed':\n // Removing or changing a default that callers may have implicitly relied on\n // changes runtime behavior for clients who never set the param explicitly.\n // We treat this as breaking so it surfaces as a major bump rather than\n // sliding through as a silent regression.\n return { kind, paramName, classification: 'breaking' };\n }\n}\n","import type { Model, TypeRef } from '../ir/types.js';\nimport { assertNever } from '../ir/types.js';\nimport type { Change, FieldChange } from './types.js';\nimport { classifyFieldChange } from './classify.js';\n\nexport function diffModels(oldModels: Model[], newModels: Model[]): Change[] {\n const changes: Change[] = [];\n const oldByName = new Map(oldModels.map((m) => [m.name, m]));\n const newByName = new Map(newModels.map((m) => [m.name, m]));\n\n for (const [name] of newByName) {\n if (!oldByName.has(name)) {\n changes.push({ kind: 'model-added', name, classification: 'additive' });\n }\n }\n\n for (const [name] of oldByName) {\n if (!newByName.has(name)) {\n changes.push({ kind: 'model-removed', name, classification: 'breaking' });\n }\n }\n\n for (const [name, newModel] of newByName) {\n const oldModel = oldByName.get(name);\n if (!oldModel) continue;\n\n const fieldChanges = diffFields(oldModel, newModel);\n if (fieldChanges.length > 0) {\n const hasBreaking = fieldChanges.some((fc) => fc.classification === 'breaking');\n changes.push({\n kind: 'model-modified',\n name,\n fieldChanges,\n classification: hasBreaking ? 'breaking' : 'additive',\n });\n }\n }\n\n return changes;\n}\n\nfunction diffFields(oldModel: Model, newModel: Model): FieldChange[] {\n const changes: FieldChange[] = [];\n const oldByName = new Map(oldModel.fields.map((f) => [f.name, f]));\n const newByName = new Map(newModel.fields.map((f) => [f.name, f]));\n\n for (const [name, field] of newByName) {\n if (!oldByName.has(name)) {\n changes.push(classifyFieldChange('field-added', name, field.required));\n }\n }\n\n for (const [name] of oldByName) {\n if (!newByName.has(name)) {\n changes.push(classifyFieldChange('field-removed', name));\n }\n }\n\n for (const [name, newField] of newByName) {\n const oldField = oldByName.get(name);\n if (!oldField) continue;\n\n if (!typeRefsEqual(oldField.type, newField.type)) {\n if (primitivesDifferOnlyByFormat(oldField.type, newField.type)) {\n changes.push({\n ...classifyFieldChange('field-format-changed', name),\n details: formatChangeDetails(oldField.type, newField.type),\n });\n } else {\n changes.push({\n kind: 'field-type-changed',\n fieldName: name,\n classification: 'breaking',\n details: `type changed`,\n });\n }\n }\n\n if (oldField.required !== newField.required) {\n changes.push(classifyFieldChange('field-required-changed', name, newField.required));\n }\n\n if (!!oldField.readOnly !== !!newField.readOnly || !!oldField.writeOnly !== !!newField.writeOnly) {\n changes.push(classifyFieldChange('field-access-changed', name));\n }\n }\n\n return changes;\n}\n\n/**\n * True when both refs are primitives with the same base `type` but different\n * `format`. Used to downgrade format-only diffs from breaking type changes to\n * additive `field-format-changed` / `param-format-changed` events: the wire\n * base type is unchanged, so the diff is a hint to language emitters rather\n * than a source-level break.\n */\nexport function primitivesDifferOnlyByFormat(a: TypeRef, b: TypeRef): boolean {\n if (a.kind !== 'primitive' || b.kind !== 'primitive') return false;\n if (a.type !== b.type) return false;\n return (a.format ?? '') !== (b.format ?? '');\n}\n\nexport function formatChangeDetails(a: TypeRef, b: TypeRef): string {\n const oldFmt = a.kind === 'primitive' ? a.format : undefined;\n const newFmt = b.kind === 'primitive' ? b.format : undefined;\n return `format ${oldFmt ?? '<unset>'} → ${newFmt ?? '<unset>'}`;\n}\n\nexport function typeRefsEqual(a: TypeRef, b: TypeRef): boolean {\n if (a.kind !== b.kind) return false;\n\n switch (a.kind) {\n case 'primitive':\n return b.kind === 'primitive' && a.type === b.type && (a.format ?? '') === ((b as typeof a).format ?? '');\n case 'array':\n return b.kind === 'array' && typeRefsEqual(a.items, b.items);\n case 'model':\n return b.kind === 'model' && a.name === b.name;\n case 'enum':\n return b.kind === 'enum' && a.name === b.name;\n case 'literal':\n return b.kind === 'literal' && a.value === b.value;\n case 'nullable':\n return b.kind === 'nullable' && typeRefsEqual(a.inner, b.inner);\n case 'union': {\n if (b.kind !== 'union') return false;\n if (a.variants.length !== b.variants.length) return false;\n if (!a.variants.every((v, i) => typeRefsEqual(v, b.variants[i]))) return false;\n // Compare discriminator\n if (!a.discriminator && !b.discriminator) return true;\n if (!a.discriminator || !b.discriminator) return false;\n if (a.discriminator.property !== b.discriminator.property) return false;\n const aKeys = Object.keys(a.discriminator.mapping).sort();\n const bKeys = Object.keys(b.discriminator.mapping).sort();\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every((k, i) => k === bKeys[i] && a.discriminator!.mapping[k] === b.discriminator!.mapping[k]);\n }\n case 'map':\n return b.kind === 'map' && typeRefsEqual(a.valueType, b.valueType);\n }\n return assertNever(a);\n}\n","import type { ErrorResponse, Operation } from '../ir/types.js';\nimport type { Change, ParamChange } from './types.js';\nimport { classifyParamChange } from './classify.js';\nimport { formatChangeDetails, primitivesDifferOnlyByFormat, typeRefsEqual } from './models.js';\n\nexport function diffOperations(serviceName: string, oldOps: Operation[], newOps: Operation[]): Change[] {\n const changes: Change[] = [];\n const oldByName = new Map(oldOps.map((o) => [o.name, o]));\n const newByName = new Map(newOps.map((o) => [o.name, o]));\n\n for (const [name] of newByName) {\n if (!oldByName.has(name)) {\n changes.push({\n kind: 'operation-added',\n serviceName,\n operationName: name,\n classification: 'additive',\n });\n }\n }\n\n for (const [name] of oldByName) {\n if (!newByName.has(name)) {\n changes.push({\n kind: 'operation-removed',\n serviceName,\n operationName: name,\n classification: 'breaking',\n });\n }\n }\n\n for (const [name, newOp] of newByName) {\n const oldOp = oldByName.get(name);\n if (!oldOp) continue;\n\n const paramChanges = diffParams(oldOp, newOp);\n const responseChanged = !typeRefsEqual(oldOp.response, newOp.response);\n const requestBodyChanged = !requestBodiesEqual(oldOp.requestBody, newOp.requestBody);\n const httpMethodChanged = oldOp.httpMethod !== newOp.httpMethod;\n const pathChanged = oldOp.path !== newOp.path;\n const paginatedChanged = !!oldOp.pagination !== !!newOp.pagination;\n const injectIdempotencyKeyChanged = oldOp.injectIdempotencyKey !== newOp.injectIdempotencyKey;\n const errorsDiff = classifyErrorsChange(oldOp.errors, newOp.errors);\n const errorsChanged = errorsDiff !== 'none';\n\n const hasChanges =\n paramChanges.length > 0 ||\n responseChanged ||\n requestBodyChanged ||\n httpMethodChanged ||\n pathChanged ||\n paginatedChanged ||\n injectIdempotencyKeyChanged ||\n errorsChanged;\n\n if (hasChanges) {\n // paginated: false→true is additive (SDK gains pagination helper)\n // paginated: true→false is breaking (SDK loses pagination helper)\n const paginatedBreaking = paginatedChanged && !newOp.pagination;\n // injectIdempotencyKey: false→true is additive (SDK gains idempotency key)\n // injectIdempotencyKey: true→false is breaking (SDK loses idempotency key)\n const injectIdempotencyKeyBreaking = injectIdempotencyKeyChanged && !newOp.injectIdempotencyKey;\n const errorsBreaking = errorsDiff === 'breaking';\n\n const hasBreaking =\n responseChanged ||\n requestBodyChanged ||\n httpMethodChanged ||\n pathChanged ||\n paginatedBreaking ||\n injectIdempotencyKeyBreaking ||\n errorsBreaking ||\n paramChanges.some((pc) => pc.classification === 'breaking');\n changes.push({\n kind: 'operation-modified',\n serviceName,\n operationName: name,\n paramChanges,\n responseChanged,\n requestBodyChanged,\n httpMethodChanged,\n pathChanged,\n paginatedChanged,\n injectIdempotencyKeyChanged,\n errorsChanged,\n classification: hasBreaking ? 'breaking' : 'additive',\n });\n }\n }\n\n return changes;\n}\n\nfunction requestBodiesEqual(a: Operation['requestBody'], b: Operation['requestBody']): boolean {\n if (!a && !b) return true;\n if (!a || !b) return false;\n return typeRefsEqual(a, b);\n}\n\nfunction classifyErrorsChange(\n oldErrors: ErrorResponse[],\n newErrors: ErrorResponse[],\n): 'none' | 'additive' | 'breaking' {\n const oldByCode = new Map(oldErrors.map((e) => [e.statusCode, e]));\n const newByCode = new Map(newErrors.map((e) => [e.statusCode, e]));\n\n let hasAdditive = false;\n let hasBreaking = false;\n\n // New error codes added → additive (SDK gains new error classes)\n for (const code of newByCode.keys()) {\n if (!oldByCode.has(code)) hasAdditive = true;\n }\n\n // Old error codes removed → breaking (SDK loses error classes)\n for (const code of oldByCode.keys()) {\n if (!newByCode.has(code)) hasBreaking = true;\n }\n\n // Shared error codes with changed types → breaking\n for (const [code, newErr] of newByCode) {\n const oldErr = oldByCode.get(code);\n if (!oldErr) continue;\n if (!oldErr.type && !newErr.type) continue;\n if (!oldErr.type || !newErr.type || !typeRefsEqual(oldErr.type, newErr.type)) {\n hasBreaking = true;\n }\n }\n\n if (hasBreaking) return 'breaking';\n if (hasAdditive) return 'additive';\n return 'none';\n}\n\nfunction diffParams(oldOp: Operation, newOp: Operation): ParamChange[] {\n const changes: ParamChange[] = [];\n const tagged = (loc: 'path' | 'query' | 'header', params: typeof oldOp.queryParams) =>\n params.map((p) => ({ p, loc }));\n const allOldParams = [\n ...tagged('path', oldOp.pathParams),\n ...tagged('query', oldOp.queryParams),\n ...tagged('header', oldOp.headerParams),\n ];\n const allNewParams = [\n ...tagged('path', newOp.pathParams),\n ...tagged('query', newOp.queryParams),\n ...tagged('header', newOp.headerParams),\n ];\n const oldByName = new Map(allOldParams.map((e) => [e.p.name, e]));\n const newByName = new Map(allNewParams.map((e) => [e.p.name, e]));\n\n for (const [name, entry] of newByName) {\n if (!oldByName.has(name)) {\n changes.push(classifyParamChange('param-added', name, entry.p.required));\n }\n }\n\n for (const [name] of oldByName) {\n if (!newByName.has(name)) {\n changes.push(classifyParamChange('param-removed', name));\n }\n }\n\n for (const [name, newEntry] of newByName) {\n const oldEntry = oldByName.get(name);\n if (!oldEntry) continue;\n\n if (!typeRefsEqual(oldEntry.p.type, newEntry.p.type)) {\n if (primitivesDifferOnlyByFormat(oldEntry.p.type, newEntry.p.type)) {\n const change = classifyParamChange('param-format-changed', name);\n change.details = formatChangeDetails(oldEntry.p.type, newEntry.p.type);\n changes.push(change);\n } else {\n changes.push(classifyParamChange('param-type-changed', name));\n }\n }\n\n if (oldEntry.p.required !== newEntry.p.required) {\n changes.push(classifyParamChange('param-required-changed', name, newEntry.p.required));\n }\n\n const oldDefault = serializeDefault(oldEntry.p.default);\n const newDefault = serializeDefault(newEntry.p.default);\n if (oldDefault !== newDefault) {\n const change = classifyParamChange('param-default-changed', name);\n change.oldDefault = oldDefault;\n change.newDefault = newDefault;\n change.paramLocation = newEntry.loc;\n change.details = `default ${oldDefault ?? '<unset>'} → ${newDefault ?? '<unset>'}`;\n changes.push(change);\n }\n }\n\n return changes;\n}\n\nfunction serializeDefault(value: unknown): string | null {\n if (value === undefined) return null;\n if (value === null) return 'null';\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n // Objects/arrays: stable JSON. Stringification of equal-valued objects is\n // deterministic enough for this comparison since callers typically pass\n // primitives; complex defaults are rare.\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n","import type { Service } from '../ir/types.js';\nimport type { Change } from './types.js';\nimport { diffOperations } from './operations.js';\n\nexport function diffServices(oldServices: Service[], newServices: Service[]): Change[] {\n const changes: Change[] = [];\n const oldByName = new Map(oldServices.map((s) => [s.name, s]));\n const newByName = new Map(newServices.map((s) => [s.name, s]));\n\n for (const [name] of newByName) {\n if (!oldByName.has(name)) {\n changes.push({ kind: 'service-added', name, classification: 'additive' });\n }\n }\n\n for (const [name] of oldByName) {\n if (!newByName.has(name)) {\n changes.push({ kind: 'service-removed', name, classification: 'breaking' });\n }\n }\n\n for (const [name, newService] of newByName) {\n const oldService = oldByName.get(name);\n if (!oldService) continue;\n\n changes.push(...diffOperations(name, oldService.operations, newService.operations));\n }\n\n return changes;\n}\n","import type { ApiSpec, Enum } from '../ir/types.js';\nimport type { BehaviorChange, Change, DiffReport, EnumValueChange } from './types.js';\nimport { diffModels } from './models.js';\nimport { diffServices } from './services.js';\n\nexport function diffSpecs(oldSpec: ApiSpec, newSpec: ApiSpec): DiffReport {\n const changes: Change[] = [\n ...diffModels(oldSpec.models, newSpec.models),\n ...diffEnums(oldSpec.enums, newSpec.enums),\n ...diffServices(oldSpec.services, newSpec.services),\n ];\n\n const behaviorChanges = collectBehaviorChanges(changes);\n\n return {\n oldVersion: oldSpec.version,\n newVersion: newSpec.version,\n changes,\n behaviorChanges,\n summary: { ...summarize(changes), behaviorChanges: behaviorChanges.length },\n };\n}\n\nfunction collectBehaviorChanges(changes: Change[]): BehaviorChange[] {\n const out: BehaviorChange[] = [];\n for (const c of changes) {\n if (c.kind !== 'operation-modified') continue;\n for (const pc of c.paramChanges) {\n if (pc.kind !== 'param-default-changed') continue;\n out.push({\n kind: 'param-default-changed',\n serviceName: c.serviceName,\n operationName: c.operationName,\n paramName: pc.paramName,\n paramLocation: pc.paramLocation ?? 'query',\n oldDefault: pc.oldDefault ?? null,\n newDefault: pc.newDefault ?? null,\n classification: 'breaking',\n });\n }\n }\n return out;\n}\n\nfunction diffEnums(oldEnums: Enum[], newEnums: Enum[]): Change[] {\n const changes: Change[] = [];\n const oldByName = new Map(oldEnums.map((e) => [e.name, e]));\n const newByName = new Map(newEnums.map((e) => [e.name, e]));\n\n for (const [name] of newByName) {\n if (!oldByName.has(name)) {\n changes.push({ kind: 'enum-added', name, classification: 'additive' });\n }\n }\n\n for (const [name] of oldByName) {\n if (!newByName.has(name)) {\n changes.push({ kind: 'enum-removed', name, classification: 'breaking' });\n }\n }\n\n for (const [name, newEnum] of newByName) {\n const oldEnum = oldByName.get(name);\n if (!oldEnum) continue;\n\n const valueChanges = diffEnumValues(oldEnum, newEnum);\n if (valueChanges.length > 0) {\n const hasBreaking = valueChanges.some((vc) => vc.classification === 'breaking');\n changes.push({\n kind: 'enum-modified',\n name,\n valueChanges,\n classification: hasBreaking ? 'breaking' : 'additive',\n });\n }\n }\n\n return changes;\n}\n\nfunction diffEnumValues(oldEnum: Enum, newEnum: Enum): EnumValueChange[] {\n const changes: EnumValueChange[] = [];\n const oldByName = new Map(oldEnum.values.map((v) => [v.name, v]));\n const newByName = new Map(newEnum.values.map((v) => [v.name, v]));\n\n for (const [name] of newByName) {\n if (!oldByName.has(name)) {\n changes.push({ kind: 'value-added', valueName: name, classification: 'additive' });\n }\n }\n\n for (const [name] of oldByName) {\n if (!newByName.has(name)) {\n changes.push({ kind: 'value-removed', valueName: name, classification: 'breaking' });\n }\n }\n\n for (const [name, newVal] of newByName) {\n const oldVal = oldByName.get(name);\n if (!oldVal) continue;\n\n if (oldVal.value !== newVal.value) {\n changes.push({\n kind: 'value-changed',\n valueName: name,\n classification: 'breaking',\n details: `value changed from '${oldVal.value}' to '${newVal.value}'`,\n });\n }\n }\n\n return changes;\n}\n\nfunction summarize(changes: Change[]) {\n let added = 0;\n let removed = 0;\n let modified = 0;\n let breaking = 0;\n let additive = 0;\n\n for (const c of changes) {\n if (c.kind.endsWith('-added')) added++;\n else if (c.kind.endsWith('-removed')) removed++;\n else if (c.kind.endsWith('-modified')) modified++;\n\n if (c.classification === 'breaking') breaking++;\n else additive++;\n }\n\n return { added, removed, modified, breaking, additive };\n}\n","import { parseSpec, type OpenApiDocument } from '../parser/parse.js';\nimport { diffSpecs } from '../differ/diff.js';\nimport { CommandError } from '../errors.js';\nimport { expandDocUrls } from '../utils/expand-doc-urls.js';\n\nexport async function diffCommand(opts: {\n old: string;\n new: string;\n operationIdTransform?: (id: string) => string;\n schemaNameTransform?: (name: string) => string;\n transformSpec?: (spec: OpenApiDocument) => OpenApiDocument;\n docUrl?: string;\n}): Promise<void> {\n const parseOptions = {\n operationIdTransform: opts.operationIdTransform,\n schemaNameTransform: opts.schemaNameTransform,\n transformSpec: opts.transformSpec,\n };\n let [oldSpec, newSpec] = await Promise.all([parseSpec(opts.old, parseOptions), parseSpec(opts.new, parseOptions)]);\n if (opts.docUrl) {\n oldSpec = expandDocUrls(oldSpec, opts.docUrl);\n newSpec = expandDocUrls(newSpec, opts.docUrl);\n }\n\n const diff = diffSpecs(oldSpec, newSpec);\n console.log(JSON.stringify(diff, null, 2));\n throw new CommandError(\n '',\n '',\n diff.summary.breaking > 0\n ? 2\n : diff.summary.modified > 0 || diff.summary.removed > 0\n ? 1\n : diff.summary.added > 0\n ? 1\n : 0,\n );\n}\n","import { writeFileSync } from 'node:fs';\nimport { getExtractor } from '../compat/extractor-registry.js';\n\nexport async function extractCommand(opts: { sdkPath: string; lang: string; output: string }): Promise<void> {\n const extractor = getExtractor(opts.lang);\n console.log(`Extracting ${opts.lang} API surface from ${opts.sdkPath}...`);\n const surface = await extractor.extract(opts.sdkPath);\n writeFileSync(opts.output, JSON.stringify(surface, null, 2));\n const symbolCount =\n Object.keys(surface.classes).length +\n Object.keys(surface.interfaces).length +\n Object.keys(surface.typeAliases).length +\n Object.keys(surface.enums).length;\n console.log(`Extracted ${symbolCount} symbols → ${opts.output}`);\n}\n","/**\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 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';\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 };\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 /** 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 ...(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 },\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 default:\n return 'positional';\n }\n}\n","import { readFileSync, writeFileSync } from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { resolve } from 'node:path';\nimport { getExtractor } from '../compat/extractor-registry.js';\nimport { parseSpec, type OpenApiDocument } from '../parser/parse.js';\nimport { apiSurfaceToSnapshot } from '../compat/ir.js';\nimport { readManifest } from '../engine/manifest.js';\nimport type { Manifest } from '../engine/manifest.js';\nimport type { CompatSnapshot } from '../compat/ir.js';\nimport type { ApiSurface, ApiClass } from '../compat/types.js';\nimport type { ApiSpec } from '../ir/types.js';\n\nconst SNAPSHOT_FILENAME = '.oagen-compat-snapshot.json';\n\n/** Normalize a name for case-insensitive matching: strip underscores and lowercase. */\nfunction normalize(name: string): string {\n return name.replace(/_/g, '').toLowerCase();\n}\n\n/**\n * Build a map of normalized service name → Set of generated method names\n * from the manifest's operations record.\n */\nfunction buildServiceMethodMap(operations: Record<string, unknown>): Map<string, Set<string>> {\n const result = new Map<string, Set<string>>();\n for (const value of Object.values(operations)) {\n if (typeof value !== 'object' || value === null) continue;\n const { sdkMethod, service } = value as { sdkMethod?: string; service?: string };\n if (typeof sdkMethod !== 'string' || typeof service !== 'string') continue;\n const key = normalize(service);\n if (!result.has(key)) result.set(key, new Set());\n result.get(key)!.add(sdkMethod);\n }\n return result;\n}\n\n/**\n * Filter an ApiSurface to only include generated symbols based on the manifest.\n *\n * Two levels of filtering:\n * 1. File-level: classes/interfaces/enums from files not in the manifest are\n * dropped entirely (they are wholly hand-written).\n * 2. Method-level: for service classes (those whose name matches a manifest\n * service), only methods listed in the manifest operations are kept.\n * Constructors and properties are always preserved since they are structural.\n * Non-service classes (models, enums, etc.) keep all their symbols.\n */\nfunction filterSurfaceByManifest(\n surface: ApiSurface,\n manifest: Manifest,\n): {\n filtered: ApiSurface;\n filesExcluded: number;\n methodsExcluded: number;\n} {\n const manifestFiles = new Set(manifest.files);\n const serviceMethodMap = manifest.operations\n ? buildServiceMethodMap(manifest.operations)\n : new Map<string, Set<string>>();\n\n let filesExcluded = 0;\n let methodsExcluded = 0;\n\n // Filter a record by manifest files, counting exclusions\n const filterByFile = <T extends { sourceFile?: string }>(record: Record<string, T>): Record<string, T> => {\n const result: Record<string, T> = {};\n for (const [name, entry] of Object.entries(record)) {\n if (entry.sourceFile && manifestFiles.has(entry.sourceFile)) {\n result[name] = entry;\n } else {\n filesExcluded++;\n }\n }\n return result;\n };\n\n // Filter classes: file-level first, then method-level for service classes\n const filteredClasses: Record<string, ApiClass> = {};\n for (const [name, cls] of Object.entries(surface.classes)) {\n if (cls.sourceFile && !manifestFiles.has(cls.sourceFile)) {\n filesExcluded++;\n continue;\n }\n\n // Check if this class is a service with known operations\n const generatedMethods = serviceMethodMap.get(normalize(name));\n if (generatedMethods) {\n // Service class from a generated file — keep all methods.\n // File-level filtering already ensures this is a generated file;\n // method-level filtering was dropping wrapper methods (e.g.\n // createM2MApplication) and utility methods (e.g. verify_event)\n // that aren't tracked as HTTP operations in the manifest.\n // Clear constructorParams: service constructors are internal DI\n // wiring (e.g. __construct($client)), not user-facing API.\n filteredClasses[name] = { ...cls, constructorParams: [] };\n } else {\n // Model / utility class — keep all symbols\n filteredClasses[name] = cls;\n }\n }\n\n // Filter exports to only include files in the manifest\n const filteredExports: Record<string, string[]> = {};\n for (const [filePath, symbols] of Object.entries(surface.exports)) {\n if (manifestFiles.has(filePath)) {\n filteredExports[filePath] = symbols;\n }\n }\n\n return {\n filtered: {\n ...surface,\n classes: filteredClasses,\n interfaces: filterByFile(surface.interfaces),\n typeAliases: filterByFile(surface.typeAliases),\n enums: filterByFile(surface.enums),\n exports: filteredExports,\n },\n filesExcluded,\n methodsExcluded,\n };\n}\n\nexport async function compatExtractCommand(opts: {\n sdkPath: string;\n lang: string;\n output: string;\n spec?: string;\n schemaNameTransform?: (name: string) => string;\n transformSpec?: (spec: OpenApiDocument) => OpenApiDocument;\n}): Promise<void> {\n const extractor = getExtractor(opts.lang);\n console.log(`Extracting ${opts.lang} compat snapshot from ${opts.sdkPath}...`);\n\n let surface = await extractor.extract(opts.sdkPath);\n\n // If the SDK has a manifest, scope extraction to only generated symbols.\n // File-level: excludes wholly hand-written files.\n const manifest = await readManifest(opts.sdkPath);\n if (manifest) {\n const { filtered, filesExcluded } = filterSurfaceByManifest(surface, manifest);\n surface = filtered;\n if (filesExcluded > 0) {\n console.log(`Manifest filter: excluded ${filesExcluded} hand-written file(s)`);\n }\n }\n\n const snapshot = apiSurfaceToSnapshot(surface);\n\n // Enrich with spec context if provided\n if (opts.spec) {\n const specContent = readFileSync(opts.spec, 'utf-8');\n snapshot.source.specSha = createHash('sha256').update(specContent).digest('hex');\n\n const parsedSpec = await parseSpec(opts.spec, {\n schemaNameTransform: opts.schemaNameTransform,\n transformSpec: opts.transformSpec,\n });\n enrichWithSpecContext(snapshot, parsedSpec);\n }\n\n const outputPath = resolve(opts.output, SNAPSHOT_FILENAME);\n writeFileSync(outputPath, JSON.stringify(snapshot, null, 2));\n console.log(`Extracted ${snapshot.symbols.length} symbols → ${outputPath}`);\n}\n\n/**\n * Enrich snapshot symbols with spec-level identity.\n *\n * - Callable symbols get `operationId` and `route` from spec operations.\n * - Property/field/constructor/service_accessor symbols get `schemaName`\n * from spec models, enabling cross-language grouping in reports.\n *\n * The `schemaName` uses the spec-level identity (e.g. \"GenerateLinkBody.admin_emails\")\n * which is the same regardless of the language's naming conventions.\n */\nfunction enrichWithSpecContext(snapshot: CompatSnapshot, spec: ApiSpec): void {\n // Build lookup: \"ServiceName.methodName\" → { operationId, method, path }\n const opLookup = new Map<string, { operationId: string; method: string; path: string }>();\n for (const service of spec.services) {\n for (const op of service.operations) {\n const key = `${service.name}.${op.name}`;\n opLookup.set(key, {\n operationId: op.name,\n method: op.httpMethod,\n path: op.path,\n });\n }\n }\n\n // Build model field lookup for schema-level identity.\n // Normalized class name → { specModelName, fields: Map<normalizedFieldName, specFieldName> }\n const norm = (s: string) => s.replace(/_/g, '').toLowerCase();\n const modelLookup = new Map<string, { specName: string; fields: Map<string, string> }>();\n for (const model of spec.models) {\n const fieldMap = new Map<string, string>();\n for (const field of model.fields) {\n fieldMap.set(norm(field.name), field.name);\n }\n modelLookup.set(norm(model.name), { specName: model.name, fields: fieldMap });\n }\n\n for (const sym of snapshot.symbols) {\n // Enrich callables with operation identity\n if (sym.kind === 'callable') {\n const match = opLookup.get(sym.fqName);\n if (match) {\n sym.operationId = match.operationId;\n sym.route = { method: match.method, path: match.path };\n }\n }\n\n // Enrich all symbols with schema-level identity\n if (sym.ownerFqName) {\n // This symbol belongs to a class — try to match the class to a spec model\n const modelMatch = modelLookup.get(norm(sym.ownerFqName));\n if (modelMatch) {\n // Extract the local name (part after the dot)\n const localName = sym.fqName.includes('.') ? sym.fqName.split('.').pop()! : sym.fqName;\n const fieldMatch = modelMatch.fields.get(norm(localName));\n if (fieldMatch) {\n sym.schemaName = `${modelMatch.specName}.${fieldMatch}`;\n } else {\n // Class-level symbol (constructor, etc.) — use just the model name\n sym.schemaName = modelMatch.specName;\n }\n }\n } else {\n // Top-level symbol (class itself) — try to match to a spec model\n const modelMatch = modelLookup.get(norm(sym.fqName));\n if (modelMatch) {\n sym.schemaName = modelMatch.specName;\n }\n }\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\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., \"WorkOS\\\\Service\\\\UserManagement::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]);\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 } 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// 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): 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));\n }\n\n // Return type changes (for callables)\n if (baseline.returns && candidate.returns && baseline.returns.name !== candidate.returns.name) {\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 // Field/property type changes\n if (baseline.typeRef && candidate.typeRef && baseline.typeRef.name !== candidate.typeRef.name) {\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): 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 (baseParam.type.name !== candParam.type.name) {\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 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' },\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 },\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 { 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., \"SSO.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 /sso/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., SSO.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));\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","/**\n * Conceptual change grouping for cross-language compatibility analysis.\n *\n * Groups related changes across languages into a single conceptual change\n * with per-language severity. This allows reports to say \"parameter rename\n * on Authorization.check is breaking in PHP, Python, Kotlin, and .NET but\n * soft-risk in Go\" rather than treating these as unrelated per-language findings.\n */\n\nimport type { LanguageId } from './ir.js';\nimport type { CompatChangeSeverity, CompatChangeCategory } from './config.js';\nimport type { CompatDiffResult } from './differ.js';\n\n/** A conceptual change with per-language severity. */\nexport interface ConceptualChange {\n /** Deterministic ID from symbol + category + match details. */\n id: string;\n /** IR-level symbol path (language-neutral). */\n symbol: string;\n /** The kind of change. */\n category: CompatChangeCategory;\n /** Per-language severity mapping. */\n impact: Partial<Record<LanguageId, CompatChangeSeverity>>;\n /** Human-readable description (from first language that reported it). */\n message: string;\n /** Old state details. */\n old: Record<string, string>;\n /** New state details. */\n new: Record<string, string>;\n}\n\n/** Cross-language conceptual rollup. */\nexport interface ConceptualRollup {\n conceptualChanges: ConceptualChange[];\n}\n\n/**\n * Group classified changes from multiple languages into conceptual changes.\n *\n * Changes are grouped by their `conceptualChangeId` — a deterministic ID\n * derived from the symbol, category, and match details. Changes with the\n * same ID across different languages represent the same conceptual change.\n */\nexport function buildConceptualRollup(\n perLanguageResults: Array<{ diff: CompatDiffResult; language: LanguageId }>,\n): ConceptualRollup {\n const grouped = new Map<string, ConceptualChange>();\n\n for (const { diff: result, language } of perLanguageResults) {\n for (const change of result.changes) {\n const existing = grouped.get(change.conceptualChangeId);\n if (existing) {\n existing.impact[language] = change.severity;\n } else {\n grouped.set(change.conceptualChangeId, {\n id: change.conceptualChangeId,\n symbol: change.symbol,\n category: change.category,\n impact: { [language]: change.severity },\n message: change.message,\n old: change.old,\n new: change.new,\n });\n }\n }\n }\n\n return {\n conceptualChanges: [...grouped.values()],\n };\n}\n\n/** Get the highest severity across all languages for a conceptual change. */\nexport function highestSeverity(change: ConceptualChange): CompatChangeSeverity {\n const severities = Object.values(change.impact);\n if (severities.includes('breaking')) return 'breaking';\n if (severities.includes('soft-risk')) return 'soft-risk';\n return 'additive';\n}\n\n/** Count conceptual changes by highest severity. */\nexport function summarizeConceptualChanges(rollup: ConceptualRollup): {\n breaking: number;\n softRisk: number;\n additive: number;\n} {\n let breaking = 0;\n let softRisk = 0;\n let additive = 0;\n for (const change of rollup.conceptualChanges) {\n const sev = highestSeverity(change);\n if (sev === 'breaking') breaking++;\n else if (sev === 'soft-risk') softRisk++;\n else additive++;\n }\n return { breaking, softRisk, additive };\n}\n","/**\n * Report generation for compatibility verification.\n *\n * Produces machine-readable JSON reports, human-readable terminal summaries,\n * and conceptual cross-language summaries.\n */\n\nimport type { LanguageId } from './ir.js';\nimport type { CompatChangeSeverity, CompatChangeCategory, CompatProvenance } from './config.js';\nimport type { CompatDiffResult } from './differ.js';\nimport { buildConceptualRollup, highestSeverity, summarizeConceptualChanges } from './concepts.js';\n\n// ---------------------------------------------------------------------------\n// Machine-readable report\n// ---------------------------------------------------------------------------\n\n/** Machine-readable compat report for a single language. */\nexport interface CompatReport {\n schemaVersion: string;\n language: string;\n summary: {\n breaking: number;\n softRisk: number;\n additive: number;\n };\n changes: CompatReportChange[];\n}\n\n/** A single change entry in the machine-readable report. */\nexport interface CompatReportChange {\n severity: CompatChangeSeverity;\n category: CompatChangeCategory;\n symbol: string;\n conceptualChangeId: string;\n provenance: CompatProvenance;\n old: Record<string, string>;\n new: Record<string, string>;\n message?: string;\n /** Spec-level remediation hint when a recognized upstream pattern was detected. */\n remediation?: string;\n}\n\n/** Generate a machine-readable compat report from a diff result. */\nexport function generateReport(diff: CompatDiffResult, language?: string): CompatReport {\n return {\n schemaVersion: '1',\n language: language ?? 'unknown',\n summary: diff.summary,\n changes: diff.changes.map((c) => ({\n severity: c.severity,\n category: c.category,\n symbol: c.symbol,\n conceptualChangeId: c.conceptualChangeId,\n provenance: c.provenance,\n old: c.old,\n new: c.new,\n ...(c.message ? { message: c.message } : {}),\n ...(c.remediation ? { remediation: c.remediation } : {}),\n })),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Human-readable terminal summary\n// ---------------------------------------------------------------------------\n\n/** Generate a human-readable summary string for terminal output. */\nexport function formatHumanSummary(diff: CompatDiffResult, opts?: { explain?: boolean; language?: string }): string {\n const lines: string[] = [];\n\n lines.push(`Compat report${opts?.language ? ` for ${opts.language}` : ''}:`);\n lines.push(\n ` ${diff.summary.breaking} breaking, ${diff.summary.softRisk} soft-risk, ${diff.summary.additive} additive`,\n );\n\n if (diff.changes.length === 0) {\n lines.push(' No compatibility changes detected.');\n return lines.join('\\n');\n }\n\n // Group by severity for display\n const breaking = diff.changes.filter((c) => c.severity === 'breaking');\n const softRisk = diff.changes.filter((c) => c.severity === 'soft-risk');\n const additive = diff.changes.filter((c) => c.severity === 'additive');\n\n if (breaking.length > 0) {\n lines.push('');\n lines.push(' Breaking:');\n for (const c of breaking) {\n lines.push(` [${c.category}] ${c.symbol} — ${c.message}`);\n if (c.remediation) {\n lines.push(` hint: ${c.remediation}`);\n }\n if (opts?.explain && c.provenance !== 'unknown') {\n lines.push(` provenance: ${c.provenance}`);\n }\n }\n }\n\n if (softRisk.length > 0) {\n lines.push('');\n lines.push(' Soft-risk:');\n for (const c of softRisk) {\n lines.push(` [${c.category}] ${c.symbol} — ${c.message}`);\n if (c.remediation) {\n lines.push(` hint: ${c.remediation}`);\n }\n if (opts?.explain && c.provenance !== 'unknown') {\n lines.push(` provenance: ${c.provenance}`);\n }\n }\n }\n\n if (additive.length > 0) {\n lines.push('');\n lines.push(` Additive: ${additive.length} new symbol(s)`);\n }\n\n return lines.join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// Conceptual cross-language summary\n// ---------------------------------------------------------------------------\n\n/** Conceptual cross-language report. */\nexport interface ConceptualReport {\n conceptualChanges: {\n id: string;\n symbol: string;\n category: CompatChangeCategory;\n impact: Partial<Record<LanguageId, CompatChangeSeverity>>;\n }[];\n}\n\n/** Generate a conceptual cross-language report from multiple per-language results. */\nexport function generateConceptualReport(\n perLanguageResults: Array<{ diff: CompatDiffResult; language: LanguageId }>,\n): ConceptualReport {\n const rollup = buildConceptualRollup(perLanguageResults);\n return {\n conceptualChanges: rollup.conceptualChanges.map((c) => ({\n id: c.id,\n symbol: c.symbol,\n category: c.category,\n impact: c.impact,\n })),\n };\n}\n\n/** Format a conceptual cross-language summary for terminal output. */\nexport function formatConceptualSummary(\n perLanguageResults: Array<{ diff: CompatDiffResult; language: LanguageId }>,\n): string {\n const rollup = buildConceptualRollup(perLanguageResults);\n const summary = summarizeConceptualChanges(rollup);\n const lines: string[] = [];\n\n lines.push('Cross-language conceptual summary:');\n lines.push(` ${summary.breaking} breaking, ${summary.softRisk} soft-risk, ${summary.additive} additive`);\n\n if (rollup.conceptualChanges.length === 0) {\n lines.push(' No cross-language changes.');\n return lines.join('\\n');\n }\n\n for (const change of rollup.conceptualChanges) {\n const sev = highestSeverity(change);\n const impactStr = Object.entries(change.impact)\n .map(([lang, s]) => `${lang}: ${s}`)\n .join(', ');\n lines.push(` [${sev}] ${change.category}: ${change.symbol}`);\n lines.push(` impact: ${impactStr}`);\n }\n\n return lines.join('\\n');\n}\n","import { readFileSync, writeFileSync } from 'node:fs';\nimport { validateSnapshot } from '../compat/schema.js';\nimport { diffSnapshots } from '../compat/differ.js';\nimport { generateReport, formatHumanSummary } from '../compat/report.js';\nimport { severityMeetsThreshold } from '../compat/config.js';\nimport type { CompatFailLevel } from '../compat/config.js';\nimport type { CompatSnapshot } from '../compat/ir.js';\n\nexport async function compatDiffCommand(opts: {\n baseline: string;\n candidate: string;\n output?: string;\n failOn?: string;\n explain?: boolean;\n}): Promise<void> {\n const baselineData = JSON.parse(readFileSync(opts.baseline, 'utf-8'));\n const candidateData = JSON.parse(readFileSync(opts.candidate, 'utf-8'));\n\n if (!validateSnapshot(baselineData)) {\n throw new Error(`Invalid baseline snapshot: ${opts.baseline}`);\n }\n if (!validateSnapshot(candidateData)) {\n throw new Error(`Invalid candidate snapshot: ${opts.candidate}`);\n }\n\n const baseline = baselineData as CompatSnapshot;\n const candidate = candidateData as CompatSnapshot;\n\n const diff = diffSnapshots(baseline, candidate);\n\n // Human-readable output to terminal\n console.log(formatHumanSummary(diff, { explain: opts.explain }));\n\n // Machine-readable output to file\n if (opts.output) {\n const report = generateReport(diff);\n writeFileSync(opts.output, JSON.stringify(report, null, 2));\n console.log(`Report written to ${opts.output}`);\n }\n\n // Fail if threshold exceeded\n const failOn = (opts.failOn ?? 'breaking') as CompatFailLevel;\n const hasFailure = diff.changes.some((c) => severityMeetsThreshold(c.severity, failOn));\n if (hasFailure) {\n process.exitCode = 1;\n }\n}\n","import { readFileSync, writeFileSync } from 'node:fs';\nimport type { CompatReport, CompatReportChange } from '../compat/report.js';\nimport type { CompatDiffResult } from '../compat/differ.js';\nimport type { LanguageId } from '../compat/ir.js';\nimport type { CompatChangeSeverity } from '../compat/config.js';\nimport { buildConceptualRollup, highestSeverity, summarizeConceptualChanges } from '../compat/concepts.js';\n\n/**\n * Format compat report(s) as a markdown PR comment.\n *\n * Single report:\n * oagen compat-summary --report node-report.json | gh pr comment --body-file -\n *\n * Multiple reports (cross-language rollup):\n * oagen compat-summary --report php.json --report python.json --report go.json\n */\nexport async function compatSummaryCommand(opts: { report: string | string[]; output?: string }): Promise<void> {\n const paths = Array.isArray(opts.report) ? opts.report : [opts.report];\n const reports = paths.map((p) => JSON.parse(readFileSync(p, 'utf-8')) as CompatReport);\n\n const md = reports.length === 1 ? formatSingleReport(reports[0]) : formatCrossLanguageRollup(reports);\n\n if (opts.output) {\n writeFileSync(opts.output, md);\n console.log(`Summary written to ${opts.output}`);\n } else {\n process.stdout.write(md);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Single-language report\n// ---------------------------------------------------------------------------\n\nfunction formatSingleReport(report: CompatReport): string {\n const lines: string[] = [];\n const { breaking, softRisk, additive } = report.summary;\n const total = breaking + softRisk + additive;\n\n if (breaking > 0) {\n lines.push(`## :x: Compat check failed — ${report.language}`);\n } else if (softRisk > 0) {\n lines.push(`## :warning: Compat check has warnings — ${report.language}`);\n } else {\n lines.push(`## :white_check_mark: Compat check passed — ${report.language}`);\n }\n\n lines.push('');\n lines.push('| Severity | Count |');\n lines.push('| --- | --- |');\n lines.push(`| Breaking | ${breaking} |`);\n lines.push(`| Soft-risk | ${softRisk} |`);\n lines.push(`| Additive | ${additive} |`);\n lines.push(`| **Total** | **${total}** |`);\n\n if (total === 0) {\n lines.push('');\n lines.push('No compatibility changes detected.');\n return lines.join('\\n') + '\\n';\n }\n\n const breakingChanges = report.changes.filter((c) => c.severity === 'breaking');\n if (breakingChanges.length > 0) {\n lines.push('');\n lines.push('### Breaking changes');\n lines.push('');\n lines.push(formatChangesTable(breakingChanges));\n }\n\n const softRiskChanges = report.changes.filter((c) => c.severity === 'soft-risk');\n if (softRiskChanges.length > 0) {\n lines.push('');\n lines.push('<details>');\n lines.push(`<summary>Soft-risk changes (${softRiskChanges.length})</summary>`);\n lines.push('');\n lines.push(formatChangesTable(softRiskChanges));\n lines.push('</details>');\n }\n\n const additiveChanges = report.changes.filter((c) => c.severity === 'additive');\n if (additiveChanges.length > 0) {\n lines.push('');\n lines.push('<details>');\n lines.push(`<summary>Additive changes (${additiveChanges.length})</summary>`);\n lines.push('');\n lines.push(formatChangesTable(additiveChanges));\n lines.push('</details>');\n }\n\n return lines.join('\\n') + '\\n';\n}\n\n// ---------------------------------------------------------------------------\n// Cross-language rollup\n// ---------------------------------------------------------------------------\n\nfunction formatCrossLanguageRollup(reports: CompatReport[]): string {\n const languages = reports.map((r) => r.language);\n\n // Convert reports to the shape buildConceptualRollup expects\n const perLanguage = reports.map((r) => ({\n diff: { changes: r.changes, summary: r.summary } as CompatDiffResult,\n language: r.language as LanguageId,\n }));\n const rollup = buildConceptualRollup(perLanguage);\n const summary = summarizeConceptualChanges(rollup);\n\n const lines: string[] = [];\n\n // Header\n if (summary.breaking > 0) {\n lines.push(`## :x: Compat check failed — ${summary.breaking} breaking across ${languages.length} languages`);\n } else if (summary.softRisk > 0) {\n lines.push(\n `## :warning: Compat check has warnings — ${summary.softRisk} soft-risk across ${languages.length} languages`,\n );\n } else {\n lines.push(`## :white_check_mark: Compat check passed — ${languages.length} languages`);\n }\n\n lines.push('');\n\n // Per-language summary table\n lines.push('| Language | Breaking | Soft-risk | Additive |');\n lines.push('| --- | --- | --- | --- |');\n for (const r of reports) {\n lines.push(`| ${r.language} | ${r.summary.breaking} | ${r.summary.softRisk} | ${r.summary.additive} |`);\n }\n\n if (rollup.conceptualChanges.length === 0) {\n lines.push('');\n lines.push('No compatibility changes detected.');\n return lines.join('\\n') + '\\n';\n }\n\n // Conceptual changes table with per-language severity\n const breakingConcepts = rollup.conceptualChanges.filter((c) => highestSeverity(c) === 'breaking');\n if (breakingConcepts.length > 0) {\n lines.push('');\n lines.push('### Breaking changes');\n lines.push('');\n lines.push(formatConceptualTable(breakingConcepts, languages));\n }\n\n const softRiskConcepts = rollup.conceptualChanges.filter((c) => highestSeverity(c) === 'soft-risk');\n if (softRiskConcepts.length > 0) {\n lines.push('');\n lines.push('<details>');\n lines.push(`<summary>Soft-risk changes (${softRiskConcepts.length})</summary>`);\n lines.push('');\n lines.push(formatConceptualTable(softRiskConcepts, languages));\n lines.push('</details>');\n }\n\n const additiveConcepts = rollup.conceptualChanges.filter((c) => highestSeverity(c) === 'additive');\n if (additiveConcepts.length > 0) {\n lines.push('');\n lines.push('<details>');\n lines.push(`<summary>Additive changes (${additiveConcepts.length})</summary>`);\n lines.push('');\n lines.push(formatConceptualTable(additiveConcepts, languages));\n lines.push('</details>');\n }\n\n return lines.join('\\n') + '\\n';\n}\n\nfunction formatConceptualTable(\n concepts: Array<{ symbol: string; category: string; impact: Partial<Record<string, CompatChangeSeverity>> }>,\n languages: string[],\n): string {\n const lines: string[] = [];\n const langHeaders = languages.map((l) => l).join(' | ');\n lines.push(`| Symbol | Category | ${langHeaders} |`);\n lines.push(`| --- | --- | ${languages.map(() => '---').join(' | ')} |`);\n for (const c of concepts) {\n const severities = languages.map((l) => severityIcon(c.impact[l])).join(' | ');\n lines.push(`| \\`${c.symbol}\\` | \\`${c.category}\\` | ${severities} |`);\n }\n return lines.join('\\n');\n}\n\nfunction severityIcon(severity: CompatChangeSeverity | undefined): string {\n if (!severity) return '—';\n switch (severity) {\n case 'breaking':\n return ':x: breaking';\n case 'soft-risk':\n return ':warning: soft-risk';\n case 'additive':\n return ':white_check_mark: additive';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\nfunction formatChangesTable(changes: CompatReportChange[]): string {\n const lines: string[] = [];\n lines.push('| Category | Symbol | Detail |');\n lines.push('| --- | --- | --- |');\n for (const c of changes) {\n const detail = c.message ?? formatOldNew(c.old, c.new);\n lines.push(`| \\`${c.category}\\` | \\`${c.symbol}\\` | ${escapeMarkdown(detail)} |`);\n }\n return lines.join('\\n');\n}\n\nfunction formatOldNew(old: Record<string, string>, updated: Record<string, string>): string {\n const parts: string[] = [];\n for (const key of Object.keys(old)) {\n if (updated[key] && old[key] !== updated[key]) {\n parts.push(`${key}: \\`${old[key]}\\` → \\`${updated[key]}\\``);\n }\n }\n return parts.length > 0 ? parts.join(', ') : '';\n}\n\nfunction escapeMarkdown(text: string): string {\n return text.replace(/\\|/g, '\\\\|').replace(/\\n/g, ' ');\n}\n","/**\n * Approval matching engine for compatibility verification.\n *\n * Matches CompatApproval entries from oagen.config.ts against classified\n * changes. Approved changes are excluded from failure thresholds.\n *\n * Approvals must be narrow (one symbol, one category, one conceptual change).\n * Overly broad approvals are rejected at validation time.\n */\n\nimport type { LanguageId } from './ir.js';\nimport type { CompatApproval } from './config.js';\nimport type { ClassifiedChange } from './classify.js';\n\n/** Result of matching a change against approvals. */\nexport interface ApprovalMatch {\n /** The change that was matched. */\n change: ClassifiedChange;\n /** The approval that matched. null if no approval covers this change. */\n approval: CompatApproval | null;\n /** Whether the change is covered by an approval. */\n approved: boolean;\n}\n\n/** Result of validating an approval for broadness. */\nexport interface ApprovalValidation {\n valid: boolean;\n errors: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\n/** Validate that an approval is narrow enough to be accepted. */\nexport function validateApproval(approval: CompatApproval): ApprovalValidation {\n const errors: string[] = [];\n\n if (!approval.symbol || approval.symbol.trim() === '') {\n errors.push('Approval must target a specific symbol');\n }\n\n if (!approval.category) {\n errors.push('Approval must specify a change category');\n }\n\n if (!approval.reason || approval.reason.trim() === '') {\n errors.push('Approval must include a reason');\n }\n\n // Wildcard symbols are too broad\n if (approval.symbol === '*' || approval.symbol.endsWith('.*') || approval.symbol.endsWith('::*')) {\n errors.push(`Approval symbol \"${approval.symbol}\" is too broad — must target a specific symbol`);\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n\n/** Validate all approvals in a config. Returns errors keyed by index. */\nexport function validateApprovals(approvals: CompatApproval[]): Map<number, string[]> {\n const result = new Map<number, string[]>();\n for (let i = 0; i < approvals.length; i++) {\n const validation = validateApproval(approvals[i]);\n if (!validation.valid) {\n result.set(i, validation.errors);\n }\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Matching\n// ---------------------------------------------------------------------------\n\n/**\n * Match a classified change against a list of approvals.\n * Returns the first matching approval, or null if none match.\n */\nexport function matchApproval(\n change: ClassifiedChange,\n approvals: CompatApproval[],\n language: LanguageId,\n): CompatApproval | null {\n for (const approval of approvals) {\n if (approvalMatchesChange(approval, change, language)) {\n return approval;\n }\n }\n return null;\n}\n\n/**\n * Apply approvals to a list of changes.\n * Returns matches for every change (approved or not).\n */\nexport function applyApprovals(\n changes: ClassifiedChange[],\n approvals: CompatApproval[],\n language: LanguageId,\n): ApprovalMatch[] {\n return changes.map((change) => {\n const approval = matchApproval(change, approvals, language);\n return {\n change,\n approval,\n approved: approval !== null,\n };\n });\n}\n\n/**\n * Filter changes to only those NOT covered by approvals.\n * These are the remaining unapproved changes that may cause failure.\n */\nexport function unapprovedChanges(\n changes: ClassifiedChange[],\n approvals: CompatApproval[],\n language: LanguageId,\n): ClassifiedChange[] {\n return changes.filter((change) => !matchApproval(change, approvals, language));\n}\n\n// ---------------------------------------------------------------------------\n// Internal matching logic\n// ---------------------------------------------------------------------------\n\nfunction approvalMatchesChange(approval: CompatApproval, change: ClassifiedChange, language: LanguageId): boolean {\n // Skip inactive approvals\n if (approval.approved === false) return false;\n\n // Category must match exactly\n if (approval.category !== change.category) return false;\n\n // Symbol must match\n if (!symbolMatches(approval.symbol, change.symbol)) return false;\n\n // Language scoping\n if (!languageMatches(approval.appliesTo, language)) return false;\n\n // Narrowing match (optional)\n if (approval.match && !narrowingMatches(approval.match, change)) return false;\n\n return true;\n}\n\nfunction symbolMatches(approvalSymbol: string, changeSymbol: string): boolean {\n // Exact match\n if (approvalSymbol === changeSymbol) return true;\n\n // Normalize common separators for cross-language matching\n // PHP uses :: and \\, others use . — normalize to dots for comparison\n const normalizedApproval = approvalSymbol.replace(/::/g, '.').replace(/\\\\/g, '.');\n const normalizedChange = changeSymbol.replace(/::/g, '.').replace(/\\\\/g, '.');\n return normalizedApproval === normalizedChange;\n}\n\nfunction languageMatches(appliesTo: CompatApproval['appliesTo'], language: LanguageId): boolean {\n if (!appliesTo || appliesTo === 'all-impacted-languages') return true;\n return appliesTo.includes(language);\n}\n\nfunction narrowingMatches(match: NonNullable<CompatApproval['match']>, change: ClassifiedChange): boolean {\n if (match.parameter) {\n // Check if the change involves this parameter\n const paramInOld = change.old.parameter === match.parameter;\n const paramInNew = change.new.parameter === match.parameter;\n if (!paramInOld && !paramInNew) return false;\n }\n if (match.member) {\n const memberInOld = change.old.member === match.member;\n const memberInNew = change.new.member === match.member;\n if (!memberInOld && !memberInNew) return false;\n }\n if (match.oldName) {\n const nameMatch = Object.values(change.old).some((v) => v === match.oldName);\n if (!nameMatch) return false;\n }\n if (match.newName) {\n const nameMatch = Object.values(change.new).some((v) => v === match.newName);\n if (!nameMatch) return false;\n }\n return true;\n}\n","import { getExtractor } from '../compat/extractor-registry.js';\nimport {\n diffSnapshots,\n specDerivedNames,\n specDerivedFieldPaths,\n specDerivedMethodPaths,\n specDerivedEnumValues,\n filterSurface,\n} from '../compat/differ.js';\nimport { apiSurfaceToSnapshot } from '../compat/ir.js';\nimport type { LanguageId } from '../compat/ir.js';\nimport { getDefaultPolicy, mergePolicy } from '../compat/policy.js';\nimport type { CompatPolicyHints } from '../compat/policy.js';\nimport type { ApiSpec } from '../ir/types.js';\nimport type { ApiSurface } from '../compat/types.js';\nimport type { CompatCheckResult } from './types.js';\n\nexport async function runCompatCheck(\n baseline: ApiSurface,\n outputDir: string,\n lang: string,\n spec?: ApiSpec,\n policyOverrides?: Partial<CompatPolicyHints>,\n): Promise<CompatCheckResult> {\n const extractor = getExtractor(lang);\n const candidate = await extractor.extract(outputDir);\n\n let scopedBaseline = baseline;\n let scopedToSpec = false;\n let scopedSymbolCount: number | undefined;\n if (spec) {\n const allowed = specDerivedNames(spec, extractor.hints);\n const fieldPaths = specDerivedFieldPaths(spec, extractor.hints);\n const methodPaths = specDerivedMethodPaths(spec);\n const enumVals = specDerivedEnumValues(spec);\n scopedBaseline = filterSurface(baseline, allowed, { fieldPaths, methodPaths, enumValues: enumVals });\n scopedToSpec = true;\n scopedSymbolCount =\n Object.keys(scopedBaseline.interfaces).length +\n Object.keys(scopedBaseline.classes).length +\n Object.keys(scopedBaseline.typeAliases).length +\n Object.keys(scopedBaseline.enums).length;\n }\n\n const baseSnap = apiSurfaceToSnapshot(scopedBaseline);\n const candSnap = apiSurfaceToSnapshot(candidate);\n\n const langId = lang as LanguageId;\n const policy = policyOverrides ? mergePolicy(getDefaultPolicy(langId), policyOverrides) : getDefaultPolicy(langId);\n\n const diff = diffSnapshots(baseSnap, candSnap, policy);\n const passed = diff.changes.every((c) => c.severity !== 'breaking');\n\n return { passed, diff, scopedToSpec, scopedSymbolCount };\n}\n","import { readdirSync, unlinkSync, statSync, openSync, readSync, closeSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { buildOverlayLookup, patchOverlay, isPatchableChange } from '../compat/overlay.js';\nimport { getExtractor } from '../compat/extractor-registry.js';\nimport type { ApiSurface } from '../compat/types.js';\nimport type { ApiSpec } from '../ir/types.js';\nimport { getEmitter } from '../engine/registry.js';\nimport { generate } from '../engine/orchestrator.js';\nimport { runCompatCheck } from './run-compat-check.js';\nimport type { OverlayRetryResult } from './types.js';\nimport { readManifestSync } from '../engine/manifest-reader.js';\n\n/** Generated file header markers used by various emitters. */\nconst GENERATED_MARKERS = ['Code generated by oagen', 'auto-generated by oagen', 'This file is auto-generated'];\n\n/**\n * Delete oagen-generated source files so the retry loop can regenerate them\n * with overlay-corrected names. Only deletes files that contain an oagen\n * generation marker, preserving hand-written files.\n */\nfunction cleanGeneratedFiles(dir: string): void {\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return;\n }\n for (const entry of entries) {\n const full = path.join(dir, entry);\n let stat;\n try {\n stat = statSync(full);\n } catch {\n continue;\n }\n if (stat.isDirectory()) {\n cleanGeneratedFiles(full);\n continue;\n }\n // Skip non-source files and manifests\n if (entry.endsWith('.json') || entry.endsWith('.lock')) continue;\n // Read only the first 200 bytes to check for generation marker\n try {\n const buf = Buffer.alloc(200);\n const fd = openSync(full, 'r');\n try {\n readSync(fd, buf, 0, 200, 0);\n } finally {\n closeSync(fd);\n }\n const header = buf.toString('utf-8');\n if (GENERATED_MARKERS.some((m) => header.includes(m))) {\n unlinkSync(full);\n }\n } catch {\n // ignore read/delete errors\n }\n }\n}\n\nexport async function runOverlayRetryLoop(opts: {\n baseline: ApiSurface;\n parsedSpec: ApiSpec;\n outputDir: string;\n lang: string;\n maxRetries: number;\n namespace?: string;\n onRetry?: (attemptNumber: number, maxRetries: number, patchableCount: number) => void;\n}): Promise<OverlayRetryResult> {\n const { baseline, parsedSpec, outputDir, lang, maxRetries, namespace, onRetry } = opts;\n\n const manifest = readManifestSync(outputDir);\n // Pass language-specific hints so property-to-class matching works correctly\n // (e.g., Ruby snake_case \"api_keys\" → PascalCase \"ApiKeys\").\n const extractor = getExtractor(lang);\n let overlay = buildOverlayLookup(baseline, manifest, parsedSpec, extractor.hints);\n let prevPreserved = -1;\n const patchedPerIteration: number[] = [];\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const compatResult = await runCompatCheck(baseline, outputDir, lang, parsedSpec);\n if (compatResult.passed) {\n return {\n status: 'passed',\n attempts: attempt,\n patchedPerIteration,\n compatResult,\n };\n }\n\n if (attempt === maxRetries) {\n return {\n status: 'max-retries',\n attempts: attempt,\n patchedPerIteration,\n compatResult,\n };\n }\n\n const patchable = compatResult.diff.changes.filter(isPatchableChange);\n if (patchable.length === 0) {\n return {\n status: 'no-patchable',\n attempts: attempt,\n patchedPerIteration,\n compatResult,\n };\n }\n\n const currentBreaking = compatResult.diff.summary.breaking;\n // Stall detection: if breaking count hasn't decreased, we're not making progress\n if (attempt > 0 && currentBreaking >= prevPreserved) {\n return {\n status: 'stalled',\n attempts: attempt,\n patchedPerIteration,\n compatResult,\n };\n }\n prevPreserved = currentBreaking;\n patchedPerIteration.push(patchable.length);\n onRetry?.(attempt + 1, maxRetries, patchable.length);\n\n overlay = patchOverlay(overlay, patchable, baseline);\n\n // Pre-delete generated source files so the writer creates them fresh\n // with overlay-corrected names. Without this, the AST merger would preserve\n // old method/class names from the existing files.\n // Only delete files that look like oagen-generated source files (have the header).\n cleanGeneratedFiles(outputDir);\n\n const emitter = getEmitter(lang);\n await generate(parsedSpec, emitter, {\n namespace: namespace ?? parsedSpec.name,\n outputDir,\n overlayLookup: overlay,\n apiSurface: baseline,\n });\n }\n\n const compatResult = await runCompatCheck(baseline, outputDir, lang, parsedSpec);\n return {\n status: 'max-retries',\n attempts: maxRetries,\n patchedPerIteration,\n compatResult,\n };\n}\n","import type { ApiSurface, LanguageHints, Violation } from './types.js';\nimport type { ApiSpec } from '../ir/types.js';\nimport { specDerivedNames, specDerivedFieldPaths } from './spec-filter.js';\nimport { diffSpecs } from '../differ/diff.js';\n\n/**\n * Detect symbols that exist in the live SDK surface but are no longer defined\n * in the current OpenAPI spec. These are \"stale\" — they compile and run but\n * represent dead code from a previous spec version.\n *\n * Requires both the old and new spec so we can distinguish hand-written SDK\n * symbols (never in any spec) from genuinely removed spec symbols.\n */\nexport function detectStaleSymbols(\n liveSurface: ApiSurface,\n oldSpec: ApiSpec,\n newSpec: ApiSpec,\n hints: LanguageHints,\n): Violation[] {\n const violations: Violation[] = [];\n\n // Step 1-3: Name-set difference for top-level symbols\n const oldNames = specDerivedNames(oldSpec, hints);\n const newNames = specDerivedNames(newSpec, hints);\n\n const removedNames = new Set<string>();\n for (const name of oldNames) {\n if (!newNames.has(name)) removedNames.add(name);\n }\n\n for (const name of removedNames) {\n if (liveSurface.classes[name]) {\n violations.push({\n category: 'staleness',\n severity: 'warning',\n symbolPath: name,\n baseline: name,\n candidate: '(removed from spec)',\n message: `Class \"${name}\" is no longer defined in the OpenAPI spec`,\n });\n }\n if (liveSurface.interfaces[name]) {\n violations.push({\n category: 'staleness',\n severity: 'warning',\n symbolPath: name,\n baseline: name,\n candidate: '(removed from spec)',\n message: `Interface \"${name}\" is no longer defined in the OpenAPI spec`,\n });\n }\n if (liveSurface.typeAliases[name]) {\n violations.push({\n category: 'staleness',\n severity: 'warning',\n symbolPath: name,\n baseline: name,\n candidate: '(removed from spec)',\n message: `Type alias \"${name}\" is no longer defined in the OpenAPI spec`,\n });\n }\n if (liveSurface.enums[name]) {\n violations.push({\n category: 'staleness',\n severity: 'warning',\n symbolPath: name,\n baseline: name,\n candidate: '(removed from spec)',\n message: `Enum \"${name}\" is no longer defined in the OpenAPI spec`,\n });\n }\n }\n\n // Step 4-6: Field-level staleness for models that still exist in new spec\n const oldFieldPaths = specDerivedFieldPaths(oldSpec, hints);\n const newFieldPaths = specDerivedFieldPaths(newSpec, hints);\n\n for (const fieldPath of oldFieldPaths) {\n if (newFieldPaths.has(fieldPath)) continue;\n\n const [modelName, fieldName] = fieldPath.split('.');\n // Only flag field-level staleness for models that still exist in the new spec\n // (fully removed models are already caught above)\n if (removedNames.has(modelName)) continue;\n\n const iface = liveSurface.interfaces[modelName];\n if (iface?.fields[fieldName]) {\n violations.push({\n category: 'staleness',\n severity: 'warning',\n symbolPath: fieldPath,\n baseline: fieldName,\n candidate: '(removed from spec)',\n message: `Field \"${fieldPath}\" is no longer defined in the OpenAPI spec`,\n });\n }\n }\n\n // Step 7: Operation-level staleness via diffSpecs\n const diff = diffSpecs(oldSpec, newSpec);\n for (const change of diff.changes) {\n if (change.kind === 'operation-removed') {\n const cls = liveSurface.classes[change.serviceName];\n if (cls?.methods[change.operationName]) {\n violations.push({\n category: 'staleness',\n severity: 'warning',\n symbolPath: `${change.serviceName}.${change.operationName}`,\n baseline: change.operationName,\n candidate: '(removed from spec)',\n message: `Method \"${change.serviceName}.${change.operationName}\" is no longer defined in the OpenAPI spec`,\n });\n }\n }\n }\n\n return violations;\n}\n","import { getExtractor } from '../compat/extractor-registry.js';\nimport { detectStaleSymbols } from '../compat/staleness.js';\nimport type { ApiSpec } from '../ir/types.js';\nimport type { ApiSurface } from '../compat/types.js';\nimport type { StalenessCheckResult } from './types.js';\n\nexport function runStalenessCheck(\n baseline: ApiSurface,\n oldSpec: ApiSpec,\n newSpec: ApiSpec,\n lang: string,\n): StalenessCheckResult {\n const extractor = getExtractor(lang);\n const violations = detectStaleSymbols(baseline, oldSpec, newSpec, extractor.hints);\n return { violations };\n}\n","import { execFileSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport * as path from 'node:path';\nimport { CommandError } from '../errors.js';\nimport type { SmokeCheckResult } from './types.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nfunction resolveScript(scriptRelPath: string): { bin: string; script: string } {\n const distScript = path.resolve(__dirname, '..', '..', 'dist', 'scripts', scriptRelPath.replace(/\\.ts$/, '.mjs'));\n if (existsSync(distScript)) {\n return { bin: 'node', script: distScript };\n }\n const srcScript = path.resolve(__dirname, '..', '..', 'scripts', scriptRelPath);\n return { bin: 'npx', script: srcScript };\n}\n\nfunction runPackagedScript(scriptRelPath: string, args: string[]): void {\n const { bin, script } = resolveScript(scriptRelPath);\n const fullArgs = bin === 'npx' ? ['tsx', script, ...args] : [script, ...args];\n execFileSync(bin, fullArgs, { stdio: 'inherit', env: process.env });\n}\n\nexport function runSmokeCheck(opts: {\n spec?: string;\n lang: string;\n output: string;\n rawResults?: string;\n smokeConfig?: string;\n smokeRunner?: string;\n}): SmokeCheckResult {\n const { spec, lang, output, rawResults, smokeConfig, smokeRunner } = opts;\n\n let baselinePath = rawResults ?? 'smoke-results-raw.json';\n let generatedBaseline = false;\n\n if (!rawResults && !existsSync('smoke-results-raw.json')) {\n if (!spec) {\n throw new CommandError(\n 'error: --spec <path> or OPENAPI_SPEC_PATH env var is required when no raw baseline exists',\n '',\n 1,\n );\n }\n\n try {\n runPackagedScript('smoke/baseline.ts', ['--spec', spec]);\n } catch {\n throw new CommandError('Baseline generation failed', '', 1);\n }\n baselinePath = 'smoke-results-spec-baseline.json';\n generatedBaseline = true;\n }\n\n const smokeArgs = ['--lang', lang, '--sdk-path', output, '--raw-results', baselinePath];\n if (spec) smokeArgs.push('--spec', spec);\n if (smokeConfig) smokeArgs.push('--smoke-config', smokeConfig);\n\n try {\n if (smokeRunner) {\n const bin = smokeRunner.endsWith('.ts') ? 'npx' : 'node';\n const fullArgs = bin === 'npx' ? ['tsx', smokeRunner, ...smokeArgs] : [smokeRunner, ...smokeArgs];\n execFileSync(bin, fullArgs, { stdio: 'inherit', env: process.env });\n } else {\n runPackagedScript('smoke/sdk-test.ts', smokeArgs);\n }\n\n return { passed: true, baselinePath, generatedBaseline };\n } catch {\n if (existsSync('smoke-compile-errors.json')) {\n return { passed: false, compileErrors: true, baselinePath, generatedBaseline };\n }\n\n const findingsCount = existsSync('smoke-diff-findings.json')\n ? (JSON.parse(readFileSync('smoke-diff-findings.json', 'utf-8')) as unknown[]).length\n : undefined;\n\n return { passed: false, findingsCount, baselinePath, generatedBaseline };\n }\n}\n","import { writeFileSync } from 'node:fs';\nimport type { VerifyDiagnostics, CompatCheckResult } from './types.js';\n\nexport function summarizeCompatCheck(result: CompatCheckResult): NonNullable<VerifyDiagnostics['compatCheck']> {\n const violationsByCategory: Record<string, number> = {};\n const violationsBySeverity: Record<string, number> = {};\n for (const c of result.diff.changes) {\n violationsByCategory[c.category] = (violationsByCategory[c.category] ?? 0) + 1;\n violationsBySeverity[c.severity] = (violationsBySeverity[c.severity] ?? 0) + 1;\n }\n\n const { breaking, softRisk, additive } = result.diff.summary;\n const totalChanges = breaking + softRisk + additive;\n const totalBaselineSymbols = totalChanges + additive; // approximate; additive are new\n const preservedSymbols = totalBaselineSymbols - breaking - softRisk;\n const preservationScore =\n totalBaselineSymbols > 0 ? Math.round((preservedSymbols / totalBaselineSymbols) * 100) : 100;\n\n return {\n totalBaselineSymbols,\n preservedSymbols,\n preservationScore,\n violationsByCategory,\n violationsBySeverity,\n additions: additive,\n scopedToSpec: result.scopedToSpec,\n ...(result.scopedSymbolCount !== undefined ? { scopedSymbolCount: result.scopedSymbolCount } : {}),\n };\n}\n\nexport function setRetryDiagnostics(\n diagData: VerifyDiagnostics,\n attempt: number,\n converged: boolean,\n finalScore: number,\n patchedPerIteration: number[],\n): void {\n diagData.retryLoop = { attempts: attempt, converged, finalScore, patchedPerIteration };\n}\n\nexport function writeDiagnostics(data: VerifyDiagnostics, filePath: string = 'verify-diagnostics.json'): void {\n writeFileSync(filePath, JSON.stringify(data, null, 2) + '\\n');\n}\n","import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { CommandError } from '../errors.js';\nimport { parseSpec, type OpenApiDocument } from '../parser/parse.js';\nimport type { ApiSurface } from '../compat/types.js';\nimport type { CompatConfig, CompatFailLevel } from '../compat/config.js';\nimport { severityMeetsThreshold } from '../compat/config.js';\nimport { generateReport, formatHumanSummary } from '../compat/report.js';\nimport { unapprovedChanges } from '../compat/approvals.js';\nimport type { LanguageId } from '../compat/ir.js';\nimport { runCompatCheck } from '../verify/run-compat-check.js';\nimport { runOverlayRetryLoop } from '../verify/run-overlay-retry-loop.js';\nimport { runStalenessCheck } from '../verify/run-staleness-check.js';\nimport { runSmokeCheck } from '../verify/run-smoke-check.js';\nimport { summarizeCompatCheck, setRetryDiagnostics, writeDiagnostics } from '../verify/write-diagnostics.js';\nimport type { VerifyDiagnostics } from '../verify/types.js';\n\nexport type { VerifyDiagnostics } from '../verify/types.js';\n\nconst separator = '='.repeat(60);\n\nfunction printCompatResult(result: ReturnType<typeof summarizeCompatCheck>, baseline: ApiSurface): void {\n if (result.scopedToSpec) {\n const totalBefore =\n Object.keys(baseline.interfaces).length +\n Object.keys(baseline.classes).length +\n Object.keys(baseline.typeAliases).length +\n Object.keys(baseline.enums).length;\n console.log(`(scoped to spec: ${result.scopedSymbolCount}/${totalBefore} baseline symbols in scope)`);\n }\n\n console.log(\n `compat: ${result.preservationScore}% (${result.preservedSymbols}/${result.totalBaselineSymbols} symbols preserved)`,\n );\n}\n\nexport async function verifyCommand(opts: {\n spec?: string;\n oldSpec?: string;\n lang: string;\n output: string;\n apiSurface?: string;\n rawResults?: string;\n smokeConfig?: string;\n smokeRunner?: string;\n scope?: 'full' | 'spec-only';\n diagnostics?: boolean;\n maxRetries?: number;\n operationIdTransform?: (id: string) => string;\n schemaNameTransform?: (name: string) => string;\n transformSpec?: (spec: OpenApiDocument) => OpenApiDocument;\n namespace?: string;\n compatConfig?: CompatConfig;\n compatReport?: string;\n compatFailOn?: string;\n compatBaseline?: string;\n compatExplain?: boolean;\n}): Promise<void> {\n const {\n spec,\n oldSpec,\n lang,\n output,\n apiSurface,\n rawResults,\n smokeConfig,\n smokeRunner,\n scope,\n diagnostics,\n operationIdTransform,\n schemaNameTransform,\n transformSpec,\n compatConfig,\n compatReport,\n compatExplain,\n } = opts;\n const maxRetries = opts.maxRetries ?? 3;\n const diagData: VerifyDiagnostics = {};\n\n // Resolve compat options: CLI flags take precedence over config\n const effectiveFailOn: CompatFailLevel =\n (opts.compatFailOn as CompatFailLevel | undefined) ?? compatConfig?.failOn ?? 'breaking';\n const effectiveReportPath = compatReport ?? compatConfig?.reportPath;\n const effectiveExplain = compatExplain ?? compatConfig?.explain ?? false;\n\n let stepNum = 1;\n const baseline: ApiSurface | undefined = apiSurface\n ? (JSON.parse(readFileSync(apiSurface, 'utf-8')) as ApiSurface)\n : undefined;\n\n if (apiSurface && baseline) {\n console.log(`\\n${separator}`);\n console.log(`Step ${stepNum}: Compat verification`);\n console.log(separator);\n\n const effectiveScope = scope ?? (spec ? 'spec-only' : 'full');\n let parsedSpec;\n if (effectiveScope === 'spec-only' && spec) {\n parsedSpec = await parseSpec(spec, { operationIdTransform, schemaNameTransform, transformSpec });\n } else if (effectiveScope === 'spec-only') {\n throw new CommandError('error: --scope spec-only requires --spec <path>', '', 1);\n }\n\n const compatFlow =\n parsedSpec && maxRetries > 0\n ? await runOverlayRetryLoop({\n baseline,\n parsedSpec,\n outputDir: output,\n lang,\n maxRetries,\n namespace: opts.namespace,\n onRetry: (attemptNumber, retryLimit, patchableCount) => {\n console.log(`\\nRetry ${attemptNumber}/${retryLimit}: patching ${patchableCount} violation(s)...`);\n },\n })\n : {\n status: 'passed' as const,\n attempts: 0,\n patchedPerIteration: [],\n compatResult: await runCompatCheck(baseline, output, lang, parsedSpec),\n };\n\n const compatSummary = summarizeCompatCheck(compatFlow.compatResult);\n printCompatResult(compatSummary, baseline);\n const classifiedDiff = compatFlow.compatResult.diff;\n for (const c of classifiedDiff.changes) {\n if (c.severity !== 'additive') {\n console.log(` [${c.category}] ${c.severity}: ${c.symbol} — ${c.message}`);\n }\n }\n const additiveCount = classifiedDiff.summary.additive;\n if (additiveCount > 0) {\n console.log(` + ${additiveCount} new symbols added`);\n }\n\n if (diagnostics) {\n diagData.compatCheck = compatSummary;\n if (parsedSpec && maxRetries > 0) {\n setRetryDiagnostics(\n diagData,\n compatFlow.attempts,\n compatFlow.status === 'passed',\n compatSummary.preservationScore,\n compatFlow.patchedPerIteration,\n );\n }\n }\n\n if (compatFlow.status === 'passed' && compatFlow.compatResult.passed) {\n if (compatFlow.attempts > 0) {\n console.log(`Compat: converged after ${compatFlow.attempts} retry iteration(s)`);\n } else {\n console.log('Compat: passed');\n }\n } else {\n if (diagnostics) {\n writeDiagnostics(diagData);\n console.log('Diagnostics written to verify-diagnostics.json');\n }\n\n if (compatFlow.status === 'no-patchable') {\n console.log(\n 'No patchable violations — cannot self-correct. Remaining violations require emitter code changes.',\n );\n } else if (compatFlow.status === 'stalled') {\n console.log(`Stalled — overlay patching is not making progress.`);\n }\n\n throw new CommandError('\\nCompat violations found — fix the emitter and re-run `oagen verify`.', '', 1);\n }\n\n // Classified compat analysis — approvals, reports, and explanations\n // The diff is already classified from runCompatCheck/runOverlayRetryLoop\n if (effectiveReportPath || effectiveExplain || (compatConfig?.allow?.length ?? 0) > 0) {\n const langId = lang as LanguageId;\n const approvals = compatConfig?.allow ?? [];\n const remaining = unapprovedChanges(classifiedDiff.changes, approvals, langId);\n const hasFailure = remaining.some((c) => severityMeetsThreshold(c.severity, effectiveFailOn));\n\n if (effectiveExplain) {\n console.log('');\n console.log(formatHumanSummary(classifiedDiff, { explain: true }));\n }\n\n if (effectiveReportPath) {\n const report = generateReport(classifiedDiff);\n writeFileSync(effectiveReportPath, JSON.stringify(report, null, 2) + '\\n');\n console.log(`Compat report written to ${effectiveReportPath}`);\n }\n\n if (hasFailure && effectiveFailOn !== 'none') {\n const unapprovedBreaking = remaining.filter((c) => severityMeetsThreshold(c.severity, effectiveFailOn));\n console.log(`\\n${unapprovedBreaking.length} unapproved change(s) at or above '${effectiveFailOn}' threshold`);\n }\n }\n\n stepNum++;\n }\n\n if (oldSpec && spec && apiSurface && baseline) {\n console.log(`\\n${separator}`);\n console.log(`Step ${stepNum}: Staleness detection`);\n console.log(separator);\n\n const oldParsedSpec = await parseSpec(oldSpec, { operationIdTransform, schemaNameTransform, transformSpec });\n const newParsedSpec = await parseSpec(spec, { operationIdTransform, schemaNameTransform, transformSpec });\n const stalenessResult = runStalenessCheck(baseline, oldParsedSpec, newParsedSpec, lang);\n\n if (stalenessResult.violations.length > 0) {\n console.log(`Found ${stalenessResult.violations.length} stale symbol(s):`);\n for (const v of stalenessResult.violations) {\n console.log(` [${v.category}] ${v.severity}: ${v.symbolPath} — ${v.message}`);\n }\n } else {\n console.log('No stale symbols detected.');\n }\n\n if (diagnostics) {\n diagData.stalenessCheck = {\n staleSymbolCount: stalenessResult.violations.length,\n staleSymbols: stalenessResult.violations.map((v) => v.symbolPath),\n };\n }\n\n stepNum++;\n }\n\n const needsBaselineStep = !rawResults && !existsSync('smoke-results-raw.json');\n if (needsBaselineStep) {\n console.log(`\\n${separator}`);\n console.log(`Step ${stepNum}: Generating spec-only baseline (no raw baseline found)`);\n console.log(separator);\n stepNum++;\n }\n\n console.log(`\\n${separator}`);\n console.log(`Step ${stepNum}: Smoke test + diff`);\n console.log(separator);\n\n const smokeResult = runSmokeCheck({\n spec,\n lang,\n output,\n rawResults,\n smokeConfig,\n smokeRunner,\n });\n\n if (diagnostics) {\n diagData.smokeCheck = {\n passed: smokeResult.passed,\n ...(smokeResult.findingsCount !== undefined ? { findingsCount: smokeResult.findingsCount } : {}),\n ...(smokeResult.compileErrors ? { compileErrors: true } : {}),\n };\n writeDiagnostics(diagData);\n console.log('Diagnostics written to verify-diagnostics.json');\n }\n\n if (!smokeResult.passed) {\n if (smokeResult.compileErrors) {\n throw new CommandError('\\nSDK compile errors — read smoke-compile-errors.json for details', '', 2);\n }\n\n throw new CommandError(\n '\\nSmoke test findings — read smoke-diff-findings.json for details\\n\\n' +\n `Remediation guide (by finding type):\n \"HTTP method differs\" → fix ${lang} emitter resources.ts (in emitter project)\n \"Request path structure differs\" → fix ${lang} emitter resources.ts (in emitter project)\n \"Query parameters differ\" → fix ${lang} emitter resources.ts (in emitter project)\n \"Request body key sets differ\" → fix ${lang} emitter models.ts or resources.ts (in emitter project)\n \"Skipped in SDK\" → fix smoke/sdk-${lang}.ts (in emitter project)\n \"Missing from SDK\" → fix smoke/sdk-${lang}.ts (in emitter project)`,\n '',\n 1,\n );\n }\n\n console.log('\\nVerify: all checks passed');\n}\n","import { toCamelCase } from '../../utils/naming.js';\n\nexport function oagenScripts(lang: string): Record<string, string> {\n return {\n [`sdk:generate:${lang}`]: `oagen generate --lang ${lang} --output ./sdk --namespace my-api --spec open-api-spec.yaml --api-surface ./sdk-${lang}-surface.json --target ../your-${lang}-sdk`,\n [`sdk:diff:${lang}`]: `oagen diff --old ./sdk/spec-snapshot.yaml --new open-api-spec.yaml --lang ${lang} --output ./sdk --target ../your-${lang}-sdk --api-surface ./sdk-${lang}-surface.json`,\n [`sdk:verify:${lang}`]: `oagen verify --lang ${lang} --output ./sdk --spec open-api-spec.yaml --api-surface ./sdk-${lang}-surface.json`,\n [`sdk:extract:${lang}`]: `oagen extract --lang ${lang} --sdk-path ../your-${lang}-sdk --output ./sdk-${lang}-surface.json`,\n };\n}\n\nexport function packageJson(lang: string): string {\n return JSON.stringify(\n {\n name: `custom-oagen-emitters`,\n version: '0.0.1',\n type: 'module',\n main: 'dist/index.js',\n types: 'dist/index.d.ts',\n exports: {\n '.': { types: './dist/index.d.ts', import: './dist/index.js' },\n './plugin': { types: './dist/plugin.d.ts', import: './dist/plugin.js' },\n },\n scripts: {\n build: 'tsup',\n test: 'vitest run',\n 'test:watch': 'vitest',\n typecheck: 'tsc --noEmit',\n ...oagenScripts(lang),\n },\n dependencies: {\n '@workos/oagen': '^0.0.1',\n },\n devDependencies: {\n tsup: '^8.4.0',\n tsx: '^4.19.0',\n vitest: '^3.0.0',\n '@types/node': '^25.3.3',\n },\n },\n null,\n 2,\n );\n}\n\nexport function tsconfigJson(): string {\n return JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n strict: true,\n declaration: true,\n declarationMap: true,\n sourceMap: true,\n outDir: 'dist',\n rootDir: '.',\n esModuleInterop: true,\n skipLibCheck: true,\n forceConsistentCasingInFileNames: true,\n resolveJsonModule: true,\n isolatedModules: true,\n },\n include: ['src', 'test'],\n exclude: ['node_modules', 'dist'],\n },\n null,\n 2,\n );\n}\n\nexport function vitestConfig(): string {\n return `import { defineConfig } from 'vitest/config';\nexport default defineConfig({\n test: { globals: true, include: ['test/**/*.test.ts'] },\n});\n`;\n}\n\nexport function tsupConfig(): string {\n return `import { defineConfig } from 'tsup';\nexport default defineConfig({\n entry: { index: 'src/index.ts', plugin: 'src/plugin.ts' },\n format: ['esm'],\n dts: true,\n clean: true,\n target: 'node20',\n});\n`;\n}\n\nexport function oagenConfig(): string {\n return `import type { OagenConfig } from '@workos/oagen';\nimport { plugin } from './src/plugin.js';\n\n// Minimal config for local emitter development.\n// The canonical consumer config lives in the consumer project's oagen.config.ts,\n// which imports the plugin bundle from this package.\nconst config: OagenConfig = {\n ...plugin,\n};\nexport default config;\n`;\n}\n\nexport function srcPlugin(lang: string): string {\n const varName = `${toCamelCase(lang)}Emitter`;\n return `import type { OagenConfig } from '@workos/oagen';\nimport { ${varName} } from './${lang}/index.js';\n\nexport const plugin: Pick<OagenConfig, 'emitters' | 'extractors' | 'smokeRunners'> = {\n emitters: [${varName}],\n extractors: [],\n smokeRunners: {},\n};\n`;\n}\n\nexport function srcIndex(lang: string): string {\n const varName = `${toCamelCase(lang)}Emitter`;\n return `export { ${varName} } from './${lang}/index.js';\nexport { plugin } from './plugin.js';\n`;\n}\n\nexport function gitignore(): string {\n return `node_modules/\ndist/\n.env\nsdk-*-surface.json\nsmoke-*.json\nsdk/\n`;\n}\n\nexport function stubEmitter(lang: string): string {\n const varName = `${toCamelCase(lang)}Emitter`;\n return `import type { Emitter, EmitterContext, GeneratedFile, ApiSpec, Model, Enum, Service } from '@workos/oagen';\n\nexport const ${varName}: Emitter = {\n language: '${lang}',\n\n generateModels(_models: Model[], _ctx: EmitterContext): GeneratedFile[] {\n return [];\n },\n\n generateEnums(_enums: Enum[], _ctx: EmitterContext): GeneratedFile[] {\n return [];\n },\n\n generateResources(_services: Service[], _ctx: EmitterContext): GeneratedFile[] {\n return [];\n },\n\n generateClient(_spec: ApiSpec, _ctx: EmitterContext): GeneratedFile[] {\n return [];\n },\n\n generateErrors(_ctx: EmitterContext): GeneratedFile[] {\n return [];\n },\n\n generateTypeSignatures(_spec: ApiSpec, _ctx: EmitterContext): GeneratedFile[] {\n return [];\n },\n\n generateTests(_spec: ApiSpec, _ctx: EmitterContext): GeneratedFile[] {\n return [];\n },\n\n buildOperationsMap(_spec: ApiSpec, _ctx: EmitterContext) {\n return {};\n },\n\n fileHeader(): string {\n return '// Auto-generated by oagen. Do not edit.';\n },\n};\n`;\n}\n","import { resolve, relative } from 'node:path';\nimport { existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';\nimport {\n packageJson,\n tsconfigJson,\n vitestConfig,\n tsupConfig,\n oagenConfig,\n srcPlugin,\n srcIndex,\n gitignore,\n stubEmitter,\n} from './templates/init.js';\n\nexport async function initCommand(opts: { lang: string; project?: string }): Promise<void> {\n const projectDir = resolve(opts.project ?? '.');\n const lang = opts.lang;\n\n if (existsSync(resolve(projectDir, 'oagen.config.ts'))) {\n throw new Error('Project already initialized — oagen.config.ts exists');\n }\n\n // Create directories\n const dirs = [`src/${lang}`, 'test', 'smoke', 'docs/sdk-architecture'];\n for (const dir of dirs) {\n mkdirSync(resolve(projectDir, dir), { recursive: true });\n }\n\n // Write template files\n const files: Array<[string, string]> = [\n ['tsconfig.json', tsconfigJson()],\n ['vitest.config.ts', vitestConfig()],\n ['tsup.config.ts', tsupConfig()],\n ['oagen.config.ts', oagenConfig()],\n ['src/plugin.ts', srcPlugin(lang)],\n ['src/index.ts', srcIndex(lang)],\n [`src/${lang}/index.ts`, stubEmitter(lang)],\n ];\n\n // Handle package.json specially - merge if it exists\n const packageJsonPath = resolve(projectDir, 'package.json');\n let packageJsonContent: string;\n if (existsSync(packageJsonPath)) {\n const existingContent = readFileSync(packageJsonPath, 'utf-8');\n const existingPkg = JSON.parse(existingContent);\n const newPkg = JSON.parse(packageJson(lang));\n // Merge: existing values take precedence, but append new scripts/devDependencies\n existingPkg.scripts = { ...newPkg.scripts, ...existingPkg.scripts };\n existingPkg.devDependencies = { ...newPkg.devDependencies, ...existingPkg.devDependencies };\n existingPkg.dependencies = { ...newPkg.dependencies, ...existingPkg.dependencies };\n // Only set exports if not already defined\n if (!existingPkg.exports) {\n existingPkg.exports = newPkg.exports;\n }\n // Only set type if not already defined\n if (!existingPkg.type) {\n existingPkg.type = newPkg.type;\n }\n // Only set main if not already defined\n if (!existingPkg.main) {\n existingPkg.main = newPkg.main;\n }\n // Only set types if not already defined\n if (!existingPkg.types) {\n existingPkg.types = newPkg.types;\n }\n packageJsonContent = JSON.stringify(existingPkg, null, 2);\n } else {\n packageJsonContent = packageJson(lang);\n }\n\n // Handle .gitignore specially - append if it exists\n const gitignorePath = resolve(projectDir, '.gitignore');\n let gitignoreContent: string;\n if (existsSync(gitignorePath)) {\n const existingContent = readFileSync(gitignorePath, 'utf-8');\n const newContent = gitignore();\n // Append new entries that don't already exist (filter out comments and empty lines for comparison)\n const existingLines = new Set(\n existingContent\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line && !line.startsWith('#')),\n );\n const newLines = newContent.split('\\n').filter((line) => {\n const trimmed = line.trim();\n return trimmed && !existingLines.has(trimmed);\n });\n gitignoreContent = existingContent + (existingContent.endsWith('\\n') ? '' : '\\n') + newLines.join('\\n');\n } else {\n gitignoreContent = gitignore();\n }\n\n for (const [filePath, content] of files) {\n const fullPath = resolve(projectDir, filePath);\n mkdirSync(resolve(fullPath, '..'), { recursive: true });\n writeFileSync(fullPath, content, 'utf-8');\n }\n\n // Write package.json\n writeFileSync(packageJsonPath, packageJsonContent, 'utf-8');\n\n // Write .gitignore\n writeFileSync(gitignorePath, gitignoreContent, 'utf-8');\n\n // Print summary\n console.log(`Initialized emitter project for \"${lang}\" in ${relative(process.cwd(), projectDir) || '.'}`);\n console.log('');\n console.log('Created:');\n for (const [filePath] of files) {\n console.log(` ${filePath}`);\n }\n for (const dir of dirs) {\n console.log(` ${dir}/`);\n }\n\n // Print next steps\n console.log('');\n console.log('Next steps:');\n console.log(` - Implement your emitter in src/${lang}/index.ts`);\n console.log(' - npm run sdk:generate -- --spec <path-to-spec> --namespace <Name>');\n console.log(' - npm run sdk:verify -- --spec <path-to-spec>');\n}\n","import { parseSpec, type OpenApiDocument } from '../parser/parse.js';\nimport { resolveOperations } from '../ir/operation-hints.js';\nimport { expandDocUrls } from '../utils/expand-doc-urls.js';\nimport type { OperationHint, ResolvedOperation } from '../ir/operation-hints.js';\n\nexport async function resolveCommand(opts: {\n spec: string;\n format?: 'table' | 'json';\n operationIdTransform?: (id: string) => string;\n schemaNameTransform?: (name: string) => string;\n transformSpec?: (spec: OpenApiDocument) => OpenApiDocument;\n docUrl?: string;\n operationHints?: Record<string, OperationHint>;\n mountRules?: Record<string, string>;\n}): Promise<void> {\n let ir = await parseSpec(opts.spec, {\n operationIdTransform: opts.operationIdTransform,\n schemaNameTransform: opts.schemaNameTransform,\n transformSpec: opts.transformSpec,\n });\n if (opts.docUrl) {\n ir = expandDocUrls(ir, opts.docUrl);\n }\n\n const resolved = resolveOperations(ir, opts.operationHints, opts.mountRules);\n const format = opts.format ?? 'table';\n\n if (format === 'json') {\n const output = resolved.map(toJsonRow);\n console.log(JSON.stringify(output, null, 2));\n return;\n }\n\n // Table format\n printTable(resolved, opts.operationHints);\n}\n\ninterface JsonRow {\n service: string;\n method: string;\n path: string;\n derivedName: string;\n hintApplied: boolean;\n mountOn: string;\n wrappers?: string[];\n}\n\nfunction toJsonRow(r: ResolvedOperation): JsonRow {\n return {\n service: r.service.name,\n method: r.operation.httpMethod.toUpperCase(),\n path: r.operation.path,\n derivedName: r.methodName,\n hintApplied: r.methodName !== r.operation.name,\n mountOn: r.mountOn,\n wrappers: r.wrappers?.map((w) => w.name),\n };\n}\n\nfunction printTable(resolved: ResolvedOperation[], hints?: Record<string, OperationHint>): void {\n const hintMap = hints ?? {};\n\n // Header\n console.log('| Service | Method | Path | Resolved Name | Hint | Mount On |');\n console.log('|---|---|---|---|---|---|');\n\n const unhinted: ResolvedOperation[] = [];\n\n for (const r of resolved) {\n const key = `${r.operation.httpMethod.toUpperCase()} ${r.operation.path}`;\n const hasHint = key in hintMap;\n const hintMarker = hasHint ? 'yes' : '';\n const mountChanged = r.mountOn !== r.service.name;\n const mountCol = mountChanged ? r.mountOn : '';\n\n console.log(\n `| ${r.service.name} | ${r.operation.httpMethod.toUpperCase()} | ${r.operation.path} | \\`${r.methodName}\\` | ${hintMarker} | ${mountCol} |`,\n );\n\n // Track wrappers\n if (r.wrappers) {\n for (const w of r.wrappers) {\n console.log(`| | | | \\`${w.name}\\` (wrapper) | yes | ${mountCol} |`);\n }\n }\n\n if (!hasHint && !mountChanged) {\n unhinted.push(r);\n }\n }\n\n console.log('');\n console.log(\n `Total: ${resolved.length} operations, ${resolved.length - unhinted.length} with hints/mounts, ${unhinted.length} algorithm-only`,\n );\n}\n","import * as path from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { pathToFileURL } from 'node:url';\nimport type { Emitter } from '../engine/types.js';\nimport type { OperationHint } from '../ir/operation-hints.js';\nimport type { Extractor } from '../compat/types.js';\nimport type { CompatConfig } from '../compat/config.js';\nimport type { OpenApiDocument } from '../parser/parse.js';\nimport { ConfigLoadError } from '../errors.js';\n\nexport interface OagenConfig {\n emitters?: Emitter[];\n extractors?: Extractor[];\n /** Compatibility verification policy. See docs/core/compatibility-policy.md. */\n compat?: CompatConfig;\n /** Path to the emitter project (where skills scaffold new emitters, tests, smoke runners). */\n emitterProject?: string;\n /** Map from language key to custom smoke runner script path. */\n smokeRunners?: Record<string, string>;\n /**\n * Custom transform for operation IDs. When provided, replaces the default\n * camelCase pass-through. Receives the raw operationId string; return the\n * desired operation name (no additional conversion is applied).\n *\n */\n operationIdTransform?: (id: string) => string;\n /**\n * Custom transform for schema (model/enum) names. Applied after the built-in\n * cleanSchemaName normalization. Receives the cleaned PascalCase name; return\n * the desired name. Collisions are detected automatically -- if a transform\n * would produce a duplicate name, the original is kept.\n */\n schemaNameTransform?: (name: string) => string;\n /** Base URL for documentation links. When set, relative paths in descriptions\n * (e.g. `/reference/authkit/user`) are expanded to full URLs. */\n docUrl?: string;\n /**\n * Pre-IR overlay applied to the bundled OpenAPI document before any IR\n * extraction. Use this when the upstream spec can't be changed but a quirk\n * in it would otherwise emit a breaking SDK change — e.g. rewriting a\n * path's response `$ref` back to its prior schema, merging the new fields\n * onto the prior schema, and dropping the fork schema.\n *\n * The function may mutate the document in place and return it, or return a\n * new object. Runs once, after `$ref` bundling and before schema/operation\n * extraction. See `docs/advanced/transform-spec.md` for examples.\n */\n transformSpec?: (spec: OpenApiDocument) => OpenApiDocument;\n /**\n * Per-operation overrides keyed by \"METHOD /path\" (e.g. \"POST /sso/token\").\n * Used by the operation resolver to override derived method names, mount\n * targets, and to split union-body operations into typed wrappers.\n */\n operationHints?: Record<string, OperationHint>;\n /**\n * Service-level mount rules: maps an IR service name to a target\n * service/namespace (PascalCase). All operations in the source service\n * are mounted on the target. Per-operation mountOn in operationHints\n * takes priority.\n */\n mountRules?: Record<string, string>;\n /**\n * Pin specific models to a specific IR service for placement, overriding the\n * default \"first service to reference the model wins\" assignment.\n *\n * Maps IR model name → IR service name (both PascalCase). Useful when a model\n * is shared across services and the natural ordering would place it in a\n * service that's wrong for the public API.\n *\n * Both names must exist in the parsed spec; unknown names throw at generation\n * time so typos fail loud. Note that keys are post-cleanSchemaName /\n * post-schemaNameTransform model names (e.g. `User`, not `UserlandUser`).\n */\n modelHints?: Record<string, string>;\n /**\n * Language-specific emitter options. The CLI passes only the active\n * language's option bag to that emitter.\n */\n emitterOptions?: Record<string, Record<string, unknown>>;\n}\n\nconst CONFIG_NAMES = ['oagen.config.ts', 'oagen.config.js', 'oagen.config.mjs'];\n\n/**\n * Load an oagen config file.\n *\n * @param configPath - Explicit path to a config file. When provided, only that\n * file is attempted (no fallback search).\n * @param cwd - Directory to search when `configPath` is omitted. Defaults to\n * `process.cwd()`. The loader tries each name in `CONFIG_NAMES` in order.\n */\nexport async function loadConfig(configPath?: string, cwd: string = process.cwd()): Promise<OagenConfig | null> {\n if (configPath) {\n const resolved = path.resolve(cwd, configPath);\n if (!existsSync(resolved)) {\n throw new ConfigLoadError(`Config file not found: ${resolved}`, 'Check that the path passed to --config exists.');\n }\n try {\n const mod = await import(pathToFileURL(resolved).href);\n return (mod.default ?? mod) as OagenConfig;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new ConfigLoadError(\n `Failed to load ${resolved}: ${message}`,\n resolved.endsWith('.ts')\n ? 'TypeScript config files require tsx or ts-node. Use .mjs instead, or run via `npx tsx`.'\n : 'Check that the config file is valid ESM.',\n );\n }\n }\n\n for (const name of CONFIG_NAMES) {\n const resolved = path.resolve(cwd, name);\n if (!existsSync(resolved)) continue;\n try {\n const mod = await import(pathToFileURL(resolved).href);\n const config = (mod.default ?? mod) as OagenConfig;\n return config;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new ConfigLoadError(\n `Failed to load ${name}: ${message}`,\n name.endsWith('.ts')\n ? 'TypeScript config files require tsx or ts-node. Use .mjs instead, or run via `npx tsx`.'\n : 'Check that the config file is valid ESM.',\n );\n }\n }\n return null;\n}\n","import { registerEmitter } from '../engine/registry.js';\nimport { registerExtractor } from '../compat/extractor-registry.js';\nimport type { OagenConfig } from './config-loader.js';\n\nexport function applyConfig(config: OagenConfig): void {\n for (const emitter of config.emitters ?? []) {\n registerEmitter(emitter);\n }\n for (const extractor of config.extractors ?? []) {\n registerExtractor(extractor);\n }\n}\n","import 'dotenv/config';\nimport { Command } from 'commander';\nimport { parseCommand } from './parse.js';\nimport { generateCommand } from './generate.js';\nimport { diffCommand } from './diff.js';\nimport { extractCommand } from './extract.js';\nimport { compatExtractCommand } from './compat-extract.js';\nimport { compatDiffCommand } from './compat-diff.js';\nimport { compatSummaryCommand } from './compat-summary.js';\nimport { verifyCommand } from './verify.js';\nimport { initCommand } from './init.js';\nimport { resolveCommand } from './resolve.js';\nimport { loadConfig } from './config-loader.js';\nimport { applyConfig } from './plugin-loader.js';\nimport { CommandError } from '../errors.js';\n\nfunction handleError(err: unknown): never {\n const exitCode = err instanceof CommandError ? err.exitCode : 1;\n const message = err instanceof Error ? err.message : String(err);\n if (message) console.error(message);\n process.exit(exitCode);\n}\n\n// Parse --config before Commander runs so we can load the right config file\n// at startup. Commander's parseOptions isn't available before .parse(), so we\n// do a simple argv scan.\nconst configArgIdx = process.argv.indexOf('--config');\nconst explicitConfigPath = configArgIdx !== -1 ? process.argv[configArgIdx + 1] : undefined;\n\n// Load config at startup so user-provided emitters/extractors are registered\n// before any command runs. loadConfig is async (dynamic import), so we use\n// top-level await.\nlet configSmokeRunners: Record<string, string> | undefined;\nlet configOperationIdTransform: ((id: string) => string) | undefined;\nlet configSchemaNameTransform: ((name: string) => string) | undefined;\nlet configTransformSpec:\n | ((spec: import('../parser/parse.js').OpenApiDocument) => import('../parser/parse.js').OpenApiDocument)\n | undefined;\nlet configDocUrl: string | undefined;\nlet configOperationHints: Record<string, import('../ir/operation-hints.js').OperationHint> | undefined;\nlet configMountRules: Record<string, string> | undefined;\nlet configModelHints: Record<string, string> | undefined;\nlet configEmitterOptions: Record<string, Record<string, unknown>> | undefined;\nlet configCompat: import('../compat/config.js').CompatConfig | undefined;\ntry {\n const config = await loadConfig(explicitConfigPath);\n if (config) {\n applyConfig(config);\n configSmokeRunners = config.smokeRunners;\n configOperationIdTransform = config.operationIdTransform;\n configSchemaNameTransform = config.schemaNameTransform;\n configTransformSpec = config.transformSpec;\n configDocUrl = config.docUrl;\n configOperationHints = config.operationHints;\n configMountRules = config.mountRules;\n configModelHints = config.modelHints;\n configEmitterOptions = config.emitterOptions;\n configCompat = config.compat;\n }\n} catch (err) {\n handleError(err);\n}\n\nconst program = new Command()\n .name('oagen')\n .description('Framework for building OpenAPI SDK emitters')\n .version('0.0.1')\n .option('--config <path>', 'Path to oagen config file (default: oagen.config.ts in cwd)');\n\nprogram\n .command('parse')\n .description('Parse an OpenAPI spec and output IR as JSON')\n .option('--spec <path>', 'Path to OpenAPI spec file (or set OPENAPI_SPEC_PATH)')\n .action((opts) => {\n opts.spec ??= process.env.OPENAPI_SPEC_PATH;\n if (!opts.spec) {\n console.error('error: --spec <path> or OPENAPI_SPEC_PATH env var is required');\n process.exit(1);\n }\n return parseCommand({\n ...opts,\n operationIdTransform: configOperationIdTransform,\n schemaNameTransform: configSchemaNameTransform,\n transformSpec: configTransformSpec,\n });\n });\n\nprogram\n .command('generate')\n .description('Run a registered emitter against an OpenAPI spec')\n .option('--spec <path>', 'Path to OpenAPI spec file (or set OPENAPI_SPEC_PATH)')\n .requiredOption('--lang <language>', 'Target language')\n .requiredOption('--output <dir>', 'Output directory')\n .option('--target <dir>', 'Target directory for live SDK integration (merged output)')\n .option('--namespace <name>', 'SDK namespace/package name')\n .option('--dry-run', 'Preview files without writing')\n .option('--api-surface <path>', 'Path to baseline API surface JSON for compat overlay')\n .option('--no-compat-check', 'Skip compat overlay even if --api-surface is provided')\n .option('--no-prune', 'Skip deletion of stale files recorded in the previous .oagen-manifest.json')\n .action((opts) => {\n opts.spec ??= process.env.OPENAPI_SPEC_PATH;\n if (!opts.spec) {\n console.error('error: --spec <path> or OPENAPI_SPEC_PATH env var is required');\n process.exit(1);\n }\n generateCommand({\n ...opts,\n operationIdTransform: configOperationIdTransform,\n schemaNameTransform: configSchemaNameTransform,\n transformSpec: configTransformSpec,\n docUrl: configDocUrl,\n operationHints: configOperationHints,\n mountRules: configMountRules,\n modelHints: configModelHints,\n emitterOptions: configEmitterOptions?.[opts.lang],\n }).catch(handleError);\n });\n\nprogram\n .command('diff')\n .description('Compare two OpenAPI specs and output a diff report')\n .requiredOption('--old <path>', 'Path to old spec')\n .requiredOption('--new <path>', 'Path to new spec')\n .action((opts) => {\n diffCommand({\n ...opts,\n operationIdTransform: configOperationIdTransform,\n schemaNameTransform: configSchemaNameTransform,\n transformSpec: configTransformSpec,\n docUrl: configDocUrl,\n }).catch(handleError);\n });\n\nprogram\n .command('extract')\n .description('Extract public API surface from a live SDK')\n .requiredOption('--sdk-path <path>', 'Path to the live SDK')\n .requiredOption('--lang <language>', 'Target language')\n .option('--output <path>', 'Output file path')\n .action((opts) => {\n opts.output ??= `sdk-${opts.lang}-surface.json`;\n extractCommand(opts).catch(handleError);\n });\n\nprogram\n .command('compat-extract')\n .description('Extract a compat snapshot from a live SDK and write .oagen-compat-snapshot.json')\n .requiredOption('--sdk-path <path>', 'Path to the live SDK')\n .requiredOption('--lang <language>', 'Target language')\n .requiredOption('--output <dir>', 'Directory to write .oagen-compat-snapshot.json into')\n .option('--spec <path>', 'Path to OpenAPI spec — enriches symbols with operationId, route, and specSha')\n .action((opts) => {\n opts.spec ??= process.env.OPENAPI_SPEC_PATH;\n compatExtractCommand({\n ...opts,\n schemaNameTransform: configSchemaNameTransform,\n transformSpec: configTransformSpec,\n }).catch(handleError);\n });\n\nprogram\n .command('compat-diff')\n .description('Diff two compat snapshot files and produce a classified change report')\n .requiredOption('--baseline <path>', 'Path to the baseline compat snapshot JSON')\n .requiredOption('--candidate <path>', 'Path to the candidate compat snapshot JSON')\n .option('--output <path>', 'Write machine-readable report to this path')\n .option('--fail-on <level>', 'Fail threshold: none, breaking, or soft-risk', 'breaking')\n .option('--explain', 'Include provenance explanations in output')\n .action((opts) => {\n compatDiffCommand(opts).catch(handleError);\n });\n\nprogram\n .command('compat-summary')\n .description('Format compat report(s) as a markdown PR comment')\n .requiredOption('--report <path...>', 'Path(s) to compat report JSON(s) — pass multiple for cross-language rollup')\n .option('--output <path>', 'Write markdown to this file instead of stdout')\n .action((opts) => {\n compatSummaryCommand(opts).catch(handleError);\n });\n\nprogram\n .command('verify')\n .description('Run smoke tests (and optional compat check) against an already-generated SDK')\n .option('--spec <path>', 'Path to OpenAPI spec file (or set OPENAPI_SPEC_PATH)')\n .requiredOption('--lang <language>', 'Target language')\n .requiredOption('--output <dir>', 'Path to the generated SDK')\n .option('--api-surface <path>', 'Baseline API surface JSON — enables compat verification')\n .option('--raw-results <path>', 'Path to an existing smoke baseline file to diff against')\n .option('--smoke-config <path>', 'Path to smoke config JSON for skip lists and service mappings')\n .option('--smoke-runner <path>', 'Path to a custom smoke runner script (overrides built-in sdk-test.ts)')\n .option(\n '--scope <mode>',\n 'Compat scope: \"full\" compares all baseline symbols, \"spec-only\" compares only symbols derivable from the OpenAPI spec (default: spec-only when --spec is provided)',\n )\n .option('--old-spec <path>', 'Previous OpenAPI spec — enables staleness detection for removed/renamed symbols')\n .option('--namespace <name>', 'SDK namespace/package name (used by retry loop for regeneration)')\n .option('--diagnostics', 'Output verify-diagnostics.json with structured violation breakdown')\n .option('--max-retries <n>', 'Max retry iterations for self-correcting overlay loop (default: 3)', '3')\n .option('--compat-report <path>', 'Write machine-readable compat report to this path')\n .option('--compat-fail-on <level>', 'Fail threshold: none, breaking, or soft-risk')\n .option('--compat-baseline <path>', 'Path to baseline compatibility snapshot')\n .option('--compat-explain', 'Include provenance explanations in compat output')\n .action((opts) => {\n opts.spec ??= process.env.OPENAPI_SPEC_PATH;\n // --spec is only required when we need to generate a baseline (no --raw-results\n // and no existing smoke-results-raw.json). Defer the check to verifyCommand.\n // CLI --smoke-runner takes precedence, then per-language smokeRunners map from config\n opts.smokeRunner ??= configSmokeRunners?.[opts.lang];\n verifyCommand({\n ...opts,\n maxRetries: parseInt(opts.maxRetries, 10),\n operationIdTransform: configOperationIdTransform,\n schemaNameTransform: configSchemaNameTransform,\n transformSpec: configTransformSpec,\n compatConfig: configCompat,\n compatReport: opts.compatReport,\n compatFailOn: opts.compatFailOn,\n compatBaseline: opts.compatBaseline,\n compatExplain: opts.compatExplain,\n }).catch(handleError);\n });\n\nprogram\n .command('resolve')\n .description('Resolve operation names from spec and output a review table')\n .option('--spec <path>', 'Path to OpenAPI spec file (or set OPENAPI_SPEC_PATH)')\n .option('--format <format>', 'Output format: table or json', 'table')\n .action((opts) => {\n opts.spec ??= process.env.OPENAPI_SPEC_PATH;\n if (!opts.spec) {\n console.error('error: --spec <path> or OPENAPI_SPEC_PATH env var is required');\n process.exit(1);\n }\n resolveCommand({\n ...opts,\n operationIdTransform: configOperationIdTransform,\n schemaNameTransform: configSchemaNameTransform,\n transformSpec: configTransformSpec,\n docUrl: configDocUrl,\n operationHints: configOperationHints,\n mountRules: configMountRules,\n }).catch(handleError);\n });\n\nprogram\n .command('init')\n .description('Scaffold a new emitter project')\n .requiredOption('--lang <language>', 'Target language')\n .option('--project <dir>', 'Project directory', '.')\n .action((opts) => {\n initCommand(opts).catch(handleError);\n });\n\nprogram.parse();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["singularize","singularize","singularize","singularize","extractDeclarationName","declarationKey","path","path","path","defaultNodeHints","path","path","path","path"],"sources":["../../src/ir/sdk-behavior.ts","../../src/errors.ts","../../src/parser/refs.ts","../../src/ir/types.ts","../../src/utils/naming.ts","../../src/parser/inline-models.ts","../../src/parser/schemas.ts","../../src/parser/pagination.ts","../../src/parser/responses.ts","../../src/parser/operations.ts","../../src/parser/normalize-inline-models.ts","../../src/parser/collect-inline-enums.ts","../../src/parser/normalize-model-refs.ts","../../src/parser/parse.ts","../../src/cli/parse.ts","../../src/engine/merge-adapters/url-fingerprint.ts","../../src/engine/merge-adapters/dotnet.ts","../../src/engine/merge-adapters/elixir.ts","../../src/engine/merge-adapters/go.ts","../../src/engine/merge-adapters/kotlin.ts","../../src/engine/merge-adapters/node.ts","../../src/engine/merge-adapters/php.ts","../../src/engine/merge-adapters/python.ts","../../src/engine/merge-adapters/ruby.ts","../../src/engine/merge-adapters/rust.ts","../../src/engine/merge-adapters/index.ts","../../src/utils/tree-sitter.ts","../../src/engine/merger.ts","../../src/engine/json-merge.ts","../../src/engine/writer.ts","../../src/ir/operation-hints.ts","../../src/engine/generate-files.ts","../../src/engine/integrate.ts","../../src/engine/formatter.ts","../../src/engine/manifest.ts","../../src/engine/orchestrator.ts","../../src/engine/registry.ts","../../src/compat/language-hints.ts","../../src/compat/overlay.ts","../../src/compat/extractor-registry.ts","../../src/engine/manifest-reader.ts","../../src/cli/overlay-loader.ts","../../src/utils/expand-doc-urls.ts","../../src/cli/generate.ts","../../src/differ/classify.ts","../../src/differ/models.ts","../../src/differ/operations.ts","../../src/differ/services.ts","../../src/differ/diff.ts","../../src/cli/diff.ts","../../src/cli/extract.ts","../../src/compat/policy.ts","../../src/compat/schema.ts","../../src/compat/ir.ts","../../src/cli/compat-extract.ts","../../src/compat/config.ts","../../src/compat/classify.ts","../../src/compat/spec-filter.ts","../../src/compat/differ.ts","../../src/compat/concepts.ts","../../src/compat/report.ts","../../src/cli/compat-diff.ts","../../src/cli/compat-summary.ts","../../src/compat/approvals.ts","../../src/verify/run-compat-check.ts","../../src/verify/run-overlay-retry-loop.ts","../../src/compat/staleness.ts","../../src/verify/run-staleness-check.ts","../../src/verify/run-smoke-check.ts","../../src/verify/write-diagnostics.ts","../../src/cli/verify.ts","../../src/cli/templates/init.ts","../../src/cli/init.ts","../../src/cli/resolve.ts","../../src/cli/config-loader.ts","../../src/cli/plugin-loader.ts","../../src/cli/index.ts"],"sourcesContent":["/**\n * SDK Behavior IR — language-agnostic runtime policies for generated SDKs.\n *\n * These types capture the \"what\" of SDK behavior (retry, telemetry, errors, etc.)\n * while emitters provide the \"how\" (language-specific mechanism).\n *\n * Emitters access these via `ctx.spec.sdk` — always populated, never undefined.\n */\n\n// ── Retry ──────────────────────────────────────────────────────────\n\n/** Retry policy — when and how to retry failed requests. */\nexport interface RetryPolicy {\n /** HTTP status codes that trigger a retry. */\n retryableStatusCodes: number[];\n /** Maximum number of retry attempts (0 = no retries). */\n maxRetries: number;\n /** Whether to retry on connection errors (DNS failure, TCP reset). */\n retryOnConnectionError: boolean;\n /** Whether to retry on timeout errors. */\n retryOnTimeout: boolean;\n /** Backoff strategy between retries. */\n backoff: BackoffStrategy;\n}\n\n/** Exponential backoff configuration.\n *\n * Formula: `delay = min(initialDelay * multiplier^attempt, maxDelay)`\n * With jitter: `delay += delay * jitterFactor * random(0, 1)`\n */\nexport interface BackoffStrategy {\n /** Initial delay in seconds before the first retry. */\n initialDelay: number;\n /** Multiplier applied to the delay on each subsequent retry. */\n multiplier: number;\n /** Maximum delay in seconds (cap). */\n maxDelay: number;\n /** Jitter factor (0..1). 0.5 means up to 50% random jitter added. */\n jitterFactor: number;\n}\n\n// ── Errors ─────────────────────────────────────────────────────────\n\n/** Error mapping — status codes to named exception kinds. */\nexport interface ErrorPolicy {\n /** Map from HTTP status code to a logical error kind name (e.g. 400 → 'BadRequest').\n * Emitters append language-specific suffixes (e.g. 'BadRequestException'). */\n statusCodeMap: Record<number, string>;\n /** Catch-all error kind for 5xx status codes not in the map. */\n serverErrorKind: string;\n /** Catch-all error kind for unrecognized status codes. */\n clientErrorKind: string;\n /** URL template for error documentation. Use {code} as placeholder for the API error code.\n * Example: 'https://workos.com/docs/errors/{code}' */\n errorDocUrlTemplate?: string;\n}\n\n// ── Telemetry ──────────────────────────────────────────────────────\n\n/** Telemetry — what request metrics to track and send. */\nexport interface TelemetryPolicy {\n /** Whether telemetry is enabled by default. Users can opt out via constructor param. */\n enabledByDefault: boolean;\n /** Header name for client telemetry data (previous request's ID + latency). */\n headerName: string;\n /** Response header name for the request ID. */\n requestIdHeader: string;\n}\n\n// ── Pagination ─────────────────────────────────────────────────────\n\n/** Pagination behavior defaults. */\nexport interface PaginationPolicy {\n /** Delay in milliseconds between pages during auto-pagination. 0 = no delay. */\n autoPageDelayMs: number;\n}\n\n// ── Idempotency ────────────────────────────────────────────────────\n\n/** Idempotency auto-generation rules. */\nexport interface IdempotencyPolicy {\n /** Header name for the idempotency key. */\n headerName: string;\n /** Whether to auto-generate a UUID v4 idempotency key for POST requests when retries > 0. */\n autoGenerateForPost: boolean;\n}\n\n// ── Logging ────────────────────────────────────────────────────────\n\n/** Logging contract — what to log at which level. */\nexport interface LoggingPolicy {\n /** Whether structured logging hooks are generated. */\n enabled: boolean;\n /** Log events that the generated client emits. */\n events: LogEvent[];\n}\n\n/** A discrete loggable event in the request lifecycle. */\nexport type LogEvent =\n | 'request.start'\n | 'request.success'\n | 'request.retry'\n | 'request.rate_limited'\n | 'request.error'\n | 'request.connection_error';\n\n// ── User-Agent ─────────────────────────────────────────────────────\n\n/** User-Agent construction rules. */\nexport interface UserAgentPolicy {\n /** Template for the SDK identifier string.\n * Placeholders: {name} = spec name, {lang} = emitter language, {version} = SDK version.\n * Each emitter interpolates with its own language string and casing conventions.\n * Example: '{name} {lang}/{version}' → 'WorkOS PHP/4.32.0' */\n sdkIdentifierTemplate: string;\n /** Whether to append the runtime/language version (e.g. PHP 8.2, Python 3.12). */\n includeRuntimeVersion: boolean;\n /** Whether to allow app info enrichment via setAppInfo(name, version, url). */\n allowAppInfo: boolean;\n /** AI agent environment variable detection entries. */\n aiAgentEnvVars: AiAgentEnvVar[];\n}\n\n/** Maps an environment variable to an AI agent slug for User-Agent enrichment. */\nexport interface AiAgentEnvVar {\n /** Environment variable to check (e.g. 'CLAUDE_CODE'). */\n envVar: string;\n /** Agent name to append to User-Agent (e.g. 'ClaudeCode'). */\n agentName: string;\n}\n\n// ── Request Guards ─────────────────────────────────────────────────\n\n/** Guards that validate request params before sending. */\nexport interface RequestGuardPolicy {\n /** Keys that should be in RequestOptions, not in params.\n * If detected in the body or query params, the SDK throws an error. */\n optionKeys: string[];\n}\n\n// ── Timeouts ───────────────────────────────────────────────────────\n\n/** Timeout configuration. */\nexport interface TimeoutPolicy {\n /** Default HTTP request timeout in seconds. */\n defaultTimeoutSeconds: number;\n /** Environment variable name to override the timeout (e.g. 'WORKOS_REQUEST_TIMEOUT'). */\n timeoutEnvVar?: string;\n}\n\n// ── Root ───────────────────────────────────────────────────────────\n\n/** Language-agnostic runtime policies for generated SDKs.\n * Attached to `ApiSpec.sdk` and consumed by emitters via `ctx.spec.sdk`. */\nexport interface SdkBehavior {\n retry: RetryPolicy;\n errors: ErrorPolicy;\n telemetry: TelemetryPolicy;\n pagination: PaginationPolicy;\n idempotency: IdempotencyPolicy;\n logging: LoggingPolicy;\n userAgent: UserAgentPolicy;\n requestGuard: RequestGuardPolicy;\n timeout: TimeoutPolicy;\n}\n\n// ── Defaults ───────────────────────────────────────────────────────\n\n/**\n * Canonical SDK behavior defaults. These match the PHP emitter's current\n * implementation (the most complete). Per-language overrides can be applied\n * via `mergeSdkBehavior()` in each SDK's `oagen.config.ts`.\n *\n * - Retry: exponential backoff with jitter, retries on 429/5xx\n * - Errors: standard HTTP status → exception kind mapping\n * - Telemetry: enabled by default, tracks request ID + latency\n * - Pagination: no inter-page delay (Node overrides to 350ms)\n * - Idempotency: auto-generate UUID v4 for retryable POSTs\n * - Logging: all lifecycle events enabled\n * - User-Agent: SDK identifier + runtime version + app info + AI agent detection\n * - Request guards: detect misplaced RequestOptions keys in params\n * - Timeout: 60s default (Python overrides to 30s)\n */\nexport function defaultSdkBehavior(): SdkBehavior {\n return {\n retry: {\n retryableStatusCodes: [429, 500, 502, 503, 504],\n maxRetries: 3,\n retryOnConnectionError: true,\n retryOnTimeout: true,\n backoff: {\n initialDelay: 1.0,\n multiplier: 2.0,\n maxDelay: 30.0,\n jitterFactor: 0.5,\n },\n },\n errors: {\n statusCodeMap: {\n 400: 'BadRequest',\n 401: 'Authentication',\n 403: 'Authorization',\n 404: 'NotFound',\n 409: 'Conflict',\n 422: 'UnprocessableEntity',\n 429: 'RateLimitExceeded',\n },\n serverErrorKind: 'Server',\n clientErrorKind: 'Api',\n errorDocUrlTemplate: 'https://workos.com/docs/errors/{code}',\n },\n telemetry: {\n enabledByDefault: true,\n headerName: 'X-WorkOS-Client-Telemetry',\n requestIdHeader: 'X-Request-ID',\n },\n pagination: {\n autoPageDelayMs: 0,\n },\n idempotency: {\n headerName: 'Idempotency-Key',\n autoGenerateForPost: true,\n },\n logging: {\n enabled: true,\n events: [\n 'request.start',\n 'request.success',\n 'request.retry',\n 'request.rate_limited',\n 'request.error',\n 'request.connection_error',\n ],\n },\n userAgent: {\n sdkIdentifierTemplate: '{name} {lang}/{version}',\n includeRuntimeVersion: true,\n allowAppInfo: true,\n aiAgentEnvVars: [\n { envVar: 'CLAUDE_CODE', agentName: 'ClaudeCode' },\n { envVar: 'CURSOR_AGENT', agentName: 'Cursor' },\n { envVar: 'CLINE_ACTIVE', agentName: 'Cline' },\n { envVar: 'WINDSURF_ACTIVE', agentName: 'Windsurf' },\n { envVar: 'COPILOT_AGENT', agentName: 'Copilot' },\n ],\n },\n requestGuard: {\n optionKeys: [\n 'api_key',\n 'apiKey',\n 'idempotency_key',\n 'idempotencyKey',\n 'extra_headers',\n 'extraHeaders',\n 'max_retries',\n 'maxRetries',\n 'base_url',\n 'baseUrl',\n ],\n },\n timeout: {\n defaultTimeoutSeconds: 60,\n },\n };\n}\n\n// ── Merge ──────────────────────────────────────────────────────────\n\n/** Recursive partial type for deep overrides. */\nexport type DeepPartial<T> = {\n [K in keyof T]?: T[K] extends (infer U)[]\n ? U[] // Arrays replace entirely (don't concat)\n : T[K] extends object\n ? DeepPartial<T[K]>\n : T[K];\n};\n\n/**\n * Deep-merge partial overrides into the canonical defaults.\n * Arrays replace entirely (so `retryableStatusCodes: [429]` replaces the full list,\n * rather than appending). Object properties are merged recursively.\n */\nexport function mergeSdkBehavior(overrides: DeepPartial<SdkBehavior>): SdkBehavior {\n return deepMerge(\n defaultSdkBehavior() as unknown as Record<string, unknown>,\n overrides as unknown as Record<string, unknown>,\n ) as unknown as SdkBehavior;\n}\n\n/**\n * Self-contained deep merge (no external imports — ir/ is layer 0).\n * Arrays and primitives from `source` replace those in `target`.\n * Objects are merged recursively.\n */\nfunction deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = { ...target };\n for (const key of Object.keys(source)) {\n const sourceVal = source[key];\n const targetVal = target[key];\n if (sourceVal === undefined) continue;\n if (\n sourceVal !== null &&\n typeof sourceVal === 'object' &&\n !Array.isArray(sourceVal) &&\n targetVal !== null &&\n typeof targetVal === 'object' &&\n !Array.isArray(targetVal)\n ) {\n result[key] = deepMerge(targetVal as Record<string, unknown>, sourceVal as Record<string, unknown>);\n } else {\n result[key] = sourceVal;\n }\n }\n return result;\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","import { readFile } from 'node:fs/promises';\nimport { resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { makeDocumentFromString, bundleDocument, createConfig, BaseResolver, Oas3_1Types } from '@redocly/openapi-core';\nimport { SpecParseError } from '../errors.js';\n\nexport interface BundledSpec {\n parsed: Record<string, unknown>;\n specPath: string;\n}\n\nexport async function loadAndBundleSpec(specPath: string): Promise<BundledSpec> {\n const absolutePath = resolve(specPath);\n const content = await readFile(absolutePath, 'utf-8');\n const document = makeDocumentFromString(content, pathToFileURL(absolutePath).href);\n\n const config = await createConfig({});\n const resolver = new BaseResolver();\n\n const result = await bundleDocument({\n document,\n config,\n types: Oas3_1Types,\n externalRefResolver: resolver,\n dereference: false,\n });\n\n if (result.problems.some((p) => p.severity === 'error')) {\n const errors = result.problems\n .filter((p) => p.severity === 'error')\n .map((p) => p.message)\n .join('\\n');\n throw new SpecParseError(\n `Failed to parse spec: ${errors}`,\n `Check the OpenAPI spec at \"${absolutePath}\" for syntax errors. Run a linter such as \\`npx @redocly/cli lint ${specPath}\\` to identify issues.`,\n );\n }\n\n return {\n parsed: result.bundle.parsed as Record<string, unknown>,\n specPath: absolutePath,\n };\n}\n","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\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\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 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. Both names must exist in\n * the spec; unknown keys/values throw a config-style error so typos fail\n * loud at generation time.\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 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 modelToService.set(modelName, serviceName);\n }\n }\n\n return modelToService;\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 * 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","import type { Model, Field } from '../ir/types.js';\nimport { toPascalCase, stripListItemMarkers, singularize } from '../utils/naming.js';\nimport type { SchemaObject } from './schemas.js';\nimport { buildFieldFromSchema, resolveSchemaName } from './schemas.js';\n\n/**\n * Qualify an inline model name with the parent schema name.\n * If `parentName` is provided and the field name doesn't already start with\n * the parent, the result is `${parentName}${PascalField}` with the trailing\n * word singularized (e.g., Connection + Domains → ConnectionDomain).\n */\nexport function qualifyInlineModelName(baseName: string, parentName?: string): string {\n if (!parentName) return baseName;\n // Strip ListItem/ByExternalId markers from parent name so inline model names\n // are clean and match the names produced by qualifyNestedName() in responses.ts.\n // e.g., ConnectionListItem + Domains → Connection + Domain = ConnectionDomain\n const cleanParent = stripListItemMarkers(parentName);\n if (baseName.startsWith(cleanParent)) return baseName;\n // Singularize the trailing PascalCase word of the combined name.\n // Split baseName into leading words + trailing word, singularize trailing.\n const trailingMatch = baseName.match(/^(.*?)([A-Z][a-z]*)$/);\n if (trailingMatch) {\n const [, prefix, trailingWord] = trailingMatch;\n const singular = singularize(trailingWord);\n return `${cleanParent}${prefix}${singular}`;\n }\n return `${cleanParent}${baseName}`;\n}\n\n/**\n * Walk all component schemas and extract inline Model definitions for fields\n * that are objects with properties (or arrays of such objects).\n * These correspond to the ModelRef entries created by schemaToTypeRef.\n */\nexport function extractInlineModelsFromSchemas(schemas: Record<string, SchemaObject> | undefined): Model[] {\n if (!schemas) return [];\n\n const inlineModels: Model[] = [];\n\n for (const [schemaName, schema] of Object.entries(schemas)) {\n const parentName = resolveSchemaName(schemaName);\n extractInlineModelsFromProperties(schema, inlineModels, parentName);\n }\n\n return inlineModels;\n}\n\nfunction extractInlineModelsFromProperties(schema: SchemaObject, results: Model[], parentName?: string): void {\n const properties = schema.properties ?? {};\n const allOfSchemas = schema.allOf ?? [];\n\n for (const sub of allOfSchemas) {\n if (sub.properties) {\n extractInlineModelsFromProperties(sub, results, parentName);\n }\n }\n\n for (const [fieldName, fieldSchema] of Object.entries(properties)) {\n if (!fieldSchema) continue;\n // Direct inline object with properties (with or without explicit type: 'object')\n if (fieldSchema.properties && (fieldSchema.type === 'object' || !fieldSchema.type)) {\n const baseName = toPascalCase(fieldName);\n const modelName = qualifyInlineModelName(baseName, parentName);\n results.push(buildInlineModel(modelName, fieldSchema));\n extractInlineModelsFromProperties(fieldSchema, results, modelName);\n }\n\n // Array of inline objects\n if (fieldSchema.type === 'array' && fieldSchema.items) {\n const items = fieldSchema.items;\n if (items.properties && (items.type === 'object' || !items.type)) {\n const baseName = toPascalCase(fieldName);\n const modelName = qualifyInlineModelName(baseName, parentName);\n results.push(buildInlineModel(modelName, items));\n extractInlineModelsFromProperties(items, results, modelName);\n }\n }\n\n // oneOf containing objects — extract every inline object variant as a\n // model so each gets its own typed class. Variant 0 keeps the bare\n // qualified inline name (e.g. `ApiKeyCreatedDataOwner`); subsequent\n // variants are prefixed by their const-discriminator value via\n // `nameOneOfVariant` (e.g. `UserApiKeyCreatedDataOwner`). When the\n // oneOf doesn't have a const-discriminator (single object variant + null\n // for nullable, or single object variant only), only variant 0 is\n // extracted and the bare name pattern preserves backward compat.\n if (fieldSchema.oneOf) {\n const inlineObjectVariants = fieldSchema.oneOf.filter(\n (v) => !v.$ref && v.properties && (v.type === 'object' || !v.type),\n );\n if (inlineObjectVariants.length > 0) {\n const baseName = toPascalCase(fieldName);\n const modelName = qualifyInlineModelName(baseName, parentName);\n const existingNames = new Set(results.map((r) => r.name));\n const namingDiscProp = deriveOneOfNamingDiscriminator(inlineObjectVariants);\n const emittedNames: string[] = [];\n for (const variant of inlineObjectVariants) {\n const variantName = nameOneOfVariant(variant, modelName, emittedNames, namingDiscProp);\n emittedNames.push(variantName);\n if (!existingNames.has(variantName)) {\n existingNames.add(variantName);\n results.push(buildInlineModel(variantName, variant));\n extractInlineModelsFromProperties(variant, results, variantName);\n }\n }\n }\n }\n }\n}\n\n/** Find a single string-const-valued property shared by every variant whose\n * values are all distinct — the implicit discriminator. Returns null when no\n * such property exists. Mirrors `deriveConstNamingDiscriminator` in schemas.ts. */\nfunction deriveOneOfNamingDiscriminator(variants: SchemaObject[]): string | null {\n if (variants.length < 2) return null;\n const candidates = Object.keys(variants[0]?.properties ?? {});\n for (const propName of candidates) {\n const values = variants.map((v) => readConstString(v.properties?.[propName]));\n if (values.some((v) => v === null)) continue;\n if (new Set(values).size !== values.length) continue;\n return propName;\n }\n return null;\n}\n\nfunction readConstString(prop: SchemaObject | undefined): string | null {\n if (!prop) return null;\n if (typeof prop.const === 'string') return prop.const;\n if (Array.isArray(prop.enum) && prop.enum.length === 1 && typeof prop.enum[0] === 'string') {\n return prop.enum[0];\n }\n return null;\n}\n\n/** Produce a per-variant model name. Variant 0 keeps the bare parent name;\n * later variants are prefixed by the const-derived label. Mirrors\n * `nameVariantModel` in schemas.ts. Falls back to a numeric suffix when no\n * discriminator is available, the const value PascalCases to nothing, or\n * the derived candidate collides with the parent or an already-emitted name. */\nfunction nameOneOfVariant(\n variant: SchemaObject,\n parentName: string,\n alreadyEmitted: string[],\n discriminatorProperty: string | null,\n): string {\n if (alreadyEmitted.length === 0) return parentName;\n if (discriminatorProperty) {\n const constValue = readConstString(variant.properties?.[discriminatorProperty]);\n if (constValue) {\n const prefix = toPascalCase(constValue);\n if (prefix) {\n const candidate = parentName.startsWith(prefix) ? parentName : `${prefix}${parentName}`;\n const collision = candidate === parentName || alreadyEmitted.includes(candidate);\n if (!collision) return candidate;\n }\n }\n }\n return `${parentName}${alreadyEmitted.length + 1}`;\n}\n\nfunction buildInlineModel(name: string, schema: SchemaObject): Model {\n const requiredSet = new Set(schema.required ?? []);\n const fields: Field[] = [];\n\n for (const [fieldName, fieldSchema] of Object.entries(schema.properties ?? {})) {\n if (!fieldSchema) continue;\n fields.push(buildFieldFromSchema(fieldName, fieldSchema, name, requiredSet));\n }\n\n return { name, description: schema.description, fields };\n}\n","import type { Model, Enum, EnumValue, Field, TypeRef } from '../ir/types.js';\nimport { walkTypeRef } from '../ir/types.js';\nimport {\n toPascalCase,\n toUpperSnakeCase,\n cleanSchemaName,\n singularize,\n stripListItemMarkers,\n splitWords,\n} from '../utils/naming.js';\n\n/**\n * Module-level transform set during extractSchemas(). Used by schemaToTypeRef()\n * to apply the same name transform to $ref model/enum references.\n */\nlet activeSchemaNameTransform: ((name: string) => string) | null = null;\n\n/**\n * Module-level set of resolved schema names whose components/schemas entry is\n * an enum (i.e. has `enum:`). Populated by extractSchemas() so schemaToTypeRef()\n * can classify a `$ref` to a top-level enum schema as `kind: 'enum'` instead of\n * `kind: 'model'`. Without this, every `$ref` was naively returned as a model\n * ref, even when the target was a shared enum like `PaginationOrder`.\n */\nlet activeEnumSchemaNames: Set<string> = new Set();\n\n/** Apply cleanSchemaName + the active transform (if any) to a raw schema name. */\nexport function resolveSchemaName(rawName: string): string {\n let name = cleanSchemaName(toPascalCase(rawName));\n if (activeSchemaNameTransform) name = activeSchemaNameTransform(name);\n return name;\n}\n\nexport interface SchemaExtractionOptions {\n schemaNameTransform?: (name: string) => string;\n}\n\nexport interface SchemaObject {\n type?: string | string[];\n format?: string;\n description?: string;\n properties?: Record<string, SchemaObject | undefined>;\n required?: string[];\n items?: SchemaObject;\n enum?: (string | number)[];\n allOf?: SchemaObject[];\n oneOf?: SchemaObject[];\n anyOf?: SchemaObject[];\n discriminator?: { propertyName: string; mapping?: Record<string, string> };\n readOnly?: boolean;\n writeOnly?: boolean;\n nullable?: boolean;\n $ref?: string;\n additionalProperties?: boolean | SchemaObject;\n const?: unknown;\n patternProperties?: Record<string, SchemaObject>;\n deprecated?: boolean;\n default?: unknown;\n example?: unknown;\n [key: string]: unknown;\n}\n\nexport interface ExtractedSchemas {\n models: Model[];\n enums: Enum[];\n}\n\nexport function extractSchemas(\n schemas: Record<string, SchemaObject> | undefined,\n options?: SchemaExtractionOptions,\n): ExtractedSchemas {\n const enums: Enum[] = [];\n\n if (!schemas) return { models: [], enums };\n\n // Build collision-safe transform if provided\n if (options?.schemaNameTransform) {\n const transform = options.schemaNameTransform;\n const rawNames = Object.keys(schemas);\n const cleanedNames = rawNames.map((n) => cleanSchemaName(toPascalCase(n)));\n const transformedToOriginals = new Map<string, string[]>();\n for (const cleaned of cleanedNames) {\n const transformed = transform(cleaned);\n if (!transformedToOriginals.has(transformed)) transformedToOriginals.set(transformed, []);\n transformedToOriginals.get(transformed)!.push(cleaned);\n }\n const unsafeToTransform = new Set<string>();\n for (const [, originals] of transformedToOriginals) {\n if (originals.length > 1) {\n for (const n of originals) unsafeToTransform.add(n);\n }\n }\n activeSchemaNameTransform = (name: string) => (unsafeToTransform.has(name) ? name : transform(name));\n } else {\n activeSchemaNameTransform = null;\n }\n\n // Pre-compute the set of resolved names whose component schema is an enum so\n // schemaToTypeRef() can classify `$ref` targets correctly. Built in a separate\n // pass because the per-schema loop mutates models/enums and we want this map\n // available before any TypeRef is resolved (operations + nested fields both\n // call schemaToTypeRef during extraction).\n activeEnumSchemaNames = new Set();\n for (const [name, schema] of Object.entries(schemas)) {\n if (schema.enum) activeEnumSchemaNames.add(resolveSchemaName(name));\n }\n\n const modelsByCleanName = new Map<string, Model>();\n\n for (const [name, schema] of Object.entries(schemas)) {\n const pascalName = resolveSchemaName(name);\n\n if (schema.enum) {\n enums.push(extractEnum(pascalName, schema));\n } else {\n const model = extractModel(pascalName, schema, schemas);\n const existing = modelsByCleanName.get(pascalName);\n if (existing) {\n // Keep the model with more fields when names collide after cleaning\n if (model.fields.length > existing.fields.length) {\n modelsByCleanName.set(pascalName, model);\n }\n } else {\n modelsByCleanName.set(pascalName, model);\n }\n\n for (const inlineModel of extractDiscriminatedAllOfVariantModels(schema, pascalName)) {\n const existingInline = modelsByCleanName.get(inlineModel.name);\n if (existingInline) {\n if (inlineModel.fields.length > existingInline.fields.length) {\n modelsByCleanName.set(inlineModel.name, inlineModel);\n }\n } else {\n modelsByCleanName.set(inlineModel.name, inlineModel);\n }\n }\n }\n }\n\n const models = [...modelsByCleanName.values()];\n\n // Collect inline models from nested object/oneOf properties\n // that schemaToTypeRef created model refs for but weren't extracted\n const modelNames = new Set(models.map((m) => m.name));\n const inlineQueue: Model[] = [...models];\n while (inlineQueue.length > 0) {\n const model = inlineQueue.pop()!;\n for (const field of model.fields) {\n collectNestedInlineModels(field.type, field.name, model.name, schemas ?? {}, models, modelNames, inlineQueue);\n }\n }\n\n // Collect inline enums from model fields\n for (const model of models) {\n collectInlineEnums(model.fields, enums);\n }\n\n // NOTE: activeSchemaNameTransform is intentionally NOT cleared here.\n // extractOperations() calls schemaToTypeRef() for $ref resolution and\n // needs the same transform active. parseSpec() calls clearSchemaNameTransform()\n // after all extraction is complete.\n return { models, enums };\n}\n\n/** Clear the module-level schemaNameTransform. Called by parseSpec() after all extraction phases. */\nexport function clearSchemaNameTransform(): void {\n activeSchemaNameTransform = null;\n activeEnumSchemaNames = new Set();\n}\n\n/**\n * Walk a single TypeRef and extract inline enum refs as top-level enum definitions.\n * Shared by both schemas.ts (field-level) and parse.ts (model-level) collection passes.\n */\nexport function collectInlineEnumFromRef(ref: TypeRef, enums: Enum[], seen: Set<string>): void {\n walkTypeRef(ref, {\n enum: (r) => {\n if (r.values && !seen.has(r.name)) {\n seen.add(r.name);\n enums.push({\n name: r.name,\n values: r.values.map((v) => ({\n name: toUpperSnakeCase(String(v)),\n value: v,\n description: undefined,\n })),\n });\n }\n },\n });\n}\n\n/**\n * Walk model fields and extract inline enum refs as top-level enum definitions.\n * This ensures type alias files are generated for inline enums.\n */\nfunction collectInlineEnums(fields: Field[], enums: Enum[]): void {\n const seen = new Set(enums.map((e) => e.name));\n for (const field of fields) {\n collectInlineEnumFromRef(field.type, enums, seen);\n }\n}\n\n/**\n * Walk a TypeRef tree and extract inline models for any model refs that point\n * to schemas with inline object properties (not in components/schemas).\n * This handles nested objects like `totp: { oneOf: [{ type: object, properties: {...} }] }`\n * that schemaToTypeRef turns into model refs but aren't extracted from components.\n */\nfunction collectNestedInlineModels(\n ref: TypeRef,\n fieldName: string,\n parentModelName: string,\n schemas: Record<string, SchemaObject>,\n models: Model[],\n modelNames: Set<string>,\n queue: Model[],\n): void {\n walkTypeRef(ref, {\n model: (modelRef) => {\n if (modelNames.has(modelRef.name)) return; // already extracted\n // Check if this model name corresponds to a component schema\n // by checking all possible original names that would map to this PascalCase name\n const isComponent = Object.keys(schemas).some((k) => resolveSchemaName(k) === modelRef.name);\n if (isComponent) return; // will be extracted from components\n\n // This is a reference to a nested inline model that wasn't extracted.\n // Look up the field schema in the parent model's component schema to extract it.\n const parentSchema = findSchemaByName(parentModelName, schemas);\n if (!parentSchema) return;\n\n const fieldSchema = findNestedFieldSchema(fieldName, parentSchema, schemas);\n if (!fieldSchema) return;\n\n // Extract inline models from the field schema\n const extracted = extractNestedSchema(modelRef.name, fieldSchema);\n for (const m of extracted) {\n if (!modelNames.has(m.name)) {\n models.push(m);\n modelNames.add(m.name);\n queue.push(m); // re-scan for deeper nesting\n }\n }\n },\n });\n}\n\n/** Find a component schema by PascalCase name. */\nfunction findSchemaByName(pascalName: string, schemas: Record<string, SchemaObject>): SchemaObject | null {\n for (const [k, v] of Object.entries(schemas)) {\n if (resolveSchemaName(k) === pascalName) return v;\n }\n return null;\n}\n\n/** Walk into a schema to find a field's sub-schema, resolving allOf and oneOf/anyOf. */\nfunction findNestedFieldSchema(\n fieldName: string,\n parentSchema: SchemaObject,\n schemas: Record<string, SchemaObject>,\n): SchemaObject | null {\n if (parentSchema.properties?.[fieldName]) {\n return parentSchema.properties[fieldName]!;\n }\n if (parentSchema.allOf) {\n for (const sub of parentSchema.allOf) {\n let resolved = sub;\n if (sub.$ref) {\n const segments = sub.$ref.split('/');\n const refName = segments[segments.length - 1];\n if (refName && schemas[refName]) resolved = schemas[refName];\n }\n if (resolved.properties?.[fieldName]) {\n return resolved.properties[fieldName]!;\n }\n }\n }\n // Also check inside oneOf/anyOf variants (pure oneOf schemas flatten variant\n // properties into the model, so the field may live inside a variant).\n for (const variant of [...(parentSchema.oneOf ?? []), ...(parentSchema.anyOf ?? [])]) {\n let resolved = variant;\n if (variant.$ref) {\n const segments = variant.$ref.split('/');\n const refName = segments[segments.length - 1];\n if (refName && schemas[refName]) resolved = schemas[refName];\n }\n if (resolved.properties?.[fieldName]) {\n return resolved.properties[fieldName]!;\n }\n }\n return null;\n}\n\n/** Extract a model (and nested models) from an inline field schema. */\nfunction extractNestedSchema(name: string, schema: SchemaObject): Model[] {\n // Handle oneOf: extract each object variant as its own model\n if (schema.oneOf) {\n const models: Model[] = [];\n\n // Collect the inline object variants up front. When every variant pins\n // the same property to a const value, we can derive meaningful names\n // from the const (e.g. `UserApiKeyOwner` instead of `ApiKeyOwner2`)\n // — much friendlier for SDK consumers than numeric suffixes.\n const inlineObjectVariants: SchemaObject[] = schema.oneOf.filter(\n (v) => !v.$ref && v.properties && (v.type === 'object' || !v.type),\n );\n const constNamingDiscriminator = deriveConstNamingDiscriminator(inlineObjectVariants);\n\n for (const variant of schema.oneOf) {\n if (variant.$ref) continue;\n if (variant.properties && (variant.type === 'object' || !variant.type)) {\n const requiredSet = new Set(variant.required ?? []);\n const fields: Field[] = [];\n for (const [fn, fs] of Object.entries(variant.properties)) {\n if (!fs) continue;\n fields.push(buildFieldFromSchema(fn, fs, name, requiredSet));\n }\n const variantName = nameVariantModel(variant, name, models, constNamingDiscriminator);\n models.push({ name: variantName, description: variant.description, fields });\n }\n }\n return models;\n }\n\n // Handle direct object\n if (schema.properties && (schema.type === 'object' || !schema.type)) {\n const requiredSet = new Set(schema.required ?? []);\n const fields: Field[] = [];\n for (const [fn, fs] of Object.entries(schema.properties)) {\n if (!fs) continue;\n fields.push(buildFieldFromSchema(fn, fs, name, requiredSet));\n }\n return [{ name, description: schema.description, fields }];\n }\n\n // Handle array with inline items\n if (schema.type === 'array' && schema.items?.properties) {\n const requiredSet = new Set(schema.items.required ?? []);\n const fields: Field[] = [];\n for (const [fn, fs] of Object.entries(schema.items.properties)) {\n if (!fs) continue;\n fields.push(buildFieldFromSchema(fn, fs, name, requiredSet));\n }\n return [{ name, description: schema.items.description, fields }];\n }\n\n return [];\n}\n\n/**\n * Derive a meaningful name for a oneOf object variant past the first,\n * falling back to the numeric-suffix scheme (`Foo2`, `Foo3`) when no\n * better signal is available. The \"better signal\" is a const-valued\n * discriminator property that distinguishes one variant from the others.\n *\n * For a schema like `ApiKey.owner` whose oneOf has two variants — one\n * with `type: { const: \"organization\" }` and one with `type: { const:\n * \"user\" }` — this returns `ApiKeyOwner` for the first variant (the\n * baseline name that the union TypeRef will reference, so consumer-\n * visible typed fields stay backward-compatible) and `UserApiKeyOwner`\n * for the second instead of `ApiKeyOwner2`. SDK consumers reading the\n * generated types can tell the variants apart at a glance.\n *\n * The first variant always keeps the bare parent name because\n * `schemaToTypeRef` builds union variants whose model refs collapse to\n * `qualifyInlineModelName(field, parent)` — so the first model name\n * must match for the union's degenerate-collapse to land on a valid\n * type. Renaming variant 0 would orphan it.\n *\n * Falls back to numeric suffix when:\n * - The variant has no discriminator property (no shared const\n * property across all object variants), OR\n * - The const value PascalCases to an empty/whitespace name, OR\n * - The derived name collides with the parent name or an already-\n * emitted variant name (numeric keeps uniqueness).\n */\nfunction nameVariantModel(\n variant: SchemaObject,\n parentName: string,\n alreadyEmitted: Model[],\n discriminator: { property: string } | null,\n): string {\n // Variant 0 keeps the bare parent name so the union TypeRef's degenerate\n // collapse target exists in the model registry.\n if (alreadyEmitted.length === 0) return parentName;\n\n if (discriminator) {\n const constValue = getConstPropertyValue(variant, discriminator.property);\n if (constValue) {\n const prefix = toPascalCase(constValue);\n if (prefix) {\n const candidate = parentName.startsWith(prefix) ? parentName : `${prefix}${parentName}`;\n const collision = candidate === parentName || alreadyEmitted.some((m) => m.name === candidate);\n if (!collision) return candidate;\n }\n }\n }\n return `${parentName}${alreadyEmitted.length + 1}`;\n}\n\n/**\n * Returns a discriminator descriptor when every inline object variant in a\n * oneOf has a string-const value on the same property — the signature of a\n * discriminated union without an explicit `discriminator:` keyword. Used by\n * `nameVariantModel` to derive variant names from the const values.\n *\n * Distinct from `detectConstPropertyDiscriminator` (which requires every\n * variant to carry a `$ref` or `title` so a name mapping can be built):\n * this pass operates on inline anonymous variants, where naming is exactly\n * what we're trying to derive.\n */\nfunction deriveConstNamingDiscriminator(variants: SchemaObject[]): { property: string } | null {\n if (variants.length < 2) return null;\n const candidates = Object.keys(variants[0]?.properties ?? {});\n for (const propName of candidates) {\n const values = variants.map((v) => getConstPropertyValue(v, propName));\n if (values.some((v) => v === null)) continue;\n if (new Set(values).size !== values.length) continue; // collisions = no signal\n return { property: propName };\n }\n return null;\n}\n\n/** Build a single Field from a schema property entry. Shared across all extraction sites. */\nexport function buildFieldFromSchema(\n fieldName: string,\n fieldSchema: SchemaObject,\n contextName: string,\n requiredSet: Set<string>,\n): Field {\n return {\n name: fieldName,\n type: schemaToTypeRef(fieldSchema, fieldName, contextName),\n required: requiredSet.has(fieldName),\n description: fieldSchema.description,\n readOnly: fieldSchema.readOnly || undefined,\n writeOnly: fieldSchema.writeOnly || undefined,\n deprecated: fieldSchema.deprecated || undefined,\n default: fieldSchema.default,\n example: fieldSchema.example,\n };\n}\n\n/**\n * If every non-null oneOf/anyOf variant is a string-valued const, return the\n * list of those const values so the union can collapse into a single enum.\n * Returns null when any variant isn't a pure string-const (model ref,\n * number const, nullable, etc.).\n */\nfunction collectLiteralStringConsts(variants: SchemaObject[]): string[] | null {\n if (variants.length === 0) return null;\n const values: string[] = [];\n for (const v of variants) {\n // A single-element enum is semantically identical to const.\n if (typeof v.const === 'string') {\n values.push(v.const);\n continue;\n }\n if (Array.isArray(v.enum) && v.enum.length === 1 && typeof v.enum[0] === 'string') {\n values.push(v.enum[0]);\n continue;\n }\n return null;\n }\n return values;\n}\n\n/** Build an EnumRef the same way the regular enum path does for naming. */\nfunction buildSyntheticEnumRef(\n values: string[],\n contextName: string | undefined,\n parentModelName: string | undefined,\n): TypeRef {\n const baseName = toPascalCase(contextName ?? 'UnknownEnum');\n const cleanParent = parentModelName ? stripListItemMarkers(parentModelName) : undefined;\n const qualifiedName = cleanParent && !baseName.startsWith(cleanParent) ? `${cleanParent}${baseName}` : baseName;\n // Run the same `schemaNameTransform` we apply to component-schema names so\n // a project-level rename map (e.g. `RadarAction` → `RadarListAction` in\n // `oagen.config.ts`) catches inline parameter enums too.\n const finalName = activeSchemaNameTransform ? activeSchemaNameTransform(qualifiedName) : qualifiedName;\n return { kind: 'enum', name: finalName, values };\n}\n\n/**\n * Detect an implicit discriminator on an oneOf where every variant is an\n * object schema that pins the same property to a const value. Returns\n * { property, mapping } so the IR can represent the union as discriminated\n * without needing an explicit `discriminator:` key in the spec.\n *\n * Both shapes are supported:\n * { properties: { event: { const: \"x\" } }, required: [\"event\"] }\n * { properties: { event: { type: \"string\", enum: [\"x\"] } } }\n *\n * Returns null when any variant doesn't fit the pattern or when variants\n * disagree on which property carries the discriminator.\n */\nfunction detectConstPropertyDiscriminator(\n variants: SchemaObject[],\n): { property: string; mapping: Record<string, string> } | null {\n if (variants.length < 2) return null;\n\n // Find properties whose const value is present on every variant.\n let candidateProperty: string | null = null;\n const candidates = Object.keys(variants[0]?.properties ?? {});\n for (const propName of candidates) {\n if (variants.every((v) => getConstPropertyValue(v, propName) !== null)) {\n candidateProperty = propName;\n break;\n }\n }\n\n if (!candidateProperty) return null;\n\n const mapping: Record<string, string> = {};\n for (const v of variants) {\n const value = getConstPropertyValue(v, candidateProperty);\n if (value === null) return null;\n // Require a $ref or title so we have a concrete model name to map to.\n const variantName = resolveVariantModelName(v);\n if (!variantName) return null;\n mapping[value] = variantName;\n }\n\n return { property: candidateProperty, mapping };\n}\n\nfunction getConstPropertyValue(schema: SchemaObject, property: string): string | null {\n const prop = schema.properties?.[property];\n if (!prop) return null;\n if (typeof prop.const === 'string') return prop.const;\n if (Array.isArray(prop.enum) && prop.enum.length === 1 && typeof prop.enum[0] === 'string') {\n return prop.enum[0];\n }\n return null;\n}\n\nfunction resolveVariantModelName(schema: SchemaObject): string | null {\n if (schema.$ref) {\n return resolveSchemaName(schema.$ref.replace(/^#\\/components\\/schemas\\//, ''));\n }\n const title = typeof schema['title'] === 'string' ? (schema['title'] as string) : null;\n if (title) return resolveSchemaName(title);\n return null;\n}\n\n/** Look up the discriminator's mapped variant name for an inline object\n * variant by reading its const-valued discriminator property. Returns null\n * when the variant doesn't pin the property to a string const, or when\n * the value isn't in the mapping. */\nfunction mapVariantToDiscriminatorEntry(\n variant: SchemaObject,\n discriminator: { property: string; mapping: Record<string, string> },\n): string | null {\n const value = getConstPropertyValue(variant, discriminator.property);\n if (value === null) return null;\n return discriminator.mapping[value] ?? null;\n}\n\n/**\n * Derive a discriminator value → variant model name mapping for an inline-\n * variant `oneOf` whose explicit `discriminator:` has no `mapping:` clause.\n *\n * Each variant model name is reproduced via `nameVariantModel` so it matches\n * what `extractNestedSchema` registered when it walked the same `oneOf` to\n * pull variants out as named models. Variant 0 keeps the bare parent name\n * (e.g. `ApiKeyOwner`); subsequent variants get a const-derived prefix\n * (e.g. `UserApiKeyOwner` for the `type: const: user` variant).\n *\n * The \"parent name\" used here mirrors the one `collectNestedInlineModels`\n * passes to `extractNestedSchema`: it's the qualified inline model name\n * built from `contextName` (the field name) plus `parentModelName` (the\n * containing model). Returns null when any non-object variant is present\n * or when a variant lacks a const value on the discriminator property.\n */\nfunction deriveInlineVariantMapping(\n variants: SchemaObject[],\n discriminatorProperty: string,\n contextName: string | undefined,\n parentModelName: string | undefined,\n): Record<string, string> | null {\n if (variants.length === 0 || !contextName) return null;\n const inlineObjectVariants = variants.filter((v) => !v.$ref && v.properties && (v.type === 'object' || !v.type));\n if (inlineObjectVariants.length !== variants.length) return null;\n\n const baseInlineName = qualifyInlineModelName(toPascalCase(contextName), parentModelName);\n const namingDiscriminator = { property: discriminatorProperty };\n const mapping: Record<string, string> = {};\n const emittedSoFar: Model[] = [];\n for (const variant of inlineObjectVariants) {\n const constValue = getConstPropertyValue(variant, discriminatorProperty);\n if (constValue === null) return null;\n const variantName = nameVariantModel(variant, baseInlineName, emittedSoFar, namingDiscriminator);\n mapping[constValue] = variantName;\n emittedSoFar.push({ name: variantName, fields: [] });\n }\n return mapping;\n}\n\nfunction extractEnum(name: string, schema: SchemaObject): Enum {\n const values: EnumValue[] = (schema.enum ?? []).map((v) => ({\n name: toUpperSnakeCase(String(v)),\n value: typeof v === 'number' ? v : String(v),\n description: undefined,\n }));\n\n const rawDefault = schema.default;\n const def =\n rawDefault !== undefined && values.some((v) => v.value === rawDefault)\n ? (rawDefault as string | number)\n : undefined;\n\n return { name, values, default: def };\n}\nfunction extractModel(name: string, schema: SchemaObject, schemas?: Record<string, SchemaObject>): Model {\n if (schema.allOf) {\n return extractAllOfModel(name, schema, schemas);\n }\n\n const requiredSet = new Set(schema.required ?? []);\n const fields: Field[] = [];\n\n for (const [fieldName, fieldSchema] of Object.entries(schema.properties ?? {})) {\n if (!fieldSchema) continue;\n fields.push(buildFieldFromSchema(fieldName, fieldSchema, name, requiredSet));\n }\n\n // Pure oneOf/anyOf schemas (no allOf, no properties): merge variant fields\n // as optional. This handles schemas like UpdateOrganizationMembership which\n // is a oneOf with mutually exclusive field groups (role_slug vs role_slugs).\n if (fields.length === 0 && (schema.oneOf || schema.anyOf)) {\n const variants = schema.oneOf ?? schema.anyOf ?? [];\n const emptyRequired = new Set<string>();\n const seenFieldNames = new Set<string>();\n for (const variant of variants) {\n if (!variant.properties) continue;\n for (const [fieldName, fieldSchema] of Object.entries(variant.properties)) {\n if (!fieldSchema || seenFieldNames.has(fieldName)) continue;\n seenFieldNames.add(fieldName);\n fields.push(buildFieldFromSchema(fieldName, fieldSchema as SchemaObject, name, emptyRequired));\n }\n }\n }\n\n // When additionalProperties is an object schema alongside properties,\n // surface it as a catch-all map field so emitters can generate Map<string, T>.\n if (schema.additionalProperties && typeof schema.additionalProperties === 'object' && schema.properties) {\n const apKeys = Object.keys(schema.additionalProperties);\n if (apKeys.length > 0) {\n const valueType = schemaToTypeRef(schema.additionalProperties as SchemaObject, 'additionalProperties', name);\n fields.push({\n name: 'additionalProperties',\n type: { kind: 'map', valueType },\n required: false,\n description: 'Additional properties not captured by named fields',\n });\n }\n }\n\n return { name, description: schema.description, fields };\n}\n\nfunction extractAllOfModel(name: string, schema: SchemaObject, schemas?: Record<string, SchemaObject>): Model {\n const fields: Field[] = [];\n const requiredSet = new Set<string>();\n let resultDiscriminator: { property: string; mapping: Record<string, string> } | undefined;\n\n for (const subSchema of schema.allOf ?? []) {\n // Resolve $ref sub-schemas by looking up the referenced component schema\n let resolved = subSchema;\n if (subSchema.$ref && schemas) {\n const segments = subSchema.$ref.split('/');\n const refName = segments[segments.length - 1];\n if (refName && schemas[refName]) {\n resolved = schemas[refName];\n }\n }\n\n // If the resolved schema is itself an allOf, recursively extract its fields\n if (resolved.allOf) {\n const nested = extractAllOfModel(name, resolved, schemas);\n for (const f of nested.fields) {\n fields.push({ ...f, required: false }); // will be re-set below\n if (f.required) requiredSet.add(f.name);\n }\n } else if (resolved.oneOf || resolved.anyOf) {\n const variants = resolved.oneOf ?? resolved.anyOf ?? [];\n // Detect discriminated union: every variant pins the same property to a\n // distinct const value (e.g. EventSchema where each variant has event: const).\n // When detected, store the discriminator instead of flattening variant fields —\n // the base allOf schema already captures the common fields.\n const discriminatorInfo = detectAllOfVariantDiscriminator(variants, name);\n if (discriminatorInfo) {\n resultDiscriminator = discriminatorInfo;\n } else {\n // Flatten oneOf/anyOf variant fields into the parent model as optional\n // fields. This handles the common allOf + oneOf pattern where the spec\n // uses mutually exclusive variant groups (e.g. password vs password_hash).\n const emptyRequired = new Set<string>();\n const seenFieldNames = new Set(fields.map((f) => f.name));\n for (const variant of variants) {\n if (!variant.properties) continue;\n for (const [fieldName, fieldSchema] of Object.entries(variant.properties)) {\n if (!fieldSchema || seenFieldNames.has(fieldName)) continue;\n seenFieldNames.add(fieldName);\n fields.push(buildFieldFromSchema(fieldName, fieldSchema as SchemaObject, name, emptyRequired));\n }\n }\n // Do NOT add variant-level required to the requiredSet — these fields\n // are optional at the parent level because they come from mutually\n // exclusive branches.\n }\n } else {\n if (resolved.required) {\n for (const r of resolved.required) requiredSet.add(r);\n }\n if (resolved.properties) {\n // Use an empty requiredSet — required flags are set in the final pass below\n const emptyRequired = new Set<string>();\n for (const [fieldName, fieldSchema] of Object.entries(resolved.properties)) {\n if (!fieldSchema) continue;\n fields.push(buildFieldFromSchema(fieldName, fieldSchema, name, emptyRequired));\n }\n }\n }\n }\n\n // Also collect required from the outer schema\n if (schema.required) {\n for (const r of schema.required) requiredSet.add(r);\n }\n\n // Set required flags\n for (const f of fields) {\n f.required = requiredSet.has(f.name);\n }\n\n return {\n name,\n description: schema.description,\n fields,\n ...(resultDiscriminator ? { discriminator: resultDiscriminator } : {}),\n };\n}\n\n/**\n * Walk through `allOf` wrappers to collect the effective top-level properties\n * of a schema. Stops at `oneOf` / `anyOf` boundaries — those are different\n * variant axes, not part of the same flat object.\n *\n * Used by `detectAllOfVariantDiscriminator` and `deriveDiscriminatedVariantName`\n * so a oneOf variant of the form `{ allOf: [{ properties: { … } }, { oneOf: […] }] }`\n * still surfaces its top-level `properties` (in particular its discriminator\n * `const`) instead of being treated as having none.\n */\nfunction getEffectiveProperties(schema: SchemaObject): Record<string, SchemaObject> {\n const props: Record<string, SchemaObject> = {};\n const visit = (s: SchemaObject): void => {\n if (s.properties) {\n for (const [k, v] of Object.entries(s.properties)) {\n if (!(k in props) && v) props[k] = v;\n }\n }\n if (s.allOf) {\n for (const sub of s.allOf) visit(sub);\n }\n // Do NOT walk into oneOf / anyOf — those are alternatives, not\n // simultaneously-present properties.\n };\n visit(schema);\n return props;\n}\n\nfunction getEffectiveConstPropertyValue(schema: SchemaObject, property: string): string | null {\n const direct = getConstPropertyValue(schema, property);\n if (direct !== null) return direct;\n const effective = getEffectiveProperties(schema)[property];\n if (!effective) return null;\n if (typeof effective.const === 'string') return effective.const;\n if (Array.isArray(effective.enum) && effective.enum.length === 1 && typeof effective.enum[0] === 'string') {\n return effective.enum[0];\n }\n return null;\n}\n\n/**\n * Detect an implicit discriminator on an allOf+oneOf where every variant is an\n * object that pins the same property to a distinct const value. Unlike\n * detectConstPropertyDiscriminator (which requires $ref or title for variant\n * model names), this version derives model names from the const value itself\n * using deriveDiscriminatedVariantName — matching how extractDiscriminatedAllOfVariantModels\n * names those models.\n *\n * Walks through allOf wrappers on each variant so a oneOf branch like\n * { allOf: [{ properties: { type: { const: 'oauth' } } }, { oneOf: […] }] }\n * still surfaces `type` as a candidate discriminator.\n *\n * Returns null when no discriminator can be reliably detected.\n */\nfunction detectAllOfVariantDiscriminator(\n variants: SchemaObject[],\n fallbackName: string,\n): { property: string; mapping: Record<string, string> } | null {\n if (variants.length < 2) return null;\n\n // Find a property whose const value is present on every variant\n // (looking through allOf wrappers on each variant).\n const firstProps = getEffectiveProperties(variants[0] ?? {});\n let candidateProperty: string | null = null;\n for (const propName of Object.keys(firstProps)) {\n if (variants.every((v) => getEffectiveConstPropertyValue(v, propName) !== null)) {\n candidateProperty = propName;\n break;\n }\n }\n if (!candidateProperty) return null;\n\n const mapping: Record<string, string> = {};\n const seenModelNames = new Set<string>();\n for (const v of variants) {\n const value = getEffectiveConstPropertyValue(v, candidateProperty);\n if (value === null) return null;\n const modelName = deriveDiscriminatedVariantName(v, fallbackName);\n // If two variants map to the same model name, the discriminator is ambiguous\n if (seenModelNames.has(modelName)) return null;\n seenModelNames.add(modelName);\n mapping[value] = modelName;\n }\n\n return { property: candidateProperty, mapping };\n}\n\nfunction extractDiscriminatedAllOfVariantModels(schema: SchemaObject, fallbackName: string): Model[] {\n const models: Model[] = [];\n const seenNames = new Set<string>();\n\n // Collect base-object properties + required from the allOf wrapper so each\n // variant can be emitted as a complete, self-contained type. Schemas like\n // `EventSchema` repeat the base fields inside every variant in the spec\n // (so this merge is a no-op there), but `ConnectApplication`'s OAuth /\n // M2M variants don't — without this, dispatcher consumers would get a\n // variant that's missing the shared `id` / `name` / `object` etc.\n const baseProperties: Record<string, SchemaObject> = {};\n const baseRequired = new Set<string>();\n for (const subSchema of schema.allOf ?? []) {\n if (subSchema.oneOf) continue; // the variant axis, handled below\n const flat = subSchema.allOf ? flattenVariantForExtraction(subSchema) : subSchema;\n if (flat.properties) {\n for (const [k, v] of Object.entries(flat.properties)) {\n if (!(k in baseProperties) && v) baseProperties[k] = v;\n }\n }\n if (flat.required) for (const r of flat.required) baseRequired.add(r);\n }\n\n for (const subSchema of schema.allOf ?? []) {\n for (const variant of subSchema.oneOf ?? []) {\n // Flatten any allOf wrapper on the variant (e.g. `ConnectApplication`'s\n // OAuth branch is `allOf: [{ properties: {…} }, { oneOf: [first-party\n // sub-variants] }]`). The flattened object has merged properties and\n // an inlined sub-variant `oneOf` so `extractInlineModelDeep` can pull\n // out a complete variant model.\n const flat = flattenVariantForExtraction(variant);\n if (!flat.properties || (flat.type !== undefined && flat.type !== 'object')) continue;\n\n // Merge base fields into the variant. Variant-specific properties win\n // on name collisions because the spec may pin a base field to a more\n // specific shape inside a variant.\n const mergedProperties: Record<string, SchemaObject> = { ...baseProperties };\n for (const [k, v] of Object.entries(flat.properties)) {\n if (v) mergedProperties[k] = v;\n }\n const mergedRequired = new Set<string>([...baseRequired, ...(flat.required ?? [])]);\n const merged: SchemaObject = {\n type: 'object',\n properties: mergedProperties,\n required: [...mergedRequired],\n };\n\n const variantName = deriveDiscriminatedVariantName(variant, fallbackName);\n for (const model of extractInlineModelDeep(variantName, merged)) {\n if (seenNames.has(model.name)) continue;\n seenNames.add(model.name);\n models.push(model);\n }\n }\n }\n\n return models;\n}\n\n/**\n * Flatten a oneOf variant schema into a single object-shaped schema for\n * variant-model extraction. Recursively merges `allOf` members and folds\n * any nested `oneOf` into an inline-oneOf field group whose properties are\n * the union across sub-branches (required only when present in every\n * sub-branch). Returns the schema unchanged when no flattening is needed.\n */\nfunction flattenVariantForExtraction(variant: SchemaObject): SchemaObject {\n if (!variant.allOf) return variant;\n\n const mergedProperties: Record<string, SchemaObject> = {};\n const mergedRequired = new Set<string>();\n const nestedOneOfs: SchemaObject[][] = [];\n\n const collect = (s: SchemaObject): void => {\n if (s.properties) {\n for (const [k, v] of Object.entries(s.properties)) {\n if (!(k in mergedProperties) && v) mergedProperties[k] = v;\n }\n }\n if (s.required) {\n for (const r of s.required) mergedRequired.add(r);\n }\n if (s.allOf) {\n for (const sub of s.allOf) collect(sub);\n }\n if (s.oneOf) nestedOneOfs.push(s.oneOf);\n };\n collect(variant);\n\n // Fold each nested oneOf into the merged shape: any field appearing in any\n // sub-branch is included as optional (or required iff present-and-required\n // in every sub-branch). Conflicting literal types widen to their primitive\n // base. This handles the `is_first_party: true | false` widening on the\n // OAuth variant's first-party sub-oneOf.\n for (const branches of nestedOneOfs) {\n const flatBranches = branches.map(flattenVariantForExtraction);\n const branchKeys = new Set<string>();\n for (const b of flatBranches) {\n for (const k of Object.keys(b.properties ?? {})) branchKeys.add(k);\n }\n for (const key of branchKeys) {\n const schemas: SchemaObject[] = [];\n for (const b of flatBranches) {\n const s = b.properties?.[key];\n if (s) schemas.push(s);\n }\n const merged = mergeBranchPropertySchemas(schemas);\n if (!(key in mergedProperties)) mergedProperties[key] = merged;\n const inAllBranches = flatBranches.every((b) => b.properties && key in b.properties);\n const requiredInAll = inAllBranches && flatBranches.every((b) => (b.required ?? []).includes(key));\n if (requiredInAll) mergedRequired.add(key);\n }\n }\n\n return {\n type: 'object',\n properties: mergedProperties,\n required: [...mergedRequired],\n };\n}\n\n/**\n * Merge same-named property schemas from across sub-variants. If every\n * occurrence is a boolean const, widen to plain boolean; if every occurrence\n * is a distinct string const, widen to plain string. Otherwise return the\n * first occurrence — emitters that build their own widened types (e.g. the\n * Node discriminated-models module) re-derive from the raw spec.\n */\nfunction mergeBranchPropertySchemas(schemas: SchemaObject[]): SchemaObject {\n if (schemas.length === 0) return {};\n if (schemas.length === 1) return schemas[0];\n\n const allBoolConst = schemas.every((s) => s.type === 'boolean' && typeof s.const === 'boolean');\n if (allBoolConst) {\n return { type: 'boolean', description: schemas[0].description };\n }\n const allStringConst = schemas.every((s) => s.type === 'string' && typeof s.const === 'string');\n if (allStringConst) {\n const values = schemas.map((s) => s.const as string);\n if (new Set(values).size === 1) return schemas[0];\n return { type: 'string', description: schemas[0].description };\n }\n return schemas[0];\n}\n\nfunction deriveDiscriminatedVariantName(schema: SchemaObject, fallbackName: string): string {\n // Walk through allOf wrappers so a variant of the form\n // `{ allOf: [{ properties: { type: const: 'oauth' } }, { oneOf: […] }] }`\n // still surfaces its discriminator const value for naming.\n const effective = getEffectiveProperties(schema);\n if (Object.keys(effective).length === 0) return fallbackName;\n\n const pickConst = (name: string): string | null => {\n const field = effective[name];\n if (!field) return null;\n if (typeof field.const === 'string') return field.const;\n if (field.enum && field.enum.length === 1 && typeof field.enum[0] === 'string') {\n return field.enum[0];\n }\n return null;\n };\n\n let constValue: string | null = null;\n for (const preferred of ['event', 'type', 'object']) {\n constValue = pickConst(preferred);\n if (constValue) break;\n }\n if (constValue === null) {\n for (const name of Object.keys(effective)) {\n constValue = pickConst(name);\n if (constValue) break;\n }\n }\n if (constValue === null) return fallbackName;\n\n const pascal = toPascalCase(constValue);\n if (!pascal) return fallbackName;\n\n // A single-word const like `oauth` or `m2m` is too generic to stand alone\n // as a top-level model name — it would collide with unrelated schemas. Pair\n // it with the parent name so the variant resolves to e.g. `ConnectApplicationOAuth`\n // / `ConnectApplicationM2M`. Multi-word consts like `action.authentication.denied`\n // are already specific enough on their own, matching the established\n // EventSchema variant naming.\n const wordCount = splitWords(constValue).length;\n if (wordCount >= 2) return pascal;\n if (pascal === fallbackName) return pascal;\n if (fallbackName.startsWith(pascal)) return fallbackName;\n if (pascal.endsWith(fallbackName)) return pascal;\n return `${fallbackName}${pascal}`;\n}\n\nfunction extractInlineModelDeep(name: string, schema: SchemaObject): Model[] {\n const requiredSet = new Set(schema.required ?? []);\n const fields: Field[] = [];\n const properties = schema.properties ?? {};\n const nestedModels: Model[] = [];\n\n for (const [fieldName, fieldSchema] of Object.entries(properties)) {\n if (!fieldSchema) continue;\n fields.push(buildFieldFromSchema(fieldName, fieldSchema, name, requiredSet));\n\n if (fieldSchema.type === 'object' && fieldSchema.properties) {\n nestedModels.push(...extractInlineModelDeep(qualifyNestedInlineName(name, fieldName), fieldSchema));\n }\n\n if (fieldSchema.type === 'array' && fieldSchema.items?.properties) {\n nestedModels.push(...extractInlineModelDeep(qualifyNestedInlineName(name, fieldName), fieldSchema.items));\n }\n\n if (fieldSchema.allOf) {\n const mergedProperties: Record<string, SchemaObject | undefined> = {};\n const mergedRequired: string[] = [];\n for (const sub of fieldSchema.allOf) {\n if (sub.properties) Object.assign(mergedProperties, sub.properties);\n if (sub.required) mergedRequired.push(...sub.required);\n }\n if (Object.keys(mergedProperties).length > 0) {\n nestedModels.push(\n ...extractInlineModelDeep(qualifyNestedInlineName(name, fieldName), {\n type: 'object',\n properties: mergedProperties,\n required: mergedRequired,\n }),\n );\n }\n }\n\n if (fieldSchema.oneOf) {\n const inlineObjectVariants = fieldSchema.oneOf.filter(\n (v) => !v.$ref && v.properties && (v.type === 'object' || !v.type),\n );\n if (inlineObjectVariants.length > 0) {\n const baseQualified = qualifyNestedInlineName(name, fieldName);\n const namingDisc = deriveConstNamingDiscriminator(inlineObjectVariants);\n const emitted: Model[] = [];\n for (const variant of inlineObjectVariants) {\n const variantName = nameVariantModel(variant, baseQualified, emitted, namingDisc);\n emitted.push({ name: variantName, fields: [] });\n nestedModels.push(...extractInlineModelDeep(variantName, variant));\n }\n }\n }\n }\n\n return [{ name, description: schema.description, fields }, ...nestedModels];\n}\n\nfunction qualifyNestedInlineName(parentName: string, fieldName: string): string {\n const pascalField = toPascalCase(fieldName);\n if (pascalField.startsWith(parentName)) return pascalField;\n\n const cleanParent = stripListItemMarkers(parentName);\n const qualified = `${cleanParent}${pascalField}`;\n const match = qualified.match(/^(.+?)([A-Z][a-z]+s?)$/);\n if (match && match[2]) {\n return match[1] + singularize(match[2]);\n }\n return qualified;\n}\n\nexport function schemaToTypeRef(schema: SchemaObject, contextName?: string, parentModelName?: string): TypeRef {\n // Handle $ref → ModelRef or EnumRef.\n // A `$ref` to a top-level component schema needs to preserve whether the\n // target is a model or an enum, because emitters route imports differently\n // for the two kinds (e.g. com.workos.models.X vs com.workos.types.X). The\n // set of enum names is precomputed by extractSchemas() in a first pass so\n // it's available even when called recursively for nested $refs.\n if (schema.$ref) {\n const segments = schema.$ref.split('/');\n const rawName = segments[segments.length - 1];\n const resolved = resolveSchemaName(rawName);\n if (activeEnumSchemaNames.has(resolved)) {\n return { kind: 'enum', name: resolved };\n }\n return { kind: 'model', name: resolved };\n }\n\n // Handle OAS 3.1 nullable type arrays: type: [string, null]\n if (Array.isArray(schema.type)) {\n const nonNullTypes = schema.type.filter((t: string) => t !== 'null');\n // type: ['null'] — only null, no real type\n if (nonNullTypes.length === 0) {\n return { kind: 'nullable', inner: { kind: 'primitive', type: 'unknown' } };\n }\n if (schema.type.includes('null') && nonNullTypes.length === 1) {\n return {\n kind: 'nullable',\n inner: schemaToTypeRef({ ...schema, type: nonNullTypes[0], nullable: false }, contextName),\n };\n }\n // Multiple non-null types → union\n if (nonNullTypes.length > 1) {\n const variants = nonNullTypes.map((t: string) => schemaToTypeRef({ ...schema, type: t }, contextName));\n const ref: TypeRef = { kind: 'union', variants };\n if (schema.type.includes('null')) {\n return { kind: 'nullable', inner: ref };\n }\n return ref;\n }\n }\n\n // Handle OAS 3.0 nullable flag\n if (schema.nullable && schema.type) {\n return {\n kind: 'nullable',\n inner: schemaToTypeRef({ ...schema, nullable: false }, contextName),\n };\n }\n\n // Handle allOf — merge properties from all sub-schemas.\n // This handles patterns like: allOf: [{ type: object, properties: {...} }, { oneOf: [...] }]\n // which are valid OAS 3.1 but weren't handled for field-level schemas.\n if (schema.allOf) {\n // If allOf contains a $ref, prefer the ref (it's a named type)\n const refItem = schema.allOf.find((s: SchemaObject) => s.$ref);\n if (refItem) {\n // If allOf has $ref AND siblings with properties, return a merged model ref\n // to avoid losing the augmentation properties\n const hasAugmentation = schema.allOf.some((s: SchemaObject) => !s.$ref && (s.properties || s.type === 'object'));\n if (hasAugmentation) {\n const baseName = toPascalCase(contextName ?? 'UnknownModel');\n return { kind: 'model', name: qualifyInlineModelName(baseName, parentModelName) };\n }\n return schemaToTypeRef(refItem, contextName, parentModelName);\n }\n // If allOf has a single item, unwrap it\n if (schema.allOf.length === 1) {\n return schemaToTypeRef(schema.allOf[0], contextName, parentModelName);\n }\n // If allOf items all have properties, treat as a merged model\n const hasProperties = schema.allOf.some((s: SchemaObject) => s.properties);\n if (hasProperties) {\n const baseName = toPascalCase(contextName ?? 'UnknownModel');\n return {\n kind: 'model',\n name: qualifyInlineModelName(baseName, parentModelName),\n };\n }\n // Fall through to other checks\n }\n\n // Handle oneOf / anyOf → Union or Nullable\n // Valid OAS 3.1: properties can have { oneOf: [{ type: object }, { type: 'null' }] }\n // without a wrapping `type` field.\n if (schema.oneOf || schema.anyOf) {\n const compositionKind: 'oneOf' | 'anyOf' = schema.oneOf ? 'oneOf' : 'anyOf';\n const rawVariants: SchemaObject[] = schema.oneOf ?? schema.anyOf ?? [];\n\n // Check for nullable pattern: oneOf: [realType, { type: 'null' }]\n const nullVariant = rawVariants.find(\n (v: SchemaObject) => v.type === 'null' || (Array.isArray(v.type) && v.type.length === 1 && v.type[0] === 'null'),\n );\n const nonNullVariants = rawVariants.filter((v) => v !== nullVariant);\n\n if (nullVariant && nonNullVariants.length === 1) {\n // Nullable single type — unwrap as nullable\n return {\n kind: 'nullable',\n inner: schemaToTypeRef(nonNullVariants[0], contextName, parentModelName),\n };\n }\n\n // Collapse an oneOf/anyOf whose non-null variants are all string-const\n // schemas into a single enum. This turns patterns like\n // provider: { oneOf: [{ const: \"AppleOAuth\" }, { const: \"GitHubOAuth\" }, ...] }\n // into a proper enum type with one member per variant instead of a\n // structurally-opaque union of literal refs.\n const literalStrings = collectLiteralStringConsts(nonNullVariants);\n if (literalStrings !== null && literalStrings.length >= 2) {\n const enumRef = buildSyntheticEnumRef(literalStrings, contextName, parentModelName);\n return nullVariant ? { kind: 'nullable', inner: enumRef } : enumRef;\n }\n\n // Resolve the discriminator. Three sources, in order:\n // 1. Explicit `discriminator:` with explicit `mapping:` — trust the spec.\n // 2. Explicit `discriminator:` with no `mapping:` — derive mapping from\n // variants' const values on the discriminator property, pairing each\n // to its inline-extracted variant model name (built the same way\n // `extractNestedSchema` names them via `nameVariantModel`). This\n // covers `ApiKey.owner`-shaped schemas where the spec uses\n // `discriminator: { propertyName: type }` but lists inline anonymous\n // `oneOf` variants instead of `$ref` links.\n // 3. No explicit discriminator but every variant pins the same const-\n // valued property AND the variants are nameable via $ref/title —\n // `detectConstPropertyDiscriminator` covers this.\n // 4. As a last resort, when (3) doesn't apply because variants are\n // inline anonymous objects, derive the same const → variant-model-\n // name mapping using `nameVariantModel`. This covers\n // `ApiKeyCreatedData.owner`-shaped schemas (oneOf with inline\n // const-discriminating variants but no `discriminator:` keyword).\n let resolvedDiscriminator: { property: string; mapping: Record<string, string> } | undefined;\n if (schema.discriminator) {\n const property = schema.discriminator.propertyName;\n const explicitMapping = schema.discriminator.mapping ?? {};\n let mapping: Record<string, string> = Object.fromEntries(\n Object.entries(explicitMapping).map(([k, v]) => [k, v.replace(/^#\\/components\\/schemas\\//, '')]),\n );\n if (Object.keys(mapping).length === 0) {\n const inlineMapping = deriveInlineVariantMapping(nonNullVariants, property, contextName, parentModelName);\n if (inlineMapping) mapping = inlineMapping;\n }\n resolvedDiscriminator = { property, mapping };\n } else if (compositionKind === 'oneOf') {\n const synthetic = detectConstPropertyDiscriminator(nonNullVariants);\n if (synthetic) {\n resolvedDiscriminator = synthetic;\n } else {\n const namingDisc = deriveConstNamingDiscriminator(nonNullVariants);\n if (namingDisc) {\n const inlineMapping = deriveInlineVariantMapping(\n nonNullVariants,\n namingDisc.property,\n contextName,\n parentModelName,\n );\n if (inlineMapping) {\n resolvedDiscriminator = { property: namingDisc.property, mapping: inlineMapping };\n }\n }\n }\n }\n\n // Build variants. When we have a discriminator with a known mapping and\n // every non-null variant is an inline object that pins the discriminator\n // property to a const, route each variant's TypeRef through that mapping.\n // This avoids the degenerate case where `qualifyInlineModelName` would\n // assign the same parent-derived name (e.g. `ApiKeyOwner`) to every\n // inline variant, collapsing the union to a single repeated model ref.\n const variants: TypeRef[] = [];\n for (const v of rawVariants) {\n if (v === nullVariant) continue;\n const inlineMappingName =\n resolvedDiscriminator && !v.$ref && v.properties && (v.type === 'object' || !v.type)\n ? mapVariantToDiscriminatorEntry(v, resolvedDiscriminator)\n : null;\n if (inlineMappingName) {\n variants.push({ kind: 'model', name: inlineMappingName });\n } else {\n variants.push(schemaToTypeRef(v, contextName, parentModelName));\n }\n }\n const hasNull = !!nullVariant;\n\n const union: TypeRef = {\n kind: 'union',\n variants,\n compositionKind,\n ...(resolvedDiscriminator ? { discriminator: resolvedDiscriminator } : {}),\n };\n return hasNull ? { kind: 'nullable', inner: union } : union;\n }\n\n // Handle const → LiteralType (supports string, number, boolean)\n if (schema.const !== undefined) {\n if (typeof schema.const === 'string' || typeof schema.const === 'number' || typeof schema.const === 'boolean') {\n return { kind: 'literal', value: schema.const };\n }\n // null const → nullable unknown\n if (schema.const === null) {\n return { kind: 'nullable', inner: { kind: 'primitive', type: 'unknown' } };\n }\n // const of object/array → map or array with unknown values\n if (typeof schema.const === 'object') {\n if (Array.isArray(schema.const)) {\n return { kind: 'array', items: { kind: 'primitive', type: 'unknown' } };\n }\n return { kind: 'map', valueType: { kind: 'primitive', type: 'unknown' } };\n }\n }\n if (schema.enum && schema.enum.length === 1) {\n const v = schema.enum[0];\n return { kind: 'literal', value: typeof v === 'number' ? v : String(v) };\n }\n\n // Handle enum\n if (schema.enum) {\n const baseName = toPascalCase(contextName ?? 'UnknownEnum');\n // Strip ListItem/ByExternalId markers from parent name so enum names are clean:\n // e.g., DirectoryListItem + State → Directory + State = DirectoryState\n const cleanParent = parentModelName ? stripListItemMarkers(parentModelName) : undefined;\n // Avoid redundant prefix: Connection + ConnectionType → ConnectionType\n const qualifiedName = cleanParent && !baseName.startsWith(cleanParent) ? `${cleanParent}${baseName}` : baseName;\n // Run `schemaNameTransform` so project-level rename maps in\n // `oagen.config.ts` reach inline parameter/field enums too — without\n // this, `RadarAction` (built from path param `action` on the Radar\n // service) couldn't be redirected to `RadarListAction` from config.\n const finalName = activeSchemaNameTransform ? activeSchemaNameTransform(qualifiedName) : qualifiedName;\n return {\n kind: 'enum',\n name: finalName,\n values: schema.enum.map((v) => (typeof v === 'number' ? v : String(v))),\n };\n }\n\n // Handle array — pass parentModelName through to qualify inline items\n if (schema.type === 'array' && schema.items) {\n return {\n kind: 'array',\n items: schemaToTypeRef(schema.items, contextName, parentModelName),\n };\n }\n // Handle array without explicit type but with items (valid OAS 3.1)\n if (!schema.type && schema.items) {\n return {\n kind: 'array',\n items: schemaToTypeRef(schema.items, contextName, parentModelName),\n };\n }\n\n // Handle object → ModelRef (if it has properties, it's a named model reference)\n // When additionalProperties is also present, we still return a ModelRef so the\n // named properties are preserved. The extractModel path will pick up the extra\n // properties as a catch-all map field named `additionalProperties`.\n if (schema.type === 'object' && schema.properties) {\n const baseName = toPascalCase(contextName ?? 'UnknownModel');\n return {\n kind: 'model',\n name: qualifyInlineModelName(baseName, parentModelName),\n };\n }\n\n // Handle freeform object with additionalProperties or patternProperties → Map<string, T>\n if (schema.type === 'object' && !schema.properties) {\n let valueType: TypeRef = { kind: 'primitive', type: 'unknown' };\n if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {\n // Empty additionalProperties ({}) means \"any value\" — keep as unknown\n const apKeys = Object.keys(schema.additionalProperties);\n if (apKeys.length > 0) {\n valueType = schemaToTypeRef(schema.additionalProperties as SchemaObject, contextName);\n }\n } else if (schema.patternProperties) {\n // patternProperties: { \"pattern\": schema } → use the first pattern's schema as value type\n const patterns = Object.values(schema.patternProperties);\n if (patterns.length > 0) {\n valueType = schemaToTypeRef(patterns[0], contextName);\n }\n }\n return {\n kind: 'map',\n valueType,\n };\n }\n\n // Handle primitives\n const primitiveMap: Record<string, 'string' | 'integer' | 'number' | 'boolean'> = {\n string: 'string',\n integer: 'integer',\n number: 'number',\n boolean: 'boolean',\n };\n\n const typeStr = Array.isArray(schema.type) ? schema.type[0] : schema.type;\n if (typeStr && primitiveMap[typeStr]) {\n return {\n kind: 'primitive',\n type: primitiveMap[typeStr],\n ...(schema.format ? { format: schema.format } : {}),\n };\n }\n\n // Handle schemas with no type — if it has properties, treat as model\n if (!schema.type && schema.properties) {\n const baseName = toPascalCase(contextName ?? 'UnknownModel');\n return {\n kind: 'model',\n name: qualifyInlineModelName(baseName, parentModelName),\n };\n }\n\n // Empty schema {} → unknown\n if (\n !schema.type &&\n !schema.$ref &&\n !schema.oneOf &&\n !schema.anyOf &&\n !schema.allOf &&\n !schema.enum &&\n !schema.properties &&\n !schema.items\n ) {\n return { kind: 'primitive', type: 'unknown' };\n }\n\n // Fallback: treat unknown schemas as unknown\n if (contextName) {\n console.warn(`[oagen] Warning: Unknown schema shape treated as unknown (context: ${contextName})`);\n }\n return { kind: 'primitive', type: 'unknown' };\n}\n\nimport { qualifyInlineModelName } from './inline-models.js';\n\nexport { qualifyInlineModelName, extractInlineModelsFromSchemas } from './inline-models.js';\n","import type { TypeRef, Parameter, PaginationMeta } from '../ir/types.js';\n\nconst CURSOR_PARAMS = ['cursor', 'after', 'before', 'starting_after', 'ending_before', 'page_token', 'next_token'];\n\nconst OFFSET_PARAMS = ['offset', 'page', 'page_number', 'skip'];\nconst LIMIT_PARAMS = ['limit', 'page_size', 'per_page', 'size', 'count'];\n\n/**\n * Detect if an operation uses pagination and return structured metadata\n * for auto-paging iterator generation.\n *\n * Supports two strategies:\n * 1. **Cursor-based**: query params include a cursor-like parameter\n * 2. **Offset-based**: query params include both an offset-like and limit-like parameter\n *\n * Returns null if no pagination pattern is detected.\n */\nexport function detectPagination(\n response: TypeRef,\n queryParams: Parameter[],\n dataPath?: string,\n): PaginationMeta | null {\n // Try cursor-based first (preferred). Scan in CURSOR_PARAMS priority order\n // rather than queryParams order so that an endpoint exposing both `before`\n // and `after` reports `after` (forward iteration) — matches the wire\n // convention where `after` advances through pages.\n const cursorParam = CURSOR_PARAMS.map((name) => queryParams.find((p) => p.name === name)).find(\n (p): p is Parameter => p !== undefined,\n );\n\n if (cursorParam) {\n const itemType: TypeRef = response.kind === 'array' ? response.items : response;\n return {\n strategy: 'cursor',\n param: cursorParam.name,\n dataPath: dataPath,\n itemType,\n };\n }\n\n // Try offset-based pagination\n const offsetParam = queryParams.find((p) => OFFSET_PARAMS.includes(p.name));\n const limitParam = queryParams.find((p) => LIMIT_PARAMS.includes(p.name));\n\n if (offsetParam && limitParam) {\n const itemType: TypeRef = response.kind === 'array' ? response.items : response;\n return {\n strategy: 'offset',\n param: offsetParam.name,\n limitParam: limitParam.name,\n dataPath: dataPath,\n itemType,\n };\n }\n\n return null;\n}\n","import type { TypeRef, Model, Field } from '../ir/types.js';\nimport { toPascalCase, singularize, stripListItemMarkers } from '../utils/naming.js';\nimport type { SchemaObject } from './schemas.js';\nimport { schemaToTypeRef, buildFieldFromSchema } from './schemas.js';\n\nexport interface ResponseExtractionResult {\n /** The TypeRef to use as the operation's response type */\n response: TypeRef;\n /** Any inline models discovered during extraction (to merge into ir.models) */\n inlineModels: Model[];\n /** Whether this response indicates a paginated list */\n isPaginated: boolean;\n /** Path to the data array within the response envelope (e.g., 'data') */\n dataPath?: string;\n /** TypeRef of individual items in a paginated list */\n itemType?: TypeRef;\n}\n\nexport function classifyAndExtractResponse(schema: SchemaObject, contextName: string): ResponseExtractionResult {\n // 1. If schema is a $ref, resolve to model name (Phase 1)\n if (schema.$ref) {\n return { response: schemaToTypeRef(schema, contextName), inlineModels: [], isPaginated: false };\n }\n\n // 2. Check for list envelope (structural detection: array prop + non-array companion)\n const envelope = detectListEnvelope(schema);\n if (envelope.isEnvelope) {\n return extractListResponse(schema, contextName, envelope.dataPath!);\n }\n\n // 3. Check for single-resource wrapper ({ resource_name: { object: \"...\", ... } })\n if (isSingleResourceWrapper(schema)) {\n return extractWrappedResource(schema, contextName);\n }\n\n // 4. Direct resource or plain inline object\n return extractDirectResource(schema, contextName);\n}\n\ninterface ListEnvelopeResult {\n isEnvelope: boolean;\n dataPath: string | null;\n}\n\nconst KNOWN_DATA_PATHS = new Set(['data', 'items', 'results', 'records', 'entries', 'values', 'nodes', 'edges']);\n\nconst PAGINATION_METADATA_PATTERNS = [\n 'meta',\n 'metadata',\n 'pagination',\n 'cursor',\n 'has_more',\n 'page_info',\n 'total',\n 'next_page',\n 'previous_page',\n 'offset',\n];\n\nfunction detectListEnvelope(schema: SchemaObject): ListEnvelopeResult {\n // Collect all property sources (allOf sub-schemas or flat schema)\n const propSources: Record<string, SchemaObject | undefined>[] = [];\n if (schema.allOf) {\n for (const sub of schema.allOf) {\n if (sub.properties) propSources.push(sub.properties);\n }\n }\n if (schema.properties) {\n propSources.push(schema.properties);\n }\n\n if (propSources.length === 0) return { isEnvelope: false, dataPath: null };\n\n // Merge all properties into a single view\n const mergedProps: Record<string, SchemaObject | undefined> = {};\n for (const source of propSources) {\n Object.assign(mergedProps, source);\n }\n\n // Find array-typed properties and non-array companion properties\n const arrayProps: string[] = [];\n const nonArrayKeys: string[] = [];\n\n for (const [key, propSchema] of Object.entries(mergedProps)) {\n if (!propSchema) continue;\n if (propSchema.type === 'array') {\n arrayProps.push(key);\n } else {\n nonArrayKeys.push(key);\n }\n }\n\n // List envelope heuristic: exactly one array property + at least one non-array companion\n // that looks like pagination metadata. A `data` array alone (e.g. with only an\n // `object` discriminant companion) is NOT sufficient — the companion must indicate\n // actual pagination (cursor, metadata, total, etc.).\n if (arrayProps.length === 1 && nonArrayKeys.length >= 1) {\n const arrayPropName = arrayProps[0];\n\n const hasPaginationCompanion = nonArrayKeys.some((key) =>\n PAGINATION_METADATA_PATTERNS.some((pattern) => key.toLowerCase().includes(pattern)),\n );\n\n if (KNOWN_DATA_PATHS.has(arrayPropName) && hasPaginationCompanion) {\n return { isEnvelope: true, dataPath: arrayPropName };\n }\n\n // Non-standard array property name — still treat as envelope if pagination companion exists\n if (hasPaginationCompanion) {\n return { isEnvelope: true, dataPath: arrayPropName };\n }\n }\n\n return { isEnvelope: false, dataPath: null };\n}\n\nfunction extractListResponse(schema: SchemaObject, contextName: string, dataPath: string): ResponseExtractionResult {\n let itemTypeRef: TypeRef = { kind: 'primitive', type: 'string' };\n const inlineModels: Model[] = [];\n\n // Collect all property sources (allOf sub-schemas or flat schema)\n const propSources: Record<string, SchemaObject | undefined>[] = [];\n if (schema.allOf) {\n for (const sub of schema.allOf) {\n if (sub.properties) propSources.push(sub.properties);\n }\n }\n if (schema.properties) {\n propSources.push(schema.properties);\n }\n\n for (const props of propSources) {\n const dataProp = props[dataPath];\n if (!dataProp) continue;\n\n if (dataProp.type === 'array' && dataProp.items) {\n const items = dataProp.items;\n if (items.$ref) {\n itemTypeRef = schemaToTypeRef(items, contextName);\n } else if (items.type === 'object' && items.properties) {\n const itemName = contextName.replace(/Response$/, '') + 'Item';\n itemTypeRef = { kind: 'model', name: itemName };\n inlineModels.push(...extractInlineModel(itemName, items));\n }\n }\n }\n\n return {\n response: { kind: 'array', items: itemTypeRef },\n inlineModels,\n isPaginated: true,\n dataPath,\n itemType: itemTypeRef,\n };\n}\n\nfunction hasDiscriminantConstField(schema: SchemaObject): { property: string; value: string } | null {\n if (!schema.properties) return null;\n\n // Prefer well-known discriminant properties for backward compatibility\n const preferred = ['object', 'type'];\n for (const name of preferred) {\n const field = schema.properties[name];\n if (!field) continue;\n if (field.const !== undefined && typeof field.const === 'string') {\n return { property: name, value: field.const };\n }\n if (field.enum && field.enum.length === 1 && typeof field.enum[0] === 'string') {\n return { property: name, value: field.enum[0] };\n }\n }\n\n // Fall back to any property with a const or single-value enum\n for (const [name, field] of Object.entries(schema.properties)) {\n if (!field) continue;\n if (field.const !== undefined && typeof field.const === 'string') {\n return { property: name, value: field.const };\n }\n if (field.enum && field.enum.length === 1 && typeof field.enum[0] === 'string') {\n return { property: name, value: field.enum[0] };\n }\n }\n\n return null;\n}\n\nfunction isSingleResourceWrapper(schema: SchemaObject): boolean {\n if (schema.type !== 'object') return false;\n if (!schema.properties) return false;\n\n // Find the wrapper property: use required[0] if available, or the single property key\n let wrapperKey: string | undefined;\n if (schema.required && schema.required.length === 1) {\n wrapperKey = schema.required[0];\n } else {\n const propKeys = Object.keys(schema.properties);\n if (propKeys.length === 1) {\n wrapperKey = propKeys[0];\n }\n }\n if (!wrapperKey) return false;\n\n const propSchema = schema.properties[wrapperKey];\n if (!propSchema) return false;\n\n // Direct object with a discriminant const field\n if (propSchema.type === 'object' && hasDiscriminantConstField(propSchema) !== null) return true;\n\n // oneOf with object + null (nullable resource)\n if (propSchema.oneOf) {\n return propSchema.oneOf.some((v) => v.type === 'object' && hasDiscriminantConstField(v) !== null);\n }\n\n return false;\n}\n\nfunction extractWrappedResource(schema: SchemaObject, contextName: string): ResponseExtractionResult {\n const props = schema.properties!;\n const wrapperKey = schema.required && schema.required.length === 1 ? schema.required[0] : Object.keys(props)[0];\n const propSchema = props[wrapperKey]!;\n const inlineModels: Model[] = [];\n\n // Derive model name from the object const value or wrapper property name\n const resourceName = contextName.replace(/Response$/, '');\n\n if (propSchema.oneOf) {\n const objectVariant = propSchema.oneOf.find((v) => v.type === 'object' && hasDiscriminantConstField(v) !== null);\n\n if (objectVariant) {\n const modelName = deriveModelName(objectVariant, resourceName);\n inlineModels.push(...extractInlineModel(modelName, objectVariant));\n\n const hasNullVariant = propSchema.oneOf.some(\n (v) => v.type === 'null' || (Array.isArray(v.type) && v.type.includes('null')),\n );\n\n const modelRef: TypeRef = { kind: 'model', name: modelName };\n return {\n response: hasNullVariant ? { kind: 'nullable', inner: modelRef } : modelRef,\n inlineModels,\n isPaginated: false,\n };\n }\n }\n\n // Direct object\n const modelName = deriveModelName(propSchema, resourceName);\n inlineModels.push(...extractInlineModel(modelName, propSchema));\n\n return {\n response: { kind: 'model', name: modelName },\n inlineModels,\n isPaginated: false,\n };\n}\n\nfunction extractDirectResource(schema: SchemaObject, contextName: string): ResponseExtractionResult {\n const inlineModels: Model[] = [];\n\n // Direct object with properties (with or without explicit type: 'object')\n if (schema.properties && (schema.type === 'object' || !schema.type)) {\n const modelName = deriveModelName(schema, contextName);\n inlineModels.push(...extractInlineModel(modelName, schema));\n return {\n response: { kind: 'model', name: modelName },\n inlineModels,\n isPaginated: false,\n };\n }\n\n // allOf with properties — merge into a single model\n if (schema.allOf) {\n const mergedProperties: Record<string, SchemaObject | undefined> = {};\n const mergedRequired: string[] = [];\n for (const sub of schema.allOf) {\n if (sub.properties) {\n Object.assign(mergedProperties, sub.properties);\n }\n if (sub.required) {\n mergedRequired.push(...sub.required);\n }\n }\n if (Object.keys(mergedProperties).length > 0) {\n const merged: SchemaObject = { type: 'object', properties: mergedProperties, required: mergedRequired };\n const modelName = deriveModelName(merged, contextName);\n inlineModels.push(...extractInlineModel(modelName, merged));\n return {\n response: { kind: 'model', name: modelName },\n inlineModels,\n isPaginated: false,\n };\n }\n }\n\n // oneOf — delegate to schemaToTypeRef (returns union) but also extract inline models\n // from object variants so the model refs resolve\n if (schema.oneOf) {\n for (const variant of schema.oneOf) {\n if (variant.properties && (variant.type === 'object' || !variant.type)) {\n const modelName = deriveModelName(variant, contextName);\n const existingNames = new Set(inlineModels.map((m) => m.name));\n if (!existingNames.has(modelName)) {\n inlineModels.push(...extractInlineModel(modelName, variant));\n }\n }\n }\n }\n\n // Array with inline object items — extract the item model\n if (schema.type === 'array' && schema.items) {\n const items = schema.items;\n if (items.$ref) {\n return {\n response: { kind: 'array', items: schemaToTypeRef(items, contextName) },\n inlineModels,\n isPaginated: false,\n };\n }\n if (items.properties && (items.type === 'object' || !items.type)) {\n const itemName = contextName.replace(/Response$/, '') + 'Item';\n inlineModels.push(...extractInlineModel(itemName, items));\n return {\n response: { kind: 'array', items: { kind: 'model', name: itemName } },\n inlineModels,\n isPaginated: false,\n };\n }\n }\n\n // Non-object schema (primitive, union, etc.) — delegate to schemaToTypeRef\n return {\n response: schemaToTypeRef(schema, contextName),\n inlineModels,\n isPaginated: false,\n };\n}\n\nfunction deriveModelName(schema: SchemaObject, fallback: string): string {\n if (!schema.properties) return toPascalCase(fallback);\n\n // Prefer well-known discriminant properties for backward compatibility\n const preferred = ['object', 'type'];\n for (const name of preferred) {\n const field = schema.properties[name];\n if (field && field.const && typeof field.const === 'string') {\n return toPascalCase(field.const);\n }\n }\n\n // Fall back to any property with a const string value\n for (const [, field] of Object.entries(schema.properties)) {\n if (field && field.const && typeof field.const === 'string') {\n return toPascalCase(field.const);\n }\n }\n\n return toPascalCase(fallback);\n}\n\n/**\n * Qualify a nested inline model name with its parent to avoid generic names.\n * e.g., parent=\"Connection\" + field=\"domains\" → \"ConnectionDomain\" (singularized)\n * Only qualifies when the field name alone would be too generic.\n */\nfunction qualifyNestedName(parentName: string, fieldName: string): string {\n const pascalField = toPascalCase(fieldName);\n // If the field name already starts with the parent name, don't double-prefix\n if (pascalField.startsWith(parentName)) return pascalField;\n // Qualify with parent and singularize:\n // Connection + Domains → ConnectionDomains → singularize lead word → ConnectionDomain\n const cleanParent = stripListItemMarkers(parentName);\n const qualified = `${cleanParent}${pascalField}`;\n // Singularize the trailing word: ConnectionDomains → ConnectionDomain\n const match = qualified.match(/^(.+?)([A-Z][a-z]+s?)$/);\n if (match && match[2]) {\n const trailing = singularize(match[2]);\n return match[1] + trailing;\n }\n return qualified;\n}\n\nfunction extractInlineModel(name: string, schema: SchemaObject): Model[] {\n const requiredSet = new Set(schema.required ?? []);\n const fields: Field[] = [];\n const properties = schema.properties ?? {};\n const nestedModels: Model[] = [];\n\n for (const [fieldName, fieldSchema] of Object.entries(properties)) {\n if (!fieldSchema) continue;\n fields.push(buildFieldFromSchema(fieldName, fieldSchema, name, requiredSet));\n\n // Recursively extract nested inline objects — qualify with parent name\n // to avoid generic names like \"Domains\" when multiple parents have a \"domains\" field\n if (fieldSchema.type === 'object' && fieldSchema.properties) {\n const nestedName = qualifyNestedName(name, fieldName);\n nestedModels.push(...extractInlineModel(nestedName, fieldSchema));\n }\n if (fieldSchema.type === 'array' && fieldSchema.items) {\n const items = fieldSchema.items;\n if (items.type === 'object' && items.properties) {\n const nestedName = qualifyNestedName(name, fieldName);\n nestedModels.push(...extractInlineModel(nestedName, items));\n }\n }\n // Handle allOf with inline object properties — merge into a single nested model\n if (fieldSchema.allOf) {\n const mergedProperties: Record<string, SchemaObject | undefined> = {};\n const mergedRequired: string[] = [];\n for (const sub of fieldSchema.allOf) {\n if (sub.properties) Object.assign(mergedProperties, sub.properties);\n if (sub.required) mergedRequired.push(...sub.required);\n }\n if (Object.keys(mergedProperties).length > 0) {\n const nestedName = qualifyNestedName(name, fieldName);\n const merged: SchemaObject = { type: 'object', properties: mergedProperties, required: mergedRequired };\n const existingNames = new Set(nestedModels.map((m) => m.name));\n if (!existingNames.has(nestedName)) {\n nestedModels.push(...extractInlineModel(nestedName, merged));\n }\n }\n }\n // Handle oneOf containing inline objects — extract the first non-null object variant\n if (fieldSchema.oneOf) {\n const objectVariant = fieldSchema.oneOf.find((v) => v.properties && (v.type === 'object' || !v.type));\n if (objectVariant) {\n const nestedName = qualifyNestedName(name, fieldName);\n const existingNames = new Set(nestedModels.map((m) => m.name));\n if (!existingNames.has(nestedName)) {\n nestedModels.push(...extractInlineModel(nestedName, objectVariant));\n }\n }\n }\n }\n\n return [{ name, description: schema.description, fields }, ...nestedModels];\n}\n","import type {\n Service,\n Operation,\n HttpMethod,\n Parameter,\n ParameterGroup,\n TypeRef,\n ErrorResponse,\n SuccessResponse,\n SecurityRequirement,\n Model,\n Field,\n PaginationMeta,\n} from '../ir/types.js';\nimport { toPascalCase, toCamelCase, cleanSchemaName } from '../utils/naming.js';\nimport type { SchemaObject } from './schemas.js';\nimport { schemaToTypeRef, buildFieldFromSchema } from './schemas.js';\nimport { detectPagination } from './pagination.js';\nimport { classifyAndExtractResponse } from './responses.js';\n\ninterface PathItem {\n get?: OperationObject;\n post?: OperationObject;\n put?: OperationObject;\n patch?: OperationObject;\n delete?: OperationObject;\n head?: OperationObject;\n options?: OperationObject;\n trace?: OperationObject;\n parameters?: ParameterObject[];\n}\n\ninterface ParameterGroupExtension {\n optional: boolean;\n variants: Record<string, string[]>;\n}\n\ninterface OperationObject {\n operationId?: string;\n summary?: string;\n description?: string;\n tags?: string[];\n parameters?: ParameterObject[];\n requestBody?: RequestBodyObject;\n responses?: Record<string, ResponseObject>;\n deprecated?: boolean;\n 'x-oagen-async'?: boolean;\n security?: Array<Record<string, string[]>>;\n 'x-mutually-exclusive-parameter-groups'?: Record<string, ParameterGroupExtension>;\n 'x-mutually-exclusive-body-groups'?: Record<string, ParameterGroupExtension>;\n}\n\ninterface ParameterObject {\n name: string;\n in: 'path' | 'query' | 'header' | 'cookie';\n required?: boolean;\n description?: string;\n schema?: SchemaObject;\n deprecated?: boolean;\n example?: unknown;\n style?: string;\n explode?: boolean;\n}\n\ninterface RequestBodyObject {\n required?: boolean;\n content?: Record<string, { schema?: SchemaObject }>;\n}\n\ninterface ResponseObject {\n description?: string;\n content?: Record<string, { schema?: SchemaObject }>;\n}\n\nconst HTTP_METHODS: HttpMethod[] = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'];\n\nexport interface OperationExtractionResult {\n services: Service[];\n inlineModels: Model[];\n}\n\nexport function extractOperations(\n paths: Record<string, PathItem> | undefined,\n operationIdTransform?: (id: string) => string,\n componentSchemas?: Record<string, SchemaObject>,\n): OperationExtractionResult {\n if (!paths) return { services: [], inlineModels: [] };\n\n const serviceMap = new Map<string, Operation[]>();\n const inlineModels: Model[] = [];\n\n for (const [path, pathItem] of Object.entries(paths)) {\n const pathLevelParams = pathItem.parameters ?? [];\n\n for (const method of HTTP_METHODS) {\n const op = pathItem[method];\n if (!op) continue;\n\n const serviceName = inferServiceName(path, op.tags?.[0]);\n\n const { operation, inlineModels: opModels } = buildOperation(\n method,\n path,\n op,\n pathLevelParams,\n operationIdTransform,\n serviceName,\n componentSchemas,\n );\n inlineModels.push(...opModels);\n const ops = serviceMap.get(serviceName) ?? [];\n ops.push(operation);\n serviceMap.set(serviceName, ops);\n }\n }\n\n // Split services when a single tag groups operations from multiple path prefixes.\n // Example: /organizations and /organization_domains both tagged \"organizations\"\n // should become separate services based on their first path segment.\n for (const [serviceName, operations] of serviceMap) {\n const pathGroups = new Map<string, Operation[]>();\n for (const op of operations) {\n const firstSeg = op.path.split('/').filter(Boolean)[0] ?? '';\n const groupKey = firstSeg.startsWith('{') ? serviceName : toPascalCase(firstSeg);\n const group = pathGroups.get(groupKey) ?? [];\n group.push(op);\n pathGroups.set(groupKey, group);\n }\n // Only split if there are multiple distinct path-prefix groups AND\n // at least one group name differs from the current service name\n if (pathGroups.size > 1) {\n const needsSplit = [...pathGroups.keys()].some((k) => k !== serviceName);\n if (needsSplit) {\n serviceMap.delete(serviceName);\n for (const [groupName, groupOps] of pathGroups) {\n const existing = serviceMap.get(groupName) ?? [];\n existing.push(...groupOps);\n serviceMap.set(groupName, existing);\n }\n }\n }\n }\n\n // Disambiguate operation names within each service.\n // Multiple operations can get the same name (e.g., several \"list\" endpoints\n // in UserManagement for users, invitations, auth factors, etc.).\n for (const [, operations] of serviceMap) {\n disambiguateOperationNames(operations);\n }\n\n const services = Array.from(serviceMap.entries()).map(([name, operations]) => ({\n name,\n operations,\n }));\n\n return { services, inlineModels };\n}\n\nfunction inferServiceName(path: string, tag?: string): string {\n // Prefer OpenAPI tag when available — tags represent the logical grouping\n // (e.g., \"multi-factor-auth\" for /auth/factors/* endpoints).\n if (tag) {\n return toPascalCase(tag);\n }\n // Fallback: extract first meaningful path segment: /widgets/{id}/sub → \"Widgets\"\n const segments = path.split('/').filter(Boolean);\n const first = segments[0] ?? 'Default';\n // Skip path params\n if (first.startsWith('{')) return 'Default';\n return toPascalCase(first);\n}\n\n/**\n * Strip overload indices (e.g. NestJS emits `Foo_bar[0]` when a controller\n * method handles multiple routes) from an operationId so derived names never\n * leak the bracketed digit. Without this, `authenticate[0]` would surface as\n * `authenticate0` in method names and `Authenticate0Request` in body model\n * names. Brackets at the end (or with trailing whitespace) are common in\n * NestJS-style backends; this regex is intentionally narrow to avoid eating\n * legitimate digits like `oauth2`.\n */\nfunction normalizeOperationIdForNaming(operationId: string): string {\n return operationId.replace(/\\[\\d+\\]\\s*$/, '');\n}\n\nfunction inferOperationName(\n method: HttpMethod,\n path: string,\n operationId?: string,\n operationIdTransform?: (id: string) => string,\n): string {\n if (operationId) {\n const normalized = normalizeOperationIdForNaming(operationId);\n if (operationIdTransform) {\n return operationIdTransform(normalized);\n }\n return toCamelCase(normalized);\n }\n\n // Fallback when no operationId is available — use method + path to build\n // a descriptive name like \"listUsers\", \"getOrganization\", \"deleteAuthFactor\"\n const verb = inferVerb(method, path);\n const resource = inferResourceFromPath(path);\n return resource ? toCamelCase(`${verb}_${resource}`) : verb;\n}\n\n/**\n * Infer the CRUD verb from HTTP method and path shape.\n */\nfunction inferVerb(method: HttpMethod, path: string): string {\n const segments = path.split('/').filter(Boolean);\n const hasTrailingParam = segments.length > 0 && segments[segments.length - 1].startsWith('{');\n\n switch (method) {\n case 'get':\n return hasTrailingParam ? 'get' : 'list';\n case 'post':\n return 'create';\n case 'put':\n case 'patch':\n return 'update';\n case 'delete':\n return 'delete';\n case 'head':\n return 'check';\n case 'options':\n return 'options';\n case 'trace':\n return 'trace';\n default:\n return method;\n }\n}\n\n/**\n * Extract a resource noun from the path for operation naming.\n * Uses the last non-param segment (the resource being operated on).\n *\n * Examples:\n * /user_management/users → \"Users\"\n * /user_management/users/{id} → \"User\" (singular for item operations)\n * /user_management/users/{id}/auth_factors → \"AuthFactors\"\n * /organizations/{id}/api_keys → \"ApiKeys\"\n * /sso/authorize → \"Authorize\" (action endpoint)\n */\nfunction inferResourceFromPath(path: string): string | null {\n const segments = path.split('/').filter(Boolean);\n if (segments.length <= 1) return null;\n\n // Find the last meaningful (non-param) segment\n let resourceSegment: string | null = null;\n for (let i = segments.length - 1; i >= 0; i--) {\n if (!segments[i].startsWith('{')) {\n resourceSegment = segments[i];\n break;\n }\n }\n\n if (!resourceSegment) return null;\n // Skip the service name (first segment) — it would be redundant\n if (resourceSegment === segments[0]) return null;\n\n return toPascalCase(resourceSegment);\n}\n\n/**\n * Detect and resolve name collisions within a service's operations.\n *\n * When multiple operations share the same name (e.g., several \"list\" from\n * different sub-resources), disambiguate by appending the resource noun\n * from the path. Only renames operations on DIFFERENT paths — same-name\n * operations on the same path (e.g., PUT + PATCH both \"update\") are left as-is\n * since they represent the same logical resource.\n */\nfunction disambiguateOperationNames(operations: Operation[]): void {\n // Group by name\n const byName = new Map<string, Operation[]>();\n for (const op of operations) {\n const group = byName.get(op.name) ?? [];\n group.push(op);\n byName.set(op.name, group);\n }\n\n for (const [name, group] of byName) {\n if (group.length <= 1) continue;\n\n // Check if these are genuinely different resources (different paths)\n // vs the same resource with different methods (PUT + PATCH)\n const uniquePaths = new Set(group.map((op) => op.path));\n if (uniquePaths.size <= 1) continue; // same path, different methods — no disambiguation needed\n\n for (const op of group) {\n const resource = inferResourceFromPath(op.path);\n if (resource) {\n const newName = toCamelCase(`${name}_${resource}`);\n (op as { name: string }).name = newName;\n }\n }\n\n // If disambiguation still left collisions (same sub-resource),\n // use the full distinguishing path segment chain\n const renamed = new Map<string, Operation[]>();\n for (const op of group) {\n const rGroup = renamed.get(op.name) ?? [];\n rGroup.push(op);\n renamed.set(op.name, rGroup);\n }\n for (const [, rGroup] of renamed) {\n if (rGroup.length <= 1) continue;\n // Still colliding — different paths map to same resource name.\n // Use deeper path context to disambiguate.\n for (const op of rGroup) {\n const deeper = inferDeeperContext(op.path);\n if (deeper) {\n (op as { name: string }).name = toCamelCase(`${op.name}_${deeper}`);\n }\n }\n }\n }\n}\n\n/**\n * Extract a deeper disambiguation context from the path when the last\n * segment isn't unique enough. Uses the second-to-last non-param segment.\n *\n * /users/{id}/auth_factors → already captured as \"AuthFactors\"\n * /users/external_id/{external_id} → \"ExternalId\" (special path, not a sub-resource)\n */\nfunction inferDeeperContext(path: string): string | null {\n const segments = path.split('/').filter(Boolean);\n const nonParams = segments.filter((s) => !s.startsWith('{'));\n // Skip first (service) and last (already used) — use the middle ones\n if (nonParams.length >= 3) {\n return toPascalCase(nonParams.slice(1, -1).join('_'));\n }\n return null;\n}\n\n/**\n * Extract mutually-exclusive parameter groups from the `x-mutually-exclusive-parameter-groups`\n * operation extension. Cross-references grouped parameter names against the already-extracted\n * IR parameter arrays so emitters get object-identity references.\n */\nfunction extractParameterGroups(\n op: OperationObject,\n allIRParams: Parameter[],\n operationContext: string,\n): ParameterGroup[] | undefined {\n const raw = op['x-mutually-exclusive-parameter-groups'];\n if (!raw || typeof raw !== 'object') return undefined;\n\n const paramByName = new Map<string, Parameter>();\n for (const p of allIRParams) {\n paramByName.set(p.name, p);\n }\n\n const groups: ParameterGroup[] = [];\n\n for (const [groupName, groupDef] of Object.entries(raw)) {\n if (!groupDef || typeof groupDef !== 'object') {\n throw new Error(\n `Malformed x-mutually-exclusive-parameter-groups.${groupName} in ${operationContext}: expected an object with \"optional\" and \"variants\".`,\n );\n }\n\n if (typeof groupDef.optional !== 'boolean') {\n throw new Error(\n `Malformed x-mutually-exclusive-parameter-groups.${groupName}.optional in ${operationContext}: expected a boolean.`,\n );\n }\n\n if (!groupDef.variants || typeof groupDef.variants !== 'object') {\n throw new Error(\n `Malformed x-mutually-exclusive-parameter-groups.${groupName}.variants in ${operationContext}: expected an object mapping variant names to parameter name arrays.`,\n );\n }\n\n if (Object.keys(groupDef.variants).length === 0) {\n throw new Error(\n `Malformed x-mutually-exclusive-parameter-groups.${groupName} in ${operationContext}: group has zero variants.`,\n );\n }\n\n const variants = Object.entries(groupDef.variants).map(([variantName, paramNames]) => {\n if (!Array.isArray(paramNames) || paramNames.length === 0) {\n throw new Error(\n `Malformed x-mutually-exclusive-parameter-groups.${groupName}.variants.${variantName} in ${operationContext}: expected a non-empty array of parameter names.`,\n );\n }\n const parameters: Parameter[] = paramNames.map((pName) => {\n const irParam = paramByName.get(pName);\n if (!irParam) {\n throw new Error(\n `x-mutually-exclusive-parameter-groups.${groupName}.variants.${variantName} references parameter \"${pName}\" which does not exist in the operation's parameters[] (${operationContext}).`,\n );\n }\n return irParam;\n });\n return { name: variantName, parameters };\n });\n\n groups.push({\n name: groupName,\n optional: groupDef.optional,\n variants,\n });\n }\n\n return groups.length > 0 ? groups : undefined;\n}\n\n/**\n * Extract mutually-exclusive body parameter groups from the\n * `x-mutually-exclusive-body-groups` operation extension. Unlike query\n * parameter groups (whose parameters live in operation.queryParams), body\n * group parameters are synthetic — built from the oneOf variant schemas in\n * the request body. Emitters use the group's presence to generate sum-type\n * interfaces and custom JSON marshalling instead of flat optional fields.\n */\nfunction extractBodyParameterGroups(op: OperationObject, operationContext: string): ParameterGroup[] | undefined {\n const raw = op['x-mutually-exclusive-body-groups'];\n if (!raw || typeof raw !== 'object') return undefined;\n\n // Collect the body schema's oneOf variant fields so we can resolve types.\n // The body schema has been structurally rewritten to allOf: [base, { oneOf: [...] }]\n // by the spec generator; the variant properties live inside oneOf branches.\n const bodySchema = op.requestBody?.content?.['application/json']?.schema;\n const variantFieldSchemas = new Map<string, SchemaObject>();\n\n if (bodySchema) {\n // Walk allOf → oneOf → variant.properties to find all variant fields\n for (const sub of bodySchema.allOf ?? []) {\n for (const variant of sub.oneOf ?? []) {\n if (variant.properties) {\n for (const [name, fieldSchema] of Object.entries(variant.properties)) {\n if (fieldSchema) variantFieldSchemas.set(name, fieldSchema);\n }\n }\n }\n }\n // Also check top-level oneOf (for inline schemas that aren't wrapped in allOf)\n for (const variant of bodySchema.oneOf ?? []) {\n if (variant.properties) {\n for (const [name, fieldSchema] of Object.entries(variant.properties)) {\n if (fieldSchema) variantFieldSchemas.set(name, fieldSchema);\n }\n }\n }\n }\n\n const groups: ParameterGroup[] = [];\n\n for (const [groupName, groupDef] of Object.entries(raw)) {\n if (!groupDef || typeof groupDef !== 'object') continue;\n if (typeof groupDef.optional !== 'boolean') continue;\n if (!groupDef.variants || typeof groupDef.variants !== 'object') continue;\n if (Object.keys(groupDef.variants).length === 0) continue;\n\n const variants = Object.entries(groupDef.variants).map(([variantName, paramNames]) => {\n if (!Array.isArray(paramNames) || paramNames.length === 0) {\n throw new Error(\n `Malformed x-mutually-exclusive-body-groups.${groupName}.variants.${variantName} in ${operationContext}: expected a non-empty array of parameter names.`,\n );\n }\n const parameters: Parameter[] = paramNames.map((pName) => {\n const fieldSchema = variantFieldSchemas.get(pName);\n const fieldType: TypeRef = fieldSchema\n ? schemaToTypeRef(fieldSchema, toPascalCase(pName))\n : { kind: 'primitive', type: 'string' };\n return {\n name: pName,\n type: fieldType,\n required: false, // group variant fields are always optional at the struct level\n description: fieldSchema?.description,\n };\n });\n return { name: variantName, parameters };\n });\n\n groups.push({\n name: groupName,\n optional: groupDef.optional,\n variants,\n });\n }\n\n return groups.length > 0 ? groups : undefined;\n}\n\nfunction buildOperation(\n method: HttpMethod,\n path: string,\n op: OperationObject,\n pathLevelParams: ParameterObject[],\n operationIdTransform?: (id: string) => string,\n serviceName?: string,\n componentSchemas?: Record<string, SchemaObject>,\n): { operation: Operation; inlineModels: Model[] } {\n const allParams = [...pathLevelParams, ...(op.parameters ?? [])];\n\n const hasIdempotencyHeader = allParams.some((p) => p.in === 'header' && p.name.toLowerCase() === 'idempotency-key');\n\n // Use the service name as context so inline parameter enums get qualified\n // names. e.g., service \"SSO\" + param \"provider\" → \"SSOProvider\".\n const opContext = serviceName;\n const pathParams = extractParams(allParams, 'path', opContext, componentSchemas);\n const queryParams = extractParams(allParams, 'query', opContext, componentSchemas);\n const headerParams = extractParams(allParams, 'header', opContext, componentSchemas).filter(\n (p) => p.name.toLowerCase() !== 'idempotency-key',\n );\n const cookieParams = extractParams(allParams, 'cookie', opContext, componentSchemas);\n\n const reqBodyModels: Model[] = [];\n const { body: requestBody, encoding: requestBodyEncoding } = extractRequestBody(op.requestBody, op, reqBodyModels);\n const {\n response,\n successResponses,\n errors,\n inlineModels,\n isPaginated,\n dataPath: responseDataPath,\n itemType: responseItemType,\n } = extractResponses(op.responses, op, path, method);\n inlineModels.push(...reqBodyModels);\n\n // Build structured pagination metadata from response classification and query param detection\n const paginationFromParams = detectPagination(response, queryParams, responseDataPath);\n let pagination: PaginationMeta | undefined;\n if (isPaginated) {\n const itemType = responseItemType ?? (response.kind === 'array' ? response.items : response);\n pagination = {\n strategy: paginationFromParams?.strategy ?? 'cursor',\n param: paginationFromParams?.param ?? 'after',\n limitParam: paginationFromParams?.limitParam,\n dataPath: responseDataPath ?? paginationFromParams?.dataPath,\n itemType,\n };\n } else if (paginationFromParams) {\n pagination = paginationFromParams;\n }\n\n // Extract per-operation security overrides\n const security = extractOperationSecurity(op.security);\n\n // Extract mutually-exclusive parameter groups (query/path/header/cookie)\n const allIRParams = [...pathParams, ...queryParams, ...headerParams, ...cookieParams];\n const opLabel = op.operationId ?? `${method.toUpperCase()} ${path}`;\n const queryParamGroups = extractParameterGroups(op, allIRParams, opLabel);\n\n // Extract mutually-exclusive body parameter groups\n const bodyParamGroups = extractBodyParameterGroups(op, opLabel);\n\n // Merge both sources into a single parameterGroups array\n const parameterGroups =\n queryParamGroups || bodyParamGroups ? [...(queryParamGroups ?? []), ...(bodyParamGroups ?? [])] : undefined;\n\n return {\n operation: {\n name: inferOperationName(method, path, op.operationId, operationIdTransform),\n description: buildDescription(op.summary, op.description),\n httpMethod: method,\n path,\n pathParams,\n queryParams,\n headerParams,\n cookieParams: cookieParams.length > 0 ? cookieParams : undefined,\n requestBody,\n requestBodyEncoding,\n response,\n successResponses,\n errors,\n pagination,\n injectIdempotencyKey: hasIdempotencyHeader,\n deprecated: op.deprecated || undefined,\n async: op['x-oagen-async'],\n security,\n parameterGroups,\n },\n inlineModels,\n };\n}\n\n/**\n * Extract per-operation security requirements from an OpenAPI security directive.\n * Returns undefined when the operation uses the spec-level default security.\n *\n * OpenAPI security format: `security: [{ schemeName: [scope1, scope2] }]`\n */\nfunction extractOperationSecurity(\n security: Array<Record<string, string[]>> | undefined,\n): SecurityRequirement[] | undefined {\n if (!security || security.length === 0) return undefined;\n\n const requirements: SecurityRequirement[] = [];\n for (const entry of security) {\n for (const [schemeName, scopes] of Object.entries(entry)) {\n requirements.push({ schemeName, scopes: scopes ?? [] });\n }\n }\n return requirements.length > 0 ? requirements : undefined;\n}\n\nfunction buildDescription(summary: string | undefined, description: string | undefined): string | undefined {\n if (summary && description && summary !== description) {\n return `${summary}\\n\\n${description}`;\n }\n return description ?? summary;\n}\n\nfunction extractParams(\n params: ParameterObject[],\n location: 'path' | 'query' | 'header' | 'cookie',\n operationContext?: string,\n componentSchemas?: Record<string, SchemaObject>,\n): Parameter[] {\n return params\n .filter((p) => p.in === location)\n .map((p) => {\n const refTarget = resolveParamSchemaRef(p.schema, componentSchemas);\n return {\n name: p.name,\n type: p.schema\n ? schemaToTypeRef(p.schema, p.name, operationContext ? toPascalCase(operationContext) : undefined)\n : ({ kind: 'primitive', type: 'string' } as TypeRef),\n required: p.required ?? false,\n description: p.description,\n deprecated: p.deprecated || p.schema?.deprecated || refTarget?.deprecated || undefined,\n default: p.schema?.default ?? refTarget?.default,\n example: p.example ?? p.schema?.example ?? refTarget?.example,\n style: p.style as Parameter['style'],\n explode: p.explode,\n };\n });\n}\n\n/**\n * If a parameter's schema is a `$ref` to `#/components/schemas/X`, return the\n * referenced component schema. Used to surface schema-level metadata (default,\n * example, deprecated) that wouldn't otherwise be visible at the param level.\n *\n * Refs are not pre-resolved by the bundler (`dereference: false` in refs.ts),\n * so without this, a param like `schema: { $ref: '.../PaginationOrder' }`\n * silently loses the target's `default: desc` and the SDK stops emitting the\n * spec-mandated default value in generated method signatures.\n */\nfunction resolveParamSchemaRef(\n schema: SchemaObject | undefined,\n componentSchemas: Record<string, SchemaObject> | undefined,\n): SchemaObject | undefined {\n if (!schema || !componentSchemas) return undefined;\n const ref = (schema as { $ref?: string }).$ref;\n if (!ref) return undefined;\n const match = /^#\\/components\\/schemas\\/(.+)$/.exec(ref);\n if (!match) return undefined;\n return componentSchemas[match[1]];\n}\n\nfunction extractRequestBody(\n body: RequestBodyObject | undefined,\n op: OperationObject | undefined,\n inlineModels: Model[],\n): { body?: TypeRef; encoding?: 'json' | 'form-data' | 'form-urlencoded' | 'binary' | 'text' } {\n if (!body?.content) return {};\n\n // Detect encoding and find schema from content type in priority order\n let encoding: 'json' | 'form-data' | 'form-urlencoded' | 'binary' | 'text' = 'json';\n let schema: SchemaObject | undefined;\n\n if (body.content['application/json']?.schema) {\n encoding = 'json';\n schema = body.content['application/json']!.schema;\n } else if (body.content['multipart/form-data']?.schema) {\n encoding = 'form-data';\n schema = body.content['multipart/form-data']!.schema;\n } else if (body.content['application/x-www-form-urlencoded']?.schema) {\n encoding = 'form-urlencoded';\n schema = body.content['application/x-www-form-urlencoded']!.schema;\n } else if (body.content['application/octet-stream']) {\n encoding = 'binary';\n schema = body.content['application/octet-stream']!.schema;\n } else if (body.content['text/plain']) {\n encoding = 'text';\n schema = body.content['text/plain']!.schema;\n }\n\n if (!schema) {\n // For binary/text, a schema is optional — produce a primitive TypeRef\n if (encoding === 'binary') {\n return { body: { kind: 'primitive', type: 'string', format: 'binary' }, encoding };\n }\n if (encoding === 'text') {\n return { body: { kind: 'primitive', type: 'string' }, encoding };\n }\n return {};\n }\n\n const rawName = op?.operationId\n ? toPascalCase(normalizeOperationIdForNaming(op.operationId)) + 'Request'\n : 'RequestBody';\n const contextName = cleanSchemaName(rawName);\n\n // If the request body is an inline object with properties, extract it as a model\n if (schema.properties && (schema.type === 'object' || !schema.type)) {\n const requiredSet = new Set(schema.required ?? []);\n const fields: Field[] = [];\n for (const [fieldName, fieldSchema] of Object.entries(schema.properties)) {\n if (!fieldSchema) continue;\n fields.push(buildFieldFromSchema(fieldName, fieldSchema, contextName, requiredSet));\n }\n inlineModels.push({ name: contextName, description: undefined, fields });\n return { body: { kind: 'model', name: contextName }, encoding };\n }\n\n // If the request body is a oneOf, extract each variant as an inline model\n // and build a union type pointing to them by name.\n if (schema.oneOf) {\n const variants: TypeRef[] = [];\n\n for (const variant of schema.oneOf) {\n if (variant.$ref) {\n const ref = schemaToTypeRef(variant, contextName);\n variants.push(ref);\n } else if (variant.type === 'null') {\n // skip null variant in union, handle separately\n } else if (variant.properties && (variant.type === 'object' || !variant.type)) {\n const variantName = deriveOneOfVariantName(variant, contextName, inlineModels);\n const requiredSet = new Set(variant.required ?? []);\n const fields: Field[] = [];\n for (const [fieldName, fieldSchema] of Object.entries(variant.properties)) {\n if (!fieldSchema) continue;\n fields.push(buildFieldFromSchema(fieldName, fieldSchema, variantName, requiredSet));\n }\n inlineModels.push({ name: variantName, description: variant.description, fields });\n variants.push({ kind: 'model', name: variantName });\n } else {\n variants.push(schemaToTypeRef(variant, contextName));\n }\n }\n\n const hasNull = schema.oneOf.some(\n (v: SchemaObject) => v.type === 'null' || (Array.isArray(v.type) && v.type.includes('null')),\n );\n const union: TypeRef = {\n kind: 'union',\n variants,\n ...(schema.discriminator\n ? {\n discriminator: { property: schema.discriminator.propertyName, mapping: schema.discriminator.mapping ?? {} },\n }\n : {}),\n };\n const body = hasNull ? ({ kind: 'nullable', inner: union } as TypeRef) : union;\n return { body, encoding };\n }\n\n return { body: schemaToTypeRef(schema, contextName), encoding };\n}\n\n/** Derive a unique variant name for a oneOf inline model. */\nfunction deriveOneOfVariantName(variant: SchemaObject, baseName: string, existingModels: Model[]): string {\n // Try to use a distinguishing property (e.g., \"grant_type\" field's const/enum value)\n if (variant.properties) {\n for (const [, propSchema] of Object.entries(variant.properties)) {\n if (propSchema?.const && typeof propSchema.const === 'string') {\n return toPascalCase(propSchema.const) + baseName.replace(/Request$/, '') + 'Request';\n }\n }\n }\n // Fallback: append a numeric suffix\n const existingNames = new Set(existingModels.map((m) => m.name));\n let name = baseName;\n let suffix = 2;\n while (existingNames.has(name)) {\n name = `${baseName}${suffix}`;\n suffix++;\n }\n return name;\n}\n\nfunction deriveResponseName(op: OperationObject | undefined, path: string, method: HttpMethod): string {\n if (op?.operationId) {\n return cleanSchemaName(toPascalCase(normalizeOperationIdForNaming(op.operationId)) + 'Response');\n }\n const segments = path.split('/').filter(Boolean);\n const resource = segments[0] ?? 'Unknown';\n return toPascalCase(resource) + toPascalCase(method) + 'Response';\n}\n\nfunction extractResponses(\n responses?: Record<string, ResponseObject>,\n op?: OperationObject,\n path?: string,\n method?: HttpMethod,\n): {\n response: TypeRef;\n successResponses?: SuccessResponse[];\n errors: ErrorResponse[];\n inlineModels: Model[];\n isPaginated: boolean;\n dataPath?: string;\n itemType?: TypeRef;\n} {\n const errors: ErrorResponse[] = [];\n let response: TypeRef = { kind: 'primitive', type: 'string' };\n let inlineModels: Model[] = [];\n let isPaginated = false;\n let dataPath: string | undefined;\n let itemType: TypeRef | undefined;\n\n if (!responses) return { response, errors, inlineModels, isPaginated };\n\n const allSuccessResponses: SuccessResponse[] = [];\n\n for (const [statusCode, resp] of Object.entries(responses)) {\n const code = parseInt(statusCode, 10);\n\n if (code >= 200 && code < 300) {\n let extractedType: TypeRef = { kind: 'primitive', type: 'unknown' };\n const jsonContent = resp.content?.['application/json'];\n if (jsonContent?.schema) {\n const contextName = deriveResponseName(op, path ?? '/', method ?? 'get');\n const result = classifyAndExtractResponse(jsonContent.schema, contextName);\n extractedType = result.response;\n // Keep track of inline models and pagination from the latest 2xx with a schema\n inlineModels = result.inlineModels;\n isPaginated = result.isPaginated;\n dataPath = result.dataPath;\n itemType = result.itemType;\n } else if (resp.content) {\n // Handle non-JSON response content types (text/plain, binary, XML, etc.)\n if (resp.content['application/octet-stream'] || resp.content['application/pdf']) {\n extractedType = { kind: 'primitive', type: 'string', format: 'binary' };\n } else if (\n resp.content['text/plain'] ||\n resp.content['text/html'] ||\n resp.content['text/xml'] ||\n resp.content['application/xml']\n ) {\n extractedType = { kind: 'primitive', type: 'string' };\n } else {\n // Try the first available content type's schema\n const firstKey = Object.keys(resp.content)[0];\n if (firstKey) {\n const firstContent = resp.content[firstKey];\n if (firstContent?.schema) {\n extractedType = schemaToTypeRef(\n firstContent.schema,\n deriveResponseName(op, path ?? '/', method ?? 'get'),\n );\n }\n }\n }\n }\n allSuccessResponses.push({ statusCode: code, type: extractedType });\n } else if (code >= 300 && code < 400) {\n // 3xx redirects — include so emitter can detect redirect endpoints\n allSuccessResponses.push({ statusCode: code, type: { kind: 'primitive', type: 'unknown' } });\n } else if (code >= 400) {\n const jsonContent = resp.content?.['application/json'];\n const type = jsonContent?.schema ? schemaToTypeRef(jsonContent.schema, `Error${code}`) : undefined;\n errors.push({ statusCode: code, type });\n }\n }\n\n // Primary response = lowest 2xx with a body schema, falling back to first 2xx\n if (allSuccessResponses.length > 0) {\n const sorted = [...allSuccessResponses].sort((a, b) => a.statusCode - b.statusCode);\n const primary =\n sorted.find((r) => r.type.kind !== 'primitive' || (r.type as { type: string }).type !== 'unknown') ?? sorted[0];\n response = primary.type;\n }\n\n const successResponses = allSuccessResponses.length > 1 ? allSuccessResponses : undefined;\n\n return { response, successResponses, errors, inlineModels, isPaginated, dataPath, itemType };\n}\n","import type { Model, Service, TypeRef } from '../ir/types.js';\nimport { walkTypeRef } from '../ir/types.js';\n\nfunction keepLargestByName(models: Model[]): Model[] {\n const byName = new Map<string, Model>();\n for (const model of models) {\n const existing = byName.get(model.name);\n if (!existing || model.fields.length > existing.fields.length) {\n byName.set(model.name, model);\n }\n }\n return [...byName.values()];\n}\n\nfunction rewriteModelRef(ref: TypeRef, oldName: string, newName: string): void {\n walkTypeRef(ref, {\n model: (r) => {\n if (r.name === oldName) (r as { name: string }).name = newName;\n },\n });\n}\n\nfunction rewriteModelRefs(models: Model[], services: Service[], oldName: string, newName: string): void {\n for (const model of models) {\n for (const field of model.fields) {\n rewriteModelRef(field.type, oldName, newName);\n }\n }\n for (const service of services) {\n for (const op of service.operations) {\n rewriteModelRef(op.response, oldName, newName);\n if (op.requestBody) {\n rewriteModelRef(op.requestBody, oldName, newName);\n }\n }\n }\n}\n\nexport function mergeInlineResponseModels(schemaModels: Model[], inlineModels: Model[]): Model[] {\n const mergedSchemaModels = [...schemaModels];\n const schemaModelNames = new Set(mergedSchemaModels.map((m) => m.name));\n const schemaModelsByName = new Map(mergedSchemaModels.map((m) => [m.name, m]));\n\n const deduplicatedInlineModels = inlineModels.filter((model) => {\n if (!schemaModelNames.has(model.name)) return true;\n\n const existing = schemaModelsByName.get(model.name)!;\n const existingFieldNames = new Set(existing.fields.map((f) => f.name));\n const inlineFieldNames = new Set(model.fields.map((f) => f.name));\n const hasDifference =\n model.fields.some((f) => !existingFieldNames.has(f.name)) ||\n existing.fields.some((f) => !inlineFieldNames.has(f.name));\n\n if (hasDifference && model.fields.length > existing.fields.length) {\n const idx = mergedSchemaModels.indexOf(existing);\n if (idx !== -1) mergedSchemaModels[idx] = model;\n schemaModelsByName.set(model.name, model);\n console.warn(\n `[oagen] Warning: Inline model \"${model.name}\" has more fields than component schema (${model.fields.length} vs ${existing.fields.length}) — using inline response model`,\n );\n } else if (hasDifference) {\n console.warn(\n `[oagen] Warning: Inline model \"${model.name}\" has different fields than component schema — using component schema`,\n );\n }\n\n return false;\n });\n\n return [...mergedSchemaModels, ...keepLargestByName(deduplicatedInlineModels)];\n}\n\nexport function mergeFieldInlineModels(existingModels: Model[], fieldInlineModels: Model[]): Model[] {\n const modelNames = new Set(existingModels.map((m) => m.name));\n const modelsByName = new Map(existingModels.map((m) => [m.name, m]));\n\n const deduplicatedFieldModels = fieldInlineModels.filter((model) => {\n if (!modelNames.has(model.name)) return true;\n\n const existing = modelsByName.get(model.name)!;\n const existingFieldNames = new Set(existing.fields.map((f) => f.name));\n const inlineFieldNames = new Set(model.fields.map((f) => f.name));\n const hasDifference =\n model.fields.some((f) => !existingFieldNames.has(f.name)) ||\n existing.fields.some((f) => !inlineFieldNames.has(f.name));\n\n if (hasDifference) {\n console.warn(\n `[oagen] Warning: Inline model \"${model.name}\" has different fields than component schema — using component schema`,\n );\n }\n\n return false;\n });\n\n return [...existingModels, ...keepLargestByName(deduplicatedFieldModels)];\n}\n\nfunction hasModelConstDiscriminant(model: Model): boolean {\n return model.fields.some(\n (f) => (f.name === 'object' || f.name === 'type') && f.type.kind === 'literal' && typeof f.type.value === 'string',\n );\n}\n\nfunction isModelReferencedByOthers(name: string, models: Model[], excludeNames: Set<string>): boolean {\n for (const model of models) {\n if (excludeNames.has(model.name)) continue;\n for (const field of model.fields) {\n let found = false;\n walkTypeRef(field.type, {\n model: (r) => {\n if (r.name === name) found = true;\n },\n });\n if (found) return true;\n }\n }\n return false;\n}\n\nexport function collapseJsonSuffixModels(models: Model[], services: Service[]): Model[] {\n const normalizedModels = [...models];\n const byName = new Map(normalizedModels.map((m) => [m.name, m]));\n\n // Pass 1: collect merge candidates\n const mergeCandidates: Array<{ jsonModel: Model; baseModel: Model }> = [];\n for (const model of normalizedModels) {\n if (!model.name.endsWith('Json')) continue;\n\n const baseName = model.name.slice(0, -4);\n const baseModel = byName.get(baseName);\n if (!baseModel || model.fields.length <= baseModel.fields.length) continue;\n\n const isSuperset = baseModel.fields.every((f) => model.fields.some((mf) => mf.name === f.name));\n if (!isSuperset) continue;\n\n // Guard: both models have a const discriminant — they are distinct entities\n if (hasModelConstDiscriminant(model) && hasModelConstDiscriminant(baseModel)) continue;\n\n // Guard: a third model explicitly references the Json-suffix model\n if (isModelReferencedByOthers(model.name, normalizedModels, new Set([model.name, baseName]))) continue;\n\n mergeCandidates.push({ jsonModel: model, baseModel });\n }\n\n // Pass 2: apply merges\n const toRemove = new Set<string>();\n for (const { jsonModel, baseModel } of mergeCandidates) {\n baseModel.fields = jsonModel.fields;\n toRemove.add(jsonModel.name);\n rewriteModelRefs(normalizedModels, services, jsonModel.name, baseModel.name);\n console.warn(\n `[oagen] Merged \"${jsonModel.name}\" into \"${baseModel.name}\" (${jsonModel.fields.length} fields, superset)`,\n );\n }\n\n // Pass 3: cascade renames to inline children of collapsed Json-suffix models.\n // e.g. when AuditLogSchemaJson → AuditLogSchema, also rename\n // AuditLogSchemaJsonTarget → AuditLogSchemaTarget.\n for (const { jsonModel, baseModel } of mergeCandidates) {\n const jsonPrefix = jsonModel.name;\n const basePrefix = baseModel.name;\n\n for (const model of normalizedModels) {\n if (toRemove.has(model.name)) continue;\n if (model.name.length <= jsonPrefix.length) continue;\n if (!model.name.startsWith(jsonPrefix)) continue;\n\n const newName = basePrefix + model.name.slice(jsonPrefix.length);\n const existing = byName.get(newName);\n\n if (existing && !toRemove.has(existing.name)) {\n toRemove.add(model.name);\n rewriteModelRefs(normalizedModels, services, model.name, newName);\n console.warn(`[oagen] Collapsed child \"${model.name}\" into existing \"${newName}\"`);\n } else {\n rewriteModelRefs(normalizedModels, services, model.name, newName);\n model.name = newName;\n byName.set(newName, model);\n console.warn(`[oagen] Renamed child \"${jsonPrefix}…\" → \"${newName}\"`);\n }\n }\n }\n\n return normalizedModels.filter((m) => !toRemove.has(m.name));\n}\n","import type { Enum, Model, Service } from '../ir/types.js';\nimport { collectInlineEnumFromRef } from './schemas.js';\n\nexport function collectInlineEnumsFromModels(models: Model[], enums: Enum[]): void {\n const enumNames = new Set(enums.map((e) => e.name));\n for (const model of models) {\n for (const field of model.fields) {\n collectInlineEnumFromRef(field.type, enums, enumNames);\n }\n }\n}\n\n/**\n * Collect inline enum definitions from operation parameters (query, path, header)\n * and promote them to top-level enums so emitters can generate typed enum files.\n */\nexport function collectInlineEnumsFromOperations(services: Service[], enums: Enum[]): void {\n const enumNames = new Set(enums.map((e) => e.name));\n for (const service of services) {\n for (const op of service.operations) {\n for (const param of [...op.pathParams, ...op.queryParams, ...op.headerParams, ...(op.cookieParams ?? [])]) {\n collectInlineEnumFromRef(param.type, enums, enumNames);\n }\n }\n }\n}\n","import type { ApiSpec, TypeRef } from '../ir/types.js';\nimport { walkTypeRef } from '../ir/types.js';\n\nexport function validateModelRefs(spec: ApiSpec): void {\n const knownNames = new Set<string>();\n for (const m of spec.models) knownNames.add(m.name);\n for (const e of spec.enums) knownNames.add(e.name);\n\n function walkRef(ref: TypeRef, context: string): void {\n walkTypeRef(ref, {\n model: (r) => {\n if (!knownNames.has(r.name)) {\n console.warn(`[oagen] Warning: Unresolved model reference \"${r.name}\" (context: ${context})`);\n }\n },\n });\n }\n\n for (const model of spec.models) {\n for (const field of model.fields) {\n walkRef(field.type, `${model.name}.${field.name}`);\n }\n }\n\n for (const service of spec.services) {\n for (const op of service.operations) {\n for (const p of [...op.pathParams, ...op.queryParams, ...op.headerParams]) {\n walkRef(p.type, `${service.name}.${op.name}.${p.name}`);\n }\n if (op.requestBody) walkRef(op.requestBody, `${service.name}.${op.name}.requestBody`);\n walkRef(op.response, `${service.name}.${op.name}.response`);\n }\n }\n}\n","import type { ApiSpec, AuthScheme, ServerEntry } from '../ir/types.js';\nimport { defaultSdkBehavior } from '../ir/sdk-behavior.js';\nimport { SpecParseError } from '../errors.js';\nimport { loadAndBundleSpec } from './refs.js';\nimport { extractSchemas, extractInlineModelsFromSchemas, clearSchemaNameTransform } from './schemas.js';\nimport { extractOperations } from './operations.js';\nimport {\n mergeInlineResponseModels,\n collapseJsonSuffixModels,\n mergeFieldInlineModels,\n} from './normalize-inline-models.js';\nimport { collectInlineEnumsFromModels, collectInlineEnumsFromOperations } from './collect-inline-enums.js';\nimport { validateModelRefs } from './normalize-model-refs.js';\n\n/**\n * A bundled OpenAPI document, post-`$ref` resolution but pre-IR extraction.\n *\n * This is the shape the spec author wrote, with external refs inlined and\n * internal refs left intact. It is intentionally loose (`Record<string,\n * unknown>`) so `transformSpec` can reach arbitrary spec extensions without\n * fighting types — narrow with `as` at use sites.\n */\nexport type OpenApiDocument = Record<string, unknown>;\n\nexport interface ParseOptions {\n operationIdTransform?: (id: string) => string;\n schemaNameTransform?: (name: string) => string;\n /**\n * Pre-IR overlay applied to the bundled OpenAPI document before any IR\n * extraction runs. Use this when the upstream spec can't be changed but you\n * need to patch around a spec quirk that would otherwise emit a breaking SDK\n * change — e.g. rewriting a path's response `$ref` back to its prior schema,\n * merging the new fields onto the prior schema, and dropping the fork.\n *\n * The function may mutate the document in place and return it, or return a\n * new object; the returned value is what the rest of oagen sees.\n *\n * Runs once, after `$ref` bundling and before schema/operation extraction.\n * If you need to inspect the resulting IR instead, post-process the\n * `ApiSpec` returned by `parseSpec`.\n */\n transformSpec?: (spec: OpenApiDocument) => OpenApiDocument;\n}\n\nexport async function parseSpec(specPath: string, options?: ParseOptions): Promise<ApiSpec> {\n const { parsed } = await loadAndBundleSpec(specPath);\n const transformed = options?.transformSpec ? options.transformSpec(parsed) : parsed;\n\n const spec = transformed as {\n openapi?: string;\n info?: { title?: string; version?: string; description?: string };\n servers?: Array<{ url?: string; description?: string }>;\n paths?: Record<string, unknown>;\n components?: {\n schemas?: Record<string, unknown>;\n securitySchemes?: Record<\n string,\n { type: string; scheme?: string; in?: string; name?: string; flows?: Record<string, unknown> }\n >;\n };\n };\n\n // Validate OpenAPI version\n const version = spec.openapi ?? '';\n if (!version.startsWith('3.')) {\n throw new SpecParseError(\n `Unsupported OpenAPI version: ${version}. oagen requires OpenAPI 3.x`,\n `Update the spec to OpenAPI 3.0 or 3.1. If you are using Swagger 2.x, convert it first with \\`npx swagger2openapi ${specPath}\\`.`,\n );\n }\n\n const { models, enums } = extractSchemas(\n spec.components?.schemas as Record<string, Record<string, unknown>> | undefined,\n { schemaNameTransform: options?.schemaNameTransform },\n );\n\n const { services, inlineModels } = extractOperations(\n spec.paths as Record<string, Record<string, unknown>> | undefined,\n options?.operationIdTransform,\n spec.components?.schemas as Record<string, Record<string, unknown>> | undefined,\n );\n\n const responseNormalizedModels = mergeInlineResponseModels(models, inlineModels);\n\n // Extract inline models from model field definitions (objects/arrays with properties).\n // schemaNameTransform is kept active so inline child names use the\n // transformed parent name (e.g. AuditLogSchemaJson→AuditLogSchema yields\n // AuditLogSchemaTarget, not AuditLogSchemaJsonTarget).\n const fieldInlineModels = extractInlineModelsFromSchemas(\n spec.components?.schemas as Record<string, Record<string, unknown>> | undefined,\n );\n clearSchemaNameTransform();\n const fieldMergedModels = mergeFieldInlineModels(responseNormalizedModels, fieldInlineModels);\n const finalModels = collapseJsonSuffixModels(fieldMergedModels, services);\n collectInlineEnumsFromModels(finalModels, enums);\n collectInlineEnumsFromOperations(services, enums);\n\n const auth = extractAuthSchemes(spec.components?.securitySchemes);\n\n const serverEntries: ServerEntry[] = (spec.servers ?? [])\n .map((s) => ({ url: s.url ?? '', description: s.description }))\n .filter((s) => s.url);\n\n const result: ApiSpec = {\n name: spec.info?.title ?? 'Unknown API',\n version: spec.info?.version ?? '0.0.0',\n description: spec.info?.description,\n baseUrl: serverEntries[0]?.url ?? '',\n servers: serverEntries.length > 0 ? serverEntries : undefined,\n services,\n models: finalModels,\n enums,\n auth,\n sdk: defaultSdkBehavior(),\n };\n\n validateModelRefs(result);\n\n return result;\n}\n/** Extract authentication schemes from OpenAPI securitySchemes. */\nfunction extractAuthSchemes(\n securitySchemes?: Record<\n string,\n { type: string; scheme?: string; in?: string; name?: string; flows?: Record<string, unknown> }\n >,\n): AuthScheme[] | undefined {\n if (!securitySchemes) return undefined;\n const schemes: AuthScheme[] = [];\n for (const [, scheme] of Object.entries(securitySchemes)) {\n if (scheme.type === 'http' && scheme.scheme === 'bearer') {\n schemes.push({ kind: 'bearer' });\n } else if (scheme.type === 'apiKey' && scheme.in && scheme.name) {\n schemes.push({ kind: 'apiKey', in: scheme.in as 'header' | 'query' | 'cookie', name: scheme.name });\n } else if (scheme.type === 'oauth2' && scheme.flows) {\n schemes.push({ kind: 'oauth2', flows: scheme.flows });\n }\n }\n return schemes.length > 0 ? schemes : undefined;\n}\n","import { parseSpec, type OpenApiDocument } from '../parser/parse.js';\n\nexport async function parseCommand(opts: {\n spec: string;\n operationIdTransform?: (id: string) => string;\n schemaNameTransform?: (name: string) => string;\n transformSpec?: (spec: OpenApiDocument) => OpenApiDocument;\n}): Promise<void> {\n const ir = await parseSpec(opts.spec, {\n operationIdTransform: opts.operationIdTransform,\n schemaNameTransform: opts.schemaNameTransform,\n transformSpec: opts.transformSpec,\n });\n console.log(JSON.stringify(ir, null, 2));\n}\n","import type Parser from 'tree-sitter';\nimport type { UrlFingerprintConfig } from './types.js';\n\n/**\n * Extract a URL path fingerprint from a method body using tree-sitter AST traversal.\n *\n * Walks the AST subtree of the member node looking for the first string literal\n * that starts with '/'. Normalizes interpolation expressions to '{}' and format\n * specifiers (%s, %d, etc.) to '{}' for cross-language comparison.\n *\n * @returns A normalized URL fingerprint like \"/organizations/{}\" or undefined if none found.\n */\nexport function extractUrlFingerprint(memberNode: Parser.SyntaxNode, config: UrlFingerprintConfig): string | undefined {\n const stringTypes = new Set(config.stringNodeTypes);\n const contentTypes = new Set(config.contentNodeTypes);\n const interpolationTypes = new Set(config.interpolationNodeTypes);\n const formatFns = config.formatFunctionNames ? new Set(config.formatFunctionNames) : null;\n\n // Iterative DFS through the method's AST subtree\n const stack: Parser.SyntaxNode[] = [memberNode];\n\n while (stack.length > 0) {\n const node = stack.pop()!;\n\n if (stringTypes.has(node.type)) {\n const fp = resolveFingerprint(node, contentTypes, interpolationTypes);\n if (fp?.startsWith('/')) return fp;\n }\n\n // For format functions (Go's Sprintf, Rust's format!): check if this call\n // matches and extract the first string argument.\n if (formatFns && isFormatCall(node, formatFns)) {\n const fp = extractFromFormatCall(node, stringTypes, contentTypes, interpolationTypes);\n if (fp?.startsWith('/')) return fp;\n }\n\n // Push children in reverse order so leftmost child is processed first\n for (let i = node.childCount - 1; i >= 0; i--) {\n const child = node.child(i);\n if (child) stack.push(child);\n }\n }\n\n return undefined;\n}\n\n/**\n * Resolve the text content of a string node, normalizing interpolations to '{}'.\n */\nfunction resolveFingerprint(\n stringNode: Parser.SyntaxNode,\n contentTypes: Set<string>,\n interpolationTypes: Set<string>,\n): string | undefined {\n // Leaf string node (no children besides quotes) — strip quotes\n if (stringNode.namedChildCount === 0) {\n return normalizeFormatSpecifiers(stripQuotes(stringNode.text));\n }\n\n // Composite string (has content fragments + interpolation children)\n let result = '';\n for (let i = 0; i < stringNode.childCount; i++) {\n const child = stringNode.child(i)!;\n if (contentTypes.has(child.type)) {\n result += child.text;\n } else if (interpolationTypes.has(child.type)) {\n result += '{}';\n }\n // Skip quote delimiters, interpolation markers, etc.\n }\n\n return result ? normalizeFormatSpecifiers(result) : normalizeFormatSpecifiers(stripQuotes(stringNode.text));\n}\n\n/** Check if a node is a call to one of the format functions (e.g., fmt.Sprintf, format!). */\nfunction isFormatCall(node: Parser.SyntaxNode, formatFns: Set<string>): boolean {\n // Rust macro: format!(...) — tree-sitter may parse as macro_invocation\n if (node.type === 'macro_invocation') {\n const macroName = node.childForFieldName('macro')?.text;\n return !!(macroName && formatFns.has(macroName.replace(/!$/, '')));\n }\n\n if (node.type !== 'call_expression') return false;\n const fnNode = node.childForFieldName('function');\n if (!fnNode) return false;\n\n // Direct call: Sprintf(...) or format!(...)\n if (formatFns.has(fnNode.text)) return true;\n\n // Member call: fmt.Sprintf(...)\n if (fnNode.type === 'selector_expression' || fnNode.type === 'member_expression') {\n const prop = fnNode.childForFieldName('field') ?? fnNode.childForFieldName('property');\n if (prop && formatFns.has(prop.text)) return true;\n }\n return false;\n}\n\n/** Extract the first string argument from a format function call. */\nfunction extractFromFormatCall(\n callNode: Parser.SyntaxNode,\n stringTypes: Set<string>,\n contentTypes: Set<string>,\n interpolationTypes: Set<string>,\n): string | undefined {\n const args = callNode.childForFieldName('arguments');\n if (!args) return undefined;\n\n for (let i = 0; i < args.childCount; i++) {\n const arg = args.child(i)!;\n if (stringTypes.has(arg.type)) {\n return resolveFingerprint(arg, contentTypes, interpolationTypes);\n }\n }\n return undefined;\n}\n\n/** Strip surrounding quote characters from a string literal. */\nfunction stripQuotes(text: string): string {\n // Handle various quote styles: \"...\", '...', `...`, f\"...\", $\"...\", @\"...\"\n const match = text.match(/^(?:f|r|b|@|\\$)?(?:\"\"\"([\\s\\S]*)\"\"\"|'''([\\s\\S]*)'''|\"(.*)\"|'(.*)'|`(.*)`)$/s);\n if (match) return match[1] ?? match[2] ?? match[3] ?? match[4] ?? match[5] ?? text;\n return text;\n}\n\n/** Replace printf-style format specifiers (%s, %d, %v, %f) with {}. */\nfunction normalizeFormatSpecifiers(s: string): string {\n return s.replace(/%[sdvf]/g, '{}');\n}\n","import type Parser from 'tree-sitter';\nimport type {\n MergeAdapter,\n MergeStatement,\n MergeImport,\n DocstringInfo,\n SymbolDocstrings,\n MemberDocstrings,\n} from './types.js';\nimport { extractUrlFingerprint } from './url-fingerprint.js';\n\nconst DOTNET_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['string_literal', 'interpolated_string_expression'],\n contentNodeTypes: ['string_content', 'string_literal_content'],\n interpolationNodeTypes: ['interpolation'],\n};\n\nconst DECLARATION_TYPES = new Set([\n 'class_declaration',\n 'struct_declaration',\n 'interface_declaration',\n 'enum_declaration',\n 'record_declaration',\n]);\n\nfunction extractDeclarationName(node: Parser.SyntaxNode): string | null {\n if (DECLARATION_TYPES.has(node.type)) {\n const nameNode = node.childForFieldName('name') ?? node.children.find((c) => c.type === 'identifier');\n return nameNode?.text ?? null;\n }\n if (node.type === 'namespace_declaration' || node.type === 'file_scoped_namespace_declaration') {\n const nameNode =\n node.children.find((c) => c.type === 'qualified_name') ?? node.children.find((c) => c.type === 'identifier');\n return nameNode ? `__namespace:${nameNode.text}` : null;\n }\n return null;\n}\n\nfunction collectPrecedingXmlDocComments(\n children: Parser.SyntaxNode[],\n index: number,\n source: string,\n): DocstringInfo | null {\n let lastIdx = -1;\n let firstIdx = -1;\n for (let k = index - 1; k >= 0; k--) {\n const prev = children[k];\n if (prev.type === 'comment') {\n const text = source.slice(prev.startIndex, prev.endIndex);\n if (text.startsWith('///')) {\n if (lastIdx === -1) lastIdx = k;\n firstIdx = k;\n } else {\n break;\n }\n } else {\n break;\n }\n }\n if (firstIdx === -1) return null;\n const first = children[firstIdx];\n const last = children[lastIdx];\n return { text: source.slice(first.startIndex, last.endIndex), startIndex: first.startIndex, endIndex: last.endIndex };\n}\n\n/**\n * Collect declarations from a list of sibling nodes (root level or namespace body).\n */\nfunction collectDeclarations(\n children: Parser.SyntaxNode[],\n source: string,\n statements: MergeStatement[],\n imports: MergeImport[],\n importAnchors: string[],\n importInsertionAnchor: { value?: string },\n): void {\n for (const child of children) {\n if (child.type === 'comment') continue;\n\n if (child.type === 'using_directive') {\n const text = source.slice(child.startIndex, child.endIndex);\n imports.push({ key: text.trim(), text });\n importAnchors.push(text);\n continue;\n }\n\n if (child.type === 'file_scoped_namespace_declaration') {\n importInsertionAnchor.value = source.slice(child.startIndex, child.endIndex);\n // File-scoped namespace: subsequent declarations are siblings at root\n continue;\n }\n\n if (child.type === 'namespace_declaration') {\n importInsertionAnchor.value = source.slice(child.startIndex, child.endIndex);\n // Block namespace: recurse into declaration_list\n const body = child.children.find((c) => c.type === 'declaration_list');\n if (body) {\n collectDeclarations(body.namedChildren, source, statements, imports, importAnchors, importInsertionAnchor);\n }\n continue;\n }\n\n const name = extractDeclarationName(child);\n statements.push({\n key: name,\n kind: name ? 'declaration' : 'other',\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n}\n\nexport const dotnetMergeAdapter: MergeAdapter = {\n language: 'dotnet',\n grammarModule: 'tree-sitter-c-sharp',\n testFilePatterns: [/Tests?\\.cs$/],\n urlFingerprintConfig: DOTNET_URL_FINGERPRINT_CONFIG,\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n const statements: MergeStatement[] = [];\n const importInsertionAnchor: { value?: string } = {};\n\n collectDeclarations(tree.rootNode.children, source, statements, imports, importAnchors, importInsertionAnchor);\n\n return {\n imports,\n importAnchors,\n importInsertionAnchor: importInsertionAnchor.value,\n statements,\n };\n },\n renderImports(imports) {\n return imports.map((entry) => entry.text);\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n\n function processChildren(children: Parser.SyntaxNode[]): void {\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n\n // Recurse into namespaces\n if (child.type === 'namespace_declaration') {\n const body = child.children.find((c) => c.type === 'declaration_list');\n if (body) processChildren(body.children);\n continue;\n }\n\n const name = extractDeclarationName(child);\n if (!name || name.startsWith('__namespace:')) continue;\n\n const docstring = collectPrecedingXmlDocComments(children, i, source);\n const members = new Map<string, MemberDocstrings>();\n\n // Extract member docstrings\n const body = child.children.find((c) => c.type === 'declaration_list');\n if (body) {\n const bodyChildren = body.children;\n for (let j = 0; j < bodyChildren.length; j++) {\n const member = bodyChildren[j];\n if (member.type !== 'method_declaration' && member.type !== 'property_declaration') continue;\n // For methods, the second identifier is the name (first is return type)\n const identifiers = member.children.filter((c) => c.type === 'identifier');\n const memberName =\n member.type === 'method_declaration'\n ? identifiers.length >= 2\n ? identifiers[1]!.text\n : identifiers[0]?.text\n : identifiers[0]?.text;\n if (!memberName) continue;\n const memberDoc = collectPrecedingXmlDocComments(bodyChildren, j, source);\n members.set(memberName, {\n docstring: memberDoc,\n declStartIndex: member.startIndex,\n declColumn: member.startPosition.column,\n urlFingerprint: extractUrlFingerprint(member, DOTNET_URL_FINGERPRINT_CONFIG),\n });\n }\n }\n\n result.set(name, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members,\n });\n }\n }\n\n processChildren(tree.rootNode.children);\n return result;\n },\n};\n","import type Parser from 'tree-sitter';\nimport type {\n MergeAdapter,\n MergeStatement,\n MergeImport,\n DocstringInfo,\n SymbolDocstrings,\n MemberDocstrings,\n} from './types.js';\nimport { extractUrlFingerprint } from './url-fingerprint.js';\n\nconst ELIXIR_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['string'],\n contentNodeTypes: ['quoted_content'],\n interpolationNodeTypes: ['interpolation'],\n};\n\nfunction isDefmodule(node: Parser.SyntaxNode): boolean {\n return node.type === 'call' && node.children[0]?.text === 'defmodule';\n}\n\nfunction getModuleName(node: Parser.SyntaxNode): string | null {\n if (!isDefmodule(node)) return null;\n const args = node.children.find((c) => c.type === 'arguments');\n if (!args) return null;\n const alias = args.children.find((c) => c.type === 'alias');\n return alias?.text ?? null;\n}\n\nfunction getDoBlock(node: Parser.SyntaxNode): Parser.SyntaxNode | null {\n return node.children.find((c) => c.type === 'do_block') ?? null;\n}\n\n/** Check if a node is an @moduledoc or @doc attribute. */\nfunction isDocAttribute(node: Parser.SyntaxNode): string | null {\n if (node.type !== 'unary_operator') return null;\n const call = node.children.find((c) => c.type === 'call');\n if (!call) return null;\n const id = call.children.find((c) => c.type === 'identifier');\n if (id?.text === 'moduledoc' || id?.text === 'doc') return id.text;\n return null;\n}\n\n/** Check if a node is a def/defp call. */\nfunction getDefName(node: Parser.SyntaxNode): string | null {\n if (node.type !== 'call') return null;\n const id = node.children[0];\n if (!id || (id.text !== 'def' && id.text !== 'defp')) return null;\n const args = node.children.find((c) => c.type === 'arguments');\n if (!args) return null;\n // The function name is either a simple identifier or a call (for functions with params)\n for (const arg of args.namedChildren) {\n if (arg.type === 'identifier') return arg.text;\n if (arg.type === 'call') {\n const nameNode = arg.children.find((c) => c.type === 'identifier');\n return nameNode?.text ?? null;\n }\n }\n return null;\n}\n\n/** Check if a node is an alias/import/require/use call. */\nfunction isImportLike(node: Parser.SyntaxNode): boolean {\n if (node.type !== 'call') return false;\n const id = node.children[0];\n return id?.type === 'identifier' && ['alias', 'import', 'require', 'use'].includes(id.text);\n}\n\nexport const elixirMergeAdapter: MergeAdapter = {\n language: 'elixir',\n grammarModule: 'tree-sitter-elixir',\n testFilePatterns: [/_test\\.exs$/],\n urlFingerprintConfig: ELIXIR_URL_FINGERPRINT_CONFIG,\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n const statements: MergeStatement[] = [];\n\n for (const child of tree.rootNode.children) {\n if (child.type === 'comment') continue;\n\n // Top-level alias/import/require/use (rare but possible outside modules)\n if (isImportLike(child)) {\n const text = source.slice(child.startIndex, child.endIndex);\n imports.push({ key: text.trim(), text });\n importAnchors.push(text);\n continue;\n }\n\n const moduleName = getModuleName(child);\n statements.push({\n key: moduleName,\n kind: moduleName ? 'declaration' : 'other',\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n\n return { imports, importAnchors, statements };\n },\n renderImports(imports) {\n return imports.map((entry) => entry.text);\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n const rootChildren = tree.rootNode.children;\n\n for (let i = 0; i < rootChildren.length; i++) {\n const child = rootChildren[i];\n const moduleName = getModuleName(child);\n if (!moduleName) continue;\n\n // Look for @moduledoc inside the do_block\n let docstring: DocstringInfo | null = null;\n const doBlock = getDoBlock(child);\n const members = new Map<string, MemberDocstrings>();\n\n if (doBlock) {\n const bodyChildren = doBlock.children;\n\n // Find @moduledoc\n for (const bodyChild of bodyChildren) {\n if (isDocAttribute(bodyChild) === 'moduledoc') {\n docstring = {\n text: source.slice(bodyChild.startIndex, bodyChild.endIndex),\n startIndex: bodyChild.startIndex,\n endIndex: bodyChild.endIndex,\n };\n break;\n }\n }\n\n // Find @doc + def pairs for member docstrings\n for (let j = 0; j < bodyChildren.length; j++) {\n const bodyChild = bodyChildren[j];\n const defName = getDefName(bodyChild);\n if (!defName) continue;\n\n // Look for preceding @doc attribute\n let memberDoc: DocstringInfo | null = null;\n for (let k = j - 1; k >= 0; k--) {\n const prev = bodyChildren[k];\n if (isDocAttribute(prev) === 'doc') {\n memberDoc = {\n text: source.slice(prev.startIndex, prev.endIndex),\n startIndex: prev.startIndex,\n endIndex: prev.endIndex,\n };\n break;\n }\n if (prev.type === 'comment') continue;\n break;\n }\n\n members.set(defName, {\n docstring: memberDoc,\n declStartIndex: bodyChild.startIndex,\n declColumn: bodyChild.startPosition.column,\n urlFingerprint: extractUrlFingerprint(bodyChild, ELIXIR_URL_FINGERPRINT_CONFIG),\n });\n }\n }\n\n result.set(moduleName, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members,\n });\n }\n\n return result;\n },\n};\n","import type Parser from 'tree-sitter';\nimport type { MergeAdapter, MergeStatement, MergeImport, DocstringInfo, SymbolDocstrings } from './types.js';\n\nconst GO_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['interpreted_string_literal'],\n contentNodeTypes: ['interpreted_string_literal_content'],\n interpolationNodeTypes: [],\n formatFunctionNames: ['Sprintf'],\n};\n\nfunction lastIdentifier(text: string): string | null {\n const matches = [...text.matchAll(/[A-Za-z_][A-Za-z0-9_]*/g)];\n return matches.length > 0 ? matches[matches.length - 1]![0] : null;\n}\n\nfunction receiverKey(node: Parser.SyntaxNode): string | null {\n const receiver = node.childForFieldName('receiver');\n if (!receiver) return null;\n return lastIdentifier(receiver.text);\n}\n\nfunction declarationKey(node: Parser.SyntaxNode): string | null {\n switch (node.type) {\n case 'package_clause': {\n const pkg = lastIdentifier(node.text);\n return pkg ? `__package:${pkg}` : '__package:';\n }\n case 'type_declaration': {\n const spec = node.firstNamedChild?.type === 'type_spec' ? node.firstNamedChild : node.namedChildren[0];\n const nameNode = spec?.childForFieldName('name');\n return nameNode?.text ?? null;\n }\n case 'function_declaration': {\n return node.childForFieldName('name')?.text ?? null;\n }\n case 'method_declaration': {\n const name = node.childForFieldName('name')?.text ?? null;\n const receiver = receiverKey(node);\n return name && receiver ? `method:${receiver}.${name}` : name;\n }\n case 'const_declaration':\n case 'var_declaration': {\n return node.text.split(/\\s+/).slice(0, 3).join(' ');\n }\n default:\n return null;\n }\n}\n\nfunction importEntries(node: Parser.SyntaxNode, source: string): MergeImport[] {\n const entries: MergeImport[] = [];\n\n const collect = (spec: Parser.SyntaxNode): void => {\n const path = spec.childForFieldName('path')?.text ?? spec.text;\n const name = spec.childForFieldName('name')?.text ?? '';\n const text = source.slice(spec.startIndex, spec.endIndex);\n entries.push({\n key: `${name}:${path.replace(/^\"|\"$/g, '')}`,\n text,\n });\n };\n\n for (const child of node.namedChildren) {\n if (child.type === 'import_spec') {\n collect(child);\n continue;\n }\n if (child.type === 'import_spec_list') {\n for (const spec of child.namedChildren) {\n if (spec.type === 'import_spec') collect(spec);\n }\n }\n }\n\n return entries;\n}\n\nfunction collectPrecedingGoComments(\n children: Parser.SyntaxNode[],\n index: number,\n source: string,\n): DocstringInfo | null {\n let lastIdx = -1;\n let firstIdx = -1;\n for (let k = index - 1; k >= 0; k--) {\n const prev = children[k];\n if (prev.type === 'comment') {\n const text = source.slice(prev.startIndex, prev.endIndex);\n if (text.startsWith('//')) {\n if (lastIdx === -1) lastIdx = k;\n firstIdx = k;\n } else {\n break;\n }\n } else {\n break;\n }\n }\n if (firstIdx === -1) return null;\n const first = children[firstIdx];\n const last = children[lastIdx];\n return { text: source.slice(first.startIndex, last.endIndex), startIndex: first.startIndex, endIndex: last.endIndex };\n}\n\nexport const goMergeAdapter: MergeAdapter = {\n language: 'go',\n grammarModule: 'tree-sitter-go',\n testFilePatterns: [/_test\\.go$/],\n urlFingerprintConfig: GO_URL_FINGERPRINT_CONFIG,\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n let importInsertionAnchor: string | undefined;\n const statements: MergeStatement[] = [];\n\n for (const child of tree.rootNode.children) {\n if (child.type === 'comment') continue;\n\n if (child.type === 'package_clause') {\n importInsertionAnchor = source.slice(child.startIndex, child.endIndex);\n }\n\n if (child.type === 'import_declaration') {\n imports.push(...importEntries(child, source));\n importAnchors.push(source.slice(child.startIndex, child.endIndex));\n continue;\n }\n\n const key = declarationKey(child);\n statements.push({\n key,\n kind: key ? 'declaration' : 'other',\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n\n return { imports, importAnchors, importInsertionAnchor, statements };\n },\n renderImports(imports) {\n if (imports.length === 0) return [];\n if (imports.length === 1) return [`import ${imports[0]!.text}`];\n return [`import (\\n${imports.map((entry) => ` ${entry.text}`).join('\\n')}\\n)`];\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n const rootChildren = tree.rootNode.children;\n\n for (let i = 0; i < rootChildren.length; i++) {\n const child = rootChildren[i];\n const key = declarationKey(child);\n if (!key || key.startsWith('__package:')) continue;\n\n const docstring = collectPrecedingGoComments(rootChildren, i, source);\n result.set(key, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members: new Map(),\n });\n }\n\n return result;\n },\n};\n","import type Parser from 'tree-sitter';\nimport type {\n MergeAdapter,\n MergeStatement,\n MergeImport,\n MergeMember,\n DeepMergeSymbol,\n DocstringInfo,\n SymbolDocstrings,\n MemberDocstrings,\n} from './types.js';\nimport { extractUrlFingerprint } from './url-fingerprint.js';\n\nconst KOTLIN_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['string_literal'],\n contentNodeTypes: ['string_content'],\n interpolationNodeTypes: ['interpolated_expression'],\n};\n\nfunction extractDeclarationName(node: Parser.SyntaxNode): string | null {\n if (node.type === 'class_declaration') {\n // Handles class, data class, enum class, etc.\n const nameNode = node.children.find((c) => c.type === 'type_identifier');\n return nameNode?.text ?? null;\n }\n if (node.type === 'function_declaration') {\n const nameNode = node.children.find((c) => c.type === 'simple_identifier');\n return nameNode?.text ?? null;\n }\n if (node.type === 'object_declaration') {\n const nameNode = node.children.find((c) => c.type === 'type_identifier');\n return nameNode?.text ?? null;\n }\n if (node.type === 'type_alias') {\n const nameNode = node.children.find((c) => c.type === 'type_identifier');\n return nameNode?.text ?? null;\n }\n if (node.type === 'property_declaration') {\n const nameNode = node.children.find((c) => c.type === 'variable_declaration');\n if (nameNode) {\n const id = nameNode.children.find((c) => c.type === 'simple_identifier');\n return id?.text ?? null;\n }\n }\n return null;\n}\n\nfunction findPrecedingKdoc(children: Parser.SyntaxNode[], index: number, source: string): DocstringInfo | null {\n for (let k = index - 1; k >= 0; k--) {\n const prev = children[k];\n if (prev.type === 'multiline_comment') {\n const text = source.slice(prev.startIndex, prev.endIndex);\n if (text.startsWith('/**')) {\n return { text, startIndex: prev.startIndex, endIndex: prev.endIndex };\n }\n return null;\n }\n if (prev.type === 'line_comment') continue;\n return null;\n }\n return null;\n}\n\nfunction extractKotlinClassMembers(classBody: Parser.SyntaxNode, source: string): MergeMember[] {\n const members: MergeMember[] = [];\n const children = classBody.namedChildren;\n\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n let memberName: string | null = null;\n\n if (child.type === 'property_declaration') {\n const varDecl = child.children.find((c) => c.type === 'variable_declaration');\n memberName = varDecl?.children.find((c) => c.type === 'simple_identifier')?.text ?? null;\n } else if (child.type === 'function_declaration') {\n memberName = child.children.find((c) => c.type === 'simple_identifier')?.text ?? null;\n } else if (child.type === 'companion_object') {\n memberName = 'companion';\n }\n\n if (!memberName) continue;\n\n // Fold trailing getter/setter into the property's text span\n let endIdx = child.endIndex;\n if (child.type === 'property_declaration') {\n while (i + 1 < children.length) {\n const next = children[i + 1];\n if (next.type === 'getter' || next.type === 'setter') {\n endIdx = next.endIndex;\n i++;\n } else {\n break;\n }\n }\n }\n\n // Include preceding KDoc comment in the text span so deep merge\n // inserts the member with its documentation intact.\n let startIdx = child.startIndex;\n for (let k = i - 1; k >= 0; k--) {\n const prev = children[k];\n if (prev.type === 'multiline_comment') {\n const text = source.slice(prev.startIndex, prev.endIndex);\n if (text.startsWith('/**')) startIdx = prev.startIndex;\n break;\n }\n if (prev.type === 'line_comment') continue;\n break;\n }\n\n members.push({ key: memberName, text: source.slice(startIdx, endIdx), startIndex: startIdx, endIndex: endIdx });\n }\n\n return members;\n}\n\n/**\n * KDoc signature that identifies a generator-emitted service accessor inside\n * the WorkOS class. The Kotlin client emitter writes every accessor with this\n * exact doc preamble — when the existing file carries a member with this doc\n * but the regenerated content omits it, the member is stale (its mount target\n * was remapped or removed) and gets pruned.\n */\nconst KOTLIN_MANAGED_ACCESSOR_DOC =\n /\\/\\*\\*[\\s\\S]*?Lazily-constructed \\[[^\\]]+\\] accessor for this \\[WorkOS\\] client\\.[\\s\\S]*?\\*\\//;\n\nexport const kotlinMergeAdapter: MergeAdapter = {\n language: 'kotlin',\n grammarModule: 'tree-sitter-kotlin',\n testFilePatterns: [/Test\\.kt$/],\n urlFingerprintConfig: KOTLIN_URL_FINGERPRINT_CONFIG,\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n const statements: MergeStatement[] = [];\n\n for (const child of tree.rootNode.children) {\n if (child.type === 'multiline_comment' || child.type === 'line_comment') continue;\n\n if (child.type === 'import_list') {\n const fullText = source.slice(child.startIndex, child.endIndex);\n importAnchors.push(fullText);\n for (const imp of child.namedChildren) {\n if (imp.type === 'import_header') {\n const text = source.slice(imp.startIndex, imp.endIndex).trim();\n // Key on the full import path\n const idNode = imp.children.find((c) => c.type === 'identifier');\n const key = idNode?.text ?? text;\n imports.push({ key, text });\n }\n }\n continue;\n }\n\n const name = extractDeclarationName(child);\n statements.push({\n key: name,\n kind: name ? 'declaration' : 'other',\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n\n return { imports, importAnchors, statements };\n },\n renderImports(imports) {\n return imports.map((entry) => entry.text);\n },\n isManagedMember(member) {\n return KOTLIN_MANAGED_ACCESSOR_DOC.test(member.text);\n },\n shouldSkipDeepMerge(_symbolName, existingMemberKeys, newMembers) {\n // Skip if new members reference instance properties that don't exist in the target\n const newText = newMembers.map((m) => m.text).join('\\n');\n for (const match of newText.matchAll(/this\\.(\\w+)/g)) {\n const propName = match[1];\n if (propName && !existingMemberKeys.has(propName)) return true;\n }\n return false;\n },\n extractMembers(tree, source) {\n const result = new Map<string, DeepMergeSymbol>();\n\n for (const child of tree.rootNode.children) {\n if (child.type !== 'class_declaration') continue;\n const nameNode = child.children.find((c) => c.type === 'type_identifier');\n if (!nameNode) continue;\n const body = child.children.find((c) => c.type === 'class_body');\n if (!body) continue;\n\n const members = extractKotlinClassMembers(body, source);\n const firstMember = body.firstNamedChild;\n const memberIndent = firstMember ? ' '.repeat(firstMember.startPosition.column) : undefined;\n result.set(nameNode.text, { members, bodyEndLine: body.endPosition.row, memberIndent });\n }\n\n return result;\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n const rootChildren = tree.rootNode.children;\n\n for (let i = 0; i < rootChildren.length; i++) {\n const child = rootChildren[i];\n const name = extractDeclarationName(child);\n if (!name) continue;\n\n const docstring = findPrecedingKdoc(rootChildren, i, source);\n const members = new Map<string, MemberDocstrings>();\n\n // Extract member docstrings for classes\n if (child.type === 'class_declaration') {\n const body = child.children.find((c) => c.type === 'class_body' || c.type === 'enum_class_body');\n if (body) {\n const bodyChildren = body.children;\n for (let j = 0; j < bodyChildren.length; j++) {\n const member = bodyChildren[j];\n const memberName = extractDeclarationName(member);\n if (!memberName) continue;\n const memberDoc = findPrecedingKdoc(bodyChildren, j, source);\n members.set(memberName, {\n docstring: memberDoc,\n declStartIndex: member.startIndex,\n declColumn: member.startPosition.column,\n urlFingerprint: extractUrlFingerprint(member, KOTLIN_URL_FINGERPRINT_CONFIG),\n });\n }\n }\n }\n\n result.set(name, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members,\n });\n }\n\n return result;\n },\n};\n","import type Parser from 'tree-sitter';\nimport { normalizeJsExtension } from '../../utils/naming.js';\nimport type {\n MergeAdapter,\n MergeStatement,\n MergeImport,\n DeepMergeSymbol,\n MergeMember,\n DocstringInfo,\n SymbolDocstrings,\n} from './types.js';\nimport { extractUrlFingerprint } from './url-fingerprint.js';\n\nconst REEXPORT_PREFIX = '__export:';\n\nfunction extractDeclName(node: Parser.SyntaxNode): string | null {\n const nameNode = node.childForFieldName('name');\n if (nameNode) return nameNode.text;\n\n if (node.type === 'lexical_declaration') {\n const declarator = node.firstNamedChild;\n if (declarator?.type === 'variable_declarator') {\n const name = declarator.childForFieldName('name');\n if (name) return name.text;\n }\n }\n\n return null;\n}\n\nfunction extractNodeKey(node: Parser.SyntaxNode): { key: string | null; kind: MergeStatement['kind'] } {\n if (node.type === 'export_statement') {\n const decl = node.childForFieldName('declaration');\n if (decl) {\n return { key: extractDeclName(decl), kind: 'declaration' };\n }\n\n const source = node.childForFieldName('source');\n if (source) {\n return { key: `${REEXPORT_PREFIX}${normalizeJsExtension(source.text)}`, kind: 'reexport' };\n }\n\n return { key: null, kind: 'other' };\n }\n return { key: extractDeclName(node), kind: extractDeclName(node) ? 'declaration' : 'other' };\n}\n\nfunction extractClassMembers(classBody: Parser.SyntaxNode, source: string): MergeMember[] {\n const members: MergeMember[] = [];\n for (const child of classBody.namedChildren) {\n if (child.type === 'method_definition') {\n const nameNode = child.childForFieldName('name');\n if (nameNode && nameNode.text !== 'constructor') {\n members.push({ key: nameNode.text, text: source.slice(child.startIndex, child.endIndex) });\n }\n } else if (child.type === 'public_field_definition') {\n const nameNode = child.childForFieldName('name');\n if (nameNode) {\n // tree-sitter may exclude the trailing semicolon from\n // public_field_definition nodes — include it if present\n let endIdx = child.endIndex;\n if (source[endIdx] === ';') {\n endIdx += 1;\n }\n members.push({ key: nameNode.text, text: source.slice(child.startIndex, endIdx) });\n }\n }\n }\n return members;\n}\n\nfunction extractInterfaceMembers(body: Parser.SyntaxNode, source: string): MergeMember[] {\n const members: MergeMember[] = [];\n for (const child of body.namedChildren) {\n if (child.type === 'property_signature' || child.type === 'method_signature') {\n const nameNode = child.childForFieldName('name');\n if (nameNode) {\n members.push({ key: nameNode.text, text: source.slice(child.startIndex, child.endIndex) });\n }\n }\n }\n return members;\n}\n\nfunction extractEnumMembers(body: Parser.SyntaxNode, source: string): MergeMember[] {\n const members: MergeMember[] = [];\n for (const child of body.namedChildren) {\n if (child.type === 'enum_assignment') {\n const nameNode = child.childForFieldName('name');\n if (nameNode) {\n members.push({ key: nameNode.text, text: source.slice(child.startIndex, child.endIndex) });\n }\n } else if (child.type === 'property_identifier') {\n members.push({ key: child.text, text: source.slice(child.startIndex, child.endIndex) });\n }\n }\n return members;\n}\n\nfunction isCommentNode(node: Parser.SyntaxNode): boolean {\n // tree-sitter extras (comments) may report the parent node's type\n // instead of 'comment' — check grammarType as fallback\n return node.type === 'comment' || (node as any).grammarType === 'comment';\n}\n\nfunction findPrecedingDocstring(children: Parser.SyntaxNode[], index: number, source: string): DocstringInfo | null {\n for (let k = index - 1; k >= 0; k--) {\n const prev = children[k];\n if (isCommentNode(prev)) {\n const text = source.slice(prev.startIndex, prev.endIndex);\n if (text.startsWith('/**')) {\n return { text, startIndex: prev.startIndex, endIndex: prev.endIndex };\n }\n return null;\n }\n if (prev.type === ',' || prev.type === ';' || prev.type === '{') continue;\n return null;\n }\n return null;\n}\n\nconst CLASS_MEMBER_TYPES = new Set(['method_definition', 'public_field_definition']);\nconst INTERFACE_MEMBER_TYPES = new Set(['property_signature', 'method_signature']);\nconst ENUM_MEMBER_TYPES = new Set(['enum_assignment', 'property_identifier']);\n\nconst NODE_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['string', 'template_string'],\n contentNodeTypes: ['string_fragment'],\n interpolationNodeTypes: ['template_substitution'],\n};\n\nfunction extractBodyMemberDocstrings(\n body: Parser.SyntaxNode,\n source: string,\n memberTypes: Set<string>,\n): Map<\n string,\n { docstring: DocstringInfo | null; declStartIndex: number; declColumn: number; urlFingerprint?: string }\n> {\n const result = new Map<\n string,\n { docstring: DocstringInfo | null; declStartIndex: number; declColumn: number; urlFingerprint?: string }\n >();\n const allChildren = body.children;\n for (let i = 0; i < allChildren.length; i++) {\n const child = allChildren[i];\n if (!memberTypes.has(child.type)) continue;\n let memberName: string | null = null;\n if (child.type === 'property_identifier') {\n memberName = child.text;\n } else {\n const nameNode = child.childForFieldName('name');\n if (nameNode) memberName = nameNode.text;\n }\n if (!memberName || memberName === 'constructor') continue;\n const docstring = findPrecedingDocstring(allChildren, i, source);\n const fp = extractUrlFingerprint(child, NODE_URL_FINGERPRINT_CONFIG);\n result.set(memberName, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n urlFingerprint: fp,\n });\n }\n return result;\n}\n\nexport const nodeMergeAdapter: MergeAdapter = {\n language: 'node',\n grammarModule: 'tree-sitter-typescript/bindings/node/typescript.js',\n normalizeReexport: normalizeJsExtension,\n testFilePatterns: [/\\.(spec|test)\\.[jt]sx?$/],\n urlFingerprintConfig: NODE_URL_FINGERPRINT_CONFIG,\n shouldSkipDeepMerge(_symbolName, existingMemberKeys, newMembers) {\n // If new members reference instance properties (this.X) that don't exist\n // in the target class, the merged code would be broken.\n // Exception: `this.workos` is always valid — it's the constructor-injected\n // WorkOS client instance that every generated resource class uses.\n const newText = newMembers.map((m) => m.text).join('\\n');\n for (const match of newText.matchAll(/this\\.(\\w+)/g)) {\n const propName = match[1];\n if (propName === 'workos') continue;\n if (propName && !existingMemberKeys.has(propName)) {\n return true;\n }\n }\n return false;\n },\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n const statements: MergeStatement[] = [];\n\n for (const child of tree.rootNode.children) {\n if (child.type === 'comment') continue;\n\n if (child.type === 'import_statement') {\n const text = source.slice(child.startIndex, child.endIndex);\n // Key on module path so `import { X }` and `import type { X }` from\n // the same module are treated as duplicates\n const sourceNode = child.childForFieldName('source');\n const modulePath = sourceNode ? normalizeJsExtension(sourceNode.text) : normalizeJsExtension(text.trim());\n imports.push({ key: modulePath, text });\n importAnchors.push(text);\n continue;\n }\n\n const { key, kind } = extractNodeKey(child);\n statements.push({\n key,\n kind,\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n\n return { imports, importAnchors, statements };\n },\n renderImports(imports) {\n return imports.map((entry) => entry.text);\n },\n extractMembers(tree, source) {\n const result = new Map<string, DeepMergeSymbol>();\n\n for (const child of tree.rootNode.children) {\n if (child.type !== 'export_statement') continue;\n const decl = child.childForFieldName('declaration');\n if (!decl) continue;\n\n const nameNode = decl.childForFieldName('name');\n if (!nameNode) continue;\n const symbolName = nameNode.text;\n\n if (decl.type === 'class_declaration') {\n const body = decl.childForFieldName('body');\n if (!body) continue;\n const members = extractClassMembers(body, source);\n const firstMember = body.firstNamedChild;\n const memberIndent = firstMember ? ' '.repeat(firstMember.startPosition.column) : undefined;\n result.set(symbolName, { members, bodyEndLine: body.endPosition.row, memberIndent });\n } else if (decl.type === 'interface_declaration') {\n const body = decl.childForFieldName('body');\n if (!body) continue;\n const members = extractInterfaceMembers(body, source);\n const firstMember = body.firstNamedChild;\n const memberIndent = firstMember ? ' '.repeat(firstMember.startPosition.column) : undefined;\n result.set(symbolName, { members, bodyEndLine: body.endPosition.row, memberIndent });\n } else if (decl.type === 'enum_declaration') {\n const body = decl.childForFieldName('body');\n if (!body) continue;\n const members = extractEnumMembers(body, source);\n const firstMember = body.firstNamedChild;\n const memberIndent = firstMember ? ' '.repeat(firstMember.startPosition.column) : undefined;\n result.set(symbolName, { members, bodyEndLine: body.endPosition.row, memberIndent });\n }\n }\n\n return result;\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n const rootChildren = tree.rootNode.children;\n\n for (let i = 0; i < rootChildren.length; i++) {\n const child = rootChildren[i];\n if (child.type !== 'export_statement') continue;\n const decl = child.childForFieldName('declaration');\n if (!decl) continue;\n const nameNode = decl.childForFieldName('name');\n if (!nameNode) continue;\n\n // Find preceding JSDoc for this top-level symbol\n const docstring = findPrecedingDocstring(rootChildren, i, source);\n\n // Extract member-level docstrings\n let members = new Map<string, { docstring: DocstringInfo | null; declStartIndex: number; declColumn: number }>();\n const body = decl.childForFieldName('body');\n if (body) {\n if (decl.type === 'class_declaration') {\n members = extractBodyMemberDocstrings(body, source, CLASS_MEMBER_TYPES);\n } else if (decl.type === 'interface_declaration') {\n members = extractBodyMemberDocstrings(body, source, INTERFACE_MEMBER_TYPES);\n } else if (decl.type === 'enum_declaration') {\n members = extractBodyMemberDocstrings(body, source, ENUM_MEMBER_TYPES);\n }\n }\n\n result.set(nameNode.text, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members,\n });\n }\n\n return result;\n },\n};\n","import type Parser from 'tree-sitter';\nimport type {\n MergeAdapter,\n MergeStatement,\n MergeImport,\n DocstringInfo,\n SymbolDocstrings,\n MemberDocstrings,\n} from './types.js';\nimport { extractUrlFingerprint } from './url-fingerprint.js';\n\nconst PHP_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['encapsed_string', 'string'],\n contentNodeTypes: ['string_content'],\n interpolationNodeTypes: ['variable_name'],\n};\n\nfunction extractPhpDeclarationName(node: Parser.SyntaxNode): string | null {\n switch (node.type) {\n case 'class_declaration':\n case 'interface_declaration':\n case 'trait_declaration':\n case 'enum_declaration':\n case 'function_definition': {\n const nameNode = node.childForFieldName('name');\n return nameNode?.text ?? null;\n }\n case 'namespace_definition': {\n const nameNode = node.childForFieldName('name');\n return nameNode ? `__namespace:${nameNode.text}` : '__namespace:';\n }\n default:\n return null;\n }\n}\n\nfunction findPhpDocstring(children: Parser.SyntaxNode[], index: number, source: string): DocstringInfo | null {\n for (let k = index - 1; k >= 0; k--) {\n const prev = children[k];\n if (prev.type === 'comment') {\n const text = source.slice(prev.startIndex, prev.endIndex);\n if (text.startsWith('/**')) {\n return { text, startIndex: prev.startIndex, endIndex: prev.endIndex };\n }\n return null;\n }\n if (prev.type === ';' || prev.type === '{') continue;\n return null;\n }\n return null;\n}\n\nexport const phpMergeAdapter: MergeAdapter = {\n language: 'php',\n grammarModule: 'tree-sitter-php',\n testFilePatterns: [/Test\\.php$/],\n urlFingerprintConfig: PHP_URL_FINGERPRINT_CONFIG,\n resolveGrammar: (mod) => {\n // ESM import wraps in { default: { php, php_only } }\n const m = (mod as Record<string, unknown>)?.default ?? mod;\n if (typeof m === 'object' && m !== null && 'php' in (m as Record<string, unknown>))\n return (m as { php: unknown }).php;\n return m;\n },\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n let importInsertionAnchor: string | undefined;\n const statements: MergeStatement[] = [];\n\n for (const child of tree.rootNode.children) {\n if (child.type === 'comment') continue;\n\n if (child.type === 'namespace_definition') {\n importInsertionAnchor = source.slice(child.startIndex, child.endIndex);\n }\n\n if (child.type === 'namespace_use_declaration') {\n const text = source.slice(child.startIndex, child.endIndex);\n imports.push({ key: text.trim(), text });\n importAnchors.push(text);\n continue;\n }\n\n const declarationName = extractPhpDeclarationName(child);\n const kind: MergeStatement['kind'] = declarationName ? 'declaration' : 'other';\n\n statements.push({\n key: declarationName,\n kind,\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n\n return { imports, importAnchors, importInsertionAnchor, statements };\n },\n renderImports(imports) {\n return imports.map((entry) => entry.text);\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n const rootChildren = tree.rootNode.children;\n\n for (let i = 0; i < rootChildren.length; i++) {\n const child = rootChildren[i];\n const name = extractPhpDeclarationName(child);\n if (!name || name.startsWith('__namespace:')) continue;\n\n const docstring = findPhpDocstring(rootChildren, i, source);\n const members = new Map<string, MemberDocstrings>();\n\n const body = child.childForFieldName('body');\n if (body) {\n const bodyChildren = body.children;\n for (let j = 0; j < bodyChildren.length; j++) {\n const member = bodyChildren[j];\n if (member.type !== 'method_declaration') continue;\n const memberName = member.childForFieldName('name')?.text;\n if (!memberName) continue;\n const memberDoc = findPhpDocstring(bodyChildren, j, source);\n members.set(memberName, {\n docstring: memberDoc,\n declStartIndex: member.startIndex,\n declColumn: member.startPosition.column,\n urlFingerprint: extractUrlFingerprint(member, PHP_URL_FINGERPRINT_CONFIG),\n });\n }\n }\n\n result.set(name, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members,\n });\n }\n\n return result;\n },\n};\n","import type Parser from 'tree-sitter';\nimport type {\n MergeAdapter,\n MergeStatement,\n MergeImport,\n DocstringInfo,\n SymbolDocstrings,\n MemberDocstrings,\n} from './types.js';\nimport { extractUrlFingerprint } from './url-fingerprint.js';\n\nconst PYTHON_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['string'],\n contentNodeTypes: ['string_content'],\n interpolationNodeTypes: ['interpolation'],\n};\n\nfunction extractPythonDeclarationName(node: Parser.SyntaxNode): string | null {\n if (node.type === 'class_definition' || node.type === 'function_definition') {\n const nameNode = node.childForFieldName('name');\n return nameNode?.text ?? null;\n }\n\n // Detect `__all__ = [...]` assignments so they get a key and can be deduplicated\n if (node.type === 'expression_statement') {\n const firstChild = node.firstNamedChild;\n if (firstChild?.type === 'assignment') {\n const left = firstChild.childForFieldName('left');\n if (left?.type === 'identifier' && left.text === '__all__') {\n return '__all__';\n }\n }\n }\n\n return null;\n}\n\nfunction extractPythonDocstring(bodyNode: Parser.SyntaxNode, source: string): DocstringInfo | null {\n // Python docstrings are the first expression_statement in a body block\n // where the expression is a string literal\n for (const child of bodyNode.namedChildren) {\n if (child.type === 'expression_statement') {\n const expr = child.firstNamedChild;\n if (expr?.type === 'string') {\n const text = source.slice(child.startIndex, child.endIndex);\n return { text, startIndex: child.startIndex, endIndex: child.endIndex };\n }\n }\n // Only the FIRST statement can be a docstring\n break;\n }\n return null;\n}\n\nfunction collectPrecedingPythonComments(\n children: Parser.SyntaxNode[],\n index: number,\n source: string,\n): DocstringInfo | null {\n let lastIdx = -1;\n let firstIdx = -1;\n for (let k = index - 1; k >= 0; k--) {\n const prev = children[k];\n if (prev.type === 'comment') {\n if (lastIdx === -1) lastIdx = k;\n firstIdx = k;\n } else {\n break;\n }\n }\n if (firstIdx === -1) return null;\n const first = children[firstIdx];\n const last = children[lastIdx];\n return { text: source.slice(first.startIndex, last.endIndex), startIndex: first.startIndex, endIndex: last.endIndex };\n}\n\nexport const pythonMergeAdapter: MergeAdapter = {\n language: 'python',\n grammarModule: 'tree-sitter-python',\n testFilePatterns: [/(?:^|\\/)test_.*\\.py$/, /_test\\.py$/],\n urlFingerprintConfig: PYTHON_URL_FINGERPRINT_CONFIG,\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n const statements: MergeStatement[] = [];\n\n for (const child of tree.rootNode.children) {\n if (child.type === 'comment') continue;\n\n if (child.type === 'import_statement' || child.type === 'import_from_statement') {\n const text = source.slice(child.startIndex, child.endIndex);\n imports.push({ key: text.trim(), text });\n importAnchors.push(text);\n continue;\n }\n\n const declarationName = extractPythonDeclarationName(child);\n const kind: MergeStatement['kind'] = declarationName ? 'declaration' : 'other';\n\n statements.push({\n key: declarationName,\n kind,\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n\n return { imports, importAnchors, statements };\n },\n renderImports(imports) {\n return imports.map((entry) => entry.text);\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n const rootChildren = tree.rootNode.children;\n\n for (let i = 0; i < rootChildren.length; i++) {\n const child = rootChildren[i];\n const name = extractPythonDeclarationName(child);\n if (!name) continue;\n\n // Python: class/function docstrings are inside the body, OR use # comments before\n let docstring: DocstringInfo | null = null;\n const body = child.childForFieldName('body');\n if (body) {\n docstring = extractPythonDocstring(body, source);\n }\n // Fallback: check for # comments before the declaration\n if (!docstring) {\n docstring = collectPrecedingPythonComments(rootChildren, i, source);\n }\n\n const members = new Map<string, MemberDocstrings>();\n\n // Extract method docstrings for classes\n if (child.type === 'class_definition' && body) {\n for (const member of body.namedChildren) {\n if (member.type !== 'function_definition') continue;\n const memberName = member.childForFieldName('name')?.text;\n if (!memberName) continue;\n\n let memberDoc: DocstringInfo | null = null;\n const memberBody = member.childForFieldName('body');\n if (memberBody) {\n memberDoc = extractPythonDocstring(memberBody, source);\n }\n\n members.set(memberName, {\n docstring: memberDoc,\n declStartIndex: member.startIndex,\n declColumn: member.startPosition.column,\n urlFingerprint: extractUrlFingerprint(member, PYTHON_URL_FINGERPRINT_CONFIG),\n });\n }\n }\n\n result.set(name, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members,\n });\n }\n\n return result;\n },\n};\n","import type Parser from 'tree-sitter';\nimport type {\n MergeAdapter,\n MergeStatement,\n MergeImport,\n DocstringInfo,\n SymbolDocstrings,\n MemberDocstrings,\n} from './types.js';\nimport { extractUrlFingerprint } from './url-fingerprint.js';\n\nconst RUBY_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['string'],\n contentNodeTypes: ['string_content'],\n interpolationNodeTypes: ['interpolation'],\n};\n\nfunction isRequireCall(node: Parser.SyntaxNode): boolean {\n if (node.type !== 'call') return false;\n const method = node.childForFieldName('method');\n if (!method) return false;\n return method.text === 'require' || method.text === 'require_relative';\n}\n\nfunction extractRubyDeclarationName(node: Parser.SyntaxNode): string | null {\n if (node.type !== 'class' && node.type !== 'module') return null;\n const nameNode = node.childForFieldName('name');\n return nameNode?.text ?? null;\n}\n\nfunction collectPrecedingRubyComments(\n children: Parser.SyntaxNode[],\n index: number,\n source: string,\n): DocstringInfo | null {\n let lastIdx = -1;\n let firstIdx = -1;\n for (let k = index - 1; k >= 0; k--) {\n const prev = children[k];\n const nodeType = (prev as any).grammarType ?? prev.type;\n if (nodeType === 'comment') {\n const text = source.slice(prev.startIndex, prev.endIndex);\n if (text.startsWith('#')) {\n if (lastIdx === -1) lastIdx = k;\n firstIdx = k;\n } else {\n break;\n }\n } else {\n break;\n }\n }\n if (firstIdx === -1) return null;\n const first = children[firstIdx];\n const last = children[lastIdx];\n return { text: source.slice(first.startIndex, last.endIndex), startIndex: first.startIndex, endIndex: last.endIndex };\n}\n\nexport const rubyMergeAdapter: MergeAdapter = {\n language: 'ruby',\n grammarModule: 'tree-sitter-ruby',\n testFilePatterns: [/_test\\.rb$/, /_spec\\.rb$/],\n urlFingerprintConfig: RUBY_URL_FINGERPRINT_CONFIG,\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n const statements: MergeStatement[] = [];\n\n for (const child of tree.rootNode.children) {\n if (child.type === 'comment') continue;\n\n const declarationName = extractRubyDeclarationName(child);\n if (isRequireCall(child)) {\n const text = source.slice(child.startIndex, child.endIndex);\n imports.push({ key: text.trim(), text });\n importAnchors.push(text);\n continue;\n }\n\n const kind: MergeStatement['kind'] = declarationName ? 'declaration' : 'other';\n\n statements.push({\n key: declarationName,\n kind,\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n\n return { imports, importAnchors, statements };\n },\n renderImports(imports) {\n return imports.map((entry) => entry.text);\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n const rootChildren = tree.rootNode.children;\n\n for (let i = 0; i < rootChildren.length; i++) {\n const child = rootChildren[i];\n const name = extractRubyDeclarationName(child);\n if (!name) continue;\n\n const docstring = collectPrecedingRubyComments(rootChildren, i, source);\n const members = new Map<string, MemberDocstrings>();\n\n // Ruby class/module bodies: comments may appear in class children\n // (before body_statement) or in body_statement children (between methods)\n if (child.type === 'class' || child.type === 'module') {\n const allClassChildren = child.children;\n const body = child.childForFieldName('body');\n\n // Check for comment before body_statement in class children\n // (docstring for the first method)\n let firstMethodDocFromClass: DocstringInfo | null = null;\n for (let j = 0; j < allClassChildren.length; j++) {\n if (allClassChildren[j] === body || allClassChildren[j].type === 'body_statement') {\n firstMethodDocFromClass = collectPrecedingRubyComments(allClassChildren, j, source);\n break;\n }\n }\n\n if (body) {\n const bodyChildren = body.children;\n let firstMethodHandled = false;\n for (let j = 0; j < bodyChildren.length; j++) {\n const member = bodyChildren[j];\n if (member.type !== 'method') continue;\n const memberName = member.childForFieldName('name')?.text;\n if (!memberName) continue;\n\n let memberDoc: DocstringInfo | null;\n if (!firstMethodHandled && firstMethodDocFromClass) {\n memberDoc = firstMethodDocFromClass;\n firstMethodHandled = true;\n } else {\n memberDoc = collectPrecedingRubyComments(bodyChildren, j, source);\n firstMethodHandled = true;\n }\n\n members.set(memberName, {\n docstring: memberDoc,\n declStartIndex: member.startIndex,\n declColumn: member.startPosition.column,\n urlFingerprint: extractUrlFingerprint(member, RUBY_URL_FINGERPRINT_CONFIG),\n });\n }\n }\n }\n\n result.set(name, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members,\n });\n }\n\n return result;\n },\n};\n","import type Parser from 'tree-sitter';\nimport type { MergeAdapter, MergeStatement, MergeImport, DocstringInfo, SymbolDocstrings } from './types.js';\n\nconst RUST_URL_FINGERPRINT_CONFIG = {\n stringNodeTypes: ['string_literal'],\n contentNodeTypes: ['string_content'],\n interpolationNodeTypes: [],\n};\n\nfunction declarationKey(node: Parser.SyntaxNode): string | null {\n switch (node.type) {\n case 'struct_item':\n case 'enum_item':\n case 'function_item':\n case 'trait_item':\n case 'type_item':\n case 'const_item': {\n return node.childForFieldName('name')?.text ?? null;\n }\n case 'impl_item': {\n const typeName = node.childForFieldName('type')?.text ?? 'unknown';\n const traitName = node.childForFieldName('trait')?.text;\n return traitName ? `impl:${traitName}->${typeName}` : `impl:${typeName}`;\n }\n default:\n return null;\n }\n}\n\nfunction collectPrecedingRustDocComments(\n children: Parser.SyntaxNode[],\n index: number,\n source: string,\n): DocstringInfo | null {\n let lastIdx = -1;\n let firstIdx = -1;\n for (let k = index - 1; k >= 0; k--) {\n const prev = children[k];\n if (prev.type === 'line_comment') {\n const text = source.slice(prev.startIndex, prev.endIndex);\n if (text.startsWith('///')) {\n if (lastIdx === -1) lastIdx = k;\n firstIdx = k;\n } else {\n break;\n }\n } else {\n break;\n }\n }\n if (firstIdx === -1) return null;\n const first = children[firstIdx];\n const last = children[lastIdx];\n return { text: source.slice(first.startIndex, last.endIndex), startIndex: first.startIndex, endIndex: last.endIndex };\n}\n\nexport const rustMergeAdapter: MergeAdapter = {\n language: 'rust',\n grammarModule: 'tree-sitter-rust',\n testFilePatterns: [/_test\\.rs$/, /(?:^|\\/)tests\\/.*\\.rs$/],\n urlFingerprintConfig: RUST_URL_FINGERPRINT_CONFIG,\n parseStatements(tree, source) {\n const imports: MergeImport[] = [];\n const importAnchors: string[] = [];\n const statements: MergeStatement[] = [];\n\n for (const child of tree.rootNode.children) {\n if (child.type === 'comment') continue;\n\n if (child.type === 'use_declaration') {\n const text = source.slice(child.startIndex, child.endIndex);\n imports.push({ key: text.trim(), text });\n importAnchors.push(text);\n continue;\n }\n\n const key = declarationKey(child);\n statements.push({\n key,\n kind: key ? 'declaration' : 'other',\n text: source.slice(child.startIndex, child.endIndex),\n });\n }\n\n return { imports, importAnchors, statements };\n },\n renderImports(imports) {\n return imports.map((entry) => entry.text);\n },\n extractDocstrings(tree, source) {\n const result = new Map<string, SymbolDocstrings>();\n const rootChildren = tree.rootNode.children;\n\n for (let i = 0; i < rootChildren.length; i++) {\n const child = rootChildren[i];\n const key = declarationKey(child);\n if (!key) continue;\n\n const docstring = collectPrecedingRustDocComments(rootChildren, i, source);\n result.set(key, {\n docstring,\n declStartIndex: child.startIndex,\n declColumn: child.startPosition.column,\n members: new Map(),\n });\n }\n\n return result;\n },\n};\n","import type { MergeAdapter } from './types.js';\nimport { dotnetMergeAdapter } from './dotnet.js';\nimport { elixirMergeAdapter } from './elixir.js';\nimport { goMergeAdapter } from './go.js';\nimport { kotlinMergeAdapter } from './kotlin.js';\nimport { nodeMergeAdapter } from './node.js';\nimport { phpMergeAdapter } from './php.js';\nimport { pythonMergeAdapter } from './python.js';\nimport { rubyMergeAdapter } from './ruby.js';\nimport { rustMergeAdapter } from './rust.js';\n\nconst adapters = new Map<string, MergeAdapter>([\n ['dotnet', dotnetMergeAdapter],\n ['elixir', elixirMergeAdapter],\n ['go', goMergeAdapter],\n ['kotlin', kotlinMergeAdapter],\n ['node', nodeMergeAdapter],\n ['php', phpMergeAdapter],\n ['python', pythonMergeAdapter],\n ['ruby', rubyMergeAdapter],\n ['rust', rustMergeAdapter],\n]);\n\nexport function getMergeAdapter(language: string): MergeAdapter | undefined {\n return adapters.get(language);\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","/**\n * AST-level file merger using tree-sitter.\n *\n * When generating into a directory that already contains files, the merger\n * parses both the existing and generated content, detects top-level symbols,\n * and only appends symbols that don't already exist. Hand-written code is\n * never modified or removed.\n *\n * Supports any language with a tree-sitter grammar package.\n */\n\nimport Parser from 'tree-sitter';\nimport { getMergeAdapter } from './merge-adapters/index.js';\nimport type { MergeImport, ParsedMergeFile, SymbolDocstrings } from './merge-adapters/types.js';\n\n// Cache parser instances per language\nconst parserCache = new Map<string, Parser>();\n\nimport { safeParse } from '../utils/tree-sitter.js';\n\n// --- @deprecated preservation ---\n\n/**\n * When replacing an existing docstring with a generated one, carry over any\n * `@deprecated` lines from the existing doc that aren't present in the\n * generated doc. This prevents hand-written deprecation notices from being\n * silently dropped during docstring refresh.\n */\nfunction preserveDeprecatedTags(existingDoc: string, generatedDoc: string): string {\n // Check if the existing docstring contains @deprecated anywhere\n if (!existingDoc.includes('@deprecated')) return generatedDoc;\n\n // If generated doc already has @deprecated, no need to merge\n if (generatedDoc.includes('@deprecated')) return generatedDoc;\n\n // Extract the @deprecated content from the existing doc.\n // Handle both multi-line (`* @deprecated ...`) and one-liner (`/** @deprecated ... */`) formats.\n const deprecatedParts: string[] = [];\n for (const line of existingDoc.split('\\n')) {\n if (/@deprecated\\b/.test(line)) {\n // Normalize to JSDoc member format: ` * @deprecated ...`\n const match = line.match(/@deprecated\\b.*/);\n if (match) {\n // Strip trailing */ and whitespace (from one-liner JSDoc like `/** @deprecated ... */`)\n const cleaned = match[0].replace(/\\s*\\*\\/\\s*$/, '');\n deprecatedParts.push(` * ${cleaned}`);\n }\n }\n }\n if (deprecatedParts.length === 0) return generatedDoc;\n\n // Insert @deprecated lines before the closing */ of the generated doc\n const closingIdx = generatedDoc.lastIndexOf('*/');\n if (closingIdx === -1) return generatedDoc;\n const before = generatedDoc.slice(0, closingIdx);\n const after = generatedDoc.slice(closingIdx);\n return before + deprecatedParts.join('\\n') + '\\n ' + after;\n}\n\n// --- @oagen-ignore region helpers ---\n\ninterface IgnoredRegion {\n startIndex: number;\n endIndex: number;\n}\n\nfunction findIgnoredRegions(source: string): IgnoredRegion[] {\n const regions: IgnoredRegion[] = [];\n const startTag = '@oagen-ignore-start';\n const endTag = '@oagen-ignore-end';\n let searchFrom = 0;\n\n while (true) {\n const startIdx = source.indexOf(startTag, searchFrom);\n if (startIdx === -1) break;\n const endIdx = source.indexOf(endTag, startIdx + startTag.length);\n if (endIdx === -1) break; // Unclosed — silently ignore\n regions.push({ startIndex: startIdx, endIndex: endIdx + endTag.length });\n searchFrom = endIdx + endTag.length;\n }\n\n return regions;\n}\n\nfunction buildIgnoredSymbolNames(docstrings: Map<string, SymbolDocstrings>, regions: IgnoredRegion[]): Set<string> {\n if (regions.length === 0) return new Set();\n const ignored = new Set<string>();\n for (const [name, info] of docstrings) {\n if (regions.some((r) => info.declStartIndex >= r.startIndex && info.declStartIndex <= r.endIndex)) {\n ignored.add(name);\n }\n }\n return ignored;\n}\n\nfunction clampIndex(value: number, contentLength: number): number {\n if (!Number.isFinite(value)) return 0;\n if (value < 0) return 0;\n if (value > contentLength) return contentLength;\n return value;\n}\n\n/**\n * Resolve the declaration line start for insertion using the current content,\n * instead of relying on parser column arithmetic. This avoids misplaced inserts\n * when parser columns/offsets drift.\n */\nfunction declarationLineStart(content: string, declStartIndex: number): number {\n const idx = clampIndex(declStartIndex, content.length);\n const prevNewline = content.lastIndexOf('\\n', Math.max(0, idx - 1));\n return prevNewline === -1 ? 0 : prevNewline + 1;\n}\n\n/**\n * Resolve a docstring range by searching for the nearest matching text before\n * the declaration start. Falls back to parser-provided offsets when search fails.\n */\nfunction resolveDocRange(\n content: string,\n docText: string,\n declStartIndex: number,\n fallbackStart: number,\n fallbackEnd: number,\n): { start: number; end: number } {\n const safeDecl = clampIndex(declStartIndex, content.length);\n const safeFallbackStart = clampIndex(fallbackStart, content.length);\n const safeFallbackEnd = clampIndex(fallbackEnd, content.length);\n const found = content.lastIndexOf(docText, safeDecl);\n if (found !== -1) {\n return { start: found, end: found + docText.length };\n }\n return { start: safeFallbackStart, end: safeFallbackEnd };\n}\n\n/**\n * Check if a tree-sitter grammar is configured for the given language.\n */\nexport function hasGrammar(language: string): boolean {\n return getMergeAdapter(language) !== undefined;\n}\n\nasync function getParser(language: string): Promise<Parser> {\n const cached = parserCache.get(language);\n if (cached) return cached;\n\n const adapter = getMergeAdapter(language);\n if (!adapter) {\n throw new Error(\n `No tree-sitter grammar configured for language \"${language}\". ` +\n `Add a merge adapter and install the corresponding tree-sitter grammar package.`,\n );\n }\n\n const mod = await import(adapter.grammarModule);\n const exported = adapter.resolveGrammar ? adapter.resolveGrammar(mod) : mod;\n const grammar = (exported as { default?: unknown }).default ?? exported;\n const parser = new Parser();\n parser.setLanguage(grammar);\n parserCache.set(language, parser);\n return parser;\n}\n\ninterface ParsedSymbols {\n names: Set<string>;\n /** Trimmed text of unnamed top-level statements (for text-based dedup) */\n unnamedTexts: Set<string>;\n}\n\n/**\n * Extract all top-level symbol names (and unnamed statement texts) from source code.\n */\nexport async function extractTopLevelSymbols(source: string, language: string): Promise<ParsedSymbols> {\n const parser = await getParser(language);\n const adapter = getMergeAdapter(language);\n if (!adapter) {\n throw new Error(`No merge adapter configured for language \"${language}\"`);\n }\n if (typeof source !== 'string') {\n throw new Error(`extractTopLevelSymbols: expected string source, got ${typeof source}`);\n }\n const tree = safeParse(parser, source);\n const names = new Set<string>();\n const unnamedTexts = new Set<string>();\n const parsed = adapter.parseStatements(tree, source);\n\n for (const imp of parsed.imports) {\n names.add(imp.key);\n }\n for (const statement of parsed.statements) {\n if (statement.key) {\n names.add(statement.key);\n } else {\n unnamedTexts.add(statement.text.trim());\n }\n }\n\n return { names, unnamedTexts };\n}\n\n/** Convenience wrapper that returns only the name set. */\nexport async function extractTopLevelNames(source: string, language: string): Promise<Set<string>> {\n return (await extractTopLevelSymbols(source, language)).names;\n}\n\n/**\n * Extract top-level statements from generated source with their names\n * and exact text span.\n */\nexport async function extractStatements(source: string, language: string): Promise<ParsedMergeFile> {\n const parser = await getParser(language);\n const adapter = getMergeAdapter(language);\n if (!adapter) {\n throw new Error(`No merge adapter configured for language \"${language}\"`);\n }\n const tree = safeParse(parser, source);\n return adapter.parseStatements(tree, source);\n}\n\n/**\n * Return a map of top-level class name → { bodyEndLine, bodyEndCol } using\n * tree-sitter. `bodyEndLine` is 0-based. For brace-delimited classes the\n * end points at the closing brace line; for indentation-delimited classes\n * it points one past the last line of the class body.\n */\nexport async function extractClassEndLines(\n source: string,\n language: string,\n): Promise<Map<string, { bodyEndLine: number }>> {\n const parser = await getParser(language);\n const tree = safeParse(parser, source);\n const map = new Map<string, { bodyEndLine: number }>();\n\n function processClassNode(node: Parser.SyntaxNode): void {\n const nameNode =\n node.childForFieldName('name') ??\n node.children.find((c) => c.type === 'type_identifier' || c.type === 'identifier');\n if (!nameNode) return;\n const name = nameNode.text;\n\n const body =\n node.childForFieldName('body') ?? node.children.find((c) => c.type === 'class_body' || c.type === 'body');\n const endRow = body ? body.endPosition.row : node.endPosition.row;\n const lastChar = source[body ? body.endIndex - 1 : node.endIndex - 1];\n\n if (lastChar === '}') {\n map.set(name, { bodyEndLine: endRow });\n } else {\n map.set(name, { bodyEndLine: endRow + 1 });\n }\n }\n\n // Walk the tree recursively. Ruby (and Python) often nest target classes\n // inside `module Foo` / `class Outer:` containers, so a flat iteration over\n // root children would miss them.\n function walk(node: Parser.SyntaxNode): void {\n if (node.type === 'class' || node.type === 'class_definition' || node.type === 'class_declaration') {\n processClassNode(node);\n }\n if (node.type === 'decorated_definition') {\n for (const inner of node.namedChildren) {\n if (inner.type === 'class_definition') processClassNode(inner);\n }\n }\n if (node.type === 'export_statement') {\n for (const inner of node.namedChildren) {\n if (inner.type === 'class_declaration') processClassNode(inner);\n }\n }\n for (const child of node.namedChildren) walk(child);\n }\n for (const child of tree.rootNode.children) {\n walk(child);\n }\n\n return map;\n}\n\nexport interface MergeResult {\n content: string;\n added: number;\n preserved: number;\n changed: boolean;\n}\n\n/**\n * Merge generated content into an existing file.\n *\n * - Parses both files with tree-sitter\n * - Detects which top-level symbols already exist\n * - Appends only new symbols\n * - Never modifies or removes existing code\n * - Adds auto-generated header if not present\n */\nexport async function mergeIntoExisting(\n existingContent: string,\n generatedContent: string,\n language: string,\n header: string,\n): Promise<MergeResult> {\n const adapter = getMergeAdapter(language);\n if (!adapter) {\n throw new Error(`No merge adapter configured for language \"${language}\"`);\n }\n\n // Parse existing file once — extract both symbols and statements from the same AST pass\n const existingStatements = await extractStatements(existingContent, language);\n const generatedStatements = await extractStatements(generatedContent, language);\n\n const existingKeys = new Set<string>();\n const existingUnnamedTexts = new Set<string>();\n const existingImportKeys = new Set<string>();\n const existingReexports = new Set<string>();\n let lastImportEndIndex = -1;\n\n // Collect import keys AND imported identifiers (to prevent adding declarations\n // that clash with already-imported names)\n const existingImportedNames = new Set<string>();\n for (const imp of existingStatements.imports) {\n existingImportKeys.add(imp.key);\n // Extract identifiers from import text: import { Foo, Bar } from '...'\n const braceMatch = imp.text.match(/\\{([^}]+)\\}/);\n if (braceMatch) {\n for (const name of braceMatch[1].split(',')) {\n const trimmed = name.replace(/\\btype\\b/, '').trim();\n if (trimmed) existingImportedNames.add(trimmed);\n }\n }\n }\n for (const anchor of existingStatements.importAnchors) {\n const linesBefore = existingContent.slice(0, existingContent.indexOf(anchor)).split('\\n').length - 1;\n const stmtLines = anchor.split('\\n').length;\n lastImportEndIndex = linesBefore + stmtLines - 1;\n }\n if (lastImportEndIndex === -1 && existingStatements.importInsertionAnchor) {\n const linesBefore =\n existingContent.slice(0, existingContent.indexOf(existingStatements.importInsertionAnchor)).split('\\n').length -\n 1;\n const stmtLines = existingStatements.importInsertionAnchor.split('\\n').length;\n lastImportEndIndex = linesBefore + stmtLines - 1;\n }\n\n // Track all names exported by existing statements (both direct exports and\n // re-export aliases like `export { X as Y }`). Used to prevent the merger\n // from appending a re-export that introduces a duplicate exported name.\n const existingExportedNames = new Set<string>();\n\n for (const stmt of existingStatements.statements) {\n if (stmt.kind === 'reexport') {\n existingReexports.add(adapter.normalizeReexport ? adapter.normalizeReexport(stmt.text.trim()) : stmt.text.trim());\n // Collect aliased export names from re-exports\n const braceMatch = stmt.text.match(/\\{([^}]+)\\}/);\n if (braceMatch) {\n for (const part of braceMatch[1].split(',')) {\n const segments = part.trim().split(/\\s+as\\s+/);\n const exportedName = (segments[1] ?? segments[0]).trim();\n if (exportedName) existingExportedNames.add(exportedName);\n }\n }\n }\n if (stmt.key) {\n existingKeys.add(stmt.key);\n existingExportedNames.add(stmt.key);\n } else {\n existingUnnamedTexts.add(stmt.text.trim());\n }\n }\n\n const headerLine = header.trim();\n\n const newImports: MergeImport[] = [];\n const toAppend: string[] = [];\n let preserved = 0;\n\n for (const imp of generatedStatements.imports) {\n if (imp.text.trim() === headerLine) continue;\n if (existingImportKeys.has(imp.key)) {\n // The existing file already imports from this module path.\n // Check if the generated import adds identifiers not present in\n // the existing import — if so, create a supplemental import with\n // only the new identifiers. The supplemental participates in the\n // usage-based filter (below) so unused identifiers are dropped.\n const braceMatch = imp.text.match(/\\{([^}]+)\\}/);\n if (braceMatch) {\n const names = braceMatch[1]\n .split(',')\n .map((n) => n.replace(/\\btype\\b/, '').trim())\n .filter(Boolean);\n const newNames = names.filter((n) => !existingImportedNames.has(n) && !existingKeys.has(n));\n if (newNames.length > 0) {\n const isTypeImport = imp.text.trimStart().startsWith('import type');\n const prefix = isTypeImport ? 'import type' : 'import';\n const sourceMatch = imp.text.match(/from\\s+(['\"][^'\"]+['\"]);?/);\n if (sourceMatch) {\n newImports.push({\n key: imp.key + '#supplemental',\n text: `${prefix} { ${newNames.join(', ')} } from ${sourceMatch[1]};`,\n });\n }\n }\n }\n preserved++;\n continue;\n }\n // Strip out identifiers that are already imported from another path.\n // This prevents duplicates when the generated file uses a specific path\n // (e.g., '../interfaces/organization.interface') while the existing file\n // imports the same names from a barrel (e.g., '../interfaces').\n const braceMatch = imp.text.match(/\\{([^}]+)\\}/);\n if (braceMatch) {\n const names = braceMatch[1]\n .split(',')\n .map((n) => n.replace(/\\btype\\b/, '').trim())\n .filter(Boolean);\n // Check against both existing imports AND existing top-level declarations\n const isAlreadyDefined = (n: string) => existingImportedNames.has(n) || existingKeys.has(n);\n if (names.length > 0 && names.every(isAlreadyDefined)) {\n preserved++;\n continue;\n }\n // If only SOME identifiers are already defined, strip them out and keep only new ones\n if (names.some(isAlreadyDefined)) {\n const newNames = names.filter((n) => !isAlreadyDefined(n));\n if (newNames.length === 0) {\n preserved++;\n continue;\n }\n // Rebuild the import with only new identifiers\n const isTypeImport = imp.text.trimStart().startsWith('import type');\n const prefix = isTypeImport ? 'import type' : 'import';\n const sourceMatch = imp.text.match(/from\\s+(['\"][^'\"]+['\"]);?/);\n if (sourceMatch) {\n const newText = `${prefix} { ${newNames.join(', ')} } from ${sourceMatch[1]};`;\n newImports.push({ key: imp.key, text: newText });\n continue;\n }\n }\n }\n newImports.push(imp);\n }\n\n for (const stmt of generatedStatements.statements) {\n // Skip the header comment\n if (stmt.text.trim() === headerLine) continue;\n\n // Skip re-export statements that duplicate existing re-exports\n // (e.g., generated uses .js extension but existing doesn't).\n // Allow genuinely new re-exports through.\n if (stmt.kind === 'reexport') {\n const normalizedText = adapter.normalizeReexport ? adapter.normalizeReexport(stmt.text.trim()) : stmt.text.trim();\n if (existingReexports.has(normalizedText) || (stmt.key !== null && existingKeys.has(stmt.key))) {\n preserved++;\n continue;\n }\n // Also skip re-exports whose aliased names are already defined as\n // top-level exports in the existing file (e.g., generated file has\n // `export { X as deserializeFoo } from '...'` but existing file\n // already has `export const deserializeFoo = ...`).\n const braceMatch = stmt.text.match(/\\{([^}]+)\\}/);\n if (braceMatch) {\n const exportedNames = braceMatch[1]\n .split(',')\n .map((n) => {\n const parts = n.trim().split(/\\s+as\\s+/);\n return (parts[1] ?? parts[0]).trim();\n })\n .filter(Boolean);\n if (exportedNames.length > 0 && exportedNames.every((n) => existingExportedNames.has(n))) {\n preserved++;\n continue;\n }\n }\n }\n\n if (stmt.key && (existingKeys.has(stmt.key) || existingImportedNames.has(stmt.key))) {\n preserved++;\n continue;\n }\n\n if (!stmt.key) {\n if (existingUnnamedTexts.has(stmt.text.trim())) {\n preserved++;\n continue;\n }\n }\n\n toAppend.push(stmt.text);\n }\n\n if (newImports.length === 0 && toAppend.length === 0) {\n // No top-level changes — check for deep merge before returning\n if (!adapter.extractMembers) {\n // Still need to check docstring refresh below\n }\n }\n\n let result = existingContent;\n\n // Append new top-level symbols first (so deep merge can see them)\n if (toAppend.length > 0) {\n result = result.trimEnd() + '\\n\\n' + toAppend.join('\\n\\n') + '\\n';\n }\n\n // Deep merge pass: add new members to existing symbols\n // Runs after import/symbol merge so line numbers are based on the updated content\n let deepAdded = 0;\n let deepPruned = 0;\n const insertions: { line: number; text: string }[] = [];\n if (adapter.extractMembers) {\n const parser = await getParser(language);\n const resultTree = safeParse(parser, result);\n const generatedTree = safeParse(parser, generatedContent);\n const resultSymbols = adapter.extractMembers(resultTree, result);\n const generatedSymbols = adapter.extractMembers(generatedTree, generatedContent);\n\n // Build ignored symbol set from @oagen-ignore-start/@oagen-ignore-end regions\n const existingTree = safeParse(parser, existingContent);\n const existingDocs = adapter.extractDocstrings(existingTree, existingContent);\n const deepIgnoredRegions = findIgnoredRegions(existingContent);\n const deepIgnoredSymbols = buildIgnoredSymbolNames(existingDocs, deepIgnoredRegions);\n\n // Pass 1: prune stale \"managed\" members (existing members the adapter\n // recognizes as generator-owned but that no longer appear in the\n // regenerated content — e.g. accessors whose mount target was remapped).\n // Done as byte-range deletes before line-based insertions so insertion\n // line numbers stay valid for the post-prune result.\n if (adapter.isManagedMember) {\n const pruneEdits: { start: number; end: number }[] = [];\n for (const [symbolName, genSymbol] of generatedSymbols) {\n if (deepIgnoredSymbols.has(symbolName)) continue;\n const existSymbol = resultSymbols.get(symbolName);\n if (!existSymbol) continue;\n const genMemberKeys = new Set(genSymbol.members.map((m) => m.key));\n for (const existMember of existSymbol.members) {\n if (genMemberKeys.has(existMember.key)) continue;\n if (existMember.startIndex === undefined || existMember.endIndex === undefined) continue;\n if (!adapter.isManagedMember(existMember)) continue;\n pruneEdits.push({ start: existMember.startIndex, end: existMember.endIndex });\n }\n }\n if (pruneEdits.length > 0) {\n pruneEdits.sort((a, b) => b.start - a.start);\n for (const edit of pruneEdits) {\n let end = edit.end;\n while (end < result.length && (result[end] === ' ' || result[end] === '\\t')) end++;\n if (result[end] === '\\n') end++;\n result = result.slice(0, edit.start) + result.slice(end);\n }\n deepPruned = pruneEdits.length;\n // Re-extract since byte offsets and line numbers shifted.\n const reTree = safeParse(parser, result);\n resultSymbols.clear();\n for (const [k, v] of adapter.extractMembers(reTree, result)) resultSymbols.set(k, v);\n }\n }\n\n // Pass 2: append new members the regenerated content adds.\n for (const [symbolName, genSymbol] of generatedSymbols) {\n if (deepIgnoredSymbols.has(symbolName)) continue;\n const existSymbol = resultSymbols.get(symbolName);\n if (!existSymbol) continue; // New symbol — handled by top-level append\n\n const existingMemberKeys = new Set(existSymbol.members.map((m) => m.key));\n const newMembers = genSymbol.members.filter((m) => !existingMemberKeys.has(m.key));\n\n if (newMembers.length > 0) {\n // Let the adapter decide whether to skip deep merge (e.g., when new members\n // reference dependencies the existing symbol doesn't provide)\n if (adapter.shouldSkipDeepMerge?.(symbolName, existingMemberKeys, newMembers)) {\n continue;\n }\n\n const indent = existSymbol.memberIndent ?? ' ';\n const insertText = newMembers.map((m) => indent + m.text).join('\\n\\n');\n // Leading blank line separates inserted members from existing ones.\n insertions.push({ line: existSymbol.bodyEndLine, text: '\\n' + insertText });\n deepAdded += newMembers.length;\n }\n }\n\n if (insertions.length > 0) {\n // Apply bottom-up to avoid offset shifting\n insertions.sort((a, b) => b.line - a.line);\n const resultLines = result.split('\\n');\n for (const ins of insertions) {\n resultLines.splice(ins.line, 0, ins.text);\n }\n result = resultLines.join('\\n');\n }\n }\n\n // Insert new imports only when new symbols or members were actually added.\n // This prevents orphaned imports for generated code that wasn't merged in.\n // Additionally, filter imports to only include identifiers actually used in the\n // appended/inserted code — prevents orphaned imports for generated code that\n // referenced types used in other (non-appended) generated functions.\n if (newImports.length > 0 && (toAppend.length > 0 || deepAdded > 0)) {\n // Build text of all new code that was actually added (appended + deep-merged members)\n const addedParts: string[] = [...toAppend];\n if (insertions) {\n for (const ins of insertions) {\n addedParts.push(ins.text);\n }\n }\n const addedCodeText = addedParts.join('\\n');\n\n // Filter imports to only identifiers that appear in the added code.\n // Strip individual unused identifiers from each import rather than\n // keeping/dropping the entire import — prevents orphaned imports when\n // a generated import line contains both used and unused identifiers\n // (e.g., `import { deserializeFoo, serializeFoo }` where only\n // serializeFoo is used in the appended code).\n const filteredImports: MergeImport[] = [];\n for (const imp of newImports) {\n const braceMatch = imp.text.match(/\\{([^}]+)\\}/);\n if (!braceMatch) {\n // Non-destructured import (e.g., default import) — keep as-is\n filteredImports.push(imp);\n continue;\n }\n const names = braceMatch[1]\n .split(',')\n .map((n) => n.replace(/\\btype\\b/, '').trim())\n .filter(Boolean);\n const usedNames = names.filter((name) => addedCodeText.includes(name));\n if (usedNames.length === 0) continue; // Drop entirely\n if (usedNames.length === names.length) {\n // All identifiers used — keep original import\n filteredImports.push(imp);\n } else {\n // Rebuild import with only used identifiers\n const isTypeImport = imp.text.trimStart().startsWith('import type');\n const prefix = isTypeImport ? 'import type' : 'import';\n const sourceMatch = imp.text.match(/from\\s+(['\"][^'\"]+['\"]);?/);\n if (sourceMatch) {\n filteredImports.push({\n key: imp.key,\n text: `${prefix} { ${usedNames.join(', ')} } from ${sourceMatch[1]};`,\n });\n } else {\n filteredImports.push(imp);\n }\n }\n }\n\n if (filteredImports.length > 0) {\n const renderedImports = adapter.renderImports\n ? adapter.renderImports(filteredImports)\n : filteredImports.map((entry) => entry.text);\n const lines = result.split('\\n');\n const insertIdx = lastImportEndIndex + 1;\n lines.splice(insertIdx, 0, ...renderedImports);\n result = lines.join('\\n');\n }\n }\n\n // Docstring refresh pass: update existing docstrings to match generated content\n let docstringUpdates = 0;\n {\n const parser = await getParser(language);\n const resultTree = safeParse(parser, result);\n const generatedTree = safeParse(parser, generatedContent);\n const resultDocs = adapter.extractDocstrings(resultTree, result);\n const generatedDocs = adapter.extractDocstrings(generatedTree, generatedContent);\n const docIgnoredRegions = findIgnoredRegions(result);\n const docIgnoredSymbols = buildIgnoredSymbolNames(resultDocs, docIgnoredRegions);\n\n const edits: { start: number; end: number; newText: string }[] = [];\n\n for (const [symbolName, genInfo] of generatedDocs) {\n const existInfo = resultDocs.get(symbolName);\n if (!existInfo) continue;\n if (docIgnoredSymbols.has(symbolName)) continue;\n\n // Skip header comments being treated as docstrings\n const genDoc = genInfo.docstring && genInfo.docstring.text.trim() !== headerLine ? genInfo.docstring : null;\n\n // Top-level docstring\n if (genDoc) {\n if (existInfo.docstring) {\n const isPreserved = existInfo.docstring.text.includes('@oagen-ignore');\n if (!isPreserved && existInfo.docstring.text !== genDoc.text) {\n const newText = preserveDeprecatedTags(existInfo.docstring.text, genDoc.text);\n const range = resolveDocRange(\n result,\n existInfo.docstring.text,\n existInfo.declStartIndex,\n existInfo.docstring.startIndex,\n existInfo.docstring.endIndex,\n );\n edits.push({\n start: range.start,\n end: range.end,\n newText,\n });\n docstringUpdates++;\n }\n } else {\n const lineStart = declarationLineStart(result, existInfo.declStartIndex);\n const indent = ' '.repeat(existInfo.declColumn);\n edits.push({\n start: lineStart,\n end: lineStart,\n newText: indent + genDoc.text + '\\n',\n });\n docstringUpdates++;\n }\n }\n\n // Member-level docstrings — first pass: match by name\n const matchedExistMembers = new Set<string>();\n for (const [memberName, genMember] of genInfo.members) {\n const existMember = existInfo.members.get(memberName);\n if (!existMember) continue;\n matchedExistMembers.add(memberName);\n if (!genMember.docstring) continue;\n\n if (existMember.docstring) {\n const isPreserved = existMember.docstring.text.includes('@oagen-ignore');\n if (!isPreserved && existMember.docstring.text !== genMember.docstring.text) {\n const newText = preserveDeprecatedTags(existMember.docstring.text, genMember.docstring.text);\n const range = resolveDocRange(\n result,\n existMember.docstring.text,\n existMember.declStartIndex,\n existMember.docstring.startIndex,\n existMember.docstring.endIndex,\n );\n edits.push({\n start: range.start,\n end: range.end,\n newText,\n });\n docstringUpdates++;\n }\n } else {\n const lineStart = declarationLineStart(result, existMember.declStartIndex);\n const indent = ' '.repeat(existMember.declColumn);\n edits.push({\n start: lineStart,\n end: lineStart,\n newText: indent + genMember.docstring.text + '\\n',\n });\n docstringUpdates++;\n }\n }\n\n // Member-level docstrings — second pass: URL fingerprint fallback\n // Match generated members to existing members by URL pattern when\n // name-based matching fails (e.g., generated \"find\" vs existing \"getOrganization\"\n // both call this.workos.get('/organizations/${id}')).\n //\n // Safety: only attempt fingerprint matching when there is exactly ONE\n // unmatched generated member and ONE unmatched existing member for a\n // given fingerprint. When multiple members share the same URL path\n // (e.g., POST and GET on /authorization/roles), fingerprint matching\n // is ambiguous and would swap docstrings between methods.\n const unmatchedGenByFp = new Map<\n string,\n { name: string; member: typeof genInfo.members extends Map<string, infer V> ? V : never }[]\n >();\n for (const [genName, genMember] of genInfo.members) {\n if (matchedExistMembers.has(genName)) continue; // name-matched in pass 1 (as an exist member) — skip\n if (!genMember.docstring || !genMember.urlFingerprint) continue;\n // Skip if this generated member was already name-matched\n if (existInfo.members.has(genName)) continue;\n const bucket = unmatchedGenByFp.get(genMember.urlFingerprint) ?? [];\n bucket.push({ name: genName, member: genMember });\n unmatchedGenByFp.set(genMember.urlFingerprint, bucket);\n }\n const unmatchedExistByFp = new Map<\n string,\n { name: string; member: typeof existInfo.members extends Map<string, infer V> ? V : never }[]\n >();\n for (const [existName, existMember] of existInfo.members) {\n if (matchedExistMembers.has(existName)) continue;\n if (!existMember.urlFingerprint) continue;\n const bucket = unmatchedExistByFp.get(existMember.urlFingerprint) ?? [];\n bucket.push({ name: existName, member: existMember });\n unmatchedExistByFp.set(existMember.urlFingerprint, bucket);\n }\n for (const [fp, genBucket] of unmatchedGenByFp) {\n if (genBucket.length !== 1) continue; // ambiguous — skip\n const existBucket = unmatchedExistByFp.get(fp);\n if (!existBucket || existBucket.length !== 1) continue; // ambiguous — skip\n const genMember = genBucket[0].member;\n const existEntry = existBucket[0];\n const existMember = existEntry.member;\n if (!genMember.docstring) continue;\n\n if (existMember.docstring) {\n const isPreserved = existMember.docstring.text.includes('@oagen-ignore');\n if (isPreserved) continue;\n if (existMember.docstring.text !== genMember.docstring.text) {\n const newText = preserveDeprecatedTags(existMember.docstring.text, genMember.docstring.text);\n const range = resolveDocRange(\n result,\n existMember.docstring.text,\n existMember.declStartIndex,\n existMember.docstring.startIndex,\n existMember.docstring.endIndex,\n );\n edits.push({\n start: range.start,\n end: range.end,\n newText,\n });\n docstringUpdates++;\n }\n } else {\n const lineStart = declarationLineStart(result, existMember.declStartIndex);\n const indent = ' '.repeat(existMember.declColumn);\n edits.push({\n start: lineStart,\n end: lineStart,\n newText: indent + genMember.docstring.text + '\\n',\n });\n docstringUpdates++;\n }\n matchedExistMembers.add(existEntry.name);\n }\n }\n\n if (edits.length > 0) {\n edits.sort((a, b) => b.start - a.start);\n for (const edit of edits) {\n result = result.slice(0, edit.start) + edit.newText + result.slice(edit.end);\n }\n }\n }\n\n const importsActuallyAdded =\n toAppend.length > 0 || deepAdded > 0\n ? adapter.renderImports\n ? adapter.renderImports(newImports).length\n : newImports.length\n : 0;\n const topLevelAdded = importsActuallyAdded + toAppend.length;\n const totalAdded = topLevelAdded + deepAdded;\n\n if (totalAdded === 0 && docstringUpdates === 0 && deepPruned === 0) {\n return { content: existingContent, added: 0, preserved, changed: false };\n }\n\n return {\n content: result,\n added: totalAdded,\n preserved,\n changed: true,\n };\n}\n","/**\n * Deep merge two parsed JSON values.\n *\n * - Objects: recursively merge, preserving existing keys not in generated\n * - Arrays: generated replaces existing entirely (generated owns array contents)\n * - Primitives: generated wins\n */\nexport function deepMergeJson(existing: unknown, generated: unknown): unknown {\n if (\n typeof existing === 'object' &&\n existing !== null &&\n !Array.isArray(existing) &&\n typeof generated === 'object' &&\n generated !== null &&\n !Array.isArray(generated)\n ) {\n const merged: Record<string, unknown> = { ...(existing as Record<string, unknown>) };\n for (const [key, value] of Object.entries(generated as Record<string, unknown>)) {\n if (key in merged) {\n merged[key] = deepMergeJson(merged[key], value);\n } else {\n merged[key] = value;\n }\n }\n return merged;\n }\n\n // Arrays and primitives: generated wins\n return generated;\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { GeneratedFile } from './types.js';\nimport { mergeIntoExisting, hasGrammar, extractClassEndLines, extractStatements } from './merger.js';\nimport { deepMergeJson } from './json-merge.js';\nimport { getMergeAdapter } from './merge-adapters/index.js';\n\nexport interface WriteOptions {\n /** The emitter language (e.g., \"node\", \"ruby\"). Used to select the\n * tree-sitter grammar for AST-level merging. */\n language?: string;\n /** The auto-generated file header string. */\n header?: string;\n}\n\nexport interface WriteResult {\n written: string[];\n merged: string[];\n skipped: string[];\n identical: string[];\n ignored: string[];\n}\n\n/**\n * Write generated files to disk with AST-level merging.\n *\n * When a file already exists:\n * - skipIfExists → leave it alone entirely\n * - AST merge available → parse both, append only new symbols\n * - No grammar → skip (never clobber hand-written code)\n *\n * New files are always written in full.\n */\nexport async function writeFiles(\n files: GeneratedFile[],\n outputDir: string,\n options?: WriteOptions,\n): Promise<WriteResult> {\n const result: WriteResult = {\n written: [],\n merged: [],\n skipped: [],\n identical: [],\n ignored: [],\n };\n const sorted = [...files].sort((a, b) => a.path.localeCompare(b.path));\n const language = options?.language;\n const header = options?.header ?? '';\n\n for (const file of sorted) {\n const fullPath = path.join(outputDir, file.path);\n\n // Repair on-disk casing when an emitter renames a generated file in a\n // case-only way (e.g. `AuthenticationMfaFailed.kt` → `AuthenticationMFAFailed.kt`\n // after adding `MFA` to an acronym list). On case-insensitive filesystems\n // (APFS, NTFS) `writeFile` would otherwise reuse the existing inode and\n // preserve the stale casing — surfacing later as ktlint/eslint errors.\n await renameMismatchedCasing(fullPath);\n\n // Check if file already exists\n let existingContent: string | null = null;\n try {\n existingContent = await fs.readFile(fullPath, 'utf-8');\n } catch {\n // File doesn't exist\n }\n\n // New file → write in full\n if (existingContent === null) {\n await fs.mkdir(path.dirname(fullPath), { recursive: true });\n await fs.writeFile(fullPath, file.content, 'utf-8');\n result.written.push(file.path);\n continue;\n }\n\n // skipIfExists → hard skip, no merge (but ensure header is present).\n // JSON files are skipped from header injection because a leading `//`\n // comment makes the file invalid JSON.\n if (file.skipIfExists) {\n if (header && !existingContent.startsWith(header) && !file.path.endsWith('.json')) {\n await fs.writeFile(fullPath, header + '\\n\\n' + existingContent, 'utf-8');\n }\n result.skipped.push(file.path);\n continue;\n }\n\n // @oagen-ignore-file → skip entirely (existing file opts out of all generation)\n if (existingContent.includes('@oagen-ignore-file')) {\n result.ignored.push(file.path);\n continue;\n }\n\n // Don't merge test files into hand-written test files — generated tests are\n // designed for the standalone generated SDK and will have wrong\n // signatures/fixtures when merged into hand-written tests.\n // However, if the existing test file is itself auto-generated (has the oagen\n // header), allow overwriteExisting to take effect so new methods get coverage.\n const adapter = language ? getMergeAdapter(language) : undefined;\n const isTestFile = adapter?.testFilePatterns\n ? adapter.testFilePatterns.some((p) => p.test(file.path))\n : isDefaultTestFile(file.path);\n if (isTestFile) {\n const isExistingAutoGenerated = header && existingContent.startsWith(header);\n if (!isExistingAutoGenerated && !file.overwriteExisting) {\n result.skipped.push(file.path);\n continue;\n }\n // Auto-generated test file or overwriteExisting — fall through to overwriteExisting / identical checks\n }\n\n // Identical content → no-op\n if (existingContent === file.content) {\n result.identical.push(file.path);\n continue;\n }\n\n // Force overwrite — but preserve any @oagen-ignore regions from existing content\n if (file.overwriteExisting) {\n const content =\n existingContent.includes('@oagen-ignore-start') && language && hasGrammar(language)\n ? await overwriteWithPreservedRegions(existingContent, file.content, language)\n : file.content;\n await fs.writeFile(fullPath, content, 'utf-8');\n result.written.push(file.path);\n continue;\n }\n\n // JSON files → deep merge preserving existing keys\n if (file.path.endsWith('.json')) {\n try {\n const existingJson = JSON.parse(existingContent);\n const generatedJson = JSON.parse(file.content);\n const merged = deepMergeJson(existingJson, generatedJson);\n const mergedContent = JSON.stringify(merged, null, 2) + '\\n';\n if (mergedContent === existingContent) {\n result.identical.push(file.path);\n } else {\n await fs.writeFile(fullPath, mergedContent, 'utf-8');\n result.merged.push(file.path);\n }\n } catch {\n // Parse failed — fall back to overwrite\n await fs.writeFile(fullPath, file.content, 'utf-8');\n result.written.push(file.path);\n }\n continue;\n }\n\n // Source files with grammar → AST-level merge\n if (language && hasGrammar(language)) {\n try {\n const mergeResult = await mergeIntoExisting(existingContent, file.content, language, header);\n\n // Ensure header is present on merged content\n let finalContent = mergeResult.content;\n if (header && !finalContent.startsWith(header)) {\n finalContent = header + '\\n\\n' + finalContent;\n }\n\n if (!mergeResult.changed && finalContent === existingContent) {\n result.identical.push(file.path);\n continue;\n }\n\n await fs.writeFile(fullPath, finalContent, 'utf-8');\n result.merged.push(file.path);\n continue;\n } catch (err) {\n // AST merge failed (e.g. tree-sitter grammar ABI issue) — fall back to overwrite\n console.warn(\n `[oagen] AST merge failed for ${file.path}, falling back to overwrite.${err instanceof Error ? ` ${err.message}` : ''}`,\n );\n await fs.writeFile(fullPath, file.content, 'utf-8');\n result.written.push(file.path);\n continue;\n }\n }\n\n // No grammar available → skip to avoid clobbering\n result.skipped.push(file.path);\n }\n\n return result;\n}\n\n/**\n * If a sibling exists with the same name except for letter case, rename it to\n * the requested casing. Uses a two-step rename via a temporary unique name so\n * case-insensitive filesystems (APFS on macOS, NTFS on Windows) actually\n * update the entry — `rename('Foo', 'FOO')` is a no-op on those systems.\n */\nasync function renameMismatchedCasing(fullPath: string): Promise<void> {\n const dir = path.dirname(fullPath);\n const target = path.basename(fullPath);\n let entries: string[];\n try {\n entries = await fs.readdir(dir);\n } catch {\n return;\n }\n if (entries.includes(target)) return;\n const targetLower = target.toLowerCase();\n const mismatch = entries.find((e) => e.toLowerCase() === targetLower);\n if (!mismatch) return;\n const oldPath = path.join(dir, mismatch);\n const tempPath = path.join(dir, `.oagen-case-${process.pid}-${Date.now()}-${target}`);\n await fs.rename(oldPath, tempPath);\n await fs.rename(tempPath, fullPath);\n}\n\n/** Comprehensive fallback when no adapter is available. */\nfunction isDefaultTestFile(filePath: string): boolean {\n return (\n /\\.(spec|test)\\.[jt]sx?$/.test(filePath) ||\n filePath.endsWith('_test.go') ||\n filePath.endsWith('_test.rb') ||\n filePath.endsWith('_spec.rb') ||\n /(?:^|\\/)test_.*\\.py$/.test(filePath) ||\n filePath.endsWith('_test.py') ||\n filePath.endsWith('Test.php') ||\n filePath.endsWith('_test.rs') ||\n /(?:^|\\/)tests\\/.*\\.rs$/.test(filePath)\n );\n}\n\n// --- @oagen-ignore region preservation for overwriteExisting ---\n\n/**\n * Overwrite a file with generated content while preserving\n * `@oagen-ignore-start` / `@oagen-ignore-end` regions (and their\n * required imports) from the existing file.\n *\n * Uses tree-sitter via `extractClassEndLines` to find accurate class\n * boundaries so ignore blocks are inserted at the correct position even\n * when docstrings contain unindented text.\n */\nexport async function overwriteWithPreservedRegions(\n existingContent: string,\n generatedContent: string,\n language: string,\n): Promise<string> {\n const existingLines = existingContent.split('\\n');\n const generatedLines = generatedContent.split('\\n');\n\n // 1. Extract ignore blocks, their containing class, and the anchor line\n // (first non-blank line after the block in the existing file).\n const blocks: { containingClass: string; containingScope: string; lines: string[]; anchor: string }[] = [];\n for (let i = 0; i < existingLines.length; i++) {\n if (!existingLines[i].includes('@oagen-ignore-start')) continue;\n const startIdx = i;\n while (i < existingLines.length && !existingLines[i].includes('@oagen-ignore-end')) i++;\n let anchor = '';\n for (let a = i + 1; a < existingLines.length; a++) {\n if (existingLines[a].trim()) {\n anchor = existingLines[a].trimStart();\n break;\n }\n }\n blocks.push({\n containingClass: findContainingClass(existingLines, startIdx),\n containingScope: findContainingDescribeScope(existingLines, startIdx),\n lines: existingLines.slice(startIdx, i + 1),\n anchor,\n });\n }\n if (blocks.length === 0) return generatedContent;\n\n // 2. Splice extra imports from existing into generated.\n // First strip any `@oagen-ignore-start`..`@oagen-ignore-end` regions the\n // generator itself emitted: we are about to re-insert the on-disk versions,\n // and if we left the generator's seed blocks in place we'd end up with two\n // copies of every ignore block per regeneration (monotonically growing).\n const result = stripIgnoreRegions(generatedLines);\n spliceExtraImports(existingLines, result);\n\n // 3. Build class-end map from the generated content (after import splicing)\n // via tree-sitter for accurate boundary detection.\n const genSource = result.join('\\n');\n const classEndLines = await extractClassEndLines(genSource, language);\n\n // 4. Group ignore blocks by class and determine insertion points\n const blocksByClass = new Map<string, Array<{ containingScope: string; lines: string[]; anchor: string }>>();\n for (const b of blocks) {\n if (!blocksByClass.has(b.containingClass)) blocksByClass.set(b.containingClass, []);\n blocksByClass.get(b.containingClass)!.push({\n containingScope: b.containingScope,\n lines: b.lines,\n anchor: b.anchor,\n });\n }\n\n // 4a. Handle replacement blocks: ignore blocks that redefine their\n // containing class replace the generated class entirely.\n // Also handles top-level blocks (no containing class) that define\n // a class matching one in the generated content.\n const replacedClasses = new Set<string>();\n const handledBlockKeys = new Set<string>();\n const replacements: {\n startLine: number;\n endLine: number;\n content: string[];\n }[] = [];\n for (const [className, classBlocks] of blocksByClass) {\n // Determine the target class for replacement. When the block has a\n // containing class, we check if the block redefines that class. When\n // there is no containing class (top-level ignore block), we look for a\n // class definition inside the block that matches a generated class.\n let targetClass = className;\n if (!targetClass) {\n for (const entry of classBlocks) {\n for (const l of entry.lines) {\n const m = l.match(/^(?:export\\s+)?class\\s+(\\w+)/);\n if (m && classEndLines.has(m[1])) {\n targetClass = m[1];\n break;\n }\n }\n if (targetClass) break;\n }\n }\n if (!targetClass) continue;\n const isReplacement = classBlocks.some((entry) =>\n entry.lines.some((l) => {\n const m = l.match(/^(?:export\\s+)?class\\s+(\\w+)/);\n return m?.[1] === targetClass;\n }),\n );\n if (!isReplacement) continue;\n const info = classEndLines.get(targetClass);\n if (!info) continue;\n const startLine = findClassDeclarationStart(result, targetClass, info.bodyEndLine);\n if (startLine < 0) continue;\n const content: string[] = [];\n for (const entry of classBlocks) {\n content.push('');\n content.push(...entry.lines);\n }\n replacements.push({ startLine, endLine: info.bodyEndLine, content });\n replacedClasses.add(targetClass);\n handledBlockKeys.add(className);\n }\n // Apply replacements bottom-up to preserve line indices\n replacements.sort((a, b) => b.startLine - a.startLine);\n for (const rep of replacements) {\n result.splice(rep.startLine, rep.endLine - rep.startLine, ...rep.content);\n }\n\n // 4a-bis. Top-level declarations protected by ignore regions win over their\n // generated counterparts. For each top-level block, drop generated\n // declarations (interface/type/const/function/…) whose names are\n // declared inside the block; the block content replaces the first\n // such declaration in place. Without this, every regeneration\n // re-emits a duplicate of each region-protected declaration.\n let regionDeclarationEdits = 0;\n {\n const topLevelEntries = blocksByClass.get('');\n if (topLevelEntries) {\n // When 4a already placed the top-level blocks (as part of a class\n // replacement), only delete generated duplicates — never re-insert.\n const alreadyPlaced = handledBlockKeys.has('');\n const remaining: typeof topLevelEntries = [];\n for (const entry of topLevelEntries) {\n const outcome = await applyRegionDeclarationOverride(result, entry.lines, language, !alreadyPlaced);\n if (outcome.edited) regionDeclarationEdits++;\n if (!alreadyPlaced && !outcome.placed) remaining.push(entry);\n }\n if (!alreadyPlaced) {\n if (remaining.length === 0) {\n blocksByClass.delete('');\n } else {\n blocksByClass.set('', remaining);\n }\n }\n }\n }\n\n // 4b. Standard insertions for non-replacement blocks\n // Rebuild class end lines if replacements shifted line numbers.\n let effectiveClassEndLines = classEndLines;\n if (replacedClasses.size > 0 || regionDeclarationEdits > 0) {\n effectiveClassEndLines = await extractClassEndLines(result.join('\\n'), language);\n }\n\n const insertions: { line: number; order: number; content: string[] }[] = [];\n let insertionOrder = 0;\n for (const [className, classBlocks] of blocksByClass) {\n if (handledBlockKeys.has(className) || replacedClasses.has(className)) continue;\n const info = className ? effectiveClassEndLines.get(className) : undefined;\n\n // Insert each block individually so each can use its own anchor.\n for (const entry of classBlocks) {\n let insertLine: number | undefined;\n\n // Try anchor-based positioning: find the first line in the generated\n // file whose trimmed-start content matches the anchor (the first\n // non-blank line that followed this block in the existing file).\n // Skip anchors that are just punctuation (braces, etc.) since they\n // match too many locations. Accept doc comment starters (/** /// #)\n // as valid anchors since they're structurally meaningful.\n // Also skip bare language keywords (`end`, `end;`, `end)`) that appear\n // on many lines and would match the wrong location (e.g. nesting the\n // block inside a Ruby method body instead of at class level).\n const isAmbiguousAnchor = /^end[;)\\s]*$/.test(entry.anchor);\n if (\n entry.anchor &&\n !entry.anchor.includes('@oagen-ignore') &&\n !isAmbiguousAnchor &&\n /[a-zA-Z]|^\\/\\*|^\\/\\//.test(entry.anchor)\n ) {\n for (let li = 0; li < result.length; li++) {\n if (result[li].trimStart() === entry.anchor) {\n insertLine = li;\n break;\n }\n }\n }\n\n // Fallback: class body end, or for top-level import blocks, after the\n // last import line (so they stay near the top of the file, not at the\n // bottom where they'd trigger E402 lint errors).\n if (insertLine === undefined) {\n if (info) {\n insertLine = info.bodyEndLine;\n } else {\n const scopeEndLine = entry.containingScope\n ? findDescribeScopeEndLine(result, entry.containingScope)\n : undefined;\n const blockHasImportsFallback = entry.lines.some((l: string) => /^\\s*(import|from)\\s/.test(l));\n if (scopeEndLine !== undefined) {\n insertLine = scopeEndLine;\n } else if (blockHasImportsFallback || hasTopLevelDeclaration(entry.lines)) {\n let lastImportLine = 0;\n for (let li = 0; li < result.length; li++) {\n const trimmed = result[li].trimStart();\n if (/^(import|from)\\s/.test(trimmed)) lastImportLine = li + 1;\n }\n insertLine = lastImportLine;\n } else {\n insertLine = result.length;\n }\n }\n }\n\n // When inserting an import-containing ignore block, move up past\n // blank separator lines so the block sits flush with surrounding\n // imports (e.g., Kotlin's ktlint forbids blank lines within import\n // blocks).\n const blockHasImports = entry.lines.some((l: string) => /^\\s*import\\s/.test(l));\n if (blockHasImports) {\n while (\n insertLine >= 2 &&\n result[insertLine - 1]?.trim() === '' &&\n /^\\s*(import|using|from)\\s/.test(result[insertLine - 2] ?? '')\n ) {\n insertLine--;\n }\n }\n\n // Skip the leading blank line when the block is adjacent to imports\n // or already preceded by a blank line (avoids double-blank-line gaps).\n // Exclude C# `using` directives — StyleCop SA1515 requires a blank\n // line before comments, so collapsing breaks the build.\n const prevLine = insertLine > 0 ? (result[insertLine - 1]?.trimStart() ?? '') : '';\n const prevIsImport = /^import\\s/.test(prevLine) || /^from\\s/.test(prevLine);\n const prevIsBlank = insertLine > 0 && prevLine === '';\n const blockContent = prevIsImport || prevIsBlank ? [...entry.lines] : ['', ...entry.lines];\n // Add a trailing blank line when the next line is a doc comment\n // (C# SA1514 requires a blank line before `///` doc headers).\n const nextLine = result[insertLine]?.trimStart() ?? '';\n if (nextLine.startsWith('///')) {\n blockContent.push('');\n }\n insertions.push({ line: insertLine, order: insertionOrder++, content: blockContent });\n }\n }\n\n // Apply bottom-up to preserve line indices. Blocks with the same insertion\n // line must be applied in reverse discovery order because each splice inserts\n // at the same index; otherwise repeated generation flips their order.\n insertions.sort((a, b) => b.line - a.line || b.order - a.order);\n for (const ins of insertions) {\n result.splice(ins.line, 0, ...ins.content);\n }\n\n removeDuplicateImportsCoveredByIgnoreBlocks(result);\n\n return result.join('\\n');\n}\n\n/**\n * Remove every `@oagen-ignore-start`..`@oagen-ignore-end` region from the\n * supplied lines, collapsing stretches of blank lines that get left behind.\n * Used to drop generator-emitted seed blocks before splicing the on-disk\n * versions back in — otherwise every regen doubles up.\n */\nfunction stripIgnoreRegions(lines: string[]): string[] {\n const out: string[] = [];\n let skipping = false;\n for (const line of lines) {\n if (!skipping && line.includes('@oagen-ignore-start')) {\n skipping = true;\n // Drop a preceding blank line if we have one queued up — otherwise\n // regen leaves a stray blank line above the spliced-in block.\n while (out.length > 0 && out[out.length - 1].trim() === '') out.pop();\n continue;\n }\n if (skipping) {\n if (line.includes('@oagen-ignore-end')) skipping = false;\n continue;\n }\n out.push(line);\n }\n return out;\n}\n\n/** Scan backwards from `lineIdx` to find the nearest class declaration name. */\nfunction findContainingClass(lines: string[], lineIdx: number): string {\n if (/^\\S/.test(lines[lineIdx] ?? '')) return '';\n // Allow leading whitespace and language-specific modifiers before `class`.\n // Covers: `public class Foo` (C#/Java), `export class Foo` (TS),\n // `class Foo` (Python/Ruby), `internal sealed class Foo` (C#), etc.\n for (let j = lineIdx - 1; j >= 0; j--) {\n const m = lines[j].match(\n /^\\s*(?:(?:export|public|private|protected|internal|abstract|sealed|static|partial)\\s+)*class\\s+(\\w+)/,\n );\n if (m) return m[1];\n }\n return '';\n}\n\nfunction findContainingDescribeScope(lines: string[], lineIdx: number): string {\n const markerLine = lines[lineIdx] ?? '';\n if (/^\\S/.test(markerLine)) return '';\n const markerIndent = leadingSpaces(markerLine);\n for (let j = lineIdx - 1; j >= 0; j--) {\n const line = lines[j];\n const indent = leadingSpaces(line);\n if (indent >= markerIndent) continue;\n const match = line.match(/^\\s*describe\\((['\"`])(.+?)\\1\\s*,/);\n if (match) return match[2];\n if (/^\\s*(?:export\\s+)?class\\s+\\w+/.test(line)) return '';\n }\n return '';\n}\n\nfunction findDescribeScopeEndLine(lines: string[], scopeName: string): number | undefined {\n for (let i = 0; i < lines.length; i++) {\n const match = lines[i].match(/^\\s*describe\\((['\"`])(.+?)\\1\\s*,/);\n if (!match || match[2] !== scopeName) continue;\n\n let depth = 0;\n for (let j = i; j < lines.length; j++) {\n depth += countChar(lines[j], '{');\n depth -= countChar(lines[j], '}');\n if (j > i && depth <= 0) return j;\n }\n }\n return undefined;\n}\n\nfunction leadingSpaces(line: string): number {\n return line.match(/^\\s*/)?.[0].length ?? 0;\n}\n\nfunction countChar(line: string, char: string): number {\n return [...line].filter((c) => c === char).length;\n}\n\nfunction hasTopLevelDeclaration(lines: string[]): boolean {\n return lines.some((line) =>\n /^(?:export\\s+)?(?:interface|type|class|function|const|let|var|enum)\\s+\\w+/.test(line.trim()),\n );\n}\n\n/**\n * Find the start line of a class declaration (including decorators above it)\n * by scanning backwards from `beforeLine`.\n */\nfunction findClassDeclarationStart(lines: string[], className: string, beforeLine: number): number {\n // Match optional indentation so Ruby/Python nested classes are found.\n const classPattern = new RegExp(`^\\\\s*(?:export\\\\s+)?class\\\\s+${className}\\\\b`);\n for (let i = beforeLine - 1; i >= 0; i--) {\n if (!classPattern.test(lines[i])) continue;\n // Scan backward past decorators\n let start = i;\n while (start > 0 && /^\\s*@\\w+/.test(lines[start - 1])) {\n start--;\n }\n return start;\n }\n return -1;\n}\n\n// --- region-protected top-level declaration overrides ---\n\n/**\n * Conservative top-level declaration matcher for ignore-block content.\n * Matches column-0 declarations like `export interface X`, `type X = …`,\n * `const X = …`, `function X(…)`, `class X` (export optional). Names found\n * here are only acted on when the language's merge adapter also reports a\n * generated top-level statement with the same key, so false positives are\n * filtered by the real parser.\n */\nconst REGION_DECLARATION_PATTERN =\n /^(?:export\\s+)?(?:declare\\s+)?(?:interface|type|enum|class|const|let|var|async\\s+function|function)\\s+([A-Za-z_$][\\w$]*)/;\n\n/** Extract top-level symbol names declared inside an ignore block's lines. */\nfunction collectRegionDeclaredNames(blockLines: string[]): Set<string> {\n const names = new Set<string>();\n for (const line of blockLines) {\n if (line.includes('@oagen-ignore')) continue;\n const m = line.match(REGION_DECLARATION_PATTERN);\n if (m) names.add(m[1]);\n }\n return names;\n}\n\n/** Inclusive line ranges of `@oagen-ignore-start`..`@oagen-ignore-end` regions. */\nfunction collectIgnoreRegionLineRanges(lines: string[]): Array<{ start: number; end: number }> {\n const ranges: Array<{ start: number; end: number }> = [];\n let start = -1;\n for (let i = 0; i < lines.length; i++) {\n if (start === -1 && lines[i].includes('@oagen-ignore-start')) {\n start = i;\n continue;\n }\n if (start !== -1 && lines[i].includes('@oagen-ignore-end')) {\n ranges.push({ start, end: i });\n start = -1;\n }\n }\n return ranges;\n}\n\n/**\n * Walk upward from a declaration's first line over its contiguous comment\n * block (doc comment), so the comment is dropped together with the\n * declaration. Stops at blank lines, region markers, and line 0 (a comment\n * on line 0 is the file header, not a docstring).\n */\nfunction extendOverPrecedingComments(lines: string[], startLine: number): number {\n let s = startLine;\n while (s > 1) {\n const prev = lines[s - 1].trim();\n if (prev === '' || prev.includes('@oagen-ignore')) break;\n const isComment = prev.startsWith('//') || prev.startsWith('/*') || prev.startsWith('*') || prev.startsWith('#');\n if (!isComment) break;\n s--;\n }\n return s;\n}\n\n/**\n * Drop generated top-level declarations that are redeclared inside an ignore\n * block (\"region wins\"). When `placeBlock` is set and at least one generated\n * declaration matches, the block's lines replace the first match in place\n * (mirroring the class-replacement behavior above); any further matches are\n * deleted. Mutates `result` in place.\n *\n * Returns `placed` (the block content now lives in `result` and must not be\n * inserted again) and `edited` (line numbers shifted).\n */\nasync function applyRegionDeclarationOverride(\n result: string[],\n blockLines: string[],\n language: string,\n placeBlock: boolean,\n): Promise<{ placed: boolean; edited: boolean }> {\n const names = collectRegionDeclaredNames(blockLines);\n if (names.size === 0) return { placed: false, edited: false };\n\n const source = result.join('\\n');\n let parsed;\n try {\n parsed = await extractStatements(source, language);\n } catch {\n return { placed: false, edited: false };\n }\n\n const regionRanges = collectIgnoreRegionLineRanges(result);\n const inRegion = (line: number) => regionRanges.some((r) => line >= r.start && line <= r.end);\n\n const spans: Array<{ start: number; end: number }> = [];\n for (const stmt of parsed.statements) {\n if (stmt.kind !== 'declaration' || !stmt.key || !names.has(stmt.key)) continue;\n // Locate the statement's line span; skip occurrences inside ignore\n // regions (those ARE the protected content).\n let idx = source.indexOf(stmt.text);\n let startLine = -1;\n while (idx !== -1) {\n const line = source.slice(0, idx).split('\\n').length - 1;\n if (!inRegion(line)) {\n startLine = line;\n break;\n }\n idx = source.indexOf(stmt.text, idx + 1);\n }\n if (startLine === -1) continue;\n const endLine = startLine + stmt.text.split('\\n').length - 1;\n spans.push({ start: extendOverPrecedingComments(result, startLine), end: endLine });\n }\n if (spans.length === 0) return { placed: false, edited: false };\n\n spans.sort((a, b) => a.start - b.start);\n\n // Delete all matches after the first, bottom-up to preserve indices.\n for (let i = spans.length - 1; i >= 1; i--) {\n const span = spans[i];\n let deleteCount = span.end - span.start + 1;\n // Collapse the blank separator the deletion leaves behind.\n const prevBlank = span.start === 0 || (result[span.start - 1] ?? '').trim() === '';\n const nextBlank = (result[span.end + 1] ?? '').trim() === '';\n if (prevBlank && nextBlank && span.end + 1 < result.length) deleteCount++;\n result.splice(span.start, deleteCount);\n }\n\n const first = spans[0];\n if (placeBlock) {\n result.splice(first.start, first.end - first.start + 1, ...blockLines);\n return { placed: true, edited: true };\n }\n\n let deleteCount = first.end - first.start + 1;\n const prevBlank = first.start === 0 || (result[first.start - 1] ?? '').trim() === '';\n const nextBlank = (result[first.end + 1] ?? '').trim() === '';\n if (prevBlank && nextBlank && first.end + 1 < result.length) deleteCount++;\n result.splice(first.start, deleteCount);\n return { placed: false, edited: true };\n}\n\n/**\n * Collect `from X import Y, Z` identifiers grouped by module, handling\n * both single-line and multiline (parenthesized) forms.\n */\nfunction collectFromImports(lines: string[]): Map<string, Set<string>> {\n const byModule = new Map<string, Set<string>>();\n for (let i = 0; i < lines.length; i++) {\n if (!/^from\\s+/.test(lines[i])) continue;\n\n let fullText = lines[i];\n if (fullText.includes('(') && !fullText.includes(')')) {\n while (i + 1 < lines.length) {\n i++;\n fullText += ' ' + lines[i].trim();\n if (lines[i].includes(')')) break;\n }\n }\n\n const normalized = fullText.replace(/[()]/g, '').replace(/\\s+/g, ' ').trim();\n const match = normalized.match(/^from\\s+(\\S+)\\s+import\\s+(.+)$/);\n if (!match) continue;\n\n const mod = match[1];\n if (!byModule.has(mod)) byModule.set(mod, new Set());\n for (const id of match[2]\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)) {\n byModule.get(mod)!.add(id);\n }\n }\n return byModule;\n}\n\n/**\n * Collected TypeScript imports grouped by form. Each map keys on the module\n * specifier (e.g. `./foo`, `node:fs`).\n */\ninterface TsImports {\n /** `import { X, Y } from 'module'` — module → identifier names. */\n named: Map<string, Set<string>>;\n /** `import type { X } from 'module'` — module → identifier names. */\n typeOnly: Map<string, Set<string>>;\n /** `import X from 'module'` or `import type X from 'module'` — module → name. */\n defaults: Map<string, string>;\n /** `import * as X from 'module'` — module → namespace alias name. */\n namespaces: Map<string, string>;\n /** `import 'module'` — modules imported for side effects only. */\n sideEffects: Set<string>;\n}\n\n/**\n * Collect TypeScript imports, grouped by form. Handles single-line and\n * multi-line `{ … }` named imports. Disjoint from Python's `from X import Y`\n * syntax so this can be called in parallel with `collectFromImports`.\n */\nfunction collectTsImports(lines: string[]): TsImports {\n const out: TsImports = {\n named: new Map(),\n typeOnly: new Map(),\n defaults: new Map(),\n namespaces: new Map(),\n sideEffects: new Set(),\n };\n\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i].trim();\n if (!/^import(\\s|$)/.test(trimmed)) continue;\n\n // Accumulate multi-line `{ … }` imports.\n let fullText = lines[i];\n if (fullText.includes('{') && !fullText.includes('}')) {\n while (i + 1 < lines.length) {\n i++;\n fullText += ' ' + lines[i].trim();\n if (lines[i].includes('}')) break;\n }\n }\n\n const normalized = fullText.replace(/\\s+/g, ' ').trim().replace(/;\\s*$/, '');\n\n // `import 'module'`\n let m = normalized.match(/^import\\s+['\"]([^'\"]+)['\"]$/);\n if (m) {\n out.sideEffects.add(m[1]);\n continue;\n }\n\n // `import * as X from 'module'`\n m = normalized.match(/^import\\s+\\*\\s+as\\s+(\\w+)\\s+from\\s+['\"]([^'\"]+)['\"]$/);\n if (m) {\n out.namespaces.set(m[2], m[1]);\n continue;\n }\n\n // `import [Default,] { X, Y as Z } from 'module'` or `import type { X } from 'module'`\n m = normalized.match(/^import\\s+(type\\s+)?(?:(\\w+)\\s*,\\s*)?\\{\\s*([^}]*)\\s*\\}\\s+from\\s+['\"]([^'\"]+)['\"]$/);\n if (m) {\n const isTypeOnly = !!m[1];\n const defaultName = m[2];\n const namesRaw = m[3];\n const mod = m[4];\n if (defaultName) out.defaults.set(mod, defaultName);\n const names = namesRaw\n .split(',')\n .map((s) => s.trim().replace(/\\s+as\\s+\\w+$/, ''))\n .filter(Boolean);\n for (const rawName of names) {\n const isInlineTypeOnly = rawName.startsWith('type ');\n const name = rawName.replace(/^type\\s+/, '');\n const target = isTypeOnly || isInlineTypeOnly ? out.typeOnly : out.named;\n if (!target.has(mod)) target.set(mod, new Set());\n target.get(mod)!.add(name);\n }\n continue;\n }\n\n // `import X from 'module'` or `import type X from 'module'`\n m = normalized.match(/^import\\s+(?:type\\s+)?(\\w+)\\s+from\\s+['\"]([^'\"]+)['\"]$/);\n if (m) {\n out.defaults.set(m[2], m[1]);\n continue;\n }\n }\n\n return out;\n}\n\n/**\n * Add imports from the existing file that are absent from the generated\n * result. Handles:\n *\n * - Python: `import X` and `from X import Y`\n * - TypeScript: `import { X } from 'module'`, `import type { X } from 'module'`,\n * `import X from 'module'`, `import * as X from 'module'`, `import 'module'`\n * - PHP: `use Foo\\Bar;` and `use Foo\\Bar as Baz;` (namespace-qualified only)\n * - Ruby: `require '…'` and `require_relative '…'`\n *\n * Mutates `resultLines` in place.\n */\nfunction filterOutIgnoreRegions(lines: string[]): string[] {\n const out: string[] = [];\n let skipping = false;\n for (const line of lines) {\n if (!skipping && line.includes('@oagen-ignore-start')) {\n skipping = true;\n continue;\n }\n if (skipping) {\n if (line.includes('@oagen-ignore-end')) skipping = false;\n continue;\n }\n out.push(line);\n }\n return out;\n}\n\nfunction collectIgnoreRegionUsageText(lines: string[]): string {\n const out: string[] = [];\n let skipping = false;\n for (const line of lines) {\n if (!skipping && line.includes('@oagen-ignore-start')) {\n skipping = true;\n continue;\n }\n if (!skipping) continue;\n if (/^\\s*(import|from)\\s/.test(line)) continue;\n out.push(line);\n if (line.includes('@oagen-ignore-end')) skipping = false;\n }\n return out.join('\\n');\n}\n\nfunction removeDuplicateImportsCoveredByIgnoreBlocks(lines: string[]): void {\n const ignoredImports = new Set<string>();\n const importStatements = collectImportStatements(lines);\n for (const stmt of importStatements) {\n if (stmt.inIgnore) ignoredImports.add(normalizeImportStatement(stmt.lines));\n }\n if (ignoredImports.size === 0) return;\n\n for (const stmt of [...importStatements].reverse()) {\n if (stmt.inIgnore) continue;\n if (ignoredImports.has(normalizeImportStatement(stmt.lines))) {\n lines.splice(stmt.start, stmt.end - stmt.start + 1);\n }\n }\n}\n\nfunction collectImportStatements(\n lines: string[],\n): Array<{ start: number; end: number; lines: string[]; inIgnore: boolean }> {\n const statements: Array<{ start: number; end: number; lines: string[]; inIgnore: boolean }> = [];\n let inIgnore = false;\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (!inIgnore && line.includes('@oagen-ignore-start')) {\n inIgnore = true;\n continue;\n }\n if (inIgnore && line.includes('@oagen-ignore-end')) {\n inIgnore = false;\n continue;\n }\n if (!isImportLine(line)) continue;\n\n const start = i;\n let end = i;\n const statementLines = [line];\n const opens = (line.match(/[({]/g) ?? []).length;\n const closes = (line.match(/[)}]/g) ?? []).length;\n if (opens > closes) {\n while (end + 1 < lines.length) {\n end++;\n statementLines.push(lines[end]);\n if ((lines[end].match(/[)}]/g) ?? []).length > 0 && /\\bfrom\\b/.test(lines[end])) break;\n }\n i = end;\n }\n statements.push({ start, end, lines: statementLines, inIgnore });\n }\n return statements;\n}\n\nfunction normalizeImportStatement(lines: string[]): string {\n return lines.join('\\n').replace(/,\\s*}/g, ' }').replace(/\\s+/g, ' ').trim();\n}\n\nfunction isImportLine(line: string): boolean {\n const trimmed = line.trim();\n return (\n /^import(\\s|$)/.test(trimmed) ||\n /^from\\s+/.test(trimmed) ||\n /^use\\s+[\\w\\\\]/.test(trimmed) ||\n /^require(_relative)?\\s+['\"]/.test(trimmed)\n );\n}\n\nfunction identifierUsed(source: string, identifier: string): boolean {\n return new RegExp(`\\\\b${identifier.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\\b`).test(source);\n}\n\nfunction spliceExtraImports(existingLines: string[], resultLines: string[]): void {\n // Imports inside @oagen-ignore regions are converted into normal imports\n // only when non-import ignore content still references them. This prevents\n // stale import-only ignore blocks from creating duplicate or unused imports.\n const existingOutsideIgnore = filterOutIgnoreRegions(existingLines);\n const ignoreRegionText = collectIgnoreRegionUsageText(existingLines);\n\n // Python-style `import hashlib`. Excludes TS forms like `import X from '…'`\n // (have a `from` clause) and TS multi-line type imports whose first line is\n // `import type {` (have a brace) — both are handled by the TS collector\n // below.\n const isPythonSimpleImport = (l: string) => /^import\\s+\\w/.test(l) && !/\\sfrom\\s/.test(l) && !/[{}]/.test(l);\n\n // Simple imports (import hashlib, import json, …)\n const existingSimple = new Set(existingOutsideIgnore.filter(isPythonSimpleImport).map((l) => l.trim()));\n const generatedSimple = new Set(resultLines.filter(isPythonSimpleImport).map((l) => l.trim()));\n const extraSimple = [...existingSimple].filter((l) => !generatedSimple.has(l));\n\n // From-imports — compare by module and find extra identifiers\n const existingFrom = collectFromImports(existingOutsideIgnore);\n const generatedFrom = collectFromImports(resultLines);\n\n // Build a set of all identifiers imported by the generated file (across all modules)\n // so we can detect when an existing barrel import's identifiers are covered by\n // more-specific generated imports (e.g., `from x.y import Z` covers `from x import Z`).\n const allGeneratedIds = new Set<string>();\n for (const ids of generatedFrom.values()) {\n for (const id of ids) allGeneratedIds.add(id);\n }\n\n const extraFromLines: string[] = [];\n for (const [mod, existIds] of existingFrom) {\n const genIds = generatedFrom.get(mod);\n if (!genIds) {\n // The exact module isn't in the generated file — but check whether every\n // identifier is already imported from a different (e.g., more-specific) module.\n const extra = [...existIds].filter((id) => !allGeneratedIds.has(id));\n if (extra.length > 0) {\n extraFromLines.push(`from ${mod} import ${extra.join(', ')}`);\n }\n } else {\n const extra = [...existIds].filter((id) => !genIds.has(id) && !allGeneratedIds.has(id));\n if (extra.length > 0) {\n extraFromLines.push(`from ${mod} import ${extra.join(', ')}`);\n }\n }\n }\n\n // TypeScript imports.\n const existingTs = collectTsImports(existingOutsideIgnore);\n const generatedTs = collectTsImports(resultLines);\n const extraTsLines: string[] = [];\n\n for (const mod of existingTs.sideEffects) {\n if (!generatedTs.sideEffects.has(mod)) extraTsLines.push(`import '${mod}';`);\n }\n for (const [mod, name] of existingTs.defaults) {\n if (generatedTs.defaults.has(mod)) continue;\n if (!identifierUsed(ignoreRegionText, name)) continue;\n extraTsLines.push(`import ${name} from '${mod}';`);\n }\n for (const [mod, name] of existingTs.namespaces) {\n if (!identifierUsed(ignoreRegionText, name)) continue;\n if (!generatedTs.namespaces.has(mod)) extraTsLines.push(`import * as ${name} from '${mod}';`);\n }\n for (const [mod, existIds] of existingTs.named) {\n const genIds = generatedTs.named.get(mod) ?? new Set<string>();\n const genTypeIds = generatedTs.typeOnly.get(mod) ?? new Set<string>();\n const extra = [...existIds].filter(\n (id) => !genIds.has(id) && !genTypeIds.has(id) && identifierUsed(ignoreRegionText, id),\n );\n if (extra.length > 0) extraTsLines.push(`import { ${extra.join(', ')} } from '${mod}';`);\n }\n for (const [mod, existIds] of existingTs.typeOnly) {\n const genIds = generatedTs.typeOnly.get(mod) ?? new Set<string>();\n const genNamedIds = generatedTs.named.get(mod) ?? new Set<string>();\n const extra = [...existIds].filter(\n (id) => !genIds.has(id) && !genNamedIds.has(id) && identifierUsed(ignoreRegionText, id),\n );\n if (extra.length > 0) extraTsLines.push(`import type { ${extra.join(', ')} } from '${mod}';`);\n }\n\n // PHP `use Foo\\Bar;` and `use Foo\\Bar as Baz;` — namespace-qualified only\n // (a backslash anywhere in the path) so this doesn't mistakenly hoist\n // single-segment in-class trait references like `use TraitName;`.\n const isPhpUseImport = (l: string) => /^use\\s+[\\w\\\\]+\\\\[\\w\\\\]*(\\s+as\\s+\\w+)?\\s*;?$/.test(l);\n const existingPhpUse = new Set(existingOutsideIgnore.filter(isPhpUseImport).map((l) => l.trim()));\n const generatedPhpUse = new Set(resultLines.filter(isPhpUseImport).map((l) => l.trim()));\n const extraPhpUse = [...existingPhpUse].filter((l) => !generatedPhpUse.has(l));\n\n // Ruby `require '...'` and `require_relative '...'`. Dedupe by (kind, path)\n // so quote style differs without producing duplicates — e.g. when the\n // emitter writes `require 'json'` but a Ruby formatter has rewritten the\n // on-disk copy to `require \"json\"`.\n const rubyRequireRe = /^(require(?:_relative)?)\\s+['\"]([^'\"]+)['\"]\\s*$/;\n const rubyRequireKey = (l: string): string | undefined => {\n const m = l.trim().match(rubyRequireRe);\n return m ? `${m[1]}\\t${m[2]}` : undefined;\n };\n const generatedRubyRequireKeys = new Set<string>();\n for (const l of resultLines) {\n const key = rubyRequireKey(l);\n if (key) generatedRubyRequireKeys.add(key);\n }\n const seenExistingKeys = new Set<string>();\n const extraRubyRequire: string[] = [];\n for (const l of existingOutsideIgnore) {\n const key = rubyRequireKey(l);\n if (!key) continue;\n if (generatedRubyRequireKeys.has(key)) continue;\n if (seenExistingKeys.has(key)) continue;\n seenExistingKeys.add(key);\n extraRubyRequire.push(l.trim());\n }\n\n const allExtra = [...extraSimple, ...extraFromLines, ...extraTsLines, ...extraPhpUse, ...extraRubyRequire];\n if (allExtra.length === 0) return;\n\n // Find last import line in resultLines (accounting for multiline imports).\n // Recognizes Python (`from X import Y`, `import X`), TS (`import …`), PHP\n // (`use …`), and Ruby (`require`, `require_relative`).\n const isImportStart = (l: string) =>\n /^\\s*import(\\s|$)/.test(l) ||\n /^from\\s+/.test(l) ||\n /^\\s*use\\s+[\\w\\\\]/.test(l) ||\n /^\\s*require(_relative)?\\s+['\"]/.test(l);\n let lastImportIdx = -1;\n for (let i = 0; i < resultLines.length; i++) {\n if (!isImportStart(resultLines[i])) continue;\n lastImportIdx = i;\n const opens = (resultLines[i].match(/[({]/g) ?? []).length;\n const closes = (resultLines[i].match(/[)}]/g) ?? []).length;\n if (opens > closes) {\n while (i + 1 < resultLines.length) {\n i++;\n lastImportIdx = i;\n if ((resultLines[i].match(/[)}]/g) ?? []).length > 0) break;\n }\n }\n }\n\n if (lastImportIdx >= 0) {\n resultLines.splice(lastImportIdx + 1, 0, ...allExtra);\n }\n}\n","import type { ApiSpec, Service, Operation, HttpMethod } from './types.js';\n\n/** Minimal snake_case converter for path segments (avoids cross-layer import). */\nfunction toSnake(s: string): string {\n return s\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/[-\\s.]+/g, '_')\n .toLowerCase();\n}\n\n// ---------------------------------------------------------------------------\n// Hint types — consumer-provided overrides for operation resolution\n// ---------------------------------------------------------------------------\n\n/** Per-operation override keyed by \"METHOD /path\" (e.g. \"POST /sso/token\"). */\nexport interface OperationHint {\n /** Override the algorithm-derived method name. */\n name?: string;\n /** Remount this operation to a different service/namespace (PascalCase). */\n mountOn?: string;\n /** Split a union-body operation into N typed wrapper methods. */\n split?: SplitHint[];\n /** Inject constant body defaults (e.g. { grant_type: 'password' }). */\n defaults?: Record<string, string | number | boolean>;\n /** Fields the SDK reads from client config at runtime (e.g. ['client_id']). */\n inferFromClient?: string[];\n /**\n * Marks this operation as a URL builder rather than a real HTTP call. Emitters\n * should generate a method that returns the constructed URL (typically as a\n * string) without performing any I/O. Used for OAuth-style redirect endpoints\n * such as /sso/authorize and /user_management/sessions/logout.\n */\n urlBuilder?: boolean;\n}\n\nexport interface SplitHint {\n /** Wrapper method name (snake_case). */\n name: string;\n /** The discriminated union variant model name (e.g. 'PasswordSessionAuthenticateRequest'). */\n targetVariant: string;\n /** Constant body fields injected by the wrapper. */\n defaults?: Record<string, string | number | boolean>;\n /** Fields the SDK reads from client config at runtime. */\n inferFromClient?: string[];\n /** Only these body fields are exposed as method params. If omitted, all non-default/non-inferred fields are exposed. */\n exposedParams?: string[];\n /**\n * Subset of exposedParams that should be emitted as optional even when the\n * variant model would otherwise mark them required (or when the variant has\n * no addressable model, as happens for inline oneOf branches).\n */\n optionalParams?: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Resolved output — consumed by emitters\n// ---------------------------------------------------------------------------\n\nexport interface ResolvedOperation {\n /** The original IR operation (preserves description, params, types, etc.). */\n operation: Operation;\n /** The original IR service that owns this operation. */\n service: Service;\n /** Resolved snake_case method name (emitters convert to their convention). */\n methodName: string;\n /** Resolved target service/namespace (PascalCase). */\n mountOn: string;\n /** For split operations: one wrapper per union variant. */\n wrappers?: ResolvedWrapper[];\n /** Constant defaults injected into query/body at runtime (from operation-level hint). */\n defaults: Record<string, string | number | boolean>;\n /** Fields the SDK reads from client config at runtime (from operation-level hint). */\n inferFromClient: string[];\n /** Marks this operation as a URL builder; emitters should not generate an HTTP call. */\n urlBuilder: boolean;\n}\n\nexport interface ResolvedWrapper {\n /** Wrapper method name (snake_case). */\n name: string;\n /** The discriminated union variant model name. */\n targetVariant: string;\n /** Constant body defaults injected by the wrapper. */\n defaults: Record<string, string | number | boolean>;\n /** Fields read from client config at runtime. */\n inferFromClient: string[];\n /** Body fields exposed as method params. */\n exposedParams: string[];\n /** Optional body fields (not required in the variant). */\n optionalParams: string[];\n /** Response model name (if any). */\n responseModelName: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// Algorithm\n// ---------------------------------------------------------------------------\n\n/**\n * Action verbs recognised at the terminal path segment.\n * When a path ends with one of these, we use it as the verb instead of\n * deriving a CRUD verb from the HTTP method.\n */\nconst ACTION_VERBS = new Set([\n 'accept',\n 'activate',\n 'authorize',\n 'challenge',\n 'check',\n 'complete',\n 'confirm',\n 'deactivate',\n 'disable',\n 'enable',\n 'enroll',\n 'generate',\n 'reactivate',\n 'resend',\n 'revoke',\n 'send',\n 'verify',\n]);\n\n/** Map HTTP method → default CRUD verb. */\nconst CRUD_VERB: Record<HttpMethod, string> = {\n get: 'list',\n post: 'create',\n put: 'update',\n patch: 'update',\n delete: 'delete',\n head: 'get',\n options: 'list',\n trace: 'list',\n};\n\n/**\n * Naive singularization: strips trailing \"s\" with common-sense exceptions.\n * Good enough for API resource nouns; not a general-purpose English stemmer.\n */\nfunction singularize(word: string): string {\n if (word.length <= 2) return word;\n if (word.endsWith('ies')) return word.slice(0, -3) + 'y';\n if (\n word.endsWith('ses') ||\n word.endsWith('zes') ||\n word.endsWith('xes') ||\n word.endsWith('ches') ||\n word.endsWith('shes')\n ) {\n return word.slice(0, -2);\n }\n if (word.endsWith('ss') || word.endsWith('us') || word.endsWith('is')) return word;\n if (word.endsWith('s')) return word.slice(0, -1);\n return word;\n}\n\n/**\n * Derive a snake_case method name from an operation's HTTP method and path.\n *\n * Rules:\n * 1. Strip path-param segments (`{id}`, `{slug}`, etc.)\n * 2. If the terminal segment is an action verb, use it as the verb\n * 3. Otherwise, use the CRUD verb for the HTTP method\n * 4. For GET on a collection (no trailing {id}), use \"list\"; with {id}, use \"get\"\n * 5. For POST on a resource path, if only one path param, use \"create\" singular\n * 6. Singularize the resource noun for single-resource operations\n */\nexport function deriveMethodName(op: Operation, _service: Service): string {\n const segments = op.path.split('/').filter(Boolean);\n\n // Separate static segments from param segments\n const staticSegments: string[] = [];\n let trailingParam = false;\n for (const seg of segments) {\n if (seg.startsWith('{') && seg.endsWith('}')) {\n trailingParam = true;\n } else {\n staticSegments.push(seg);\n trailingParam = false;\n }\n }\n\n if (staticSegments.length === 0) {\n return `${CRUD_VERB[op.httpMethod] ?? 'get'}_root`;\n }\n\n const terminal = toSnake(staticSegments[staticSegments.length - 1]);\n\n // Check if terminal is an action verb\n if (ACTION_VERBS.has(terminal)) {\n // Resource context from preceding segments\n const context = staticSegments.slice(0, -1).filter((s) => !s.startsWith('{'));\n const resource = context.length > 0 ? toSnake(singularize(context[context.length - 1])) : '';\n if (resource) {\n return `${terminal}_${resource}`;\n }\n return terminal;\n }\n\n // Determine verb from HTTP method\n let verb = CRUD_VERB[op.httpMethod] ?? 'get';\n\n // GET with trailing {id} → \"get\" instead of \"list\"\n if (op.httpMethod === 'get' && trailingParam) {\n verb = 'get';\n }\n\n // Build resource name from static segments.\n // When path params separate static segments, include the penultimate static\n // segment (singularized) as a parent-context prefix to disambiguate nested paths.\n // e.g. /authorization/organizations/{id}/roles → \"organization_roles\"\n let resource = toSnake(terminal);\n if (staticSegments.length >= 2) {\n const penultimate = staticSegments[staticSegments.length - 2];\n // Check if a path param appears between the penultimate and terminal segments\n // in the original path by finding both positions and looking for {…} between them.\n const penIdx = segments.lastIndexOf(penultimate);\n const termIdx = segments.lastIndexOf(staticSegments[staticSegments.length - 1]);\n const hasParamBetween = segments.slice(penIdx + 1, termIdx).some((s) => s.startsWith('{'));\n if (hasParamBetween) {\n const prefix = toSnake(singularize(penultimate));\n resource = `${prefix}_${resource}`;\n }\n }\n\n // Singularize when:\n // * there's a trailing path param (single-resource read/update/delete), or\n // * the verb itself implies a single-resource operation (e.g. POST → create\n // always creates one item even when posted to a collection endpoint).\n const isSingleResource = trailingParam || verb === 'create';\n const noun = isSingleResource ? singularize(resource) : resource;\n\n // For \"list\" verb, keep plural\n const finalNoun = verb === 'list' ? resource : noun;\n\n return `${verb}_${finalNoun}`;\n}\n\n/**\n * Resolve all operations in the spec, applying hints and mount rules.\n *\n * @param spec - The parsed API spec\n * @param hints - Per-operation overrides keyed by \"METHOD /path\"\n * @param mountRules - Service name → target service mappings\n * @returns Resolved operations ready for emitter consumption\n */\nexport function resolveOperations(\n spec: ApiSpec,\n hints?: Record<string, OperationHint>,\n mountRules?: Record<string, string>,\n): ResolvedOperation[] {\n const resolved: ResolvedOperation[] = [];\n const hintMap = hints ?? {};\n const mounts = mountRules ?? {};\n\n for (const service of spec.services) {\n for (const op of service.operations) {\n const key = `${op.httpMethod.toUpperCase()} ${op.path}`;\n const hint = hintMap[key];\n\n // Resolve method name: hint > algorithm\n const methodName = hint?.name ?? deriveMethodName(op, service);\n\n // Resolve mount target: per-op hint > service mount rule > original service\n const mountOn = hint?.mountOn ?? mounts[service.name] ?? service.name;\n\n // Build wrappers for split operations\n let wrappers: ResolvedWrapper[] | undefined;\n if (hint?.split) {\n wrappers = hint.split.map((sh) => ({\n name: sh.name,\n targetVariant: sh.targetVariant,\n defaults: sh.defaults ?? {},\n inferFromClient: sh.inferFromClient ?? [],\n exposedParams: sh.exposedParams ?? [],\n optionalParams: sh.optionalParams ?? [],\n responseModelName: resolveResponseModelName(op),\n }));\n }\n\n resolved.push({\n operation: op,\n service,\n methodName,\n mountOn,\n wrappers,\n defaults: hint?.defaults ?? {},\n inferFromClient: hint?.inferFromClient ?? [],\n urlBuilder: hint?.urlBuilder ?? false,\n });\n }\n }\n\n return resolved;\n}\n\n/** Extract the response model name from an operation (for wrapper metadata). */\nfunction resolveResponseModelName(op: Operation): string | null {\n if (op.httpMethod === 'delete') return null;\n const ref = op.response;\n if (ref.kind === 'model') return ref.name;\n if (ref.kind === 'nullable' && ref.inner.kind === 'model') return ref.inner.name;\n return null;\n}\n","import type { ApiSpec, Model, TypeRef, Service } from '../ir/types.js';\nimport { walkTypeRef } from '../ir/types.js';\nimport type { OperationHint } from '../ir/operation-hints.js';\nimport { resolveOperations } from '../ir/operation-hints.js';\nimport type { Emitter, EmitterContext, GeneratedFile, OperationsMap } from './types.js';\nimport type { ApiSurface, OverlayLookup } from '../compat/types.js';\nimport { toSnakeCase } from '../utils/naming.js';\n\nexport function buildEmitterContext(\n spec: ApiSpec,\n options: {\n namespace: string;\n outputDir: string;\n apiSurface?: ApiSurface;\n overlayLookup?: OverlayLookup;\n operationHints?: Record<string, OperationHint>;\n mountRules?: Record<string, string>;\n modelHints?: Record<string, string>;\n emitterOptions?: Record<string, unknown>;\n target?: string;\n priorTargetManifestPaths?: Set<string>;\n },\n): EmitterContext {\n return {\n namespace: toSnakeCase(options.namespace),\n namespacePascal: options.namespace,\n spec,\n outputDir: options.outputDir,\n apiSurface: options.apiSurface,\n overlayLookup: options.overlayLookup,\n resolvedOperations: resolveOperations(spec, options.operationHints, options.mountRules),\n modelHints: options.modelHints,\n emitterOptions: options.emitterOptions,\n targetDir: options.target,\n priorTargetManifestPaths: options.priorTargetManifestPaths,\n };\n}\n\n/**\n * Collect model and enum names transitively referenced by service operations.\n * Walks operation parameters, request bodies, responses, and pagination item\n * types, then chases model field references until the set stabilizes.\n */\nexport function collectReferencedNames(\n services: Service[],\n models: Model[],\n): { models: Set<string>; enums: Set<string> } {\n const referencedModels = new Set<string>();\n const referencedEnums = new Set<string>();\n\n const collectFromTypeRef = (ref: TypeRef): void => {\n walkTypeRef(ref, {\n model: (r) => referencedModels.add(r.name),\n enum: (r) => referencedEnums.add(r.name),\n });\n };\n\n // Seed: walk every operation's params, request body, response, errors, and pagination\n for (const service of services) {\n for (const op of service.operations) {\n for (const p of [...op.pathParams, ...op.queryParams, ...op.headerParams, ...(op.cookieParams ?? [])]) {\n collectFromTypeRef(p.type);\n }\n if (op.requestBody) collectFromTypeRef(op.requestBody);\n collectFromTypeRef(op.response);\n if (op.pagination) collectFromTypeRef(op.pagination.itemType);\n for (const err of op.errors) {\n if (err.type) collectFromTypeRef(err.type);\n }\n if (op.successResponses) {\n for (const sr of op.successResponses) {\n collectFromTypeRef(sr.type);\n }\n }\n }\n }\n\n // Preserve discriminated models as public SDK types even when no operation\n // returns them directly. This matters for event/webhook unions where the base\n // operation references a generic envelope but the variant structs are still\n // useful public surface.\n //\n // Also preserve the variants mapped from an `allOf [base, oneOf […]]` base\n // (carried as `Model.discriminator.mapping`). The base model is reached\n // through the operation; without explicitly chasing its mapping, the\n // variant structs would be unreachable and the dispatcher would dangle\n // imports.\n for (const model of models) {\n if (isDiscriminatedModel(model)) {\n referencedModels.add(model.name);\n }\n const disc = model.discriminator;\n if (disc?.mapping) {\n for (const variantName of Object.values(disc.mapping)) {\n referencedModels.add(variantName);\n }\n }\n }\n\n // Chase: transitively resolve model field references until stable\n const modelsByName = new Map(models.map((m) => [m.name, m]));\n const visited = new Set<string>();\n const queue = [...referencedModels];\n while (queue.length > 0) {\n const name = queue.pop()!;\n if (visited.has(name)) continue;\n visited.add(name);\n const model = modelsByName.get(name);\n if (!model) continue;\n for (const field of model.fields) {\n collectFromTypeRef(field.type);\n // If new models were discovered, enqueue them\n for (const m of referencedModels) {\n if (!visited.has(m)) queue.push(m);\n }\n }\n }\n\n return { models: referencedModels, enums: referencedEnums };\n}\n\nfunction isDiscriminatedModel(model: Model): boolean {\n return model.fields.some(\n (field) =>\n (field.name === 'event' || field.name === 'type' || field.name === 'object') && field.type.kind === 'literal',\n );\n}\n\n/** Collect all generated files from an emitter (no headers, no path prefixes). */\nexport function generateAllFiles(spec: ApiSpec, emitter: Emitter, ctx: EmitterContext): GeneratedFile[] {\n const referenced = collectReferencedNames(spec.services, spec.models);\n const reachableModels = spec.models.filter((m) => referenced.models.has(m.name));\n const reachableEnums = spec.enums.filter((e) => referenced.enums.has(e.name));\n const reachableSpec: ApiSpec = { ...spec, models: reachableModels, enums: reachableEnums };\n\n return [\n ...emitter.generateModels(reachableModels, ctx),\n ...emitter.generateEnums(reachableEnums, ctx),\n ...emitter.generateResources(spec.services, ctx),\n ...emitter.generateClient(spec, ctx),\n ...emitter.generateErrors(ctx),\n ...(emitter.generateTypeSignatures?.(reachableSpec, ctx) ?? []),\n ...emitter.generateTests(reachableSpec, ctx),\n ];\n}\n\n/** Apply file header to generated files, respecting headerPlacement and JSON files. */\nexport function applyFileHeaders(files: GeneratedFile[], header: string): GeneratedFile[] {\n return files.map((f) => ({\n ...f,\n content:\n !header || f.path.endsWith('.json') || f.headerPlacement === 'skip' ? f.content : header + '\\n\\n' + f.content,\n skipIfExists: f.skipIfExists ?? false,\n }));\n}\n\nexport function generateFiles(\n spec: ApiSpec,\n emitter: Emitter,\n options: {\n namespace: string;\n outputDir: string;\n apiSurface?: ApiSurface;\n overlayLookup?: OverlayLookup;\n operationHints?: Record<string, OperationHint>;\n mountRules?: Record<string, string>;\n modelHints?: Record<string, string>;\n emitterOptions?: Record<string, unknown>;\n target?: string;\n priorTargetManifestPaths?: Set<string>;\n },\n): { files: GeneratedFile[]; ctx: EmitterContext; header: string; operations?: OperationsMap } {\n const ctx = buildEmitterContext(spec, options);\n const files = generateAllFiles(spec, emitter, ctx);\n const operations = emitter.buildOperationsMap?.(spec, ctx);\n const header = emitter.fileHeader();\n return { files: applyFileHeaders(files, header), ctx, header, operations };\n}\n","import * as fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { GeneratedFile } from './types.js';\nimport { writeFiles, type WriteResult } from './writer.js';\nimport { extractStatements } from './merger.js';\nimport { hasGrammar } from './merger.js';\n\n/**\n * Resolve a relative import path against a source file path to get the\n * target file path. Handles implicit .ts extensions and /index.ts.\n */\nfunction resolveImportPath(\n fromFilePath: string,\n importModulePath: string,\n knownPaths: Set<string>,\n): string | undefined {\n // Strip quotes from module path key (tree-sitter keeps them)\n const cleaned = importModulePath.replace(/^['\"]|['\"]$/g, '');\n // Skip non-relative imports (node_modules, bare specifiers)\n if (!cleaned.startsWith('.')) return undefined;\n\n const dir = path.dirname(fromFilePath);\n const resolved = path.normalize(path.join(dir, cleaned));\n\n // Try exact match, .ts, /index.ts\n for (const candidate of [resolved, `${resolved}.ts`, `${resolved}/index.ts`]) {\n if (knownPaths.has(candidate)) return candidate;\n }\n return undefined;\n}\n\n/**\n * Determine whether a generated file is a \"root\" — a file that should always\n * be integrated into the target. Roots are entry points from which we trace\n * the import graph. Everything else must be reachable from a root.\n *\n * Roots: resource classes, client, config, errors, enums, barrel index files.\n * Non-roots: serializers, fixtures, standalone interfaces, test files.\n */\nfunction isRootFile(filePath: string): boolean {\n // Fixtures are never roots (and should be filtered by integrateTarget already)\n if (filePath.includes('/fixtures/')) return false;\n // Test files are roots — they are standalone entry points that belong in the\n // target repo even though nothing imports them.\n if (filePath.endsWith('.spec.ts') || filePath.endsWith('.test.ts')) return true;\n // Serializer files\n if (filePath.includes('/serializers/')) return false;\n // Standalone interface files (not barrel/index)\n if (filePath.includes('/interfaces/') && !filePath.endsWith('/index.ts')) return false;\n // Everything else is a root: resource classes, client, config, errors, enums, barrel files\n return true;\n}\n\n/**\n * Build a file-level dependency graph from generated files and return only\n * files reachable from root entry points. Uses tree-sitter to parse imports.\n */\nexport async function treeShakeFiles(files: GeneratedFile[], language: string): Promise<GeneratedFile[]> {\n if (!hasGrammar(language)) return files;\n\n const knownPaths = new Set(files.map((f) => f.path));\n\n // Build dependency graph: file → set of files it imports\n const deps = new Map<string, Set<string>>();\n for (const file of files) {\n // Only parse .ts/.js files (skip JSON, etc.)\n if (!file.path.endsWith('.ts') && !file.path.endsWith('.js')) {\n deps.set(file.path, new Set());\n continue;\n }\n const parsed = await extractStatements(file.content, language);\n const fileDeps = new Set<string>();\n for (const imp of parsed.imports) {\n const resolved = resolveImportPath(file.path, imp.key, knownPaths);\n if (resolved) fileDeps.add(resolved);\n }\n // Also check re-export statements (export * from './foo')\n for (const stmt of parsed.statements) {\n if (stmt.kind === 'reexport') {\n // Extract module path from \"export * from './foo'\" or \"export { X } from './foo'\"\n const match = stmt.text.match(/from\\s+['\"]([^'\"]+)['\"]/);\n if (match) {\n const resolved = resolveImportPath(file.path, match[1], knownPaths);\n if (resolved) fileDeps.add(resolved);\n }\n }\n }\n deps.set(file.path, fileDeps);\n }\n\n // Determine which file extensions are source code for this language\n const codeExtensions = new Set([\n '.ts',\n '.js',\n '.tsx',\n '.jsx',\n '.py',\n '.rb',\n '.go',\n '.rs',\n '.kt',\n '.cs',\n '.ex',\n '.exs',\n '.php',\n ]);\n\n // BFS from roots\n const reachable = new Set<string>();\n const queue: string[] = [];\n for (const file of files) {\n const ext = file.path.slice(file.path.lastIndexOf('.'));\n // Non-code files (JSON, etc.) are always reachable — they can't participate\n // in the import graph and are loaded at runtime (e.g. test fixtures).\n if (!codeExtensions.has(ext)) {\n reachable.add(file.path);\n continue;\n }\n if (isRootFile(file.path)) {\n reachable.add(file.path);\n queue.push(file.path);\n }\n }\n while (queue.length > 0) {\n const current = queue.pop()!;\n const fileDeps = deps.get(current);\n if (!fileDeps) continue;\n for (const dep of fileDeps) {\n if (!reachable.has(dep)) {\n reachable.add(dep);\n queue.push(dep);\n }\n }\n }\n\n return files.filter((f) => reachable.has(f.path));\n}\n\nexport function mapFilesForTargetIntegration(files: GeneratedFile[], language: string): GeneratedFile[] {\n const langPrefix = `${language}/`;\n return files\n .filter((f) => f.integrateTarget !== false) // integrateTarget: false files are standalone-only\n .map((f) => {\n const stripped = f.path.startsWith(langPrefix) ? f.path.replace(langPrefix, '') : f.path;\n return {\n ...f,\n skipIfExists: false, // Always merge in target — never hard-skip\n path: stripped,\n };\n });\n}\n\n/**\n * Resolve file-to-directory conflicts in the target.\n *\n * When a generated file creates a package directory (e.g., `api_keys/__init__.py`)\n * that would shadow an existing module file (e.g., `api_keys.py`), move the\n * module file's content into `_compat.py` inside the package and add a\n * re-export from `__init__.py`. This preserves backward-compatible imports\n * (e.g., `from workos.api_keys import ApiKeysModule`) while the package directory\n * provides the generated models and resource classes.\n */\nasync function resolveFileToDirectoryConflicts(\n files: GeneratedFile[],\n targetDir: string,\n): Promise<{ files: GeneratedFile[]; removals: string[] }> {\n const result = [...files];\n const removals: string[] = [];\n\n for (let i = 0; i < result.length; i++) {\n const file = result[i];\n // Match package init files: e.g., src/workos/api_keys/__init__.py\n const match = file.path.match(/^(.+)\\/__init__\\.py$/);\n if (!match) continue;\n\n const dirPath = match[1]; // e.g., src/workos/api_keys\n const moduleFilePath = `${dirPath}.py`; // e.g., src/workos/api_keys.py\n const fullModulePath = path.join(targetDir, moduleFilePath);\n\n let moduleContent: string;\n try {\n moduleContent = await fs.readFile(fullModulePath, 'utf-8');\n } catch {\n continue; // Module file doesn't exist — no conflict\n }\n\n // Create a compat shim inside the package with the old module's content\n const compatPath = `${dirPath}/_compat.py`;\n result.push({\n path: compatPath,\n content: moduleContent,\n overwriteExisting: true,\n });\n\n // Append re-export from _compat to __init__.py so existing imports work.\n // Compat must come AFTER generated models so hand-written types take\n // precedence over generated types with the same name.\n const compatImport = 'from ._compat import * # noqa: F401,F403 # pyright: ignore[reportUnusedImport]';\n const existingContent = file.content.endsWith('\\n') ? file.content : file.content + '\\n';\n result[i] = {\n ...file,\n content: existingContent + compatImport + '\\n',\n };\n\n // Schedule the shadowed module file for removal\n removals.push(fullModulePath);\n }\n\n return { files: result, removals };\n}\n\nexport interface IntegrateResult extends WriteResult {\n /** Final set of paths this run claims ownership of in the target (post tree-shake + conflict resolution). */\n emittedPaths: string[];\n}\n\nexport async function integrateGeneratedFiles(opts: {\n files: GeneratedFile[];\n language: string;\n targetDir: string;\n header: string;\n}): Promise<IntegrateResult> {\n const mapped = mapFilesForTargetIntegration(opts.files, opts.language);\n const shaken = await treeShakeFiles(mapped, opts.language);\n\n // Handle file-to-directory conflicts before writing\n const { files: resolved, removals } = await resolveFileToDirectoryConflicts(shaken, opts.targetDir);\n\n const result = await writeFiles(resolved, opts.targetDir, {\n language: opts.language,\n header: opts.header,\n });\n\n // Remove shadowed module files after integration\n for (const filePath of removals) {\n try {\n await fs.unlink(filePath);\n } catch {\n // File may already be gone\n }\n }\n\n // The manifest tracks ALL files oagen owns, including tree-shaken ones.\n // Tree-shaking decides what to write, but shaken files are still oagen-managed\n // and must not be pruned from the target on subsequent runs.\n return { ...result, emittedPaths: mapped.map((f) => f.path) };\n}\n","/**\n * Post-integration formatter.\n *\n * After generating and merging files into a target directory, runs the\n * emitter-provided format command on all written/merged files so that\n * generated code matches the target project's style conventions.\n */\n\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport * as path from 'node:path';\nimport type { Emitter } from './types.js';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Run the emitter's format command on the given target files.\n * Silently skips if the emitter has no formatCommand or returns null.\n */\nexport async function formatTargetFiles(emitter: Emitter, targetDir: string, filePaths: string[]): Promise<void> {\n if (filePaths.length === 0) return;\n if (!emitter.formatCommand) return;\n\n const formatCmd = emitter.formatCommand(targetDir);\n if (!formatCmd) return;\n\n const absolutePaths = filePaths.map((f) => path.resolve(targetDir, f));\n const batchSize = formatCmd.batchSize ?? 100;\n\n process.stderr.write(\n `[oagen] formatting ${absolutePaths.length} file(s) with ${formatCmd.cmd} (batch ${batchSize})\\n`,\n );\n\n for (let i = 0; i < absolutePaths.length; i += batchSize) {\n const batch = absolutePaths.slice(i, i + batchSize);\n try {\n await execFileAsync(formatCmd.cmd, [...formatCmd.args, ...batch], {\n cwd: targetDir,\n maxBuffer: 10 * 1024 * 1024,\n timeout: 120_000,\n });\n } catch (err) {\n // Formatter failed on this batch — continue with remaining batches.\n // Surface the failure on stderr so misconfigured commands don't silently\n // leave generated code unformatted every regen.\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[oagen] formatter batch failed: ${msg}\\n`);\n }\n }\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\n/**\n * Prune-manifest support for `oagen generate`.\n *\n * The manifest records every auto-generated file emitted on the previous run,\n * relative to the directory it lives in (either the `--output` standalone dir\n * or the `--target` integration dir). On the next run we diff the previous\n * list against the current emission set and delete anything that's no longer\n * produced — preventing stale-file accumulation across regens.\n *\n * Design notes:\n * - The manifest is versioned so future format changes can be handled safely.\n * - Paths are stored sorted for deterministic diffs in git.\n * - Deletion is gated on a header guard when one is available: we only remove\n * files whose contents start with the auto-generated header. This protects\n * a hand-maintained file that happens to share a name with a previously\n * generated one (extremely rare, but worth catching).\n * - On first adoption (no previous manifest), pruning is skipped and a\n * one-line notice is printed — no surprise deletions.\n */\n\nexport const MANIFEST_FILENAME = '.oagen-manifest.json';\nconst MANIFEST_VERSION = 2;\n\nexport interface Manifest {\n /** Schema version. Bump when the format changes incompatibly. */\n version: number;\n /** Emitter language (e.g. \"python\"). Used only as a consistency hint. */\n language: string;\n /** Human-readable or package-level SDK identity (e.g. \"workos-php\"). */\n sdkName?: string;\n /** ISO-8601 timestamp of the run that produced the current manifest contents. */\n generatedAt: string;\n /** SHA-256 hash of the source OpenAPI spec used for generation. */\n specSha?: string;\n /** Path or reference to the source spec. */\n specPath?: string;\n /** Git SHA or version of the emitter code used. */\n emitterSha?: string;\n /** Emitter version string if available. */\n emitterVersion?: string;\n /** SHA-256 hash of the effective oagen.config.ts after resolution. */\n configSha?: string;\n /** Version of the compat snapshot/report schema expected by this generation. */\n compatSchemaVersion?: string;\n /** Sorted list of paths, relative to the manifest's containing directory. */\n files: string[];\n /** Maps \"METHOD /path\" to SDK method + service property name. */\n operations?: Record<string, unknown>;\n}\n\nexport interface PruneResult {\n /** Paths actually deleted. */\n pruned: string[];\n /** Paths skipped because the header guard didn't match (preserved). */\n preserved: string[];\n /** Paths already absent on disk (nothing to do). */\n missing: string[];\n}\n\n/** Read `.oagen-manifest.json` from a directory. Returns null if absent or malformed. */\nexport async function readManifest(dir: string): Promise<Manifest | null> {\n const manifestPath = path.join(dir, MANIFEST_FILENAME);\n let raw: string;\n try {\n raw = await fs.readFile(manifestPath, 'utf-8');\n } catch {\n return null;\n }\n try {\n const parsed = JSON.parse(raw) as Partial<Manifest>;\n if (\n typeof parsed.version !== 'number' ||\n typeof parsed.language !== 'string' ||\n typeof parsed.generatedAt !== 'string' ||\n !Array.isArray(parsed.files) ||\n !parsed.files.every((p): p is string => typeof p === 'string')\n ) {\n return null;\n }\n if (parsed.version > MANIFEST_VERSION) {\n console.warn(\n `[oagen] ${MANIFEST_FILENAME} schema version ${parsed.version} is newer than supported (${MANIFEST_VERSION}); ignoring for pruning.`,\n );\n return null;\n }\n // v1 manifests are forward-compatible — new fields are simply absent\n return parsed as Manifest;\n } catch {\n return null;\n }\n}\n\n/** Options for writing a manifest. */\nexport interface WriteManifestOpts {\n language: string;\n files: Iterable<string>;\n sdkName?: string;\n specSha?: string;\n specPath?: string;\n emitterSha?: string;\n emitterVersion?: string;\n configSha?: string;\n compatSchemaVersion?: string;\n operations?: Record<string, unknown>;\n}\n\n/** Write `.oagen-manifest.json` to a directory with sorted paths. */\nexport async function writeManifest(dir: string, opts: WriteManifestOpts): Promise<void> {\n const manifestPath = path.join(dir, MANIFEST_FILENAME);\n const manifest: Manifest = {\n version: MANIFEST_VERSION,\n language: opts.language,\n ...(opts.sdkName !== undefined ? { sdkName: opts.sdkName } : {}),\n generatedAt: new Date().toISOString(),\n ...(opts.specSha !== undefined ? { specSha: opts.specSha } : {}),\n ...(opts.specPath !== undefined ? { specPath: opts.specPath } : {}),\n ...(opts.emitterSha !== undefined ? { emitterSha: opts.emitterSha } : {}),\n ...(opts.emitterVersion !== undefined ? { emitterVersion: opts.emitterVersion } : {}),\n ...(opts.configSha !== undefined ? { configSha: opts.configSha } : {}),\n ...(opts.compatSchemaVersion !== undefined ? { compatSchemaVersion: opts.compatSchemaVersion } : {}),\n files: [...new Set(opts.files)].sort(),\n ...(opts.operations !== undefined ? { operations: opts.operations } : {}),\n };\n const previous = await readManifest(dir);\n if (previous && sameManifestExceptGeneratedAt(previous, manifest)) {\n manifest.generatedAt = previous.generatedAt;\n }\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\\n', 'utf-8');\n}\n\nfunction sameManifestExceptGeneratedAt(a: Manifest, b: Manifest): boolean {\n const { generatedAt: _aGeneratedAt, ...aComparable } = a;\n const { generatedAt: _bGeneratedAt, ...bComparable } = b;\n return JSON.stringify(aComparable) === JSON.stringify(bComparable);\n}\n\n/** Return the set of previous paths no longer present in the current emission. */\nexport function computeStalePaths(prev: Manifest, currentPaths: Iterable<string>): string[] {\n const current = new Set(currentPaths);\n return prev.files.filter((p) => !current.has(p)).sort();\n}\n\n/**\n * Delete stale files from `dir`.\n *\n * When `header` is provided, a file is only deleted if its contents start with\n * that header — so hand-maintained files that somehow collide with a previously\n * generated path can't be clobbered. When `header` is omitted, the guard is\n * skipped (useful for non-source artifacts like fixture JSON).\n *\n * Returns lists for reporting. Empty parent directories are removed after\n * deletion, up to (but not including) `dir` itself.\n */\nexport async function pruneStaleFiles(\n dir: string,\n paths: string[],\n opts: { header?: string } = {},\n): Promise<PruneResult> {\n const pruned: string[] = [];\n const preserved: string[] = [];\n const missing: string[] = [];\n\n for (const relPath of paths) {\n const fullPath = path.join(dir, relPath);\n let content: string;\n try {\n content = await fs.readFile(fullPath, 'utf-8');\n } catch {\n missing.push(relPath);\n continue;\n }\n if (opts.header && !content.startsWith(opts.header)) {\n preserved.push(relPath);\n continue;\n }\n try {\n await fs.unlink(fullPath);\n pruned.push(relPath);\n } catch {\n // Racing deletion or permission issue — treat as missing rather than fatal.\n missing.push(relPath);\n continue;\n }\n await removeEmptyParents(path.dirname(fullPath), dir);\n }\n\n return { pruned, preserved, missing };\n}\n\n/**\n * Walk up from `startDir` removing empty directories until we hit `stopDir`\n * (exclusive) or a non-empty directory. Silently ignores errors.\n */\nasync function removeEmptyParents(startDir: string, stopDir: string): Promise<void> {\n let current = path.resolve(startDir);\n const stop = path.resolve(stopDir);\n while (current.startsWith(stop + path.sep) && current !== stop) {\n let entries: string[];\n try {\n entries = await fs.readdir(current);\n } catch {\n return;\n }\n if (entries.length > 0) return;\n try {\n await fs.rmdir(current);\n } catch {\n return;\n }\n current = path.dirname(current);\n }\n}\n","import type { ApiSpec } from '../ir/types.js';\nimport type { OperationHint } from '../ir/operation-hints.js';\nimport type { Emitter, GeneratedFile } from './types.js';\nimport type { ApiSurface, OverlayLookup } from '../compat/types.js';\nimport { writeFiles } from './writer.js';\nimport { generateFiles } from './generate-files.js';\nimport { integrateGeneratedFiles } from './integrate.js';\nimport { formatTargetFiles } from './formatter.js';\nimport { computeStalePaths, MANIFEST_FILENAME, pruneStaleFiles, readManifest, writeManifest } from './manifest.js';\n\nexport async function generate(\n spec: ApiSpec,\n emitter: Emitter,\n options: {\n namespace: string;\n dryRun?: boolean;\n outputDir: string;\n target?: string;\n apiSurface?: ApiSurface;\n overlayLookup?: OverlayLookup;\n operationHints?: Record<string, OperationHint>;\n mountRules?: Record<string, string>;\n modelHints?: Record<string, string>;\n emitterOptions?: Record<string, unknown>;\n /** When true, skip deletion of files recorded in the previous manifest but not in the current emission. */\n noPrune?: boolean;\n },\n): Promise<GeneratedFile[]> {\n // Read previous manifests up front so emitters can mark files the prior run\n // wrote as safe-to-overwrite (vs files a human hand-maintains). Skipped\n // when --no-prune is set so users opting out of lifecycle tracking also opt\n // out of overwrite-on-regen behavior.\n const outputPrevManifestForCtx = options.noPrune ? null : await readManifest(options.outputDir);\n const targetManifestForCtx = options.target && !options.noPrune ? await readManifest(options.target) : null;\n const priorTargetManifestPaths = targetManifestForCtx\n ? new Set(targetManifestForCtx.files)\n : outputPrevManifestForCtx\n ? new Set(outputPrevManifestForCtx.files)\n : undefined;\n\n const {\n files: withHeaders,\n header,\n operations,\n } = generateFiles(spec, emitter, {\n ...options,\n priorTargetManifestPaths,\n });\n\n if (options.dryRun) {\n if (options.target) {\n console.log(`\\nTarget integration (${options.target}):`);\n for (const f of withHeaders) {\n console.log(` ${f.path}`);\n }\n }\n return withHeaders;\n }\n\n // Reuse the manifest read before generation; nothing above writes it.\n const outputPrevManifest = outputPrevManifestForCtx;\n\n const writeResult = await writeFiles(withHeaders, options.outputDir, {\n language: emitter.language,\n header,\n });\n\n if (writeResult.merged.length > 0) {\n console.log(`Merged into ${writeResult.merged.length} existing files (additive only)`);\n }\n if (writeResult.ignored.length > 0) {\n console.log(`Ignored ${writeResult.ignored.length} files (@oagen-ignore-file)`);\n }\n\n const outputEmittedPaths = withHeaders.map((f) => f.path);\n await applyManifestPrune({\n dir: options.outputDir,\n label: 'Output',\n prevManifest: outputPrevManifest,\n currentPaths: outputEmittedPaths,\n language: emitter.language,\n header,\n noPrune: options.noPrune,\n operations,\n });\n\n // Format output files so the emitter's formatter runs even without --target.\n const allOutputFiles = [...writeResult.written, ...writeResult.merged];\n if (allOutputFiles.length > 0) {\n await formatTargetFiles(emitter, options.outputDir, allOutputFiles);\n }\n\n // Target integration pass\n if (options.target) {\n // Reuse the manifest we already read to build the emitter context. This\n // is correct because nothing between the two reads writes the manifest.\n const targetPrevManifest = targetManifestForCtx;\n\n const targetResult = await integrateGeneratedFiles({\n files: withHeaders,\n language: emitter.language,\n targetDir: options.target,\n header,\n });\n\n if (targetResult.written.length > 0) {\n console.log(`Target: created ${targetResult.written.length} new files`);\n }\n if (targetResult.merged.length > 0) {\n console.log(`Target: merged into ${targetResult.merged.length} existing files (additive only)`);\n }\n if (targetResult.skipped.length > 0) {\n console.log(`Target: skipped ${targetResult.skipped.length} files (excluded or no grammar)`);\n }\n\n await applyManifestPrune({\n dir: options.target,\n label: 'Target',\n prevManifest: targetPrevManifest,\n currentPaths: targetResult.emittedPaths,\n language: emitter.language,\n header,\n noPrune: options.noPrune,\n operations,\n });\n\n // Run the emitter's formatter on all written/merged/identical files\n const allTargetFiles = [...targetResult.written, ...targetResult.merged, ...targetResult.identical];\n if (allTargetFiles.length > 0) {\n await formatTargetFiles(emitter, options.target, allTargetFiles);\n }\n }\n\n return withHeaders;\n}\n\n/**\n * Prune files recorded in the previous manifest but absent from the current emission,\n * then write the fresh manifest. Safe on first adoption (no previous manifest).\n */\nasync function applyManifestPrune(opts: {\n dir: string;\n label: string;\n prevManifest: Awaited<ReturnType<typeof readManifest>>;\n currentPaths: string[];\n language: string;\n header: string;\n noPrune?: boolean;\n operations?: Record<string, unknown>;\n}): Promise<void> {\n const manifestOpts = { language: opts.language, files: opts.currentPaths, operations: opts.operations };\n if (opts.noPrune) {\n // Still refresh the manifest so future runs with pruning enabled have a baseline.\n await writeManifest(opts.dir, manifestOpts);\n return;\n }\n\n if (!opts.prevManifest) {\n console.log(\n `${opts.label}: no ${MANIFEST_FILENAME} found — skipping prune (this baseline manifest will be written now).`,\n );\n await writeManifest(opts.dir, manifestOpts);\n return;\n }\n\n const stale = computeStalePaths(opts.prevManifest, opts.currentPaths);\n if (stale.length > 0) {\n const { pruned, preserved } = await pruneStaleFiles(opts.dir, stale, { header: opts.header });\n if (pruned.length > 0) {\n console.log(`${opts.label}: pruned ${pruned.length} stale file${pruned.length === 1 ? '' : 's'}`);\n }\n if (preserved.length > 0) {\n console.log(\n `${opts.label}: preserved ${preserved.length} file${preserved.length === 1 ? '' : 's'} in previous manifest but lacking the auto-generated header (possibly hand-edited).`,\n );\n for (const p of preserved) console.log(` ${p}`);\n }\n }\n\n await writeManifest(opts.dir, manifestOpts);\n}\n","import { RegistryError } from '../errors.js';\nimport type { Emitter } from './types.js';\n\nconst emitters = new Map<string, Emitter>();\n\nexport function registerEmitter(emitter: Emitter): void {\n emitters.set(emitter.language, emitter);\n}\n\nexport function getEmitter(language: string): Emitter {\n const emitter = emitters.get(language);\n if (!emitter) {\n const available = [...emitters.keys()].join(', ') || '(none)';\n throw new RegistryError(\n `Unknown language: ${language}. Available: ${available}`,\n `Register an emitter for \"${language}\" via registerEmitter() or check your oagen.config.ts plugin configuration.`,\n );\n }\n return emitter;\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 { 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., WorkOS) 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","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 { readFileSync, existsSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { MANIFEST_FILENAME } from './manifest.js';\n\n/** Minimal shape matching compat/overlay.ts ManifestEntry for cross-layer use. */\ninterface 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 * Read the operations map from `.oagen-manifest.json` in the given directory\n * and convert it to `ManifestEntry[]` for the overlay builder.\n *\n * Returns undefined if the manifest is absent or has no operations field.\n */\nexport function readManifestSync(dir: string): ManifestEntry[] | undefined {\n const manifestPath = path.join(dir, MANIFEST_FILENAME);\n if (!existsSync(manifestPath)) return undefined;\n try {\n const parsed = JSON.parse(readFileSync(manifestPath, 'utf-8'));\n const operations = parsed?.operations;\n if (!operations || typeof operations !== 'object') return undefined;\n return convertOperationsToManifestEntries(operations);\n } catch {\n return undefined;\n }\n}\n\n/** Convert the operations map from .oagen-manifest.json into ManifestEntry[]. */\nfunction convertOperationsToManifestEntries(operations: Record<string, unknown>): ManifestEntry[] {\n const entries: ManifestEntry[] = [];\n for (const [httpKey, value] of Object.entries(operations)) {\n const spaceIdx = httpKey.indexOf(' ');\n const httpMethod = httpKey.slice(0, spaceIdx);\n const httpPath = httpKey.slice(spaceIdx + 1);\n\n const values = Array.isArray(value) ? value : [value];\n for (const v of values) {\n const entry = v as { sdkMethod?: string; service?: string };\n entries.push({\n operationId: '',\n sdkResourceProperty: entry.service ?? '',\n sdkMethodName: entry.sdkMethod ?? '',\n httpMethod,\n path: httpPath,\n pathParams: [],\n bodyFields: [],\n queryFields: [],\n });\n }\n }\n return entries;\n}\n","import { readFileSync } from 'node:fs';\nimport { ConfigError } from '../errors.js';\nimport { buildOverlayLookup } from '../compat/overlay.js';\nimport type { ApiSurface, LanguageHints, OverlayLookup } from '../compat/types.js';\nimport type { ApiSpec } from '../ir/types.js';\nimport { nodeHints } from '../compat/language-hints.js';\nimport { getExtractor } from '../compat/extractor-registry.js';\nimport { readManifestSync } from '../engine/manifest-reader.js';\n\nexport interface OverlayContext {\n apiSurface: ApiSurface;\n overlayLookup: OverlayLookup;\n}\n\n/**\n * Load an API surface from disk, discover/load the manifest, resolve\n * language hints, and build the overlay lookup. Shared by diff and generate.\n */\nexport function loadOverlayContext(opts: {\n apiSurfacePath: string;\n outputDir: string;\n lang: string;\n spec?: ApiSpec;\n}): OverlayContext {\n let raw: string;\n try {\n raw = readFileSync(opts.apiSurfacePath, 'utf-8');\n } catch {\n throw new ConfigError(\n `API surface file not found: ${opts.apiSurfacePath}. Run \\`oagen extract\\` first.`,\n `Generate the API surface file by running \\`oagen extract --lang ${opts.lang} --sdk-path <path-to-sdk>\\` before running this command.`,\n );\n }\n let apiSurface: ApiSurface;\n try {\n apiSurface = JSON.parse(raw) as ApiSurface;\n } catch (err) {\n throw new ConfigError(\n `Failed to parse API surface JSON: ${err instanceof Error ? err.message : String(err)}`,\n `Ensure \"${opts.apiSurfacePath}\" contains valid JSON. Re-run \\`oagen extract\\` to regenerate it.`,\n );\n }\n\n // Load operations from .oagen-manifest.json in output directory\n const manifest = readManifestSync(opts.outputDir);\n\n let hints: LanguageHints = nodeHints;\n try {\n hints = getExtractor(opts.lang).hints;\n } catch {\n // no extractor registered — use nodeHints fallback\n }\n\n const overlayLookup = buildOverlayLookup(apiSurface, manifest, opts.spec, hints);\n return { apiSurface, overlayLookup };\n}\n","import type { ApiSpec } from '../ir/types.js';\n\n/**\n * Walk all description fields in the IR and expand relative URL paths\n * (e.g. `/reference/authkit/user`) into full URLs using the given base.\n *\n * Matches markdown-style links: `[text](/path)` → `[text](https://example.com/path)`\n * and bare parenthetical refs: `(/path)` → `(https://example.com/path)`\n */\nexport function expandDocUrls(spec: ApiSpec, docUrl: string): ApiSpec {\n // Normalize: strip trailing slash so joins are clean\n const base = docUrl.replace(/\\/+$/, '');\n\n function expand(description: string | undefined): string | undefined {\n if (!description) return description;\n // Match markdown links and bare parenthetical paths with a leading slash\n return description.replace(/\\(\\/([^)]*)\\)/g, `(${base}/$1)`);\n }\n\n return {\n ...spec,\n description: expand(spec.description),\n services: spec.services.map((service) => ({\n ...service,\n description: expand(service.description),\n operations: service.operations.map((op) => ({\n ...op,\n description: expand(op.description),\n pathParams: op.pathParams.map((p) => ({ ...p, description: expand(p.description) })),\n queryParams: op.queryParams.map((p) => ({ ...p, description: expand(p.description) })),\n headerParams: op.headerParams.map((p) => ({ ...p, description: expand(p.description) })),\n })),\n })),\n models: spec.models.map((model) => ({\n ...model,\n description: expand(model.description),\n fields: model.fields.map((f) => ({ ...f, description: expand(f.description) })),\n })),\n enums: spec.enums.map((e) => ({\n ...e,\n values: e.values.map((v) => ({ ...v, description: expand(v.description) })),\n })),\n };\n}\n","import { parseSpec, type OpenApiDocument } from '../parser/parse.js';\nimport { generate } from '../engine/orchestrator.js';\nimport { getEmitter } from '../engine/registry.js';\nimport { loadOverlayContext } from './overlay-loader.js';\nimport { expandDocUrls } from '../utils/expand-doc-urls.js';\nimport type { OperationHint } from '../ir/operation-hints.js';\n\nexport async function generateCommand(opts: {\n spec: string;\n lang: string;\n output: string;\n target?: string;\n namespace?: string;\n dryRun?: boolean;\n apiSurface?: string;\n compatCheck?: boolean;\n /** From `--no-prune`. When false, manifest-driven stale-file pruning is skipped. */\n prune?: boolean;\n operationIdTransform?: (id: string) => string;\n schemaNameTransform?: (name: string) => string;\n transformSpec?: (spec: OpenApiDocument) => OpenApiDocument;\n docUrl?: string;\n operationHints?: Record<string, OperationHint>;\n mountRules?: Record<string, string>;\n modelHints?: Record<string, string>;\n emitterOptions?: Record<string, unknown>;\n}): Promise<void> {\n let ir = await parseSpec(opts.spec, {\n operationIdTransform: opts.operationIdTransform,\n schemaNameTransform: opts.schemaNameTransform,\n transformSpec: opts.transformSpec,\n });\n if (opts.docUrl) {\n ir = expandDocUrls(ir, opts.docUrl);\n }\n const emitter = getEmitter(opts.lang);\n const namespace = opts.namespace ?? ir.name;\n\n // Build overlay from API surface if provided and not disabled\n let apiSurface;\n let overlayLookup;\n if (opts.apiSurface && opts.compatCheck !== false) {\n const ctx = loadOverlayContext({\n apiSurfacePath: opts.apiSurface,\n outputDir: opts.output,\n lang: opts.lang,\n spec: ir,\n });\n apiSurface = ctx.apiSurface;\n overlayLookup = ctx.overlayLookup;\n }\n\n const files = await generate(ir, emitter, {\n namespace,\n dryRun: opts.dryRun,\n outputDir: opts.output,\n target: opts.target,\n apiSurface,\n overlayLookup,\n operationHints: opts.operationHints,\n mountRules: opts.mountRules,\n modelHints: opts.modelHints,\n emitterOptions: opts.emitterOptions,\n noPrune: opts.prune === false,\n });\n\n if (opts.dryRun) {\n for (const f of files) {\n console.log(f.path);\n }\n } else {\n console.log(`Generated ${files.length} files in ${opts.output}`);\n if (opts.target) {\n console.log(`Integrated into ${opts.target}`);\n }\n }\n}\n","import type { FieldChange, ParamChange } from './types.js';\n\nexport function classifyFieldChange(kind: FieldChange['kind'], fieldName: string, isRequired?: boolean): FieldChange {\n switch (kind) {\n case 'field-added':\n return {\n kind,\n fieldName,\n classification: isRequired ? 'breaking' : 'additive',\n };\n case 'field-removed':\n return { kind, fieldName, classification: 'breaking' };\n case 'field-type-changed':\n return { kind, fieldName, classification: 'breaking' };\n case 'field-format-changed':\n // A primitive's `format` changing (e.g., string → string format=email)\n // is classified additive at the IR level: the wire-format base type is\n // unchanged, so callers' deserialization keeps working. Per-emitter\n // compat checks catch any source-level break a specific language layers\n // on top (e.g., a typed Email value object in TypeScript).\n return { kind, fieldName, classification: 'additive' };\n case 'field-required-changed':\n return {\n kind,\n fieldName,\n classification: isRequired ? 'breaking' : 'additive',\n details: isRequired ? 'optional → required' : 'required → optional',\n };\n case 'field-access-changed':\n return { kind, fieldName, classification: 'breaking' };\n }\n}\n\nexport function classifyParamChange(kind: ParamChange['kind'], paramName: string, isRequired?: boolean): ParamChange {\n switch (kind) {\n case 'param-added':\n return {\n kind,\n paramName,\n classification: isRequired ? 'breaking' : 'additive',\n };\n case 'param-removed':\n return { kind, paramName, classification: 'breaking' };\n case 'param-type-changed':\n return { kind, paramName, classification: 'breaking' };\n case 'param-format-changed':\n // See `field-format-changed`: format-only diffs are additive at the IR\n // layer.\n return { kind, paramName, classification: 'additive' };\n case 'param-required-changed':\n return {\n kind,\n paramName,\n classification: isRequired ? 'breaking' : 'additive',\n };\n case 'param-default-changed':\n // Removing or changing a default that callers may have implicitly relied on\n // changes runtime behavior for clients who never set the param explicitly.\n // We treat this as breaking so it surfaces as a major bump rather than\n // sliding through as a silent regression.\n return { kind, paramName, classification: 'breaking' };\n }\n}\n","import type { Model, TypeRef } from '../ir/types.js';\nimport { assertNever } from '../ir/types.js';\nimport type { Change, FieldChange } from './types.js';\nimport { classifyFieldChange } from './classify.js';\n\nexport function diffModels(oldModels: Model[], newModels: Model[]): Change[] {\n const changes: Change[] = [];\n const oldByName = new Map(oldModels.map((m) => [m.name, m]));\n const newByName = new Map(newModels.map((m) => [m.name, m]));\n\n for (const [name] of newByName) {\n if (!oldByName.has(name)) {\n changes.push({ kind: 'model-added', name, classification: 'additive' });\n }\n }\n\n for (const [name] of oldByName) {\n if (!newByName.has(name)) {\n changes.push({ kind: 'model-removed', name, classification: 'breaking' });\n }\n }\n\n for (const [name, newModel] of newByName) {\n const oldModel = oldByName.get(name);\n if (!oldModel) continue;\n\n const fieldChanges = diffFields(oldModel, newModel);\n if (fieldChanges.length > 0) {\n const hasBreaking = fieldChanges.some((fc) => fc.classification === 'breaking');\n changes.push({\n kind: 'model-modified',\n name,\n fieldChanges,\n classification: hasBreaking ? 'breaking' : 'additive',\n });\n }\n }\n\n return changes;\n}\n\nfunction diffFields(oldModel: Model, newModel: Model): FieldChange[] {\n const changes: FieldChange[] = [];\n const oldByName = new Map(oldModel.fields.map((f) => [f.name, f]));\n const newByName = new Map(newModel.fields.map((f) => [f.name, f]));\n\n for (const [name, field] of newByName) {\n if (!oldByName.has(name)) {\n changes.push(classifyFieldChange('field-added', name, field.required));\n }\n }\n\n for (const [name] of oldByName) {\n if (!newByName.has(name)) {\n changes.push(classifyFieldChange('field-removed', name));\n }\n }\n\n for (const [name, newField] of newByName) {\n const oldField = oldByName.get(name);\n if (!oldField) continue;\n\n if (!typeRefsEqual(oldField.type, newField.type)) {\n if (primitivesDifferOnlyByFormat(oldField.type, newField.type)) {\n changes.push({\n ...classifyFieldChange('field-format-changed', name),\n details: formatChangeDetails(oldField.type, newField.type),\n });\n } else {\n changes.push({\n kind: 'field-type-changed',\n fieldName: name,\n classification: 'breaking',\n details: `type changed`,\n });\n }\n }\n\n if (oldField.required !== newField.required) {\n changes.push(classifyFieldChange('field-required-changed', name, newField.required));\n }\n\n if (!!oldField.readOnly !== !!newField.readOnly || !!oldField.writeOnly !== !!newField.writeOnly) {\n changes.push(classifyFieldChange('field-access-changed', name));\n }\n }\n\n return changes;\n}\n\n/**\n * True when both refs are primitives with the same base `type` but different\n * `format`. Used to downgrade format-only diffs from breaking type changes to\n * additive `field-format-changed` / `param-format-changed` events: the wire\n * base type is unchanged, so the diff is a hint to language emitters rather\n * than a source-level break.\n */\nexport function primitivesDifferOnlyByFormat(a: TypeRef, b: TypeRef): boolean {\n if (a.kind !== 'primitive' || b.kind !== 'primitive') return false;\n if (a.type !== b.type) return false;\n return (a.format ?? '') !== (b.format ?? '');\n}\n\nexport function formatChangeDetails(a: TypeRef, b: TypeRef): string {\n const oldFmt = a.kind === 'primitive' ? a.format : undefined;\n const newFmt = b.kind === 'primitive' ? b.format : undefined;\n return `format ${oldFmt ?? '<unset>'} → ${newFmt ?? '<unset>'}`;\n}\n\nexport function typeRefsEqual(a: TypeRef, b: TypeRef): boolean {\n if (a.kind !== b.kind) return false;\n\n switch (a.kind) {\n case 'primitive':\n return b.kind === 'primitive' && a.type === b.type && (a.format ?? '') === ((b as typeof a).format ?? '');\n case 'array':\n return b.kind === 'array' && typeRefsEqual(a.items, b.items);\n case 'model':\n return b.kind === 'model' && a.name === b.name;\n case 'enum':\n return b.kind === 'enum' && a.name === b.name;\n case 'literal':\n return b.kind === 'literal' && a.value === b.value;\n case 'nullable':\n return b.kind === 'nullable' && typeRefsEqual(a.inner, b.inner);\n case 'union': {\n if (b.kind !== 'union') return false;\n if (a.variants.length !== b.variants.length) return false;\n if (!a.variants.every((v, i) => typeRefsEqual(v, b.variants[i]))) return false;\n // Compare discriminator\n if (!a.discriminator && !b.discriminator) return true;\n if (!a.discriminator || !b.discriminator) return false;\n if (a.discriminator.property !== b.discriminator.property) return false;\n const aKeys = Object.keys(a.discriminator.mapping).sort();\n const bKeys = Object.keys(b.discriminator.mapping).sort();\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every((k, i) => k === bKeys[i] && a.discriminator!.mapping[k] === b.discriminator!.mapping[k]);\n }\n case 'map':\n return b.kind === 'map' && typeRefsEqual(a.valueType, b.valueType);\n }\n return assertNever(a);\n}\n","import type { ErrorResponse, Operation } from '../ir/types.js';\nimport type { Change, ParamChange } from './types.js';\nimport { classifyParamChange } from './classify.js';\nimport { formatChangeDetails, primitivesDifferOnlyByFormat, typeRefsEqual } from './models.js';\n\nexport function diffOperations(serviceName: string, oldOps: Operation[], newOps: Operation[]): Change[] {\n const changes: Change[] = [];\n const oldByName = new Map(oldOps.map((o) => [o.name, o]));\n const newByName = new Map(newOps.map((o) => [o.name, o]));\n\n for (const [name] of newByName) {\n if (!oldByName.has(name)) {\n changes.push({\n kind: 'operation-added',\n serviceName,\n operationName: name,\n classification: 'additive',\n });\n }\n }\n\n for (const [name] of oldByName) {\n if (!newByName.has(name)) {\n changes.push({\n kind: 'operation-removed',\n serviceName,\n operationName: name,\n classification: 'breaking',\n });\n }\n }\n\n for (const [name, newOp] of newByName) {\n const oldOp = oldByName.get(name);\n if (!oldOp) continue;\n\n const paramChanges = diffParams(oldOp, newOp);\n const responseChanged = !typeRefsEqual(oldOp.response, newOp.response);\n const requestBodyChanged = !requestBodiesEqual(oldOp.requestBody, newOp.requestBody);\n const httpMethodChanged = oldOp.httpMethod !== newOp.httpMethod;\n const pathChanged = oldOp.path !== newOp.path;\n const paginatedChanged = !!oldOp.pagination !== !!newOp.pagination;\n const injectIdempotencyKeyChanged = oldOp.injectIdempotencyKey !== newOp.injectIdempotencyKey;\n const errorsDiff = classifyErrorsChange(oldOp.errors, newOp.errors);\n const errorsChanged = errorsDiff !== 'none';\n\n const hasChanges =\n paramChanges.length > 0 ||\n responseChanged ||\n requestBodyChanged ||\n httpMethodChanged ||\n pathChanged ||\n paginatedChanged ||\n injectIdempotencyKeyChanged ||\n errorsChanged;\n\n if (hasChanges) {\n // paginated: false→true is additive (SDK gains pagination helper)\n // paginated: true→false is breaking (SDK loses pagination helper)\n const paginatedBreaking = paginatedChanged && !newOp.pagination;\n // injectIdempotencyKey: false→true is additive (SDK gains idempotency key)\n // injectIdempotencyKey: true→false is breaking (SDK loses idempotency key)\n const injectIdempotencyKeyBreaking = injectIdempotencyKeyChanged && !newOp.injectIdempotencyKey;\n const errorsBreaking = errorsDiff === 'breaking';\n\n const hasBreaking =\n responseChanged ||\n requestBodyChanged ||\n httpMethodChanged ||\n pathChanged ||\n paginatedBreaking ||\n injectIdempotencyKeyBreaking ||\n errorsBreaking ||\n paramChanges.some((pc) => pc.classification === 'breaking');\n changes.push({\n kind: 'operation-modified',\n serviceName,\n operationName: name,\n paramChanges,\n responseChanged,\n requestBodyChanged,\n httpMethodChanged,\n pathChanged,\n paginatedChanged,\n injectIdempotencyKeyChanged,\n errorsChanged,\n classification: hasBreaking ? 'breaking' : 'additive',\n });\n }\n }\n\n return changes;\n}\n\nfunction requestBodiesEqual(a: Operation['requestBody'], b: Operation['requestBody']): boolean {\n if (!a && !b) return true;\n if (!a || !b) return false;\n return typeRefsEqual(a, b);\n}\n\nfunction classifyErrorsChange(\n oldErrors: ErrorResponse[],\n newErrors: ErrorResponse[],\n): 'none' | 'additive' | 'breaking' {\n const oldByCode = new Map(oldErrors.map((e) => [e.statusCode, e]));\n const newByCode = new Map(newErrors.map((e) => [e.statusCode, e]));\n\n let hasAdditive = false;\n let hasBreaking = false;\n\n // New error codes added → additive (SDK gains new error classes)\n for (const code of newByCode.keys()) {\n if (!oldByCode.has(code)) hasAdditive = true;\n }\n\n // Old error codes removed → breaking (SDK loses error classes)\n for (const code of oldByCode.keys()) {\n if (!newByCode.has(code)) hasBreaking = true;\n }\n\n // Shared error codes with changed types → breaking\n for (const [code, newErr] of newByCode) {\n const oldErr = oldByCode.get(code);\n if (!oldErr) continue;\n if (!oldErr.type && !newErr.type) continue;\n if (!oldErr.type || !newErr.type || !typeRefsEqual(oldErr.type, newErr.type)) {\n hasBreaking = true;\n }\n }\n\n if (hasBreaking) return 'breaking';\n if (hasAdditive) return 'additive';\n return 'none';\n}\n\nfunction diffParams(oldOp: Operation, newOp: Operation): ParamChange[] {\n const changes: ParamChange[] = [];\n const tagged = (loc: 'path' | 'query' | 'header', params: typeof oldOp.queryParams) =>\n params.map((p) => ({ p, loc }));\n const allOldParams = [\n ...tagged('path', oldOp.pathParams),\n ...tagged('query', oldOp.queryParams),\n ...tagged('header', oldOp.headerParams),\n ];\n const allNewParams = [\n ...tagged('path', newOp.pathParams),\n ...tagged('query', newOp.queryParams),\n ...tagged('header', newOp.headerParams),\n ];\n const oldByName = new Map(allOldParams.map((e) => [e.p.name, e]));\n const newByName = new Map(allNewParams.map((e) => [e.p.name, e]));\n\n for (const [name, entry] of newByName) {\n if (!oldByName.has(name)) {\n changes.push(classifyParamChange('param-added', name, entry.p.required));\n }\n }\n\n for (const [name] of oldByName) {\n if (!newByName.has(name)) {\n changes.push(classifyParamChange('param-removed', name));\n }\n }\n\n for (const [name, newEntry] of newByName) {\n const oldEntry = oldByName.get(name);\n if (!oldEntry) continue;\n\n if (!typeRefsEqual(oldEntry.p.type, newEntry.p.type)) {\n if (primitivesDifferOnlyByFormat(oldEntry.p.type, newEntry.p.type)) {\n const change = classifyParamChange('param-format-changed', name);\n change.details = formatChangeDetails(oldEntry.p.type, newEntry.p.type);\n changes.push(change);\n } else {\n changes.push(classifyParamChange('param-type-changed', name));\n }\n }\n\n if (oldEntry.p.required !== newEntry.p.required) {\n changes.push(classifyParamChange('param-required-changed', name, newEntry.p.required));\n }\n\n const oldDefault = serializeDefault(oldEntry.p.default);\n const newDefault = serializeDefault(newEntry.p.default);\n if (oldDefault !== newDefault) {\n const change = classifyParamChange('param-default-changed', name);\n change.oldDefault = oldDefault;\n change.newDefault = newDefault;\n change.paramLocation = newEntry.loc;\n change.details = `default ${oldDefault ?? '<unset>'} → ${newDefault ?? '<unset>'}`;\n changes.push(change);\n }\n }\n\n return changes;\n}\n\nfunction serializeDefault(value: unknown): string | null {\n if (value === undefined) return null;\n if (value === null) return 'null';\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n // Objects/arrays: stable JSON. Stringification of equal-valued objects is\n // deterministic enough for this comparison since callers typically pass\n // primitives; complex defaults are rare.\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n","import type { Service } from '../ir/types.js';\nimport type { Change } from './types.js';\nimport { diffOperations } from './operations.js';\n\nexport function diffServices(oldServices: Service[], newServices: Service[]): Change[] {\n const changes: Change[] = [];\n const oldByName = new Map(oldServices.map((s) => [s.name, s]));\n const newByName = new Map(newServices.map((s) => [s.name, s]));\n\n for (const [name] of newByName) {\n if (!oldByName.has(name)) {\n changes.push({ kind: 'service-added', name, classification: 'additive' });\n }\n }\n\n for (const [name] of oldByName) {\n if (!newByName.has(name)) {\n changes.push({ kind: 'service-removed', name, classification: 'breaking' });\n }\n }\n\n for (const [name, newService] of newByName) {\n const oldService = oldByName.get(name);\n if (!oldService) continue;\n\n changes.push(...diffOperations(name, oldService.operations, newService.operations));\n }\n\n return changes;\n}\n","import type { ApiSpec, Enum } from '../ir/types.js';\nimport type { BehaviorChange, Change, DiffReport, EnumValueChange } from './types.js';\nimport { diffModels } from './models.js';\nimport { diffServices } from './services.js';\n\nexport function diffSpecs(oldSpec: ApiSpec, newSpec: ApiSpec): DiffReport {\n const changes: Change[] = [\n ...diffModels(oldSpec.models, newSpec.models),\n ...diffEnums(oldSpec.enums, newSpec.enums),\n ...diffServices(oldSpec.services, newSpec.services),\n ];\n\n const behaviorChanges = collectBehaviorChanges(changes);\n\n return {\n oldVersion: oldSpec.version,\n newVersion: newSpec.version,\n changes,\n behaviorChanges,\n summary: { ...summarize(changes), behaviorChanges: behaviorChanges.length },\n };\n}\n\nfunction collectBehaviorChanges(changes: Change[]): BehaviorChange[] {\n const out: BehaviorChange[] = [];\n for (const c of changes) {\n if (c.kind !== 'operation-modified') continue;\n for (const pc of c.paramChanges) {\n if (pc.kind !== 'param-default-changed') continue;\n out.push({\n kind: 'param-default-changed',\n serviceName: c.serviceName,\n operationName: c.operationName,\n paramName: pc.paramName,\n paramLocation: pc.paramLocation ?? 'query',\n oldDefault: pc.oldDefault ?? null,\n newDefault: pc.newDefault ?? null,\n classification: 'breaking',\n });\n }\n }\n return out;\n}\n\nfunction diffEnums(oldEnums: Enum[], newEnums: Enum[]): Change[] {\n const changes: Change[] = [];\n const oldByName = new Map(oldEnums.map((e) => [e.name, e]));\n const newByName = new Map(newEnums.map((e) => [e.name, e]));\n\n for (const [name] of newByName) {\n if (!oldByName.has(name)) {\n changes.push({ kind: 'enum-added', name, classification: 'additive' });\n }\n }\n\n for (const [name] of oldByName) {\n if (!newByName.has(name)) {\n changes.push({ kind: 'enum-removed', name, classification: 'breaking' });\n }\n }\n\n for (const [name, newEnum] of newByName) {\n const oldEnum = oldByName.get(name);\n if (!oldEnum) continue;\n\n const valueChanges = diffEnumValues(oldEnum, newEnum);\n if (valueChanges.length > 0) {\n const hasBreaking = valueChanges.some((vc) => vc.classification === 'breaking');\n changes.push({\n kind: 'enum-modified',\n name,\n valueChanges,\n classification: hasBreaking ? 'breaking' : 'additive',\n });\n }\n }\n\n return changes;\n}\n\nfunction diffEnumValues(oldEnum: Enum, newEnum: Enum): EnumValueChange[] {\n const changes: EnumValueChange[] = [];\n const oldByName = new Map(oldEnum.values.map((v) => [v.name, v]));\n const newByName = new Map(newEnum.values.map((v) => [v.name, v]));\n\n for (const [name] of newByName) {\n if (!oldByName.has(name)) {\n changes.push({ kind: 'value-added', valueName: name, classification: 'additive' });\n }\n }\n\n for (const [name] of oldByName) {\n if (!newByName.has(name)) {\n changes.push({ kind: 'value-removed', valueName: name, classification: 'breaking' });\n }\n }\n\n for (const [name, newVal] of newByName) {\n const oldVal = oldByName.get(name);\n if (!oldVal) continue;\n\n if (oldVal.value !== newVal.value) {\n changes.push({\n kind: 'value-changed',\n valueName: name,\n classification: 'breaking',\n details: `value changed from '${oldVal.value}' to '${newVal.value}'`,\n });\n }\n }\n\n return changes;\n}\n\nfunction summarize(changes: Change[]) {\n let added = 0;\n let removed = 0;\n let modified = 0;\n let breaking = 0;\n let additive = 0;\n\n for (const c of changes) {\n if (c.kind.endsWith('-added')) added++;\n else if (c.kind.endsWith('-removed')) removed++;\n else if (c.kind.endsWith('-modified')) modified++;\n\n if (c.classification === 'breaking') breaking++;\n else additive++;\n }\n\n return { added, removed, modified, breaking, additive };\n}\n","import { parseSpec, type OpenApiDocument } from '../parser/parse.js';\nimport { diffSpecs } from '../differ/diff.js';\nimport { CommandError } from '../errors.js';\nimport { expandDocUrls } from '../utils/expand-doc-urls.js';\n\nexport async function diffCommand(opts: {\n old: string;\n new: string;\n operationIdTransform?: (id: string) => string;\n schemaNameTransform?: (name: string) => string;\n transformSpec?: (spec: OpenApiDocument) => OpenApiDocument;\n docUrl?: string;\n}): Promise<void> {\n const parseOptions = {\n operationIdTransform: opts.operationIdTransform,\n schemaNameTransform: opts.schemaNameTransform,\n transformSpec: opts.transformSpec,\n };\n let [oldSpec, newSpec] = await Promise.all([parseSpec(opts.old, parseOptions), parseSpec(opts.new, parseOptions)]);\n if (opts.docUrl) {\n oldSpec = expandDocUrls(oldSpec, opts.docUrl);\n newSpec = expandDocUrls(newSpec, opts.docUrl);\n }\n\n const diff = diffSpecs(oldSpec, newSpec);\n console.log(JSON.stringify(diff, null, 2));\n throw new CommandError(\n '',\n '',\n diff.summary.breaking > 0\n ? 2\n : diff.summary.modified > 0 || diff.summary.removed > 0\n ? 1\n : diff.summary.added > 0\n ? 1\n : 0,\n );\n}\n","import { writeFileSync } from 'node:fs';\nimport { getExtractor } from '../compat/extractor-registry.js';\n\nexport async function extractCommand(opts: { sdkPath: string; lang: string; output: string }): Promise<void> {\n const extractor = getExtractor(opts.lang);\n console.log(`Extracting ${opts.lang} API surface from ${opts.sdkPath}...`);\n const surface = await extractor.extract(opts.sdkPath);\n writeFileSync(opts.output, JSON.stringify(surface, null, 2));\n const symbolCount =\n Object.keys(surface.classes).length +\n Object.keys(surface.interfaces).length +\n Object.keys(surface.typeAliases).length +\n Object.keys(surface.enums).length;\n console.log(`Extracted ${symbolCount} symbols → ${opts.output}`);\n}\n","/**\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 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';\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 };\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 /** 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 ...(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 },\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 default:\n return 'positional';\n }\n}\n","import { readFileSync, writeFileSync } from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { resolve } from 'node:path';\nimport { getExtractor } from '../compat/extractor-registry.js';\nimport { parseSpec, type OpenApiDocument } from '../parser/parse.js';\nimport { apiSurfaceToSnapshot } from '../compat/ir.js';\nimport { readManifest } from '../engine/manifest.js';\nimport type { Manifest } from '../engine/manifest.js';\nimport type { CompatSnapshot } from '../compat/ir.js';\nimport type { ApiSurface, ApiClass } from '../compat/types.js';\nimport type { ApiSpec } from '../ir/types.js';\n\nconst SNAPSHOT_FILENAME = '.oagen-compat-snapshot.json';\n\n/** Normalize a name for case-insensitive matching: strip underscores and lowercase. */\nfunction normalize(name: string): string {\n return name.replace(/_/g, '').toLowerCase();\n}\n\n/**\n * Build a map of normalized service name → Set of generated method names\n * from the manifest's operations record.\n */\nfunction buildServiceMethodMap(operations: Record<string, unknown>): Map<string, Set<string>> {\n const result = new Map<string, Set<string>>();\n for (const value of Object.values(operations)) {\n if (typeof value !== 'object' || value === null) continue;\n const { sdkMethod, service } = value as { sdkMethod?: string; service?: string };\n if (typeof sdkMethod !== 'string' || typeof service !== 'string') continue;\n const key = normalize(service);\n if (!result.has(key)) result.set(key, new Set());\n result.get(key)!.add(sdkMethod);\n }\n return result;\n}\n\n/**\n * Filter an ApiSurface to only include generated symbols based on the manifest.\n *\n * Two levels of filtering:\n * 1. File-level: classes/interfaces/enums from files not in the manifest are\n * dropped entirely (they are wholly hand-written).\n * 2. Method-level: for service classes (those whose name matches a manifest\n * service), only methods listed in the manifest operations are kept.\n * Constructors and properties are always preserved since they are structural.\n * Non-service classes (models, enums, etc.) keep all their symbols.\n */\nfunction filterSurfaceByManifest(\n surface: ApiSurface,\n manifest: Manifest,\n): {\n filtered: ApiSurface;\n filesExcluded: number;\n methodsExcluded: number;\n} {\n const manifestFiles = new Set(manifest.files);\n const serviceMethodMap = manifest.operations\n ? buildServiceMethodMap(manifest.operations)\n : new Map<string, Set<string>>();\n\n let filesExcluded = 0;\n let methodsExcluded = 0;\n\n // Filter a record by manifest files, counting exclusions\n const filterByFile = <T extends { sourceFile?: string }>(record: Record<string, T>): Record<string, T> => {\n const result: Record<string, T> = {};\n for (const [name, entry] of Object.entries(record)) {\n if (entry.sourceFile && manifestFiles.has(entry.sourceFile)) {\n result[name] = entry;\n } else {\n filesExcluded++;\n }\n }\n return result;\n };\n\n // Filter classes: file-level first, then method-level for service classes\n const filteredClasses: Record<string, ApiClass> = {};\n for (const [name, cls] of Object.entries(surface.classes)) {\n if (cls.sourceFile && !manifestFiles.has(cls.sourceFile)) {\n filesExcluded++;\n continue;\n }\n\n // Check if this class is a service with known operations\n const generatedMethods = serviceMethodMap.get(normalize(name));\n if (generatedMethods) {\n // Service class from a generated file — keep all methods.\n // File-level filtering already ensures this is a generated file;\n // method-level filtering was dropping wrapper methods (e.g.\n // createM2MApplication) and utility methods (e.g. verify_event)\n // that aren't tracked as HTTP operations in the manifest.\n // Clear constructorParams: service constructors are internal DI\n // wiring (e.g. __construct($client)), not user-facing API.\n filteredClasses[name] = { ...cls, constructorParams: [] };\n } else {\n // Model / utility class — keep all symbols\n filteredClasses[name] = cls;\n }\n }\n\n // Filter exports to only include files in the manifest\n const filteredExports: Record<string, string[]> = {};\n for (const [filePath, symbols] of Object.entries(surface.exports)) {\n if (manifestFiles.has(filePath)) {\n filteredExports[filePath] = symbols;\n }\n }\n\n return {\n filtered: {\n ...surface,\n classes: filteredClasses,\n interfaces: filterByFile(surface.interfaces),\n typeAliases: filterByFile(surface.typeAliases),\n enums: filterByFile(surface.enums),\n exports: filteredExports,\n },\n filesExcluded,\n methodsExcluded,\n };\n}\n\nexport async function compatExtractCommand(opts: {\n sdkPath: string;\n lang: string;\n output: string;\n spec?: string;\n schemaNameTransform?: (name: string) => string;\n transformSpec?: (spec: OpenApiDocument) => OpenApiDocument;\n}): Promise<void> {\n const extractor = getExtractor(opts.lang);\n console.log(`Extracting ${opts.lang} compat snapshot from ${opts.sdkPath}...`);\n\n let surface = await extractor.extract(opts.sdkPath);\n\n // If the SDK has a manifest, scope extraction to only generated symbols.\n // File-level: excludes wholly hand-written files.\n const manifest = await readManifest(opts.sdkPath);\n if (manifest) {\n const { filtered, filesExcluded } = filterSurfaceByManifest(surface, manifest);\n surface = filtered;\n if (filesExcluded > 0) {\n console.log(`Manifest filter: excluded ${filesExcluded} hand-written file(s)`);\n }\n }\n\n const snapshot = apiSurfaceToSnapshot(surface);\n\n // Enrich with spec context if provided\n if (opts.spec) {\n const specContent = readFileSync(opts.spec, 'utf-8');\n snapshot.source.specSha = createHash('sha256').update(specContent).digest('hex');\n\n const parsedSpec = await parseSpec(opts.spec, {\n schemaNameTransform: opts.schemaNameTransform,\n transformSpec: opts.transformSpec,\n });\n enrichWithSpecContext(snapshot, parsedSpec);\n }\n\n const outputPath = resolve(opts.output, SNAPSHOT_FILENAME);\n writeFileSync(outputPath, JSON.stringify(snapshot, null, 2));\n console.log(`Extracted ${snapshot.symbols.length} symbols → ${outputPath}`);\n}\n\n/**\n * Enrich snapshot symbols with spec-level identity.\n *\n * - Callable symbols get `operationId` and `route` from spec operations.\n * - Property/field/constructor/service_accessor symbols get `schemaName`\n * from spec models, enabling cross-language grouping in reports.\n *\n * The `schemaName` uses the spec-level identity (e.g. \"GenerateLinkBody.admin_emails\")\n * which is the same regardless of the language's naming conventions.\n */\nfunction enrichWithSpecContext(snapshot: CompatSnapshot, spec: ApiSpec): void {\n // Build lookup: \"ServiceName.methodName\" → { operationId, method, path }\n const opLookup = new Map<string, { operationId: string; method: string; path: string }>();\n for (const service of spec.services) {\n for (const op of service.operations) {\n const key = `${service.name}.${op.name}`;\n opLookup.set(key, {\n operationId: op.name,\n method: op.httpMethod,\n path: op.path,\n });\n }\n }\n\n // Build model field lookup for schema-level identity.\n // Normalized class name → { specModelName, fields: Map<normalizedFieldName, specFieldName> }\n const norm = (s: string) => s.replace(/_/g, '').toLowerCase();\n const modelLookup = new Map<string, { specName: string; fields: Map<string, string> }>();\n for (const model of spec.models) {\n const fieldMap = new Map<string, string>();\n for (const field of model.fields) {\n fieldMap.set(norm(field.name), field.name);\n }\n modelLookup.set(norm(model.name), { specName: model.name, fields: fieldMap });\n }\n\n for (const sym of snapshot.symbols) {\n // Enrich callables with operation identity\n if (sym.kind === 'callable') {\n const match = opLookup.get(sym.fqName);\n if (match) {\n sym.operationId = match.operationId;\n sym.route = { method: match.method, path: match.path };\n }\n }\n\n // Enrich all symbols with schema-level identity\n if (sym.ownerFqName) {\n // This symbol belongs to a class — try to match the class to a spec model\n const modelMatch = modelLookup.get(norm(sym.ownerFqName));\n if (modelMatch) {\n // Extract the local name (part after the dot)\n const localName = sym.fqName.includes('.') ? sym.fqName.split('.').pop()! : sym.fqName;\n const fieldMatch = modelMatch.fields.get(norm(localName));\n if (fieldMatch) {\n sym.schemaName = `${modelMatch.specName}.${fieldMatch}`;\n } else {\n // Class-level symbol (constructor, etc.) — use just the model name\n sym.schemaName = modelMatch.specName;\n }\n }\n } else {\n // Top-level symbol (class itself) — try to match to a spec model\n const modelMatch = modelLookup.get(norm(sym.fqName));\n if (modelMatch) {\n sym.schemaName = modelMatch.specName;\n }\n }\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\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., \"WorkOS\\\\Service\\\\UserManagement::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]);\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 } 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// 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): 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));\n }\n\n // Return type changes (for callables)\n if (baseline.returns && candidate.returns && baseline.returns.name !== candidate.returns.name) {\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 // Field/property type changes\n if (baseline.typeRef && candidate.typeRef && baseline.typeRef.name !== candidate.typeRef.name) {\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): 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 (baseParam.type.name !== candParam.type.name) {\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 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' },\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 },\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 { 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., \"SSO.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 /sso/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., SSO.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));\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","/**\n * Conceptual change grouping for cross-language compatibility analysis.\n *\n * Groups related changes across languages into a single conceptual change\n * with per-language severity. This allows reports to say \"parameter rename\n * on Authorization.check is breaking in PHP, Python, Kotlin, and .NET but\n * soft-risk in Go\" rather than treating these as unrelated per-language findings.\n */\n\nimport type { LanguageId } from './ir.js';\nimport type { CompatChangeSeverity, CompatChangeCategory } from './config.js';\nimport type { CompatDiffResult } from './differ.js';\n\n/** A conceptual change with per-language severity. */\nexport interface ConceptualChange {\n /** Deterministic ID from symbol + category + match details. */\n id: string;\n /** IR-level symbol path (language-neutral). */\n symbol: string;\n /** The kind of change. */\n category: CompatChangeCategory;\n /** Per-language severity mapping. */\n impact: Partial<Record<LanguageId, CompatChangeSeverity>>;\n /** Human-readable description (from first language that reported it). */\n message: string;\n /** Old state details. */\n old: Record<string, string>;\n /** New state details. */\n new: Record<string, string>;\n}\n\n/** Cross-language conceptual rollup. */\nexport interface ConceptualRollup {\n conceptualChanges: ConceptualChange[];\n}\n\n/**\n * Group classified changes from multiple languages into conceptual changes.\n *\n * Changes are grouped by their `conceptualChangeId` — a deterministic ID\n * derived from the symbol, category, and match details. Changes with the\n * same ID across different languages represent the same conceptual change.\n */\nexport function buildConceptualRollup(\n perLanguageResults: Array<{ diff: CompatDiffResult; language: LanguageId }>,\n): ConceptualRollup {\n const grouped = new Map<string, ConceptualChange>();\n\n for (const { diff: result, language } of perLanguageResults) {\n for (const change of result.changes) {\n const existing = grouped.get(change.conceptualChangeId);\n if (existing) {\n existing.impact[language] = change.severity;\n } else {\n grouped.set(change.conceptualChangeId, {\n id: change.conceptualChangeId,\n symbol: change.symbol,\n category: change.category,\n impact: { [language]: change.severity },\n message: change.message,\n old: change.old,\n new: change.new,\n });\n }\n }\n }\n\n return {\n conceptualChanges: [...grouped.values()],\n };\n}\n\n/** Get the highest severity across all languages for a conceptual change. */\nexport function highestSeverity(change: ConceptualChange): CompatChangeSeverity {\n const severities = Object.values(change.impact);\n if (severities.includes('breaking')) return 'breaking';\n if (severities.includes('soft-risk')) return 'soft-risk';\n return 'additive';\n}\n\n/** Count conceptual changes by highest severity. */\nexport function summarizeConceptualChanges(rollup: ConceptualRollup): {\n breaking: number;\n softRisk: number;\n additive: number;\n} {\n let breaking = 0;\n let softRisk = 0;\n let additive = 0;\n for (const change of rollup.conceptualChanges) {\n const sev = highestSeverity(change);\n if (sev === 'breaking') breaking++;\n else if (sev === 'soft-risk') softRisk++;\n else additive++;\n }\n return { breaking, softRisk, additive };\n}\n","/**\n * Report generation for compatibility verification.\n *\n * Produces machine-readable JSON reports, human-readable terminal summaries,\n * and conceptual cross-language summaries.\n */\n\nimport type { LanguageId } from './ir.js';\nimport type { CompatChangeSeverity, CompatChangeCategory, CompatProvenance } from './config.js';\nimport type { CompatDiffResult } from './differ.js';\nimport { buildConceptualRollup, highestSeverity, summarizeConceptualChanges } from './concepts.js';\n\n// ---------------------------------------------------------------------------\n// Machine-readable report\n// ---------------------------------------------------------------------------\n\n/** Machine-readable compat report for a single language. */\nexport interface CompatReport {\n schemaVersion: string;\n language: string;\n summary: {\n breaking: number;\n softRisk: number;\n additive: number;\n };\n changes: CompatReportChange[];\n}\n\n/** A single change entry in the machine-readable report. */\nexport interface CompatReportChange {\n severity: CompatChangeSeverity;\n category: CompatChangeCategory;\n symbol: string;\n conceptualChangeId: string;\n provenance: CompatProvenance;\n old: Record<string, string>;\n new: Record<string, string>;\n message?: string;\n /** Spec-level remediation hint when a recognized upstream pattern was detected. */\n remediation?: string;\n}\n\n/** Generate a machine-readable compat report from a diff result. */\nexport function generateReport(diff: CompatDiffResult, language?: string): CompatReport {\n return {\n schemaVersion: '1',\n language: language ?? 'unknown',\n summary: diff.summary,\n changes: diff.changes.map((c) => ({\n severity: c.severity,\n category: c.category,\n symbol: c.symbol,\n conceptualChangeId: c.conceptualChangeId,\n provenance: c.provenance,\n old: c.old,\n new: c.new,\n ...(c.message ? { message: c.message } : {}),\n ...(c.remediation ? { remediation: c.remediation } : {}),\n })),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Human-readable terminal summary\n// ---------------------------------------------------------------------------\n\n/** Generate a human-readable summary string for terminal output. */\nexport function formatHumanSummary(diff: CompatDiffResult, opts?: { explain?: boolean; language?: string }): string {\n const lines: string[] = [];\n\n lines.push(`Compat report${opts?.language ? ` for ${opts.language}` : ''}:`);\n lines.push(\n ` ${diff.summary.breaking} breaking, ${diff.summary.softRisk} soft-risk, ${diff.summary.additive} additive`,\n );\n\n if (diff.changes.length === 0) {\n lines.push(' No compatibility changes detected.');\n return lines.join('\\n');\n }\n\n // Group by severity for display\n const breaking = diff.changes.filter((c) => c.severity === 'breaking');\n const softRisk = diff.changes.filter((c) => c.severity === 'soft-risk');\n const additive = diff.changes.filter((c) => c.severity === 'additive');\n\n if (breaking.length > 0) {\n lines.push('');\n lines.push(' Breaking:');\n for (const c of breaking) {\n lines.push(` [${c.category}] ${c.symbol} — ${c.message}`);\n if (c.remediation) {\n lines.push(` hint: ${c.remediation}`);\n }\n if (opts?.explain && c.provenance !== 'unknown') {\n lines.push(` provenance: ${c.provenance}`);\n }\n }\n }\n\n if (softRisk.length > 0) {\n lines.push('');\n lines.push(' Soft-risk:');\n for (const c of softRisk) {\n lines.push(` [${c.category}] ${c.symbol} — ${c.message}`);\n if (c.remediation) {\n lines.push(` hint: ${c.remediation}`);\n }\n if (opts?.explain && c.provenance !== 'unknown') {\n lines.push(` provenance: ${c.provenance}`);\n }\n }\n }\n\n if (additive.length > 0) {\n lines.push('');\n lines.push(` Additive: ${additive.length} new symbol(s)`);\n }\n\n return lines.join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// Conceptual cross-language summary\n// ---------------------------------------------------------------------------\n\n/** Conceptual cross-language report. */\nexport interface ConceptualReport {\n conceptualChanges: {\n id: string;\n symbol: string;\n category: CompatChangeCategory;\n impact: Partial<Record<LanguageId, CompatChangeSeverity>>;\n }[];\n}\n\n/** Generate a conceptual cross-language report from multiple per-language results. */\nexport function generateConceptualReport(\n perLanguageResults: Array<{ diff: CompatDiffResult; language: LanguageId }>,\n): ConceptualReport {\n const rollup = buildConceptualRollup(perLanguageResults);\n return {\n conceptualChanges: rollup.conceptualChanges.map((c) => ({\n id: c.id,\n symbol: c.symbol,\n category: c.category,\n impact: c.impact,\n })),\n };\n}\n\n/** Format a conceptual cross-language summary for terminal output. */\nexport function formatConceptualSummary(\n perLanguageResults: Array<{ diff: CompatDiffResult; language: LanguageId }>,\n): string {\n const rollup = buildConceptualRollup(perLanguageResults);\n const summary = summarizeConceptualChanges(rollup);\n const lines: string[] = [];\n\n lines.push('Cross-language conceptual summary:');\n lines.push(` ${summary.breaking} breaking, ${summary.softRisk} soft-risk, ${summary.additive} additive`);\n\n if (rollup.conceptualChanges.length === 0) {\n lines.push(' No cross-language changes.');\n return lines.join('\\n');\n }\n\n for (const change of rollup.conceptualChanges) {\n const sev = highestSeverity(change);\n const impactStr = Object.entries(change.impact)\n .map(([lang, s]) => `${lang}: ${s}`)\n .join(', ');\n lines.push(` [${sev}] ${change.category}: ${change.symbol}`);\n lines.push(` impact: ${impactStr}`);\n }\n\n return lines.join('\\n');\n}\n","import { readFileSync, writeFileSync } from 'node:fs';\nimport { validateSnapshot } from '../compat/schema.js';\nimport { diffSnapshots } from '../compat/differ.js';\nimport { generateReport, formatHumanSummary } from '../compat/report.js';\nimport { severityMeetsThreshold } from '../compat/config.js';\nimport type { CompatFailLevel } from '../compat/config.js';\nimport type { CompatSnapshot } from '../compat/ir.js';\n\nexport async function compatDiffCommand(opts: {\n baseline: string;\n candidate: string;\n output?: string;\n failOn?: string;\n explain?: boolean;\n}): Promise<void> {\n const baselineData = JSON.parse(readFileSync(opts.baseline, 'utf-8'));\n const candidateData = JSON.parse(readFileSync(opts.candidate, 'utf-8'));\n\n if (!validateSnapshot(baselineData)) {\n throw new Error(`Invalid baseline snapshot: ${opts.baseline}`);\n }\n if (!validateSnapshot(candidateData)) {\n throw new Error(`Invalid candidate snapshot: ${opts.candidate}`);\n }\n\n const baseline = baselineData as CompatSnapshot;\n const candidate = candidateData as CompatSnapshot;\n\n const diff = diffSnapshots(baseline, candidate);\n\n // Human-readable output to terminal\n console.log(formatHumanSummary(diff, { explain: opts.explain }));\n\n // Machine-readable output to file\n if (opts.output) {\n const report = generateReport(diff);\n writeFileSync(opts.output, JSON.stringify(report, null, 2));\n console.log(`Report written to ${opts.output}`);\n }\n\n // Fail if threshold exceeded\n const failOn = (opts.failOn ?? 'breaking') as CompatFailLevel;\n const hasFailure = diff.changes.some((c) => severityMeetsThreshold(c.severity, failOn));\n if (hasFailure) {\n process.exitCode = 1;\n }\n}\n","import { readFileSync, writeFileSync } from 'node:fs';\nimport type { CompatReport, CompatReportChange } from '../compat/report.js';\nimport type { CompatDiffResult } from '../compat/differ.js';\nimport type { LanguageId } from '../compat/ir.js';\nimport type { CompatChangeSeverity } from '../compat/config.js';\nimport { buildConceptualRollup, highestSeverity, summarizeConceptualChanges } from '../compat/concepts.js';\n\n/**\n * Format compat report(s) as a markdown PR comment.\n *\n * Single report:\n * oagen compat-summary --report node-report.json | gh pr comment --body-file -\n *\n * Multiple reports (cross-language rollup):\n * oagen compat-summary --report php.json --report python.json --report go.json\n */\nexport async function compatSummaryCommand(opts: { report: string | string[]; output?: string }): Promise<void> {\n const paths = Array.isArray(opts.report) ? opts.report : [opts.report];\n const reports = paths.map((p) => JSON.parse(readFileSync(p, 'utf-8')) as CompatReport);\n\n const md = reports.length === 1 ? formatSingleReport(reports[0]) : formatCrossLanguageRollup(reports);\n\n if (opts.output) {\n writeFileSync(opts.output, md);\n console.log(`Summary written to ${opts.output}`);\n } else {\n process.stdout.write(md);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Single-language report\n// ---------------------------------------------------------------------------\n\nfunction formatSingleReport(report: CompatReport): string {\n const lines: string[] = [];\n const { breaking, softRisk, additive } = report.summary;\n const total = breaking + softRisk + additive;\n\n if (breaking > 0) {\n lines.push(`## :x: Compat check failed — ${report.language}`);\n } else if (softRisk > 0) {\n lines.push(`## :warning: Compat check has warnings — ${report.language}`);\n } else {\n lines.push(`## :white_check_mark: Compat check passed — ${report.language}`);\n }\n\n lines.push('');\n lines.push('| Severity | Count |');\n lines.push('| --- | --- |');\n lines.push(`| Breaking | ${breaking} |`);\n lines.push(`| Soft-risk | ${softRisk} |`);\n lines.push(`| Additive | ${additive} |`);\n lines.push(`| **Total** | **${total}** |`);\n\n if (total === 0) {\n lines.push('');\n lines.push('No compatibility changes detected.');\n return lines.join('\\n') + '\\n';\n }\n\n const breakingChanges = report.changes.filter((c) => c.severity === 'breaking');\n if (breakingChanges.length > 0) {\n lines.push('');\n lines.push('### Breaking changes');\n lines.push('');\n lines.push(formatChangesTable(breakingChanges));\n }\n\n const softRiskChanges = report.changes.filter((c) => c.severity === 'soft-risk');\n if (softRiskChanges.length > 0) {\n lines.push('');\n lines.push('<details>');\n lines.push(`<summary>Soft-risk changes (${softRiskChanges.length})</summary>`);\n lines.push('');\n lines.push(formatChangesTable(softRiskChanges));\n lines.push('</details>');\n }\n\n const additiveChanges = report.changes.filter((c) => c.severity === 'additive');\n if (additiveChanges.length > 0) {\n lines.push('');\n lines.push('<details>');\n lines.push(`<summary>Additive changes (${additiveChanges.length})</summary>`);\n lines.push('');\n lines.push(formatChangesTable(additiveChanges));\n lines.push('</details>');\n }\n\n return lines.join('\\n') + '\\n';\n}\n\n// ---------------------------------------------------------------------------\n// Cross-language rollup\n// ---------------------------------------------------------------------------\n\nfunction formatCrossLanguageRollup(reports: CompatReport[]): string {\n const languages = reports.map((r) => r.language);\n\n // Convert reports to the shape buildConceptualRollup expects\n const perLanguage = reports.map((r) => ({\n diff: { changes: r.changes, summary: r.summary } as CompatDiffResult,\n language: r.language as LanguageId,\n }));\n const rollup = buildConceptualRollup(perLanguage);\n const summary = summarizeConceptualChanges(rollup);\n\n const lines: string[] = [];\n\n // Header\n if (summary.breaking > 0) {\n lines.push(`## :x: Compat check failed — ${summary.breaking} breaking across ${languages.length} languages`);\n } else if (summary.softRisk > 0) {\n lines.push(\n `## :warning: Compat check has warnings — ${summary.softRisk} soft-risk across ${languages.length} languages`,\n );\n } else {\n lines.push(`## :white_check_mark: Compat check passed — ${languages.length} languages`);\n }\n\n lines.push('');\n\n // Per-language summary table\n lines.push('| Language | Breaking | Soft-risk | Additive |');\n lines.push('| --- | --- | --- | --- |');\n for (const r of reports) {\n lines.push(`| ${r.language} | ${r.summary.breaking} | ${r.summary.softRisk} | ${r.summary.additive} |`);\n }\n\n if (rollup.conceptualChanges.length === 0) {\n lines.push('');\n lines.push('No compatibility changes detected.');\n return lines.join('\\n') + '\\n';\n }\n\n // Conceptual changes table with per-language severity\n const breakingConcepts = rollup.conceptualChanges.filter((c) => highestSeverity(c) === 'breaking');\n if (breakingConcepts.length > 0) {\n lines.push('');\n lines.push('### Breaking changes');\n lines.push('');\n lines.push(formatConceptualTable(breakingConcepts, languages));\n }\n\n const softRiskConcepts = rollup.conceptualChanges.filter((c) => highestSeverity(c) === 'soft-risk');\n if (softRiskConcepts.length > 0) {\n lines.push('');\n lines.push('<details>');\n lines.push(`<summary>Soft-risk changes (${softRiskConcepts.length})</summary>`);\n lines.push('');\n lines.push(formatConceptualTable(softRiskConcepts, languages));\n lines.push('</details>');\n }\n\n const additiveConcepts = rollup.conceptualChanges.filter((c) => highestSeverity(c) === 'additive');\n if (additiveConcepts.length > 0) {\n lines.push('');\n lines.push('<details>');\n lines.push(`<summary>Additive changes (${additiveConcepts.length})</summary>`);\n lines.push('');\n lines.push(formatConceptualTable(additiveConcepts, languages));\n lines.push('</details>');\n }\n\n return lines.join('\\n') + '\\n';\n}\n\nfunction formatConceptualTable(\n concepts: Array<{ symbol: string; category: string; impact: Partial<Record<string, CompatChangeSeverity>> }>,\n languages: string[],\n): string {\n const lines: string[] = [];\n const langHeaders = languages.map((l) => l).join(' | ');\n lines.push(`| Symbol | Category | ${langHeaders} |`);\n lines.push(`| --- | --- | ${languages.map(() => '---').join(' | ')} |`);\n for (const c of concepts) {\n const severities = languages.map((l) => severityIcon(c.impact[l])).join(' | ');\n lines.push(`| \\`${c.symbol}\\` | \\`${c.category}\\` | ${severities} |`);\n }\n return lines.join('\\n');\n}\n\nfunction severityIcon(severity: CompatChangeSeverity | undefined): string {\n if (!severity) return '—';\n switch (severity) {\n case 'breaking':\n return ':x: breaking';\n case 'soft-risk':\n return ':warning: soft-risk';\n case 'additive':\n return ':white_check_mark: additive';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\nfunction formatChangesTable(changes: CompatReportChange[]): string {\n const lines: string[] = [];\n lines.push('| Category | Symbol | Detail |');\n lines.push('| --- | --- | --- |');\n for (const c of changes) {\n const detail = c.message ?? formatOldNew(c.old, c.new);\n lines.push(`| \\`${c.category}\\` | \\`${c.symbol}\\` | ${escapeMarkdown(detail)} |`);\n }\n return lines.join('\\n');\n}\n\nfunction formatOldNew(old: Record<string, string>, updated: Record<string, string>): string {\n const parts: string[] = [];\n for (const key of Object.keys(old)) {\n if (updated[key] && old[key] !== updated[key]) {\n parts.push(`${key}: \\`${old[key]}\\` → \\`${updated[key]}\\``);\n }\n }\n return parts.length > 0 ? parts.join(', ') : '';\n}\n\nfunction escapeMarkdown(text: string): string {\n return text.replace(/\\|/g, '\\\\|').replace(/\\n/g, ' ');\n}\n","/**\n * Approval matching engine for compatibility verification.\n *\n * Matches CompatApproval entries from oagen.config.ts against classified\n * changes. Approved changes are excluded from failure thresholds.\n *\n * Approvals must be narrow (one symbol, one category, one conceptual change).\n * Overly broad approvals are rejected at validation time.\n */\n\nimport type { LanguageId } from './ir.js';\nimport type { CompatApproval } from './config.js';\nimport type { ClassifiedChange } from './classify.js';\n\n/** Result of matching a change against approvals. */\nexport interface ApprovalMatch {\n /** The change that was matched. */\n change: ClassifiedChange;\n /** The approval that matched. null if no approval covers this change. */\n approval: CompatApproval | null;\n /** Whether the change is covered by an approval. */\n approved: boolean;\n}\n\n/** Result of validating an approval for broadness. */\nexport interface ApprovalValidation {\n valid: boolean;\n errors: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\n/** Validate that an approval is narrow enough to be accepted. */\nexport function validateApproval(approval: CompatApproval): ApprovalValidation {\n const errors: string[] = [];\n\n if (!approval.symbol || approval.symbol.trim() === '') {\n errors.push('Approval must target a specific symbol');\n }\n\n if (!approval.category) {\n errors.push('Approval must specify a change category');\n }\n\n if (!approval.reason || approval.reason.trim() === '') {\n errors.push('Approval must include a reason');\n }\n\n // Wildcard symbols are too broad\n if (approval.symbol === '*' || approval.symbol.endsWith('.*') || approval.symbol.endsWith('::*')) {\n errors.push(`Approval symbol \"${approval.symbol}\" is too broad — must target a specific symbol`);\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n\n/** Validate all approvals in a config. Returns errors keyed by index. */\nexport function validateApprovals(approvals: CompatApproval[]): Map<number, string[]> {\n const result = new Map<number, string[]>();\n for (let i = 0; i < approvals.length; i++) {\n const validation = validateApproval(approvals[i]);\n if (!validation.valid) {\n result.set(i, validation.errors);\n }\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Matching\n// ---------------------------------------------------------------------------\n\n/**\n * Match a classified change against a list of approvals.\n * Returns the first matching approval, or null if none match.\n */\nexport function matchApproval(\n change: ClassifiedChange,\n approvals: CompatApproval[],\n language: LanguageId,\n): CompatApproval | null {\n for (const approval of approvals) {\n if (approvalMatchesChange(approval, change, language)) {\n return approval;\n }\n }\n return null;\n}\n\n/**\n * Apply approvals to a list of changes.\n * Returns matches for every change (approved or not).\n */\nexport function applyApprovals(\n changes: ClassifiedChange[],\n approvals: CompatApproval[],\n language: LanguageId,\n): ApprovalMatch[] {\n return changes.map((change) => {\n const approval = matchApproval(change, approvals, language);\n return {\n change,\n approval,\n approved: approval !== null,\n };\n });\n}\n\n/**\n * Filter changes to only those NOT covered by approvals.\n * These are the remaining unapproved changes that may cause failure.\n */\nexport function unapprovedChanges(\n changes: ClassifiedChange[],\n approvals: CompatApproval[],\n language: LanguageId,\n): ClassifiedChange[] {\n return changes.filter((change) => !matchApproval(change, approvals, language));\n}\n\n// ---------------------------------------------------------------------------\n// Internal matching logic\n// ---------------------------------------------------------------------------\n\nfunction approvalMatchesChange(approval: CompatApproval, change: ClassifiedChange, language: LanguageId): boolean {\n // Skip inactive approvals\n if (approval.approved === false) return false;\n\n // Category must match exactly\n if (approval.category !== change.category) return false;\n\n // Symbol must match\n if (!symbolMatches(approval.symbol, change.symbol)) return false;\n\n // Language scoping\n if (!languageMatches(approval.appliesTo, language)) return false;\n\n // Narrowing match (optional)\n if (approval.match && !narrowingMatches(approval.match, change)) return false;\n\n return true;\n}\n\nfunction symbolMatches(approvalSymbol: string, changeSymbol: string): boolean {\n // Exact match\n if (approvalSymbol === changeSymbol) return true;\n\n // Normalize common separators for cross-language matching\n // PHP uses :: and \\, others use . — normalize to dots for comparison\n const normalizedApproval = approvalSymbol.replace(/::/g, '.').replace(/\\\\/g, '.');\n const normalizedChange = changeSymbol.replace(/::/g, '.').replace(/\\\\/g, '.');\n return normalizedApproval === normalizedChange;\n}\n\nfunction languageMatches(appliesTo: CompatApproval['appliesTo'], language: LanguageId): boolean {\n if (!appliesTo || appliesTo === 'all-impacted-languages') return true;\n return appliesTo.includes(language);\n}\n\nfunction narrowingMatches(match: NonNullable<CompatApproval['match']>, change: ClassifiedChange): boolean {\n if (match.parameter) {\n // Check if the change involves this parameter\n const paramInOld = change.old.parameter === match.parameter;\n const paramInNew = change.new.parameter === match.parameter;\n if (!paramInOld && !paramInNew) return false;\n }\n if (match.member) {\n const memberInOld = change.old.member === match.member;\n const memberInNew = change.new.member === match.member;\n if (!memberInOld && !memberInNew) return false;\n }\n if (match.oldName) {\n const nameMatch = Object.values(change.old).some((v) => v === match.oldName);\n if (!nameMatch) return false;\n }\n if (match.newName) {\n const nameMatch = Object.values(change.new).some((v) => v === match.newName);\n if (!nameMatch) return false;\n }\n return true;\n}\n","import { getExtractor } from '../compat/extractor-registry.js';\nimport {\n diffSnapshots,\n specDerivedNames,\n specDerivedFieldPaths,\n specDerivedMethodPaths,\n specDerivedEnumValues,\n filterSurface,\n} from '../compat/differ.js';\nimport { apiSurfaceToSnapshot } from '../compat/ir.js';\nimport type { LanguageId } from '../compat/ir.js';\nimport { getDefaultPolicy, mergePolicy } from '../compat/policy.js';\nimport type { CompatPolicyHints } from '../compat/policy.js';\nimport type { ApiSpec } from '../ir/types.js';\nimport type { ApiSurface } from '../compat/types.js';\nimport type { CompatCheckResult } from './types.js';\n\nexport async function runCompatCheck(\n baseline: ApiSurface,\n outputDir: string,\n lang: string,\n spec?: ApiSpec,\n policyOverrides?: Partial<CompatPolicyHints>,\n): Promise<CompatCheckResult> {\n const extractor = getExtractor(lang);\n const candidate = await extractor.extract(outputDir);\n\n let scopedBaseline = baseline;\n let scopedToSpec = false;\n let scopedSymbolCount: number | undefined;\n if (spec) {\n const allowed = specDerivedNames(spec, extractor.hints);\n const fieldPaths = specDerivedFieldPaths(spec, extractor.hints);\n const methodPaths = specDerivedMethodPaths(spec);\n const enumVals = specDerivedEnumValues(spec);\n scopedBaseline = filterSurface(baseline, allowed, { fieldPaths, methodPaths, enumValues: enumVals });\n scopedToSpec = true;\n scopedSymbolCount =\n Object.keys(scopedBaseline.interfaces).length +\n Object.keys(scopedBaseline.classes).length +\n Object.keys(scopedBaseline.typeAliases).length +\n Object.keys(scopedBaseline.enums).length;\n }\n\n const baseSnap = apiSurfaceToSnapshot(scopedBaseline);\n const candSnap = apiSurfaceToSnapshot(candidate);\n\n const langId = lang as LanguageId;\n const policy = policyOverrides ? mergePolicy(getDefaultPolicy(langId), policyOverrides) : getDefaultPolicy(langId);\n\n const diff = diffSnapshots(baseSnap, candSnap, policy);\n const passed = diff.changes.every((c) => c.severity !== 'breaking');\n\n return { passed, diff, scopedToSpec, scopedSymbolCount };\n}\n","import { readdirSync, unlinkSync, statSync, openSync, readSync, closeSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { buildOverlayLookup, patchOverlay, isPatchableChange } from '../compat/overlay.js';\nimport { getExtractor } from '../compat/extractor-registry.js';\nimport type { ApiSurface } from '../compat/types.js';\nimport type { ApiSpec } from '../ir/types.js';\nimport { getEmitter } from '../engine/registry.js';\nimport { generate } from '../engine/orchestrator.js';\nimport { runCompatCheck } from './run-compat-check.js';\nimport type { OverlayRetryResult } from './types.js';\nimport { readManifestSync } from '../engine/manifest-reader.js';\n\n/** Generated file header markers used by various emitters. */\nconst GENERATED_MARKERS = ['Code generated by oagen', 'auto-generated by oagen', 'This file is auto-generated'];\n\n/**\n * Delete oagen-generated source files so the retry loop can regenerate them\n * with overlay-corrected names. Only deletes files that contain an oagen\n * generation marker, preserving hand-written files.\n */\nfunction cleanGeneratedFiles(dir: string): void {\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return;\n }\n for (const entry of entries) {\n const full = path.join(dir, entry);\n let stat;\n try {\n stat = statSync(full);\n } catch {\n continue;\n }\n if (stat.isDirectory()) {\n cleanGeneratedFiles(full);\n continue;\n }\n // Skip non-source files and manifests\n if (entry.endsWith('.json') || entry.endsWith('.lock')) continue;\n // Read only the first 200 bytes to check for generation marker\n try {\n const buf = Buffer.alloc(200);\n const fd = openSync(full, 'r');\n try {\n readSync(fd, buf, 0, 200, 0);\n } finally {\n closeSync(fd);\n }\n const header = buf.toString('utf-8');\n if (GENERATED_MARKERS.some((m) => header.includes(m))) {\n unlinkSync(full);\n }\n } catch {\n // ignore read/delete errors\n }\n }\n}\n\nexport async function runOverlayRetryLoop(opts: {\n baseline: ApiSurface;\n parsedSpec: ApiSpec;\n outputDir: string;\n lang: string;\n maxRetries: number;\n namespace?: string;\n onRetry?: (attemptNumber: number, maxRetries: number, patchableCount: number) => void;\n}): Promise<OverlayRetryResult> {\n const { baseline, parsedSpec, outputDir, lang, maxRetries, namespace, onRetry } = opts;\n\n const manifest = readManifestSync(outputDir);\n // Pass language-specific hints so property-to-class matching works correctly\n // (e.g., Ruby snake_case \"api_keys\" → PascalCase \"ApiKeys\").\n const extractor = getExtractor(lang);\n let overlay = buildOverlayLookup(baseline, manifest, parsedSpec, extractor.hints);\n let prevPreserved = -1;\n const patchedPerIteration: number[] = [];\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const compatResult = await runCompatCheck(baseline, outputDir, lang, parsedSpec);\n if (compatResult.passed) {\n return {\n status: 'passed',\n attempts: attempt,\n patchedPerIteration,\n compatResult,\n };\n }\n\n if (attempt === maxRetries) {\n return {\n status: 'max-retries',\n attempts: attempt,\n patchedPerIteration,\n compatResult,\n };\n }\n\n const patchable = compatResult.diff.changes.filter(isPatchableChange);\n if (patchable.length === 0) {\n return {\n status: 'no-patchable',\n attempts: attempt,\n patchedPerIteration,\n compatResult,\n };\n }\n\n const currentBreaking = compatResult.diff.summary.breaking;\n // Stall detection: if breaking count hasn't decreased, we're not making progress\n if (attempt > 0 && currentBreaking >= prevPreserved) {\n return {\n status: 'stalled',\n attempts: attempt,\n patchedPerIteration,\n compatResult,\n };\n }\n prevPreserved = currentBreaking;\n patchedPerIteration.push(patchable.length);\n onRetry?.(attempt + 1, maxRetries, patchable.length);\n\n overlay = patchOverlay(overlay, patchable, baseline);\n\n // Pre-delete generated source files so the writer creates them fresh\n // with overlay-corrected names. Without this, the AST merger would preserve\n // old method/class names from the existing files.\n // Only delete files that look like oagen-generated source files (have the header).\n cleanGeneratedFiles(outputDir);\n\n const emitter = getEmitter(lang);\n await generate(parsedSpec, emitter, {\n namespace: namespace ?? parsedSpec.name,\n outputDir,\n overlayLookup: overlay,\n apiSurface: baseline,\n });\n }\n\n const compatResult = await runCompatCheck(baseline, outputDir, lang, parsedSpec);\n return {\n status: 'max-retries',\n attempts: maxRetries,\n patchedPerIteration,\n compatResult,\n };\n}\n","import type { ApiSurface, LanguageHints, Violation } from './types.js';\nimport type { ApiSpec } from '../ir/types.js';\nimport { specDerivedNames, specDerivedFieldPaths } from './spec-filter.js';\nimport { diffSpecs } from '../differ/diff.js';\n\n/**\n * Detect symbols that exist in the live SDK surface but are no longer defined\n * in the current OpenAPI spec. These are \"stale\" — they compile and run but\n * represent dead code from a previous spec version.\n *\n * Requires both the old and new spec so we can distinguish hand-written SDK\n * symbols (never in any spec) from genuinely removed spec symbols.\n */\nexport function detectStaleSymbols(\n liveSurface: ApiSurface,\n oldSpec: ApiSpec,\n newSpec: ApiSpec,\n hints: LanguageHints,\n): Violation[] {\n const violations: Violation[] = [];\n\n // Step 1-3: Name-set difference for top-level symbols\n const oldNames = specDerivedNames(oldSpec, hints);\n const newNames = specDerivedNames(newSpec, hints);\n\n const removedNames = new Set<string>();\n for (const name of oldNames) {\n if (!newNames.has(name)) removedNames.add(name);\n }\n\n for (const name of removedNames) {\n if (liveSurface.classes[name]) {\n violations.push({\n category: 'staleness',\n severity: 'warning',\n symbolPath: name,\n baseline: name,\n candidate: '(removed from spec)',\n message: `Class \"${name}\" is no longer defined in the OpenAPI spec`,\n });\n }\n if (liveSurface.interfaces[name]) {\n violations.push({\n category: 'staleness',\n severity: 'warning',\n symbolPath: name,\n baseline: name,\n candidate: '(removed from spec)',\n message: `Interface \"${name}\" is no longer defined in the OpenAPI spec`,\n });\n }\n if (liveSurface.typeAliases[name]) {\n violations.push({\n category: 'staleness',\n severity: 'warning',\n symbolPath: name,\n baseline: name,\n candidate: '(removed from spec)',\n message: `Type alias \"${name}\" is no longer defined in the OpenAPI spec`,\n });\n }\n if (liveSurface.enums[name]) {\n violations.push({\n category: 'staleness',\n severity: 'warning',\n symbolPath: name,\n baseline: name,\n candidate: '(removed from spec)',\n message: `Enum \"${name}\" is no longer defined in the OpenAPI spec`,\n });\n }\n }\n\n // Step 4-6: Field-level staleness for models that still exist in new spec\n const oldFieldPaths = specDerivedFieldPaths(oldSpec, hints);\n const newFieldPaths = specDerivedFieldPaths(newSpec, hints);\n\n for (const fieldPath of oldFieldPaths) {\n if (newFieldPaths.has(fieldPath)) continue;\n\n const [modelName, fieldName] = fieldPath.split('.');\n // Only flag field-level staleness for models that still exist in the new spec\n // (fully removed models are already caught above)\n if (removedNames.has(modelName)) continue;\n\n const iface = liveSurface.interfaces[modelName];\n if (iface?.fields[fieldName]) {\n violations.push({\n category: 'staleness',\n severity: 'warning',\n symbolPath: fieldPath,\n baseline: fieldName,\n candidate: '(removed from spec)',\n message: `Field \"${fieldPath}\" is no longer defined in the OpenAPI spec`,\n });\n }\n }\n\n // Step 7: Operation-level staleness via diffSpecs\n const diff = diffSpecs(oldSpec, newSpec);\n for (const change of diff.changes) {\n if (change.kind === 'operation-removed') {\n const cls = liveSurface.classes[change.serviceName];\n if (cls?.methods[change.operationName]) {\n violations.push({\n category: 'staleness',\n severity: 'warning',\n symbolPath: `${change.serviceName}.${change.operationName}`,\n baseline: change.operationName,\n candidate: '(removed from spec)',\n message: `Method \"${change.serviceName}.${change.operationName}\" is no longer defined in the OpenAPI spec`,\n });\n }\n }\n }\n\n return violations;\n}\n","import { getExtractor } from '../compat/extractor-registry.js';\nimport { detectStaleSymbols } from '../compat/staleness.js';\nimport type { ApiSpec } from '../ir/types.js';\nimport type { ApiSurface } from '../compat/types.js';\nimport type { StalenessCheckResult } from './types.js';\n\nexport function runStalenessCheck(\n baseline: ApiSurface,\n oldSpec: ApiSpec,\n newSpec: ApiSpec,\n lang: string,\n): StalenessCheckResult {\n const extractor = getExtractor(lang);\n const violations = detectStaleSymbols(baseline, oldSpec, newSpec, extractor.hints);\n return { violations };\n}\n","import { execFileSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport * as path from 'node:path';\nimport { CommandError } from '../errors.js';\nimport type { SmokeCheckResult } from './types.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nfunction resolveScript(scriptRelPath: string): { bin: string; script: string } {\n const distScript = path.resolve(__dirname, '..', '..', 'dist', 'scripts', scriptRelPath.replace(/\\.ts$/, '.mjs'));\n if (existsSync(distScript)) {\n return { bin: 'node', script: distScript };\n }\n const srcScript = path.resolve(__dirname, '..', '..', 'scripts', scriptRelPath);\n return { bin: 'npx', script: srcScript };\n}\n\nfunction runPackagedScript(scriptRelPath: string, args: string[]): void {\n const { bin, script } = resolveScript(scriptRelPath);\n const fullArgs = bin === 'npx' ? ['tsx', script, ...args] : [script, ...args];\n execFileSync(bin, fullArgs, { stdio: 'inherit', env: process.env });\n}\n\nexport function runSmokeCheck(opts: {\n spec?: string;\n lang: string;\n output: string;\n rawResults?: string;\n smokeConfig?: string;\n smokeRunner?: string;\n}): SmokeCheckResult {\n const { spec, lang, output, rawResults, smokeConfig, smokeRunner } = opts;\n\n let baselinePath = rawResults ?? 'smoke-results-raw.json';\n let generatedBaseline = false;\n\n if (!rawResults && !existsSync('smoke-results-raw.json')) {\n if (!spec) {\n throw new CommandError(\n 'error: --spec <path> or OPENAPI_SPEC_PATH env var is required when no raw baseline exists',\n '',\n 1,\n );\n }\n\n try {\n runPackagedScript('smoke/baseline.ts', ['--spec', spec]);\n } catch {\n throw new CommandError('Baseline generation failed', '', 1);\n }\n baselinePath = 'smoke-results-spec-baseline.json';\n generatedBaseline = true;\n }\n\n const smokeArgs = ['--lang', lang, '--sdk-path', output, '--raw-results', baselinePath];\n if (spec) smokeArgs.push('--spec', spec);\n if (smokeConfig) smokeArgs.push('--smoke-config', smokeConfig);\n\n try {\n if (smokeRunner) {\n const bin = smokeRunner.endsWith('.ts') ? 'npx' : 'node';\n const fullArgs = bin === 'npx' ? ['tsx', smokeRunner, ...smokeArgs] : [smokeRunner, ...smokeArgs];\n execFileSync(bin, fullArgs, { stdio: 'inherit', env: process.env });\n } else {\n runPackagedScript('smoke/sdk-test.ts', smokeArgs);\n }\n\n return { passed: true, baselinePath, generatedBaseline };\n } catch {\n if (existsSync('smoke-compile-errors.json')) {\n return { passed: false, compileErrors: true, baselinePath, generatedBaseline };\n }\n\n const findingsCount = existsSync('smoke-diff-findings.json')\n ? (JSON.parse(readFileSync('smoke-diff-findings.json', 'utf-8')) as unknown[]).length\n : undefined;\n\n return { passed: false, findingsCount, baselinePath, generatedBaseline };\n }\n}\n","import { writeFileSync } from 'node:fs';\nimport type { VerifyDiagnostics, CompatCheckResult } from './types.js';\n\nexport function summarizeCompatCheck(result: CompatCheckResult): NonNullable<VerifyDiagnostics['compatCheck']> {\n const violationsByCategory: Record<string, number> = {};\n const violationsBySeverity: Record<string, number> = {};\n for (const c of result.diff.changes) {\n violationsByCategory[c.category] = (violationsByCategory[c.category] ?? 0) + 1;\n violationsBySeverity[c.severity] = (violationsBySeverity[c.severity] ?? 0) + 1;\n }\n\n const { breaking, softRisk, additive } = result.diff.summary;\n const totalChanges = breaking + softRisk + additive;\n const totalBaselineSymbols = totalChanges + additive; // approximate; additive are new\n const preservedSymbols = totalBaselineSymbols - breaking - softRisk;\n const preservationScore =\n totalBaselineSymbols > 0 ? Math.round((preservedSymbols / totalBaselineSymbols) * 100) : 100;\n\n return {\n totalBaselineSymbols,\n preservedSymbols,\n preservationScore,\n violationsByCategory,\n violationsBySeverity,\n additions: additive,\n scopedToSpec: result.scopedToSpec,\n ...(result.scopedSymbolCount !== undefined ? { scopedSymbolCount: result.scopedSymbolCount } : {}),\n };\n}\n\nexport function setRetryDiagnostics(\n diagData: VerifyDiagnostics,\n attempt: number,\n converged: boolean,\n finalScore: number,\n patchedPerIteration: number[],\n): void {\n diagData.retryLoop = { attempts: attempt, converged, finalScore, patchedPerIteration };\n}\n\nexport function writeDiagnostics(data: VerifyDiagnostics, filePath: string = 'verify-diagnostics.json'): void {\n writeFileSync(filePath, JSON.stringify(data, null, 2) + '\\n');\n}\n","import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { CommandError } from '../errors.js';\nimport { parseSpec, type OpenApiDocument } from '../parser/parse.js';\nimport type { ApiSurface } from '../compat/types.js';\nimport type { CompatConfig, CompatFailLevel } from '../compat/config.js';\nimport { severityMeetsThreshold } from '../compat/config.js';\nimport { generateReport, formatHumanSummary } from '../compat/report.js';\nimport { unapprovedChanges } from '../compat/approvals.js';\nimport type { LanguageId } from '../compat/ir.js';\nimport { runCompatCheck } from '../verify/run-compat-check.js';\nimport { runOverlayRetryLoop } from '../verify/run-overlay-retry-loop.js';\nimport { runStalenessCheck } from '../verify/run-staleness-check.js';\nimport { runSmokeCheck } from '../verify/run-smoke-check.js';\nimport { summarizeCompatCheck, setRetryDiagnostics, writeDiagnostics } from '../verify/write-diagnostics.js';\nimport type { VerifyDiagnostics } from '../verify/types.js';\n\nexport type { VerifyDiagnostics } from '../verify/types.js';\n\nconst separator = '='.repeat(60);\n\nfunction printCompatResult(result: ReturnType<typeof summarizeCompatCheck>, baseline: ApiSurface): void {\n if (result.scopedToSpec) {\n const totalBefore =\n Object.keys(baseline.interfaces).length +\n Object.keys(baseline.classes).length +\n Object.keys(baseline.typeAliases).length +\n Object.keys(baseline.enums).length;\n console.log(`(scoped to spec: ${result.scopedSymbolCount}/${totalBefore} baseline symbols in scope)`);\n }\n\n console.log(\n `compat: ${result.preservationScore}% (${result.preservedSymbols}/${result.totalBaselineSymbols} symbols preserved)`,\n );\n}\n\nexport async function verifyCommand(opts: {\n spec?: string;\n oldSpec?: string;\n lang: string;\n output: string;\n apiSurface?: string;\n rawResults?: string;\n smokeConfig?: string;\n smokeRunner?: string;\n scope?: 'full' | 'spec-only';\n diagnostics?: boolean;\n maxRetries?: number;\n operationIdTransform?: (id: string) => string;\n schemaNameTransform?: (name: string) => string;\n transformSpec?: (spec: OpenApiDocument) => OpenApiDocument;\n namespace?: string;\n compatConfig?: CompatConfig;\n compatReport?: string;\n compatFailOn?: string;\n compatBaseline?: string;\n compatExplain?: boolean;\n}): Promise<void> {\n const {\n spec,\n oldSpec,\n lang,\n output,\n apiSurface,\n rawResults,\n smokeConfig,\n smokeRunner,\n scope,\n diagnostics,\n operationIdTransform,\n schemaNameTransform,\n transformSpec,\n compatConfig,\n compatReport,\n compatExplain,\n } = opts;\n const maxRetries = opts.maxRetries ?? 3;\n const diagData: VerifyDiagnostics = {};\n\n // Resolve compat options: CLI flags take precedence over config\n const effectiveFailOn: CompatFailLevel =\n (opts.compatFailOn as CompatFailLevel | undefined) ?? compatConfig?.failOn ?? 'breaking';\n const effectiveReportPath = compatReport ?? compatConfig?.reportPath;\n const effectiveExplain = compatExplain ?? compatConfig?.explain ?? false;\n\n let stepNum = 1;\n const baseline: ApiSurface | undefined = apiSurface\n ? (JSON.parse(readFileSync(apiSurface, 'utf-8')) as ApiSurface)\n : undefined;\n\n if (apiSurface && baseline) {\n console.log(`\\n${separator}`);\n console.log(`Step ${stepNum}: Compat verification`);\n console.log(separator);\n\n const effectiveScope = scope ?? (spec ? 'spec-only' : 'full');\n let parsedSpec;\n if (effectiveScope === 'spec-only' && spec) {\n parsedSpec = await parseSpec(spec, { operationIdTransform, schemaNameTransform, transformSpec });\n } else if (effectiveScope === 'spec-only') {\n throw new CommandError('error: --scope spec-only requires --spec <path>', '', 1);\n }\n\n const compatFlow =\n parsedSpec && maxRetries > 0\n ? await runOverlayRetryLoop({\n baseline,\n parsedSpec,\n outputDir: output,\n lang,\n maxRetries,\n namespace: opts.namespace,\n onRetry: (attemptNumber, retryLimit, patchableCount) => {\n console.log(`\\nRetry ${attemptNumber}/${retryLimit}: patching ${patchableCount} violation(s)...`);\n },\n })\n : {\n status: 'passed' as const,\n attempts: 0,\n patchedPerIteration: [],\n compatResult: await runCompatCheck(baseline, output, lang, parsedSpec),\n };\n\n const compatSummary = summarizeCompatCheck(compatFlow.compatResult);\n printCompatResult(compatSummary, baseline);\n const classifiedDiff = compatFlow.compatResult.diff;\n for (const c of classifiedDiff.changes) {\n if (c.severity !== 'additive') {\n console.log(` [${c.category}] ${c.severity}: ${c.symbol} — ${c.message}`);\n }\n }\n const additiveCount = classifiedDiff.summary.additive;\n if (additiveCount > 0) {\n console.log(` + ${additiveCount} new symbols added`);\n }\n\n if (diagnostics) {\n diagData.compatCheck = compatSummary;\n if (parsedSpec && maxRetries > 0) {\n setRetryDiagnostics(\n diagData,\n compatFlow.attempts,\n compatFlow.status === 'passed',\n compatSummary.preservationScore,\n compatFlow.patchedPerIteration,\n );\n }\n }\n\n if (compatFlow.status === 'passed' && compatFlow.compatResult.passed) {\n if (compatFlow.attempts > 0) {\n console.log(`Compat: converged after ${compatFlow.attempts} retry iteration(s)`);\n } else {\n console.log('Compat: passed');\n }\n } else {\n if (diagnostics) {\n writeDiagnostics(diagData);\n console.log('Diagnostics written to verify-diagnostics.json');\n }\n\n if (compatFlow.status === 'no-patchable') {\n console.log(\n 'No patchable violations — cannot self-correct. Remaining violations require emitter code changes.',\n );\n } else if (compatFlow.status === 'stalled') {\n console.log(`Stalled — overlay patching is not making progress.`);\n }\n\n throw new CommandError('\\nCompat violations found — fix the emitter and re-run `oagen verify`.', '', 1);\n }\n\n // Classified compat analysis — approvals, reports, and explanations\n // The diff is already classified from runCompatCheck/runOverlayRetryLoop\n if (effectiveReportPath || effectiveExplain || (compatConfig?.allow?.length ?? 0) > 0) {\n const langId = lang as LanguageId;\n const approvals = compatConfig?.allow ?? [];\n const remaining = unapprovedChanges(classifiedDiff.changes, approvals, langId);\n const hasFailure = remaining.some((c) => severityMeetsThreshold(c.severity, effectiveFailOn));\n\n if (effectiveExplain) {\n console.log('');\n console.log(formatHumanSummary(classifiedDiff, { explain: true }));\n }\n\n if (effectiveReportPath) {\n const report = generateReport(classifiedDiff);\n writeFileSync(effectiveReportPath, JSON.stringify(report, null, 2) + '\\n');\n console.log(`Compat report written to ${effectiveReportPath}`);\n }\n\n if (hasFailure && effectiveFailOn !== 'none') {\n const unapprovedBreaking = remaining.filter((c) => severityMeetsThreshold(c.severity, effectiveFailOn));\n console.log(`\\n${unapprovedBreaking.length} unapproved change(s) at or above '${effectiveFailOn}' threshold`);\n }\n }\n\n stepNum++;\n }\n\n if (oldSpec && spec && apiSurface && baseline) {\n console.log(`\\n${separator}`);\n console.log(`Step ${stepNum}: Staleness detection`);\n console.log(separator);\n\n const oldParsedSpec = await parseSpec(oldSpec, { operationIdTransform, schemaNameTransform, transformSpec });\n const newParsedSpec = await parseSpec(spec, { operationIdTransform, schemaNameTransform, transformSpec });\n const stalenessResult = runStalenessCheck(baseline, oldParsedSpec, newParsedSpec, lang);\n\n if (stalenessResult.violations.length > 0) {\n console.log(`Found ${stalenessResult.violations.length} stale symbol(s):`);\n for (const v of stalenessResult.violations) {\n console.log(` [${v.category}] ${v.severity}: ${v.symbolPath} — ${v.message}`);\n }\n } else {\n console.log('No stale symbols detected.');\n }\n\n if (diagnostics) {\n diagData.stalenessCheck = {\n staleSymbolCount: stalenessResult.violations.length,\n staleSymbols: stalenessResult.violations.map((v) => v.symbolPath),\n };\n }\n\n stepNum++;\n }\n\n const needsBaselineStep = !rawResults && !existsSync('smoke-results-raw.json');\n if (needsBaselineStep) {\n console.log(`\\n${separator}`);\n console.log(`Step ${stepNum}: Generating spec-only baseline (no raw baseline found)`);\n console.log(separator);\n stepNum++;\n }\n\n console.log(`\\n${separator}`);\n console.log(`Step ${stepNum}: Smoke test + diff`);\n console.log(separator);\n\n const smokeResult = runSmokeCheck({\n spec,\n lang,\n output,\n rawResults,\n smokeConfig,\n smokeRunner,\n });\n\n if (diagnostics) {\n diagData.smokeCheck = {\n passed: smokeResult.passed,\n ...(smokeResult.findingsCount !== undefined ? { findingsCount: smokeResult.findingsCount } : {}),\n ...(smokeResult.compileErrors ? { compileErrors: true } : {}),\n };\n writeDiagnostics(diagData);\n console.log('Diagnostics written to verify-diagnostics.json');\n }\n\n if (!smokeResult.passed) {\n if (smokeResult.compileErrors) {\n throw new CommandError('\\nSDK compile errors — read smoke-compile-errors.json for details', '', 2);\n }\n\n throw new CommandError(\n '\\nSmoke test findings — read smoke-diff-findings.json for details\\n\\n' +\n `Remediation guide (by finding type):\n \"HTTP method differs\" → fix ${lang} emitter resources.ts (in emitter project)\n \"Request path structure differs\" → fix ${lang} emitter resources.ts (in emitter project)\n \"Query parameters differ\" → fix ${lang} emitter resources.ts (in emitter project)\n \"Request body key sets differ\" → fix ${lang} emitter models.ts or resources.ts (in emitter project)\n \"Skipped in SDK\" → fix smoke/sdk-${lang}.ts (in emitter project)\n \"Missing from SDK\" → fix smoke/sdk-${lang}.ts (in emitter project)`,\n '',\n 1,\n );\n }\n\n console.log('\\nVerify: all checks passed');\n}\n","import { toCamelCase } from '../../utils/naming.js';\n\nexport function oagenScripts(lang: string): Record<string, string> {\n return {\n [`sdk:generate:${lang}`]: `oagen generate --lang ${lang} --output ./sdk --namespace my-api --spec open-api-spec.yaml --api-surface ./sdk-${lang}-surface.json --target ../your-${lang}-sdk`,\n [`sdk:diff:${lang}`]: `oagen diff --old ./sdk/spec-snapshot.yaml --new open-api-spec.yaml --lang ${lang} --output ./sdk --target ../your-${lang}-sdk --api-surface ./sdk-${lang}-surface.json`,\n [`sdk:verify:${lang}`]: `oagen verify --lang ${lang} --output ./sdk --spec open-api-spec.yaml --api-surface ./sdk-${lang}-surface.json`,\n [`sdk:extract:${lang}`]: `oagen extract --lang ${lang} --sdk-path ../your-${lang}-sdk --output ./sdk-${lang}-surface.json`,\n };\n}\n\nexport function packageJson(lang: string): string {\n return JSON.stringify(\n {\n name: `custom-oagen-emitters`,\n version: '0.0.1',\n type: 'module',\n main: 'dist/index.js',\n types: 'dist/index.d.ts',\n exports: {\n '.': { types: './dist/index.d.ts', import: './dist/index.js' },\n './plugin': { types: './dist/plugin.d.ts', import: './dist/plugin.js' },\n },\n scripts: {\n build: 'tsup',\n test: 'vitest run',\n 'test:watch': 'vitest',\n typecheck: 'tsc --noEmit',\n ...oagenScripts(lang),\n },\n dependencies: {\n '@workos/oagen': '^0.0.1',\n },\n devDependencies: {\n tsup: '^8.4.0',\n tsx: '^4.19.0',\n vitest: '^3.0.0',\n '@types/node': '^25.3.3',\n },\n },\n null,\n 2,\n );\n}\n\nexport function tsconfigJson(): string {\n return JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n strict: true,\n declaration: true,\n declarationMap: true,\n sourceMap: true,\n outDir: 'dist',\n rootDir: '.',\n esModuleInterop: true,\n skipLibCheck: true,\n forceConsistentCasingInFileNames: true,\n resolveJsonModule: true,\n isolatedModules: true,\n },\n include: ['src', 'test'],\n exclude: ['node_modules', 'dist'],\n },\n null,\n 2,\n );\n}\n\nexport function vitestConfig(): string {\n return `import { defineConfig } from 'vitest/config';\nexport default defineConfig({\n test: { globals: true, include: ['test/**/*.test.ts'] },\n});\n`;\n}\n\nexport function tsupConfig(): string {\n return `import { defineConfig } from 'tsup';\nexport default defineConfig({\n entry: { index: 'src/index.ts', plugin: 'src/plugin.ts' },\n format: ['esm'],\n dts: true,\n clean: true,\n target: 'node20',\n});\n`;\n}\n\nexport function oagenConfig(): string {\n return `import type { OagenConfig } from '@workos/oagen';\nimport { plugin } from './src/plugin.js';\n\n// Minimal config for local emitter development.\n// The canonical consumer config lives in the consumer project's oagen.config.ts,\n// which imports the plugin bundle from this package.\nconst config: OagenConfig = {\n ...plugin,\n};\nexport default config;\n`;\n}\n\nexport function srcPlugin(lang: string): string {\n const varName = `${toCamelCase(lang)}Emitter`;\n return `import type { OagenConfig } from '@workos/oagen';\nimport { ${varName} } from './${lang}/index.js';\n\nexport const plugin: Pick<OagenConfig, 'emitters' | 'extractors' | 'smokeRunners'> = {\n emitters: [${varName}],\n extractors: [],\n smokeRunners: {},\n};\n`;\n}\n\nexport function srcIndex(lang: string): string {\n const varName = `${toCamelCase(lang)}Emitter`;\n return `export { ${varName} } from './${lang}/index.js';\nexport { plugin } from './plugin.js';\n`;\n}\n\nexport function gitignore(): string {\n return `node_modules/\ndist/\n.env\nsdk-*-surface.json\nsmoke-*.json\nsdk/\n`;\n}\n\nexport function stubEmitter(lang: string): string {\n const varName = `${toCamelCase(lang)}Emitter`;\n return `import type { Emitter, EmitterContext, GeneratedFile, ApiSpec, Model, Enum, Service } from '@workos/oagen';\n\nexport const ${varName}: Emitter = {\n language: '${lang}',\n\n generateModels(_models: Model[], _ctx: EmitterContext): GeneratedFile[] {\n return [];\n },\n\n generateEnums(_enums: Enum[], _ctx: EmitterContext): GeneratedFile[] {\n return [];\n },\n\n generateResources(_services: Service[], _ctx: EmitterContext): GeneratedFile[] {\n return [];\n },\n\n generateClient(_spec: ApiSpec, _ctx: EmitterContext): GeneratedFile[] {\n return [];\n },\n\n generateErrors(_ctx: EmitterContext): GeneratedFile[] {\n return [];\n },\n\n generateTypeSignatures(_spec: ApiSpec, _ctx: EmitterContext): GeneratedFile[] {\n return [];\n },\n\n generateTests(_spec: ApiSpec, _ctx: EmitterContext): GeneratedFile[] {\n return [];\n },\n\n buildOperationsMap(_spec: ApiSpec, _ctx: EmitterContext) {\n return {};\n },\n\n fileHeader(): string {\n return '// Auto-generated by oagen. Do not edit.';\n },\n};\n`;\n}\n","import { resolve, relative } from 'node:path';\nimport { existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';\nimport {\n packageJson,\n tsconfigJson,\n vitestConfig,\n tsupConfig,\n oagenConfig,\n srcPlugin,\n srcIndex,\n gitignore,\n stubEmitter,\n} from './templates/init.js';\n\nexport async function initCommand(opts: { lang: string; project?: string }): Promise<void> {\n const projectDir = resolve(opts.project ?? '.');\n const lang = opts.lang;\n\n if (existsSync(resolve(projectDir, 'oagen.config.ts'))) {\n throw new Error('Project already initialized — oagen.config.ts exists');\n }\n\n // Create directories\n const dirs = [`src/${lang}`, 'test', 'smoke', 'docs/sdk-architecture'];\n for (const dir of dirs) {\n mkdirSync(resolve(projectDir, dir), { recursive: true });\n }\n\n // Write template files\n const files: Array<[string, string]> = [\n ['tsconfig.json', tsconfigJson()],\n ['vitest.config.ts', vitestConfig()],\n ['tsup.config.ts', tsupConfig()],\n ['oagen.config.ts', oagenConfig()],\n ['src/plugin.ts', srcPlugin(lang)],\n ['src/index.ts', srcIndex(lang)],\n [`src/${lang}/index.ts`, stubEmitter(lang)],\n ];\n\n // Handle package.json specially - merge if it exists\n const packageJsonPath = resolve(projectDir, 'package.json');\n let packageJsonContent: string;\n if (existsSync(packageJsonPath)) {\n const existingContent = readFileSync(packageJsonPath, 'utf-8');\n const existingPkg = JSON.parse(existingContent);\n const newPkg = JSON.parse(packageJson(lang));\n // Merge: existing values take precedence, but append new scripts/devDependencies\n existingPkg.scripts = { ...newPkg.scripts, ...existingPkg.scripts };\n existingPkg.devDependencies = { ...newPkg.devDependencies, ...existingPkg.devDependencies };\n existingPkg.dependencies = { ...newPkg.dependencies, ...existingPkg.dependencies };\n // Only set exports if not already defined\n if (!existingPkg.exports) {\n existingPkg.exports = newPkg.exports;\n }\n // Only set type if not already defined\n if (!existingPkg.type) {\n existingPkg.type = newPkg.type;\n }\n // Only set main if not already defined\n if (!existingPkg.main) {\n existingPkg.main = newPkg.main;\n }\n // Only set types if not already defined\n if (!existingPkg.types) {\n existingPkg.types = newPkg.types;\n }\n packageJsonContent = JSON.stringify(existingPkg, null, 2);\n } else {\n packageJsonContent = packageJson(lang);\n }\n\n // Handle .gitignore specially - append if it exists\n const gitignorePath = resolve(projectDir, '.gitignore');\n let gitignoreContent: string;\n if (existsSync(gitignorePath)) {\n const existingContent = readFileSync(gitignorePath, 'utf-8');\n const newContent = gitignore();\n // Append new entries that don't already exist (filter out comments and empty lines for comparison)\n const existingLines = new Set(\n existingContent\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line && !line.startsWith('#')),\n );\n const newLines = newContent.split('\\n').filter((line) => {\n const trimmed = line.trim();\n return trimmed && !existingLines.has(trimmed);\n });\n gitignoreContent = existingContent + (existingContent.endsWith('\\n') ? '' : '\\n') + newLines.join('\\n');\n } else {\n gitignoreContent = gitignore();\n }\n\n for (const [filePath, content] of files) {\n const fullPath = resolve(projectDir, filePath);\n mkdirSync(resolve(fullPath, '..'), { recursive: true });\n writeFileSync(fullPath, content, 'utf-8');\n }\n\n // Write package.json\n writeFileSync(packageJsonPath, packageJsonContent, 'utf-8');\n\n // Write .gitignore\n writeFileSync(gitignorePath, gitignoreContent, 'utf-8');\n\n // Print summary\n console.log(`Initialized emitter project for \"${lang}\" in ${relative(process.cwd(), projectDir) || '.'}`);\n console.log('');\n console.log('Created:');\n for (const [filePath] of files) {\n console.log(` ${filePath}`);\n }\n for (const dir of dirs) {\n console.log(` ${dir}/`);\n }\n\n // Print next steps\n console.log('');\n console.log('Next steps:');\n console.log(` - Implement your emitter in src/${lang}/index.ts`);\n console.log(' - npm run sdk:generate -- --spec <path-to-spec> --namespace <Name>');\n console.log(' - npm run sdk:verify -- --spec <path-to-spec>');\n}\n","import { parseSpec, type OpenApiDocument } from '../parser/parse.js';\nimport { resolveOperations } from '../ir/operation-hints.js';\nimport { expandDocUrls } from '../utils/expand-doc-urls.js';\nimport type { OperationHint, ResolvedOperation } from '../ir/operation-hints.js';\n\nexport async function resolveCommand(opts: {\n spec: string;\n format?: 'table' | 'json';\n operationIdTransform?: (id: string) => string;\n schemaNameTransform?: (name: string) => string;\n transformSpec?: (spec: OpenApiDocument) => OpenApiDocument;\n docUrl?: string;\n operationHints?: Record<string, OperationHint>;\n mountRules?: Record<string, string>;\n}): Promise<void> {\n let ir = await parseSpec(opts.spec, {\n operationIdTransform: opts.operationIdTransform,\n schemaNameTransform: opts.schemaNameTransform,\n transformSpec: opts.transformSpec,\n });\n if (opts.docUrl) {\n ir = expandDocUrls(ir, opts.docUrl);\n }\n\n const resolved = resolveOperations(ir, opts.operationHints, opts.mountRules);\n const format = opts.format ?? 'table';\n\n if (format === 'json') {\n const output = resolved.map(toJsonRow);\n console.log(JSON.stringify(output, null, 2));\n return;\n }\n\n // Table format\n printTable(resolved, opts.operationHints);\n}\n\ninterface JsonRow {\n service: string;\n method: string;\n path: string;\n derivedName: string;\n hintApplied: boolean;\n mountOn: string;\n wrappers?: string[];\n}\n\nfunction toJsonRow(r: ResolvedOperation): JsonRow {\n return {\n service: r.service.name,\n method: r.operation.httpMethod.toUpperCase(),\n path: r.operation.path,\n derivedName: r.methodName,\n hintApplied: r.methodName !== r.operation.name,\n mountOn: r.mountOn,\n wrappers: r.wrappers?.map((w) => w.name),\n };\n}\n\nfunction printTable(resolved: ResolvedOperation[], hints?: Record<string, OperationHint>): void {\n const hintMap = hints ?? {};\n\n // Header\n console.log('| Service | Method | Path | Resolved Name | Hint | Mount On |');\n console.log('|---|---|---|---|---|---|');\n\n const unhinted: ResolvedOperation[] = [];\n\n for (const r of resolved) {\n const key = `${r.operation.httpMethod.toUpperCase()} ${r.operation.path}`;\n const hasHint = key in hintMap;\n const hintMarker = hasHint ? 'yes' : '';\n const mountChanged = r.mountOn !== r.service.name;\n const mountCol = mountChanged ? r.mountOn : '';\n\n console.log(\n `| ${r.service.name} | ${r.operation.httpMethod.toUpperCase()} | ${r.operation.path} | \\`${r.methodName}\\` | ${hintMarker} | ${mountCol} |`,\n );\n\n // Track wrappers\n if (r.wrappers) {\n for (const w of r.wrappers) {\n console.log(`| | | | \\`${w.name}\\` (wrapper) | yes | ${mountCol} |`);\n }\n }\n\n if (!hasHint && !mountChanged) {\n unhinted.push(r);\n }\n }\n\n console.log('');\n console.log(\n `Total: ${resolved.length} operations, ${resolved.length - unhinted.length} with hints/mounts, ${unhinted.length} algorithm-only`,\n );\n}\n","import * as path from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { pathToFileURL } from 'node:url';\nimport type { Emitter } from '../engine/types.js';\nimport type { OperationHint } from '../ir/operation-hints.js';\nimport type { Extractor } from '../compat/types.js';\nimport type { CompatConfig } from '../compat/config.js';\nimport type { OpenApiDocument } from '../parser/parse.js';\nimport { ConfigLoadError } from '../errors.js';\n\nexport interface OagenConfig {\n emitters?: Emitter[];\n extractors?: Extractor[];\n /** Compatibility verification policy. See docs/core/compatibility-policy.md. */\n compat?: CompatConfig;\n /** Path to the emitter project (where skills scaffold new emitters, tests, smoke runners). */\n emitterProject?: string;\n /** Map from language key to custom smoke runner script path. */\n smokeRunners?: Record<string, string>;\n /**\n * Custom transform for operation IDs. When provided, replaces the default\n * camelCase pass-through. Receives the raw operationId string; return the\n * desired operation name (no additional conversion is applied).\n *\n */\n operationIdTransform?: (id: string) => string;\n /**\n * Custom transform for schema (model/enum) names. Applied after the built-in\n * cleanSchemaName normalization. Receives the cleaned PascalCase name; return\n * the desired name. Collisions are detected automatically -- if a transform\n * would produce a duplicate name, the original is kept.\n */\n schemaNameTransform?: (name: string) => string;\n /** Base URL for documentation links. When set, relative paths in descriptions\n * (e.g. `/reference/authkit/user`) are expanded to full URLs. */\n docUrl?: string;\n /**\n * Pre-IR overlay applied to the bundled OpenAPI document before any IR\n * extraction. Use this when the upstream spec can't be changed but a quirk\n * in it would otherwise emit a breaking SDK change — e.g. rewriting a\n * path's response `$ref` back to its prior schema, merging the new fields\n * onto the prior schema, and dropping the fork schema.\n *\n * The function may mutate the document in place and return it, or return a\n * new object. Runs once, after `$ref` bundling and before schema/operation\n * extraction. See `docs/advanced/transform-spec.md` for examples.\n */\n transformSpec?: (spec: OpenApiDocument) => OpenApiDocument;\n /**\n * Per-operation overrides keyed by \"METHOD /path\" (e.g. \"POST /sso/token\").\n * Used by the operation resolver to override derived method names, mount\n * targets, and to split union-body operations into typed wrappers.\n */\n operationHints?: Record<string, OperationHint>;\n /**\n * Service-level mount rules: maps an IR service name to a target\n * service/namespace (PascalCase). All operations in the source service\n * are mounted on the target. Per-operation mountOn in operationHints\n * takes priority.\n */\n mountRules?: Record<string, string>;\n /**\n * Pin specific models to a specific IR service for placement, overriding the\n * default \"first service to reference the model wins\" assignment.\n *\n * Maps IR model name → IR service name (both PascalCase). Useful when a model\n * is shared across services and the natural ordering would place it in a\n * service that's wrong for the public API.\n *\n * Both names must exist in the parsed spec; unknown names throw at generation\n * time so typos fail loud. Note that keys are post-cleanSchemaName /\n * post-schemaNameTransform model names (e.g. `User`, not `UserlandUser`).\n */\n modelHints?: Record<string, string>;\n /**\n * Language-specific emitter options. The CLI passes only the active\n * language's option bag to that emitter.\n */\n emitterOptions?: Record<string, Record<string, unknown>>;\n}\n\nconst CONFIG_NAMES = ['oagen.config.ts', 'oagen.config.js', 'oagen.config.mjs'];\n\n/**\n * Load an oagen config file.\n *\n * @param configPath - Explicit path to a config file. When provided, only that\n * file is attempted (no fallback search).\n * @param cwd - Directory to search when `configPath` is omitted. Defaults to\n * `process.cwd()`. The loader tries each name in `CONFIG_NAMES` in order.\n */\nexport async function loadConfig(configPath?: string, cwd: string = process.cwd()): Promise<OagenConfig | null> {\n if (configPath) {\n const resolved = path.resolve(cwd, configPath);\n if (!existsSync(resolved)) {\n throw new ConfigLoadError(`Config file not found: ${resolved}`, 'Check that the path passed to --config exists.');\n }\n try {\n const mod = await import(pathToFileURL(resolved).href);\n return (mod.default ?? mod) as OagenConfig;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new ConfigLoadError(\n `Failed to load ${resolved}: ${message}`,\n resolved.endsWith('.ts')\n ? 'TypeScript config files require tsx or ts-node. Use .mjs instead, or run via `npx tsx`.'\n : 'Check that the config file is valid ESM.',\n );\n }\n }\n\n for (const name of CONFIG_NAMES) {\n const resolved = path.resolve(cwd, name);\n if (!existsSync(resolved)) continue;\n try {\n const mod = await import(pathToFileURL(resolved).href);\n const config = (mod.default ?? mod) as OagenConfig;\n return config;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new ConfigLoadError(\n `Failed to load ${name}: ${message}`,\n name.endsWith('.ts')\n ? 'TypeScript config files require tsx or ts-node. Use .mjs instead, or run via `npx tsx`.'\n : 'Check that the config file is valid ESM.',\n );\n }\n }\n return null;\n}\n","import { registerEmitter } from '../engine/registry.js';\nimport { registerExtractor } from '../compat/extractor-registry.js';\nimport type { OagenConfig } from './config-loader.js';\n\nexport function applyConfig(config: OagenConfig): void {\n for (const emitter of config.emitters ?? []) {\n registerEmitter(emitter);\n }\n for (const extractor of config.extractors ?? []) {\n registerExtractor(extractor);\n }\n}\n","import 'dotenv/config';\nimport { Command } from 'commander';\nimport { parseCommand } from './parse.js';\nimport { generateCommand } from './generate.js';\nimport { diffCommand } from './diff.js';\nimport { extractCommand } from './extract.js';\nimport { compatExtractCommand } from './compat-extract.js';\nimport { compatDiffCommand } from './compat-diff.js';\nimport { compatSummaryCommand } from './compat-summary.js';\nimport { verifyCommand } from './verify.js';\nimport { initCommand } from './init.js';\nimport { resolveCommand } from './resolve.js';\nimport { loadConfig } from './config-loader.js';\nimport { applyConfig } from './plugin-loader.js';\nimport { CommandError } from '../errors.js';\n\nfunction handleError(err: unknown): never {\n const exitCode = err instanceof CommandError ? err.exitCode : 1;\n const message = err instanceof Error ? err.message : String(err);\n if (message) console.error(message);\n process.exit(exitCode);\n}\n\n// Parse --config before Commander runs so we can load the right config file\n// at startup. Commander's parseOptions isn't available before .parse(), so we\n// do a simple argv scan.\nconst configArgIdx = process.argv.indexOf('--config');\nconst explicitConfigPath = configArgIdx !== -1 ? process.argv[configArgIdx + 1] : undefined;\n\n// Load config at startup so user-provided emitters/extractors are registered\n// before any command runs. loadConfig is async (dynamic import), so we use\n// top-level await.\nlet configSmokeRunners: Record<string, string> | undefined;\nlet configOperationIdTransform: ((id: string) => string) | undefined;\nlet configSchemaNameTransform: ((name: string) => string) | undefined;\nlet configTransformSpec:\n | ((spec: import('../parser/parse.js').OpenApiDocument) => import('../parser/parse.js').OpenApiDocument)\n | undefined;\nlet configDocUrl: string | undefined;\nlet configOperationHints: Record<string, import('../ir/operation-hints.js').OperationHint> | undefined;\nlet configMountRules: Record<string, string> | undefined;\nlet configModelHints: Record<string, string> | undefined;\nlet configEmitterOptions: Record<string, Record<string, unknown>> | undefined;\nlet configCompat: import('../compat/config.js').CompatConfig | undefined;\ntry {\n const config = await loadConfig(explicitConfigPath);\n if (config) {\n applyConfig(config);\n configSmokeRunners = config.smokeRunners;\n configOperationIdTransform = config.operationIdTransform;\n configSchemaNameTransform = config.schemaNameTransform;\n configTransformSpec = config.transformSpec;\n configDocUrl = config.docUrl;\n configOperationHints = config.operationHints;\n configMountRules = config.mountRules;\n configModelHints = config.modelHints;\n configEmitterOptions = config.emitterOptions;\n configCompat = config.compat;\n }\n} catch (err) {\n handleError(err);\n}\n\nconst program = new Command()\n .name('oagen')\n .description('Framework for building OpenAPI SDK emitters')\n .version('0.0.1')\n .option('--config <path>', 'Path to oagen config file (default: oagen.config.ts in cwd)');\n\nprogram\n .command('parse')\n .description('Parse an OpenAPI spec and output IR as JSON')\n .option('--spec <path>', 'Path to OpenAPI spec file (or set OPENAPI_SPEC_PATH)')\n .action((opts) => {\n opts.spec ??= process.env.OPENAPI_SPEC_PATH;\n if (!opts.spec) {\n console.error('error: --spec <path> or OPENAPI_SPEC_PATH env var is required');\n process.exit(1);\n }\n return parseCommand({\n ...opts,\n operationIdTransform: configOperationIdTransform,\n schemaNameTransform: configSchemaNameTransform,\n transformSpec: configTransformSpec,\n });\n });\n\nprogram\n .command('generate')\n .description('Run a registered emitter against an OpenAPI spec')\n .option('--spec <path>', 'Path to OpenAPI spec file (or set OPENAPI_SPEC_PATH)')\n .requiredOption('--lang <language>', 'Target language')\n .requiredOption('--output <dir>', 'Output directory')\n .option('--target <dir>', 'Target directory for live SDK integration (merged output)')\n .option('--namespace <name>', 'SDK namespace/package name')\n .option('--dry-run', 'Preview files without writing')\n .option('--api-surface <path>', 'Path to baseline API surface JSON for compat overlay')\n .option('--no-compat-check', 'Skip compat overlay even if --api-surface is provided')\n .option('--no-prune', 'Skip deletion of stale files recorded in the previous .oagen-manifest.json')\n .action((opts) => {\n opts.spec ??= process.env.OPENAPI_SPEC_PATH;\n if (!opts.spec) {\n console.error('error: --spec <path> or OPENAPI_SPEC_PATH env var is required');\n process.exit(1);\n }\n generateCommand({\n ...opts,\n operationIdTransform: configOperationIdTransform,\n schemaNameTransform: configSchemaNameTransform,\n transformSpec: configTransformSpec,\n docUrl: configDocUrl,\n operationHints: configOperationHints,\n mountRules: configMountRules,\n modelHints: configModelHints,\n emitterOptions: configEmitterOptions?.[opts.lang],\n }).catch(handleError);\n });\n\nprogram\n .command('diff')\n .description('Compare two OpenAPI specs and output a diff report')\n .requiredOption('--old <path>', 'Path to old spec')\n .requiredOption('--new <path>', 'Path to new spec')\n .action((opts) => {\n diffCommand({\n ...opts,\n operationIdTransform: configOperationIdTransform,\n schemaNameTransform: configSchemaNameTransform,\n transformSpec: configTransformSpec,\n docUrl: configDocUrl,\n }).catch(handleError);\n });\n\nprogram\n .command('extract')\n .description('Extract public API surface from a live SDK')\n .requiredOption('--sdk-path <path>', 'Path to the live SDK')\n .requiredOption('--lang <language>', 'Target language')\n .option('--output <path>', 'Output file path')\n .action((opts) => {\n opts.output ??= `sdk-${opts.lang}-surface.json`;\n extractCommand(opts).catch(handleError);\n });\n\nprogram\n .command('compat-extract')\n .description('Extract a compat snapshot from a live SDK and write .oagen-compat-snapshot.json')\n .requiredOption('--sdk-path <path>', 'Path to the live SDK')\n .requiredOption('--lang <language>', 'Target language')\n .requiredOption('--output <dir>', 'Directory to write .oagen-compat-snapshot.json into')\n .option('--spec <path>', 'Path to OpenAPI spec — enriches symbols with operationId, route, and specSha')\n .action((opts) => {\n opts.spec ??= process.env.OPENAPI_SPEC_PATH;\n compatExtractCommand({\n ...opts,\n schemaNameTransform: configSchemaNameTransform,\n transformSpec: configTransformSpec,\n }).catch(handleError);\n });\n\nprogram\n .command('compat-diff')\n .description('Diff two compat snapshot files and produce a classified change report')\n .requiredOption('--baseline <path>', 'Path to the baseline compat snapshot JSON')\n .requiredOption('--candidate <path>', 'Path to the candidate compat snapshot JSON')\n .option('--output <path>', 'Write machine-readable report to this path')\n .option('--fail-on <level>', 'Fail threshold: none, breaking, or soft-risk', 'breaking')\n .option('--explain', 'Include provenance explanations in output')\n .action((opts) => {\n compatDiffCommand(opts).catch(handleError);\n });\n\nprogram\n .command('compat-summary')\n .description('Format compat report(s) as a markdown PR comment')\n .requiredOption('--report <path...>', 'Path(s) to compat report JSON(s) — pass multiple for cross-language rollup')\n .option('--output <path>', 'Write markdown to this file instead of stdout')\n .action((opts) => {\n compatSummaryCommand(opts).catch(handleError);\n });\n\nprogram\n .command('verify')\n .description('Run smoke tests (and optional compat check) against an already-generated SDK')\n .option('--spec <path>', 'Path to OpenAPI spec file (or set OPENAPI_SPEC_PATH)')\n .requiredOption('--lang <language>', 'Target language')\n .requiredOption('--output <dir>', 'Path to the generated SDK')\n .option('--api-surface <path>', 'Baseline API surface JSON — enables compat verification')\n .option('--raw-results <path>', 'Path to an existing smoke baseline file to diff against')\n .option('--smoke-config <path>', 'Path to smoke config JSON for skip lists and service mappings')\n .option('--smoke-runner <path>', 'Path to a custom smoke runner script (overrides built-in sdk-test.ts)')\n .option(\n '--scope <mode>',\n 'Compat scope: \"full\" compares all baseline symbols, \"spec-only\" compares only symbols derivable from the OpenAPI spec (default: spec-only when --spec is provided)',\n )\n .option('--old-spec <path>', 'Previous OpenAPI spec — enables staleness detection for removed/renamed symbols')\n .option('--namespace <name>', 'SDK namespace/package name (used by retry loop for regeneration)')\n .option('--diagnostics', 'Output verify-diagnostics.json with structured violation breakdown')\n .option('--max-retries <n>', 'Max retry iterations for self-correcting overlay loop (default: 3)', '3')\n .option('--compat-report <path>', 'Write machine-readable compat report to this path')\n .option('--compat-fail-on <level>', 'Fail threshold: none, breaking, or soft-risk')\n .option('--compat-baseline <path>', 'Path to baseline compatibility snapshot')\n .option('--compat-explain', 'Include provenance explanations in compat output')\n .action((opts) => {\n opts.spec ??= process.env.OPENAPI_SPEC_PATH;\n // --spec is only required when we need to generate a baseline (no --raw-results\n // and no existing smoke-results-raw.json). Defer the check to verifyCommand.\n // CLI --smoke-runner takes precedence, then per-language smokeRunners map from config\n opts.smokeRunner ??= configSmokeRunners?.[opts.lang];\n verifyCommand({\n ...opts,\n maxRetries: parseInt(opts.maxRetries, 10),\n operationIdTransform: configOperationIdTransform,\n schemaNameTransform: configSchemaNameTransform,\n transformSpec: configTransformSpec,\n compatConfig: configCompat,\n compatReport: opts.compatReport,\n compatFailOn: opts.compatFailOn,\n compatBaseline: opts.compatBaseline,\n compatExplain: opts.compatExplain,\n }).catch(handleError);\n });\n\nprogram\n .command('resolve')\n .description('Resolve operation names from spec and output a review table')\n .option('--spec <path>', 'Path to OpenAPI spec file (or set OPENAPI_SPEC_PATH)')\n .option('--format <format>', 'Output format: table or json', 'table')\n .action((opts) => {\n opts.spec ??= process.env.OPENAPI_SPEC_PATH;\n if (!opts.spec) {\n console.error('error: --spec <path> or OPENAPI_SPEC_PATH env var is required');\n process.exit(1);\n }\n resolveCommand({\n ...opts,\n operationIdTransform: configOperationIdTransform,\n schemaNameTransform: configSchemaNameTransform,\n transformSpec: configTransformSpec,\n docUrl: configDocUrl,\n operationHints: configOperationHints,\n mountRules: configMountRules,\n }).catch(handleError);\n });\n\nprogram\n .command('init')\n .description('Scaffold a new emitter project')\n .requiredOption('--lang <language>', 'Target language')\n .option('--project <dir>', 'Project directory', '.')\n .action((opts) => {\n initCommand(opts).catch(handleError);\n });\n\nprogram.parse();\n"],"mappings":"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"}
|