{"version":3,"file":"tree-sitter-DcUvm0KA.mjs","names":[],"sources":["../src/ir/types.ts","../src/errors.ts","../src/utils/naming.ts","../src/utils/tree-sitter.ts"],"sourcesContent":["import type { SdkBehavior } from './sdk-behavior.js';\n\n/** Authentication scheme extracted from OpenAPI securitySchemes */\nexport type AuthScheme =\n  | { kind: 'bearer' }\n  | { kind: 'apiKey'; in: 'header' | 'query' | 'cookie'; name: string }\n  | { kind: 'oauth2'; flows: Record<string, unknown> };\n\n/** Root IR node representing the full API surface */\n/** A server entry from the OpenAPI servers array */\nexport interface ServerEntry {\n  url: string;\n  description?: string;\n}\n\n/** Root IR node representing the full API surface */\nexport interface ApiSpec {\n  name: string;\n  version: string;\n  description?: string;\n  baseUrl: string;\n  servers?: ServerEntry[];\n  services: Service[];\n  models: Model[];\n  enums: Enum[];\n  auth?: AuthScheme[];\n  /** Language-agnostic runtime policies (retry, errors, telemetry, etc.). */\n  sdk: SdkBehavior;\n}\n\n/** A service groups related operations (maps to an SDK resource class) */\nexport interface Service {\n  name: string;\n  description?: string;\n  operations: Operation[];\n}\n\n/** A single API operation (maps to an SDK method) */\n/** Per-operation security requirement: scheme name → scope list. */\nexport interface SecurityRequirement {\n  schemeName: string;\n  scopes: string[];\n}\n\nexport interface Operation {\n  name: string;\n  description?: string;\n  httpMethod: HttpMethod;\n  path: string;\n  pathParams: Parameter[];\n  queryParams: Parameter[];\n  headerParams: Parameter[];\n  cookieParams?: Parameter[];\n  requestBody?: TypeRef;\n  requestBodyEncoding?: 'json' | 'form-data' | 'form-urlencoded' | 'binary' | 'text';\n  response: TypeRef;\n  successResponses?: SuccessResponse[];\n  errors: ErrorResponse[];\n  pagination?: PaginationMeta;\n  injectIdempotencyKey: boolean;\n  deprecated?: boolean;\n  async?: boolean;\n  /** Per-operation security overrides. When present, overrides the global spec-level security. */\n  security?: SecurityRequirement[];\n  /**\n   * Mutually-exclusive parameter groups parsed from `x-mutually-exclusive-parameter-groups`.\n   * Each group represents a logical choice the caller must (or may) make between\n   * several subsets of query/path/header parameters. The grouped parameters remain\n   * in their original arrays (queryParams, pathParams, etc.) for wire-format purposes;\n   * this field adds the grouping metadata so emitters can render sum types.\n   */\n  parameterGroups?: ParameterGroup[];\n}\n\n/**\n * A mutually-exclusive parameter group. The caller must supply exactly one\n * variant (when `optional` is false) or may omit the group entirely (when true).\n */\nexport interface ParameterGroup {\n  /** Group name from the extension (e.g. \"parent_resource\"). */\n  name: string;\n  /** True when the whole group may be omitted. */\n  optional: boolean;\n  /** Ordered variants (insertion order matches the spec). */\n  variants: ParameterGroupVariant[];\n}\n\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  /**\n   * Optional domain-facing name override. When set, emitters derive the\n   * domain-side identifier (in their own casing) from this instead of `name`,\n   * while serialization still uses `name` for the wire key. Lets an SDK expose\n   * a wire field under a friendlier name (e.g. `connection_type` → `type`)\n   * without changing the API contract. Set via the `fieldHints` config and\n   * honored by any emitter that reads it.\n   */\n  domainName?: string;\n  type: TypeRef;\n  required: boolean;\n  description?: string;\n  readOnly?: boolean;\n  writeOnly?: boolean;\n  deprecated?: boolean;\n  default?: unknown;\n  example?: unknown;\n}\n\n/** Enum definition */\nexport interface Enum {\n  name: string;\n  values: EnumValue[];\n  /** Spec-level default value (the value of `default:` on the schema). Optional. */\n  default?: string | number;\n}\n\nexport interface EnumValue {\n  name: string;\n  value: string | number;\n  description?: string;\n  deprecated?: boolean;\n}\n\n/**\n * Exhaustive check helper for TypeRef switches.\n * If a new kind is added to TypeRef, any switch that doesn't handle it\n * will fail to compile because `never` won't accept the unhandled variant.\n *\n * Usage:\n *   switch (ref.kind) {\n *     case 'primitive': ...\n *     case 'array': ...\n *     // If you forget 'literal', TypeScript errors here:\n *     default: assertNever(ref);\n *   }\n */\nexport function assertNever(x: never): never {\n  // Inline to avoid importing from ../errors.js (ir/ is layer 0, must not import upward)\n  const kind = (x as TypeRef).kind;\n  const err = new Error(\n    `Unexpected TypeRef kind: ${kind}\\nHint: If you added a new TypeRef variant, handle it in every switch/case that calls assertNever.`,\n  );\n  err.name = 'InternalError';\n  throw err;\n}\n\n/**\n * Generic depth-first walker for TypeRef trees.\n * Handles recursion into array/nullable/union/map children and provides\n * an exhaustive `assertNever` check so callers don't need to repeat the\n * switch boilerplate.  Supply callbacks only for the leaf kinds you care about.\n */\nexport function walkTypeRef(\n  ref: TypeRef,\n  visitor: {\n    model?: (ref: ModelRef) => void;\n    enum?: (ref: EnumRef) => void;\n    primitive?: (ref: PrimitiveType) => void;\n    literal?: (ref: LiteralType) => void;\n  },\n): void {\n  switch (ref.kind) {\n    case 'model':\n      visitor.model?.(ref);\n      break;\n    case 'enum':\n      visitor.enum?.(ref);\n      break;\n    case 'array':\n      walkTypeRef(ref.items, visitor);\n      break;\n    case 'nullable':\n      walkTypeRef(ref.inner, visitor);\n      break;\n    case 'union':\n      for (const v of ref.variants) walkTypeRef(v, visitor);\n      break;\n    case 'map':\n      if (ref.keyType) walkTypeRef(ref.keyType, visitor);\n      walkTypeRef(ref.valueType, visitor);\n      break;\n    case 'literal':\n      visitor.literal?.(ref);\n      break;\n    case 'primitive':\n      visitor.primitive?.(ref);\n      break;\n    default:\n      assertNever(ref);\n  }\n}\n\n/**\n * Generic depth-first mapper for TypeRef trees.\n * Like walkTypeRef but returns a transformed value instead of void.\n * Handles recursion into array/nullable/union/map children, passing\n * already-mapped child values to the parent callback.\n */\nexport function mapTypeRef<T>(\n  ref: TypeRef,\n  mapper: {\n    primitive: (ref: PrimitiveType) => T;\n    array: (ref: ArrayType, mappedItems: T) => T;\n    model: (ref: ModelRef) => T;\n    enum: (ref: EnumRef) => T;\n    union: (ref: UnionType, mappedVariants: T[]) => T;\n    nullable: (ref: NullableType, mappedInner: T) => T;\n    literal: (ref: LiteralType) => T;\n    map: (ref: MapType, mappedValue: T, mappedKey?: T) => T;\n  },\n): T {\n  switch (ref.kind) {\n    case 'primitive':\n      return mapper.primitive(ref);\n    case 'array':\n      return mapper.array(ref, mapTypeRef(ref.items, mapper));\n    case 'model':\n      return mapper.model(ref);\n    case 'enum':\n      return mapper.enum(ref);\n    case 'union':\n      return mapper.union(\n        ref,\n        ref.variants.map((v) => mapTypeRef(v, mapper)),\n      );\n    case 'nullable':\n      return mapper.nullable(ref, mapTypeRef(ref.inner, mapper));\n    case 'literal':\n      return mapper.literal(ref);\n    case 'map':\n      return mapper.map(\n        ref,\n        mapTypeRef(ref.valueType, mapper),\n        ref.keyType ? mapTypeRef(ref.keyType, mapper) : undefined,\n      );\n    default:\n      return assertNever(ref);\n  }\n}\n\n// --- IR traversal utilities ---\n\n/**\n * Collect all model names referenced (directly or transitively) by a TypeRef.\n */\nexport function collectModelRefs(ref: TypeRef): string[] {\n  const names: string[] = [];\n  walkTypeRef(ref, { model: (r) => names.push(r.name) });\n  return names;\n}\n\n/**\n * Collect all enum names referenced by a TypeRef.\n */\nexport function collectEnumRefs(ref: TypeRef): string[] {\n  const names: string[] = [];\n  walkTypeRef(ref, { enum: (r) => names.push(r.name) });\n  return names;\n}\n\n/**\n * Collect all TypeRef-referenced model and enum names from a model's fields.\n * Returns { models, enums } sets for generating import statements.\n */\nexport function collectFieldDependencies(model: Model): {\n  models: Set<string>;\n  enums: Set<string>;\n} {\n  const models = new Set<string>();\n  const enums = new Set<string>();\n\n  for (const field of model.fields) {\n    for (const name of collectModelRefs(field.type)) {\n      if (name !== model.name) models.add(name);\n    }\n    for (const name of collectEnumRefs(field.type)) {\n      enums.add(name);\n    }\n  }\n\n  return { models, enums };\n}\n\n/**\n * Assign each model to the service that first references it.\n * Models referenced by multiple services are assigned to the first.\n * Models not referenced by any service are unassigned (absent from the map).\n *\n * @param hints - Optional pin overrides keyed by IR model name → IR service\n *   name. Applied after the natural assignment loop. 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 * Structured error hierarchy for oagen.\n *\n * Every error carries a human-readable `hint` that suggests a recovery action.\n * The hint is appended to the `message` so it appears in stack traces and logs.\n */\n\n/** Base class for all oagen errors. */\nexport class OagenError extends Error {\n  readonly hint: string;\n\n  constructor(message: string, hint: string) {\n    const fullMessage = hint ? `${message}\\nHint: ${hint}` : message;\n    super(fullMessage);\n    this.name = 'OagenError';\n    this.hint = hint;\n  }\n}\n\n/** Thrown when a command should terminate with a specific exit code. */\nexport class CommandError extends OagenError {\n  readonly exitCode: number;\n\n  constructor(message: string, hint: string, exitCode: number) {\n    super(message, hint);\n    this.name = 'CommandError';\n    this.exitCode = exitCode;\n  }\n}\n\n/** Thrown when an OpenAPI spec cannot be parsed or has an unsupported version. */\nexport class SpecParseError extends OagenError {\n  constructor(message: string, hint: string) {\n    super(message, hint);\n    this.name = 'SpecParseError';\n  }\n}\n\n/** Thrown when configuration files (manifests, API surfaces, overlays) are missing or malformed. */\nexport class ConfigError extends OagenError {\n  constructor(message: string, hint: string) {\n    super(message, hint);\n    this.name = 'ConfigError';\n  }\n}\n\n/** Thrown when a config file exists but cannot be loaded or evaluated. */\nexport class ConfigLoadError extends ConfigError {\n  constructor(message: string, hint: string) {\n    super(message, hint);\n    this.name = 'ConfigLoadError';\n  }\n}\n\n/** Thrown when a config targets a different IR version than the installed package. */\nexport class ConfigVersionMismatchError extends ConfigError {\n  constructor(message: string, hint: string) {\n    super(message, hint);\n    this.name = 'ConfigVersionMismatchError';\n  }\n}\n\n/** Thrown when an API surface extractor encounters a problem. */\nexport class ExtractorError extends OagenError {\n  constructor(message: string, hint: string) {\n    super(message, hint);\n    this.name = 'ExtractorError';\n  }\n}\n\n/** Thrown when a requested language or extractor is not found in a registry. */\nexport class RegistryError extends OagenError {\n  constructor(message: string, hint: string) {\n    super(message, hint);\n    this.name = 'RegistryError';\n  }\n}\n\n/** Thrown for internal invariant violations that indicate a bug. */\nexport class InternalError extends OagenError {\n  constructor(message: string, hint: string) {\n    super(message, hint);\n    this.name = 'InternalError';\n  }\n}\n","/**\n * Known compound tokens that the regex-based splitter over-splits.\n * Each entry is [lowercase-word-sequence, canonical-form].\n * Sorted longest-first so greedy matching works correctly.\n */\nconst COMPOUND_WORDS: [string[], string][] = [\n  [['m', '2', 'm'], 'M2M'],\n  [['o', 'auth'], 'OAuth'],\n];\n\n/**\n * Recombine adjacent words that form a known compound token.\n */\nfunction recombineCompounds(words: string[]): string[] {\n  const result: string[] = [];\n  let i = 0;\n  while (i < words.length) {\n    let matched = false;\n    for (const [pattern, canonical] of COMPOUND_WORDS) {\n      if (i + pattern.length <= words.length) {\n        const matches = pattern.every((p, j) => words[i + j].toLowerCase() === p);\n        if (matches) {\n          result.push(canonical);\n          i += pattern.length;\n          matched = true;\n          break;\n        }\n      }\n    }\n    if (!matched) {\n      result.push(words[i]);\n      i++;\n    }\n  }\n  return result;\n}\n\n/**\n * Split a string into words, handling:\n * - camelCase / PascalCase boundaries\n * - snake_case / kebab-case separators\n * - Consecutive capitals (e.g., \"HTTPClient\" → [\"HTTP\", \"Client\"])\n * - Numbers as word boundaries (e.g., \"OAuth2Token\" → [\"OAuth\", \"2\", \"Token\"])\n * - Known compounds are recombined (e.g., \"M2M\" stays as one word)\n */\nexport function splitWords(s: string): string[] {\n  if (!s) return [];\n\n  const words = s\n    .replace(/[^a-zA-Z0-9_\\-\\s.]/g, '_') // replace non-alphanumeric chars with separator\n    .replace(/([a-z])([A-Z])/g, '$1\\0$2') // camelCase boundary\n    .replace(/([A-Z]+)([A-Z][a-z])/g, '$1\\0$2') // consecutive caps boundary\n    .replace(/([a-zA-Z])(\\d)/g, '$1\\0$2') // letter to number\n    .replace(/(\\d)([a-zA-Z])/g, '$1\\0$2') // number to letter\n    .split(/[\\0_\\-\\s.]+/)\n    .filter((w) => w.length > 0);\n\n  return recombineCompounds(words);\n}\n\nexport const ACRONYM_SET = new Set(['SSO', 'FGA', 'SAML', 'SCIM', 'JWT', 'HMAC', 'M2M']);\n\nexport function toPascalCase(s: string, acronyms?: Set<string>): string {\n  const merged = acronyms ? new Set([...ACRONYM_SET, ...acronyms]) : ACRONYM_SET;\n  return splitWords(s)\n    .map((w) => {\n      const upper = w.toUpperCase();\n      if (merged.has(upper)) return upper;\n      // Special case: OAuth should stay as OAuth, not OAUTH\n      if (upper === 'OAUTH') return 'OAuth';\n      return w.charAt(0).toUpperCase() + w.slice(1).toLowerCase();\n    })\n    .join('');\n}\n\nexport function toCamelCase(s: string, acronyms?: Set<string>): string {\n  const merged = acronyms ? new Set([...ACRONYM_SET, ...acronyms]) : ACRONYM_SET;\n  const words = splitWords(s);\n  if (words.length === 0) return '';\n  return words\n    .map((w, i) => {\n      if (i === 0) return w.toLowerCase();\n      const upper = w.toUpperCase();\n      if (merged.has(upper)) return upper;\n      if (upper === 'OAUTH') return 'OAuth';\n      return w.charAt(0).toUpperCase() + w.slice(1).toLowerCase();\n    })\n    .join('');\n}\n\nexport function toSnakeCase(s: string): string {\n  return splitWords(s)\n    .map((w) => w.toLowerCase())\n    .join('_');\n}\n\nexport function toKebabCase(s: string): string {\n  return splitWords(s)\n    .map((w) => w.toLowerCase())\n    .join('-');\n}\n\nexport function toUpperSnakeCase(s: string): string {\n  return splitWords(s)\n    .map((w) => w.toUpperCase())\n    .join('_');\n}\n\nconst BACKEND_SUFFIXES = ['Controller'];\n\nexport function stripBackendSuffixes(name: string): string {\n  for (const suffix of BACKEND_SUFFIXES) {\n    if (name.endsWith(suffix) && name.length > suffix.length) {\n      return name.slice(0, -suffix.length);\n    }\n  }\n  return name;\n}\n\nexport function stripBackendPrefixes(name: string): string {\n  return name.replace(/Userland/g, '').replace(/Controller/g, '');\n}\n\n/**\n * Remove ListItem / ByExternalId / ByResourceId / ForResource markers from PascalCase names.\n * E.g. \"DirectoriesListItemState\" → \"DirectoriesState\"\n */\nexport function stripListItemMarkers(name: string): string {\n  return name\n    .replace(/ListItem/g, '')\n    .replace(/ByExternalId/g, '')\n    .replace(/ByResourceId/g, '')\n    .replace(/ForResource/g, '');\n}\n\n/** Words that look plural but must NOT be singularized. */\nconst SINGULAR_SAFE_LIST = new Set([\n  'Status',\n  'Address',\n  'Access',\n  'Process',\n  'Progress',\n  'Success',\n  'Radius',\n  'Canvas',\n  'Alias',\n  'Basis',\n  'Bus',\n  'Species',\n  'Series',\n]);\n\n/**\n * Conservative singularize for the leading PascalCase word.\n * Only applied to the first word of a PascalCase name (the resource word).\n * - `ies` → `y` (e.g. Directories → Directory)\n * - trailing `s` for words >4 chars (e.g. Organizations → Organization)\n * Safe-listed words are never singularized.\n */\nexport function singularize(word: string): string {\n  if (SINGULAR_SAFE_LIST.has(word)) return word;\n  if (word.endsWith('ies') && word.length > 4) {\n    return word.slice(0, -3) + 'y';\n  }\n  if (word.endsWith('ses') && word.length > 4) {\n    // e.g. \"Processes\" — but \"Process\" is safe-listed, this handles non-safe ones\n    return word.slice(0, -2);\n  }\n  if (word.endsWith('s') && !word.endsWith('ss') && word.length > 4) {\n    return word.slice(0, -1);\n  }\n  return word;\n}\n\n/**\n * Compose all backend name cleaning transforms in order:\n * 1. Strip backend prefixes (Userland, Controller)\n * 2. Strip backend suffixes (Dto, DTO, Controller)\n * 3. Strip ListItem / ByExternalId markers\n * 4. Singularize leading resource word\n *\n * Must be idempotent: `cleanSchemaName(cleanSchemaName(x)) === cleanSchemaName(x)`\n */\n/** Strip `.js` extensions from import/export specifiers for dedup comparison. */\nexport function normalizeJsExtension(text: string): string {\n  return text.replace(/\\.js(['\"])/g, '$1');\n}\n\nexport function cleanSchemaName(name: string): string {\n  let result = stripBackendPrefixes(stripBackendSuffixes(name));\n  result = stripListItemMarkers(result);\n\n  // Singularize the leading PascalCase word\n  const match = result.match(/^([A-Z][a-z]*)/);\n  if (match) {\n    const leadWord = match[1];\n    const singular = singularize(leadWord);\n    if (singular !== leadWord) {\n      result = singular + result.slice(leadWord.length);\n    }\n  }\n\n  return result;\n}\n","/**\n * Shared tree-sitter utilities.\n *\n * tree-sitter 0.21.x has a native binding bug: its internal UTF-16 buffer is\n * 32 768 uint16 units (32 768 characters for BMP text). When the JS input\n * callback returns a string >= 32 768 chars, `napi_get_value_string_utf16`\n * overflows and the C layer throws \"Invalid argument\". Work around this by\n * supplying a chunked callback for large sources instead of a raw string.\n */\n\nimport type Parser from 'tree-sitter';\n\nconst TS_SAFE_CHUNK = 32_767;\n\nexport function safeParse(parser: Parser, source: string): Parser.Tree {\n  if (source.length < TS_SAFE_CHUNK) {\n    return parser.parse(source);\n  }\n  return parser.parse((offset: number) => source.slice(offset, offset + TS_SAFE_CHUNK));\n}\n"],"mappings":"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"}