@workos/oagen 0.26.1 → 0.28.0

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.
@@ -1,5 +1,5 @@
1
1
  import { t as safeParse$1, v as ExtractorError } from "../tree-sitter-C6HB4OrC.mjs";
2
- import { A as getDefaultPolicy, C as defaultSeverityForCategory, D as isCompatibleSchemaVersion, E as COMPAT_SCHEMA_VERSION, O as validateSnapshot, S as summarizeChanges, T as apiSurfaceToSnapshot, _ as nodeHints, a as registerExtractor, b as classifyAddedSymbol, c as filterSurface, d as specDerivedHttpKeys, f as specDerivedMethodPaths, g as namedTypeWordsOverlap, h as defaultIsNullableOnlyDifference, i as getExtractor, j as mergePolicy, k as ALL_LANGUAGE_IDS, l as specDerivedEnumValues, m as NAMED_TYPE_RE, n as isPatchableChange, o as diffSnapshots, p as specDerivedNames, r as patchOverlay, s as diffSurfaces, t as buildOverlayLookup, u as specDerivedFieldPaths, v as resolveHints, w as severityMeetsThreshold, x as classifySymbolChanges, y as typeExistsInSurface } from "../overlay-DcvsIx5P.mjs";
2
+ import { A as getDefaultPolicy, C as defaultSeverityForCategory, D as isCompatibleSchemaVersion, E as COMPAT_SCHEMA_VERSION, O as validateSnapshot, S as summarizeChanges, T as apiSurfaceToSnapshot, _ as nodeHints, a as registerExtractor, b as classifyAddedSymbol, c as filterSurface, d as specDerivedHttpKeys, f as specDerivedMethodPaths, g as namedTypeWordsOverlap, h as defaultIsNullableOnlyDifference, i as getExtractor, j as mergePolicy, k as ALL_LANGUAGE_IDS, l as specDerivedEnumValues, m as NAMED_TYPE_RE, n as isPatchableChange, o as diffSnapshots, p as specDerivedNames, r as patchOverlay, s as diffSurfaces, t as buildOverlayLookup, u as specDerivedFieldPaths, v as resolveHints, w as severityMeetsThreshold, x as classifySymbolChanges, y as typeExistsInSurface } from "../overlay-jsSkFJ2g.mjs";
3
3
  import path, { basename, dirname, join, relative, resolve } from "node:path";
4
4
  import Parser from "tree-sitter";
5
5
  import ts from "typescript";
@@ -700,7 +700,7 @@ function parseConstElement(constElement) {
700
700
  value: valueNode.text
701
701
  };
702
702
  }
703
- function parseMethods$2(classBody) {
703
+ function parseMethods$3(classBody) {
704
704
  const methods = [];
705
705
  const allPromotedProperties = [];
706
706
  for (const child of classBody.namedChildren) {
@@ -759,7 +759,7 @@ function parseMethods$2(classBody) {
759
759
  promotedProperties: allPromotedProperties
760
760
  };
761
761
  }
762
- function parseProperties$1(classBody) {
762
+ function parseProperties$2(classBody) {
763
763
  const properties = [];
764
764
  for (const child of classBody.namedChildren) {
765
765
  if (child.type !== "property_declaration") continue;
@@ -830,8 +830,8 @@ function parseClassDeclarations(tree, sourceFile, namespace) {
830
830
  }
831
831
  const bodyNode = node.childForFieldName("body");
832
832
  if (!bodyNode) continue;
833
- const { methods, promotedProperties } = parseMethods$2(bodyNode);
834
- const properties = parseProperties$1(bodyNode);
833
+ const { methods, promotedProperties } = parseMethods$3(bodyNode);
834
+ const properties = parseProperties$2(bodyNode);
835
835
  const constants = parseConstants(bodyNode);
836
836
  const resourceAttributes = parseResourceAttributes(bodyNode);
837
837
  const hasCustomConstructor = methods.some((m) => m.name === "constructFromResponse" && m.isStatic);
@@ -858,7 +858,7 @@ function parseInterfaceDeclarations(tree, sourceFile, namespace) {
858
858
  if (!nameNode) continue;
859
859
  const bodyNode = node.childForFieldName("body");
860
860
  if (!bodyNode) continue;
861
- const { methods } = parseMethods$2(bodyNode);
861
+ const { methods } = parseMethods$3(bodyNode);
862
862
  interfaces.push({
863
863
  name: nameNode.text,
864
864
  namespace,
@@ -897,7 +897,7 @@ function parseEnumDeclarations(tree, sourceFile, namespace) {
897
897
  value
898
898
  });
899
899
  }
900
- const { methods } = parseMethods$2(bodyNode);
900
+ const { methods } = parseMethods$3(bodyNode);
901
901
  enums.push({
902
902
  name: nameNode.text,
903
903
  namespace,
@@ -970,7 +970,7 @@ function isExceptionClass$1(cls, exceptionBases) {
970
970
  if (!cls.extends) return false;
971
971
  return exceptionBases.has(cls.extends);
972
972
  }
973
- function buildSurface$6(allClasses, hints) {
973
+ function buildSurface$7(allClasses, hints) {
974
974
  const resourceBases = new Set(hints?.modelBaseClasses ?? DEFAULT_RESOURCE_BASES);
975
975
  const exceptionBases = new Set(hints?.exceptionBaseClasses ?? DEFAULT_EXCEPTION_BASES$1);
976
976
  const classes = {};
@@ -1211,7 +1211,7 @@ function createPhpExtractor(hintOverrides) {
1211
1211
  const parsed = parsePhpFile(filePath, sdkPath);
1212
1212
  allClasses.push(...parsed.classes);
1213
1213
  }
1214
- const { classes, interfaces, enums, exports } = buildSurface$6(allClasses, mergedHints);
1214
+ const { classes, interfaces, enums, exports } = buildSurface$7(allClasses, mergedHints);
1215
1215
  return {
1216
1216
  language: "php",
1217
1217
  extractedFrom: sdkPath,
@@ -1641,7 +1641,7 @@ function unwrapReturnType(returnType) {
1641
1641
  if (awaitableMatch) return awaitableMatch[1];
1642
1642
  return returnType;
1643
1643
  }
1644
- function buildSurface$5(parsedFiles, hints) {
1644
+ function buildSurface$6(parsedFiles, hints) {
1645
1645
  const MODEL_BASES = new Set(hints?.modelBaseClasses ?? DEFAULT_MODEL_BASES);
1646
1646
  const EXCEPTION_BASES = new Set(hints?.exceptionBaseClasses ?? DEFAULT_EXCEPTION_BASES);
1647
1647
  const classes = {};
@@ -2092,7 +2092,7 @@ function createPythonExtractor(hintOverrides) {
2092
2092
  const parsed = parsePythonFile(filePath, sdkPath);
2093
2093
  parsedFiles.push(parsed);
2094
2094
  }
2095
- const { classes, interfaces, typeAliases, enums, exports } = buildSurface$5(parsedFiles, mergedHints);
2095
+ const { classes, interfaces, typeAliases, enums, exports } = buildSurface$6(parsedFiles, mergedHints);
2096
2096
  return {
2097
2097
  language: "python",
2098
2098
  extractedFrom: sdkPath,
@@ -2865,7 +2865,7 @@ function buildQualifiedNames(items) {
2865
2865
  }
2866
2866
  return result;
2867
2867
  }
2868
- function buildSurface$4(allStructs, allTypes, allFuncs, allConsts) {
2868
+ function buildSurface$5(allStructs, allTypes, allFuncs, allConsts) {
2869
2869
  const classes = {};
2870
2870
  const interfaces = {};
2871
2871
  const typeAliases = {};
@@ -3110,7 +3110,7 @@ const goExtractor = {
3110
3110
  allFuncs.push(...parsed.funcs);
3111
3111
  allConsts.push(...parsed.consts);
3112
3112
  }
3113
- const { classes, interfaces, typeAliases, enums, exports } = buildSurface$4(allStructs, allTypes, allFuncs, allConsts);
3113
+ const { classes, interfaces, typeAliases, enums, exports } = buildSurface$5(allStructs, allTypes, allFuncs, allConsts);
3114
3114
  return {
3115
3115
  language: "go",
3116
3116
  extractedFrom: sdkPath,
@@ -3281,7 +3281,7 @@ function parseEnums$1(tree, sourceFile) {
3281
3281
  }
3282
3282
  return enums;
3283
3283
  }
3284
- function parseParams(paramsNode) {
3284
+ function parseParams$1(paramsNode) {
3285
3285
  const params = [];
3286
3286
  for (const child of paramsNode.namedChildren) {
3287
3287
  if (child.type === "self_parameter") continue;
@@ -3321,7 +3321,7 @@ function parseImplBlocks(tree, sourceFile) {
3321
3321
  funcs.push({
3322
3322
  receiverType,
3323
3323
  name: nameNode.text,
3324
- params: paramsNode ? parseParams(paramsNode) : [],
3324
+ params: paramsNode ? parseParams$1(paramsNode) : [],
3325
3325
  returnType: extractReturnType(child),
3326
3326
  isAsync: isAsyncFunc(child),
3327
3327
  sourceFile
@@ -3347,7 +3347,7 @@ function parseTraits(tree, sourceFile) {
3347
3347
  methods.push({
3348
3348
  receiverType: null,
3349
3349
  name: methodName.text,
3350
- params: paramsNode ? parseParams(paramsNode) : [],
3350
+ params: paramsNode ? parseParams$1(paramsNode) : [],
3351
3351
  returnType: extractReturnType(child),
3352
3352
  isAsync: isAsyncFunc(child),
3353
3353
  sourceFile
@@ -3399,7 +3399,7 @@ function unwrapResultType(returnType) {
3399
3399
  if (match) return match[1].trim();
3400
3400
  return returnType;
3401
3401
  }
3402
- function buildSurface$3(allStructs, allEnums, allFuncs, allTraits, allTypeAliases) {
3402
+ function buildSurface$4(allStructs, allEnums, allFuncs, allTraits, allTypeAliases) {
3403
3403
  const classes = {};
3404
3404
  const interfaces = {};
3405
3405
  const typeAliases = {};
@@ -3604,7 +3604,7 @@ const rustExtractor = {
3604
3604
  allTraits.push(...parsed.traits);
3605
3605
  allTypeAliases.push(...parsed.typeAliases);
3606
3606
  }
3607
- const { classes, interfaces, typeAliases, enums, exports } = buildSurface$3(allStructs, allEnums, allFuncs, allTraits, allTypeAliases);
3607
+ const { classes, interfaces, typeAliases, enums, exports } = buildSurface$4(allStructs, allEnums, allFuncs, allTraits, allTypeAliases);
3608
3608
  return {
3609
3609
  language: "rust",
3610
3610
  extractedFrom: sdkPath,
@@ -3652,7 +3652,7 @@ function extractPackageName(source) {
3652
3652
  return match ? match[1] : "unknown";
3653
3653
  }
3654
3654
  /** Strip single-line and block comments from source to avoid false matches. */
3655
- function stripComments$1(source) {
3655
+ function stripComments$2(source) {
3656
3656
  let result = source.replace(/\/\*[\s\S]*?\*\//g, "");
3657
3657
  result = result.replace(/\/\/[^\n]*/g, "");
3658
3658
  return result;
@@ -3671,7 +3671,7 @@ function extractJsonPropertyName$1(text) {
3671
3671
  */
3672
3672
  function parseConstructorParams(paramsBlock) {
3673
3673
  const fields = [];
3674
- const params = splitTopLevelCommas(paramsBlock);
3674
+ const params = splitTopLevelCommas$1(paramsBlock);
3675
3675
  for (const param of params) {
3676
3676
  const trimmed = param.trim();
3677
3677
  if (!trimmed) continue;
@@ -3693,7 +3693,7 @@ function parseConstructorParams(paramsBlock) {
3693
3693
  return fields;
3694
3694
  }
3695
3695
  /** Split a string by top-level commas, ignoring commas inside angle brackets, parens, or strings. */
3696
- function splitTopLevelCommas(text) {
3696
+ function splitTopLevelCommas$1(text) {
3697
3697
  const result = [];
3698
3698
  let depth = 0;
3699
3699
  let current = "";
@@ -3799,7 +3799,7 @@ function parseClasses$1(source, sourceFile, packageName) {
3799
3799
  const classBody = source.slice(braceStart + 1, idx - 1);
3800
3800
  const constructorParams = [];
3801
3801
  if (constructorBlock.trim()) {
3802
- const params = splitTopLevelCommas(constructorBlock);
3802
+ const params = splitTopLevelCommas$1(constructorBlock);
3803
3803
  for (const param of params) {
3804
3804
  const paramMatch = param.trim().match(/(?:(?:private|protected)\s+)?(?:val|var)\s+(\w+)\s*:\s*(.+)/);
3805
3805
  if (paramMatch) constructorParams.push({
@@ -3808,7 +3808,7 @@ function parseClasses$1(source, sourceFile, packageName) {
3808
3808
  });
3809
3809
  }
3810
3810
  }
3811
- const methods = parseMethods$1(classBody);
3811
+ const methods = parseMethods$2(classBody);
3812
3812
  if (methods.length > 0) classes.push({
3813
3813
  name,
3814
3814
  constructorParams,
@@ -3820,7 +3820,7 @@ function parseClasses$1(source, sourceFile, packageName) {
3820
3820
  return classes;
3821
3821
  }
3822
3822
  /** Parse method declarations from a class body. */
3823
- function parseMethods$1(classBody) {
3823
+ function parseMethods$2(classBody) {
3824
3824
  const methods = [];
3825
3825
  const methodRegex = /(private|protected|internal|public)?\s*(?:suspend\s+)?fun\s+(\w+)\s*\(([^)]*)\)\s*(?::\s*([^\s{]+))?/g;
3826
3826
  let match;
@@ -3832,7 +3832,7 @@ function parseMethods$1(classBody) {
3832
3832
  if (visibility === "private" || visibility === "protected") continue;
3833
3833
  const params = [];
3834
3834
  if (paramsStr.trim()) {
3835
- const paramParts = splitTopLevelCommas(paramsStr);
3835
+ const paramParts = splitTopLevelCommas$1(paramsStr);
3836
3836
  for (const part of paramParts) {
3837
3837
  const paramMatch = part.trim().match(/(\w+)\s*:\s*([^=]+?)(?:\s*=\s*(.+))?$/);
3838
3838
  if (paramMatch) {
@@ -3871,7 +3871,7 @@ function parseTypeAliases(source, sourceFile, packageName) {
3871
3871
  function parseKotlinFile(filePath, sdkPath) {
3872
3872
  const source = readFileSync(filePath, "utf-8");
3873
3873
  const relPath = relative(sdkPath, filePath);
3874
- const cleaned = stripComments$1(source);
3874
+ const cleaned = stripComments$2(source);
3875
3875
  const packageName = extractPackageName(cleaned);
3876
3876
  return {
3877
3877
  dataClasses: parseDataClasses(cleaned, relPath, packageName),
@@ -3882,7 +3882,7 @@ function parseKotlinFile(filePath, sdkPath) {
3882
3882
  }
3883
3883
  //#endregion
3884
3884
  //#region src/compat/extractors/kotlin-surface.ts
3885
- function buildSurface$2(allDataClasses, allClasses, allEnums, allTypeAliases) {
3885
+ function buildSurface$3(allDataClasses, allClasses, allEnums, allTypeAliases) {
3886
3886
  const classes = {};
3887
3887
  const interfaces = {};
3888
3888
  const typeAliases = {};
@@ -4040,7 +4040,7 @@ const kotlinExtractor = {
4040
4040
  allEnums.push(...parsed.enums);
4041
4041
  allTypeAliases.push(...parsed.typeAliases);
4042
4042
  }
4043
- const { classes, interfaces, typeAliases, enums, exports } = buildSurface$2(allDataClasses, allClasses, allEnums, allTypeAliases);
4043
+ const { classes, interfaces, typeAliases, enums, exports } = buildSurface$3(allDataClasses, allClasses, allEnums, allTypeAliases);
4044
4044
  return {
4045
4045
  language: "kotlin",
4046
4046
  extractedFrom: sdkPath,
@@ -4091,7 +4091,7 @@ function extractNamespace(source) {
4091
4091
  return "unknown";
4092
4092
  }
4093
4093
  /** Strip single-line and block comments from source. */
4094
- function stripComments(source) {
4094
+ function stripComments$1(source) {
4095
4095
  let result = source.replace(/\/\*[\s\S]*?\*\//g, "");
4096
4096
  result = result.replace(/\/\/[^\n]*/g, "");
4097
4097
  return result;
@@ -4151,8 +4151,8 @@ function parseClasses(source, sourceFile) {
4151
4151
  idx++;
4152
4152
  }
4153
4153
  const classBody = source.slice(braceStart + 1, idx - 1);
4154
- const properties = parseProperties(classBody);
4155
- const methods = parseMethods(classBody);
4154
+ const properties = parseProperties$1(classBody);
4155
+ const methods = parseMethods$1(classBody);
4156
4156
  const constructorParams = parseConstructor(classBody, name);
4157
4157
  const isService = methods.length > 0;
4158
4158
  classes.push({
@@ -4168,7 +4168,7 @@ function parseClasses(source, sourceFile) {
4168
4168
  return classes;
4169
4169
  }
4170
4170
  /** Parse properties from a class body. */
4171
- function parseProperties(classBody) {
4171
+ function parseProperties$1(classBody) {
4172
4172
  const properties = [];
4173
4173
  const lines = classBody.split("\n");
4174
4174
  let pendingJsonName = null;
@@ -4198,7 +4198,7 @@ function parseProperties(classBody) {
4198
4198
  return properties;
4199
4199
  }
4200
4200
  /** Parse methods from a class body. */
4201
- function parseMethods(classBody) {
4201
+ function parseMethods$1(classBody) {
4202
4202
  const methods = [];
4203
4203
  const methodRegex = /(private|protected|internal|public)\s+(?:(static)\s+)?(?:(async)\s+)?(\S+(?:<[^>]+>)?)\s+(\w+)\s*\(([^)]*)\)/g;
4204
4204
  let match;
@@ -4260,7 +4260,7 @@ function parseConstructor(classBody, className) {
4260
4260
  function parseCSharpFile(filePath, sdkPath) {
4261
4261
  const source = readFileSync(filePath, "utf-8");
4262
4262
  const relPath = relative(sdkPath, filePath);
4263
- const cleaned = stripComments(source);
4263
+ const cleaned = stripComments$1(source);
4264
4264
  return {
4265
4265
  classes: parseClasses(cleaned, relPath),
4266
4266
  enums: parseEnums(cleaned, relPath)
@@ -4268,7 +4268,7 @@ function parseCSharpFile(filePath, sdkPath) {
4268
4268
  }
4269
4269
  //#endregion
4270
4270
  //#region src/compat/extractors/dotnet-surface.ts
4271
- function buildSurface$1(allClasses, allEnums, _hints) {
4271
+ function buildSurface$2(allClasses, allEnums, _hints) {
4272
4272
  const classes = {};
4273
4273
  const interfaces = {};
4274
4274
  const enums = {};
@@ -4540,7 +4540,7 @@ function createDotnetExtractor(hintOverrides) {
4540
4540
  allClasses.push(...parsed.classes);
4541
4541
  allEnums.push(...parsed.enums);
4542
4542
  }
4543
- const { classes, interfaces, enums, exports } = buildSurface$1(allClasses, allEnums, mergedHints);
4543
+ const { classes, interfaces, enums, exports } = buildSurface$2(allClasses, allEnums, mergedHints);
4544
4544
  return {
4545
4545
  language: "dotnet",
4546
4546
  extractedFrom: sdkPath,
@@ -4592,7 +4592,7 @@ function walkElixirFiles(dir) {
4592
4592
  */
4593
4593
  function stripCommentsAndHeredocs(source) {
4594
4594
  let result = source.replace(/"""[\s\S]*?"""/g, "\"\"\"\"\"\"");
4595
- result = result.replace(/#[^\n]*/g, "");
4595
+ result = result.replace(/#(?!\{)[^\n]*/g, "");
4596
4596
  return result;
4597
4597
  }
4598
4598
  /**
@@ -4772,6 +4772,24 @@ function extractTypeSpecs(modules, sourceFile) {
4772
4772
  }
4773
4773
  return specs;
4774
4774
  }
4775
+ /** Named escapes Elixir recognizes inside double-quoted strings/atoms. */
4776
+ const ELIXIR_STRING_ESCAPES = {
4777
+ "0": "\0",
4778
+ a: "\x07",
4779
+ b: "\b",
4780
+ d: "",
4781
+ e: "\x1B",
4782
+ f: "\f",
4783
+ n: "\n",
4784
+ r: "\r",
4785
+ s: " ",
4786
+ t: " ",
4787
+ v: "\v"
4788
+ };
4789
+ /** Undo backslash escapes inside a double-quoted Elixir string/atom. */
4790
+ function unescapeElixirString(s) {
4791
+ return s.replace(/\\(.)/g, (_, ch) => ELIXIR_STRING_ESCAPES[ch] ?? ch);
4792
+ }
4775
4793
  function extractEnumModules(modules, sourceFile) {
4776
4794
  const enumModules = [];
4777
4795
  for (const { name: moduleName, body: moduleBody } of modules) {
@@ -4786,6 +4804,24 @@ function extractEnumModules(modules, sourceFile) {
4786
4804
  if (funcName === "values") continue;
4787
4805
  members[funcName] = funcValue;
4788
4806
  }
4807
+ const hadNamedMembers = Object.keys(members).length > 0;
4808
+ const valuesList = moduleBody.match(/def\s+values,\s*do:\s*\[((?:"(?:[^"\\]|\\.)*"|[^\]"])*)\]/);
4809
+ if (valuesList) {
4810
+ const tokenRegex = /:"((?:[^"\\]|\\.)*)"|:([a-zA-Z_][a-zA-Z0-9_@]*[?!]?)|"((?:[^"\\]|\\.)*)"|(-?\d+(?:\.\d+)?)/g;
4811
+ let token;
4812
+ while ((token = tokenRegex.exec(valuesList[1])) !== null) {
4813
+ if (!(token[1] != null || token[2] != null) && hadNamedMembers) continue;
4814
+ const text = token[1] ?? token[2] ?? token[3] ?? token[4];
4815
+ const name = token[2] ?? unescapeElixirString(text);
4816
+ if (!(name in members)) members[name] = unescapeElixirString(text);
4817
+ }
4818
+ }
4819
+ const dumpRegex = /def\s+dump\(:(?:"((?:[^"\\]|\\.)*)"|([a-zA-Z_][a-zA-Z0-9_@]*[?!]?))\),\s*do:\s*"((?:[^"\\]|\\.)*)"/g;
4820
+ let dumpMatch;
4821
+ while ((dumpMatch = dumpRegex.exec(moduleBody)) !== null) {
4822
+ const atomName = dumpMatch[1] != null ? unescapeElixirString(dumpMatch[1]) : dumpMatch[2];
4823
+ if (atomName in members) members[atomName] = unescapeElixirString(dumpMatch[3]);
4824
+ }
4789
4825
  if (Object.keys(members).length > 0) enumModules.push({
4790
4826
  moduleName,
4791
4827
  members,
@@ -4814,7 +4850,7 @@ function shortName(moduleName) {
4814
4850
  const parts = moduleName.split(".");
4815
4851
  return parts[parts.length - 1];
4816
4852
  }
4817
- function buildSurface(allStructs, allFunctions, allEnumModules, allTypeSpecs) {
4853
+ function buildSurface$1(allStructs, allFunctions, allEnumModules, allTypeSpecs) {
4818
4854
  const classes = {};
4819
4855
  const interfaces = {};
4820
4856
  const enums = {};
@@ -5004,7 +5040,7 @@ const elixirExtractor = {
5004
5040
  allEnumModules.push(...parsed.enumModules);
5005
5041
  allTypeSpecs.push(...parsed.typeSpecs);
5006
5042
  }
5007
- const { classes, interfaces, enums, exports } = buildSurface(allStructs, allFunctions, allEnumModules, allTypeSpecs);
5043
+ const { classes, interfaces, enums, exports } = buildSurface$1(allStructs, allFunctions, allEnumModules, allTypeSpecs);
5008
5044
  return {
5009
5045
  language: "elixir",
5010
5046
  extractedFrom: sdkPath,
@@ -5018,6 +5054,623 @@ const elixirExtractor = {
5018
5054
  }
5019
5055
  };
5020
5056
  //#endregion
5021
- export { ALL_LANGUAGE_IDS, COMPAT_SCHEMA_VERSION, apiSurfaceToSnapshot, applyApprovals, buildConceptualRollup, buildOverlayLookup, classifyAddedSymbol, classifySymbolChanges, defaultSeverityForCategory, diffSnapshots, diffSurfaces, dotnetExtractor, elixirExtractor, filterSurface, formatConceptualSummary, formatHumanSummary, generateConceptualReport, generateReport, getDefaultPolicy, getExtractor, goExtractor, highestSeverity, isCompatibleSchemaVersion, isPatchableChange, kotlinExtractor, matchApproval, mergePolicy, nodeExtractor, nodeHints, patchOverlay, phpExtractor, pythonExtractor, registerExtractor, resolveHints, rubyExtractor, rustExtractor, severityMeetsThreshold, specDerivedEnumValues, specDerivedFieldPaths, specDerivedHttpKeys, specDerivedMethodPaths, specDerivedNames, summarizeChanges, summarizeConceptualChanges, unapprovedChanges, validateApproval, validateApprovals, validateSnapshot };
5057
+ //#region src/compat/extractors/ios-parser.ts
5058
+ /**
5059
+ * Swift source parser — regex-based extraction of structs, classes, actors,
5060
+ * extensions, enums, and type aliases from Swift source files.
5061
+ *
5062
+ * Swift-specific concerns handled here that the other parsers can ignore:
5063
+ * - String literals may contain `//` (URLs) and braces, so comment stripping
5064
+ * and brace matching are both string-aware.
5065
+ * - Files marked `@oagen-ignore-file` are hand-maintained and skipped, so an
5066
+ * `extension` of a hand-written type (e.g. `WorkOSClient+Resources.swift`)
5067
+ * owns the surface it contributes.
5068
+ * - Generated enums carry an `unknown(String)` escape-hatch case and encode
5069
+ * member raw values in `init(rawValue:)` / `var rawValue` switches rather
5070
+ * than `case name = "value"` declarations.
5071
+ */
5072
+ const SKIP_DIRS = new Set([
5073
+ "build",
5074
+ "Tests",
5075
+ "DerivedData",
5076
+ "Pods",
5077
+ "Carthage"
5078
+ ]);
5079
+ function walkSwiftFiles(dir) {
5080
+ const results = [];
5081
+ let entries;
5082
+ try {
5083
+ entries = readdirSync(dir);
5084
+ } catch {
5085
+ return results;
5086
+ }
5087
+ for (const entry of entries) {
5088
+ const fullPath = join(dir, entry);
5089
+ let stat;
5090
+ try {
5091
+ stat = statSync(fullPath);
5092
+ } catch {
5093
+ continue;
5094
+ }
5095
+ if (stat.isDirectory()) {
5096
+ if (entry.startsWith(".") || SKIP_DIRS.has(entry)) continue;
5097
+ results.push(...walkSwiftFiles(fullPath));
5098
+ } else if (entry.endsWith(".swift") && !entry.endsWith("Tests.swift") && !entry.endsWith("Test.swift") && entry !== "Package.swift") results.push(fullPath);
5099
+ }
5100
+ return results.sort();
5101
+ }
5102
+ /** Advance past a string literal starting at `idx` (which must point at `"`).
5103
+ * Handles escapes, multi-line `"""` literals, and `\(...)` interpolations —
5104
+ * whose expressions may contain nested string literals and braces. Returns
5105
+ * the index just past the closing quote(s). */
5106
+ function skipString(source, idx) {
5107
+ const n = source.length;
5108
+ if (source.startsWith("\"\"\"", idx)) {
5109
+ const end = source.indexOf("\"\"\"", idx + 3);
5110
+ return end === -1 ? n : end + 3;
5111
+ }
5112
+ let i = idx + 1;
5113
+ while (i < n && source[i] !== "\"") {
5114
+ if (source[i] === "\\") {
5115
+ if (source[i + 1] === "(") {
5116
+ let depth = 1;
5117
+ let j = i + 2;
5118
+ while (j < n && depth > 0) {
5119
+ const ch = source[j];
5120
+ if (ch === "\"") {
5121
+ j = skipString(source, j);
5122
+ continue;
5123
+ }
5124
+ if (ch === "(") depth++;
5125
+ else if (ch === ")") depth--;
5126
+ j++;
5127
+ }
5128
+ i = j;
5129
+ continue;
5130
+ }
5131
+ i++;
5132
+ }
5133
+ i++;
5134
+ }
5135
+ return Math.min(i + 1, n);
5136
+ }
5137
+ /** Strip line and (nesting) block comments. String literals are preserved
5138
+ * verbatim, including any `//` sequences inside them (URLs). */
5139
+ function stripComments(source) {
5140
+ let out = "";
5141
+ let i = 0;
5142
+ const n = source.length;
5143
+ while (i < n) {
5144
+ const ch = source[i];
5145
+ if (ch === "\"") {
5146
+ const end = skipString(source, i);
5147
+ out += source.slice(i, end);
5148
+ i = end;
5149
+ continue;
5150
+ }
5151
+ if (ch === "/" && source[i + 1] === "/") {
5152
+ while (i < n && source[i] !== "\n") i++;
5153
+ continue;
5154
+ }
5155
+ if (ch === "/" && source[i + 1] === "*") {
5156
+ let depth = 1;
5157
+ i += 2;
5158
+ while (i < n && depth > 0) if (source[i] === "/" && source[i + 1] === "*") {
5159
+ depth++;
5160
+ i += 2;
5161
+ } else if (source[i] === "*" && source[i + 1] === "/") {
5162
+ depth--;
5163
+ i += 2;
5164
+ } else i++;
5165
+ continue;
5166
+ }
5167
+ out += ch;
5168
+ i++;
5169
+ }
5170
+ return out;
5171
+ }
5172
+ /** Given the index of an opening `{`, return the index just past its matching
5173
+ * `}`. String-aware so braces inside literals don't skew the depth. */
5174
+ function matchBrace(source, openIdx) {
5175
+ const n = source.length;
5176
+ let depth = 1;
5177
+ let i = openIdx + 1;
5178
+ while (i < n && depth > 0) {
5179
+ const ch = source[i];
5180
+ if (ch === "\"") {
5181
+ i = skipString(source, i);
5182
+ continue;
5183
+ }
5184
+ if (ch === "{") depth++;
5185
+ else if (ch === "}") depth--;
5186
+ i++;
5187
+ }
5188
+ return i;
5189
+ }
5190
+ /** Reduce a type body to its top-level text: nested `{...}` blocks are
5191
+ * replaced with a newline so declaration signatures survive while method
5192
+ * bodies, computed-property accessors, and nested types disappear. */
5193
+ function topLevelText(body) {
5194
+ let out = "";
5195
+ let i = 0;
5196
+ const n = body.length;
5197
+ while (i < n) {
5198
+ const ch = body[i];
5199
+ if (ch === "\"") {
5200
+ const end = skipString(body, i);
5201
+ out += body.slice(i, end);
5202
+ i = end;
5203
+ continue;
5204
+ }
5205
+ if (ch === "{") {
5206
+ out += "\n";
5207
+ i = matchBrace(body, i);
5208
+ continue;
5209
+ }
5210
+ out += ch;
5211
+ i++;
5212
+ }
5213
+ return out;
5214
+ }
5215
+ /** Split by top-level commas, ignoring commas nested in brackets or strings. */
5216
+ function splitTopLevelCommas(text) {
5217
+ const result = [];
5218
+ let depth = 0;
5219
+ let current = "";
5220
+ let i = 0;
5221
+ while (i < text.length) {
5222
+ const ch = text[i];
5223
+ if (ch === "\"") {
5224
+ const end = skipString(text, i);
5225
+ current += text.slice(i, end);
5226
+ i = end;
5227
+ continue;
5228
+ }
5229
+ if (ch === "<" || ch === "(" || ch === "[") {
5230
+ depth++;
5231
+ current += ch;
5232
+ } else if (ch === ">" || ch === ")" || ch === "]") {
5233
+ depth--;
5234
+ current += ch;
5235
+ } else if (ch === "," && depth === 0) {
5236
+ result.push(current);
5237
+ current = "";
5238
+ } else current += ch;
5239
+ i++;
5240
+ }
5241
+ if (current.trim()) result.push(current);
5242
+ return result;
5243
+ }
5244
+ /** Given the index of an opening `(`, return the index just past its matching `)`. */
5245
+ function matchParen(source, openIdx) {
5246
+ const n = source.length;
5247
+ let depth = 1;
5248
+ let i = openIdx + 1;
5249
+ while (i < n && depth > 0) {
5250
+ const ch = source[i];
5251
+ if (ch === "\"") {
5252
+ i = skipString(source, i);
5253
+ continue;
5254
+ }
5255
+ if (ch === "(") depth++;
5256
+ else if (ch === ")") depth--;
5257
+ i++;
5258
+ }
5259
+ return i;
5260
+ }
5261
+ const VISIBILITY_PUBLIC = /\b(?:public|open)\b/;
5262
+ /** Parse `label name: Type = default` parameter fragments. The public name is
5263
+ * the external argument label; `_ name:` falls back to the internal name. */
5264
+ function parseParams(paramsBlock) {
5265
+ const params = [];
5266
+ for (const part of splitTopLevelCommas(paramsBlock)) {
5267
+ const trimmed = part.trim();
5268
+ if (!trimmed) continue;
5269
+ const paramMatch = trimmed.match(/^(?:(\w+|_)\s+)?(\w+)\s*:\s*([^=]+?)(?:\s*=\s*(.+))?$/s);
5270
+ if (!paramMatch) continue;
5271
+ const label = paramMatch[1];
5272
+ const internalName = paramMatch[2];
5273
+ const type = paramMatch[3].trim();
5274
+ const hasDefault = paramMatch[4] !== void 0;
5275
+ const name = !label || label === "_" ? internalName : label;
5276
+ params.push({
5277
+ name,
5278
+ type,
5279
+ optional: type.endsWith("?") || hasDefault
5280
+ });
5281
+ }
5282
+ return params;
5283
+ }
5284
+ /** Parse stored and computed property declarations from top-level type text. */
5285
+ function parseProperties(surfaceText, defaultPublic) {
5286
+ const properties = [];
5287
+ const propRegex = /^[ \t]*((?:@\w+(?:\([^)]*\))?\s+)*(?:(?:public|open|package|internal|fileprivate|private|static|class|final|lazy|weak|nonisolated)(?:\([^)]*\))?\s+)*)(let|var)\s+(\w+)\s*:\s*([^\n={]+)/gm;
5288
+ let match;
5289
+ while ((match = propRegex.exec(surfaceText)) !== null) {
5290
+ const modifiers = match[1] || "";
5291
+ if (!VISIBILITY_PUBLIC.test(modifiers) && !(defaultPublic && !/\b(?:internal|fileprivate|private|package)\b/.test(modifiers))) continue;
5292
+ if (/\bstatic\b/.test(modifiers)) continue;
5293
+ const keyword = match[2];
5294
+ const name = match[3];
5295
+ const type = match[4].trim();
5296
+ properties.push({
5297
+ name,
5298
+ type,
5299
+ optional: type.endsWith("?"),
5300
+ readonly: keyword === "let"
5301
+ });
5302
+ }
5303
+ return properties;
5304
+ }
5305
+ /** Parse `func` declarations from top-level type text. */
5306
+ function parseMethods(surfaceText, defaultPublic) {
5307
+ const methods = [];
5308
+ const funcRegex = /((?:@\w+(?:\([^)]*\))?\s+)*(?:(?:public|open|package|internal|fileprivate|private|static|class|final|nonisolated|mutating)(?:\([^)]*\))?\s+)*)func\s+(\w+)(?:<[^>]*>)?\s*\(/g;
5309
+ let match;
5310
+ while ((match = funcRegex.exec(surfaceText)) !== null) {
5311
+ const modifiers = match[1] || "";
5312
+ if (!VISIBILITY_PUBLIC.test(modifiers) && !(defaultPublic && !/\b(?:internal|fileprivate|private|package)\b/.test(modifiers))) continue;
5313
+ const name = match[2];
5314
+ const parenOpen = match.index + match[0].length - 1;
5315
+ const parenClose = matchParen(surfaceText, parenOpen);
5316
+ const params = parseParams(surfaceText.slice(parenOpen + 1, parenClose - 1));
5317
+ const tailMatch = surfaceText.slice(parenClose).match(/^\s*(async)?\s*(?:throws|rethrows)?\s*(?:->\s*([^\n]+))?/);
5318
+ let returnType = tailMatch?.[2]?.trim() ?? "Void";
5319
+ const whereIdx = returnType.indexOf(" where ");
5320
+ if (whereIdx !== -1) returnType = returnType.slice(0, whereIdx).trim();
5321
+ methods.push({
5322
+ name,
5323
+ params,
5324
+ returnType,
5325
+ async: tailMatch?.[1] === "async",
5326
+ isStatic: /\b(?:static|class)\b/.test(modifiers)
5327
+ });
5328
+ funcRegex.lastIndex = parenClose;
5329
+ }
5330
+ return methods;
5331
+ }
5332
+ /** Parse `init` declarations from top-level type text. */
5333
+ function parseInits(surfaceText, defaultPublic) {
5334
+ const overloads = [];
5335
+ const initRegex = /((?:@\w+(?:\([^)]*\))?\s+)*(?:(?:public|open|package|internal|fileprivate|private|convenience|required|nonisolated)\s+)*)init\s*\??\s*\(/g;
5336
+ let match;
5337
+ while ((match = initRegex.exec(surfaceText)) !== null) {
5338
+ const modifiers = match[1] || "";
5339
+ if (!VISIBILITY_PUBLIC.test(modifiers) && !(defaultPublic && !/\b(?:internal|fileprivate|private|package)\b/.test(modifiers))) continue;
5340
+ const parenOpen = match.index + match[0].length - 1;
5341
+ const parenClose = matchParen(surfaceText, parenOpen);
5342
+ overloads.push(parseParams(surfaceText.slice(parenOpen + 1, parenClose - 1)));
5343
+ initRegex.lastIndex = parenClose;
5344
+ }
5345
+ return overloads;
5346
+ }
5347
+ function parseEnumBody(name, body, sourceFile) {
5348
+ const surface = topLevelText(body);
5349
+ const declared = [];
5350
+ const caseLineRegex = /^\s*(?:indirect\s+)?case\s+(.+)$/gm;
5351
+ let match;
5352
+ while ((match = caseLineRegex.exec(surface)) !== null) for (const entry of splitTopLevelCommas(match[1])) {
5353
+ const trimmed = entry.trim();
5354
+ if (!trimmed) continue;
5355
+ const caseMatch = trimmed.match(/^`?(\w+)`?(\([^)]*\))?(?:\s*=\s*"([^"]*)")?/);
5356
+ if (!caseMatch) continue;
5357
+ if (caseMatch[2] !== void 0) continue;
5358
+ declared.push({
5359
+ name: caseMatch[1],
5360
+ rawValue: caseMatch[3]
5361
+ });
5362
+ }
5363
+ if (declared.length === 0) return null;
5364
+ const valueByMember = /* @__PURE__ */ new Map();
5365
+ const getterRegex = /case\s+\.(\w+)\s*:\s*return\s+"((?:[^"\\]|\\.)*)"/g;
5366
+ while ((match = getterRegex.exec(body)) !== null) valueByMember.set(match[1], match[2]);
5367
+ const initRegex = /case\s+"((?:[^"\\]|\\.)*)"\s*:\s*self\s*=\s*\.(\w+)/g;
5368
+ while ((match = initRegex.exec(body)) !== null) if (!valueByMember.has(match[2])) valueByMember.set(match[2], match[1]);
5369
+ const members = {};
5370
+ for (const { name: memberName, rawValue } of declared) members[memberName] = rawValue ?? valueByMember.get(memberName) ?? memberName;
5371
+ return {
5372
+ name,
5373
+ members,
5374
+ sourceFile
5375
+ };
5376
+ }
5377
+ /** Parse a single Swift source file and return all extracted symbols.
5378
+ * Files marked `@oagen-ignore-file` are hand-maintained and yield nothing. */
5379
+ function parseSwiftFile(filePath, sdkPath) {
5380
+ const source = readFileSync(filePath, "utf-8");
5381
+ const relPath = relative(sdkPath, filePath);
5382
+ const empty = {
5383
+ types: [],
5384
+ enums: [],
5385
+ typeAliases: []
5386
+ };
5387
+ if (source.includes("@oagen-ignore-file")) return empty;
5388
+ const cleaned = stripComments(source);
5389
+ const typeDeclRegex = /((?:@\w+(?:\([^)]*\))?\s+)*(?:(?:public|open|package|internal|fileprivate|private|final|indirect)\s+)*)(struct|class|actor|enum)\s+(\w+)(?:<[^>]*>)?(?:\s*:\s*[^{]+?)?\s*\{/g;
5390
+ const extensionRegex = /(^|\n)\s*((?:public|package|internal|fileprivate|private)\s+)?extension\s+(\w+)(?:\s*:\s*[^{]+?)?\s*\{/g;
5391
+ const types = [];
5392
+ const enums = [];
5393
+ const typeAliases = [];
5394
+ let match;
5395
+ while ((match = typeDeclRegex.exec(cleaned)) !== null) {
5396
+ const modifiers = match[1] || "";
5397
+ const kind = match[2];
5398
+ const name = match[3];
5399
+ const braceIdx = match.index + match[0].length - 1;
5400
+ const bodyEnd = matchBrace(cleaned, braceIdx);
5401
+ const body = cleaned.slice(braceIdx + 1, bodyEnd - 1);
5402
+ if (!VISIBILITY_PUBLIC.test(modifiers)) continue;
5403
+ if (kind === "enum") {
5404
+ const parsed = parseEnumBody(name, body, relPath);
5405
+ if (parsed) enums.push(parsed);
5406
+ continue;
5407
+ }
5408
+ const surface = topLevelText(body);
5409
+ types.push({
5410
+ kind,
5411
+ name,
5412
+ properties: parseProperties(surface, false),
5413
+ methods: parseMethods(surface, false),
5414
+ initOverloads: parseInits(surface, false),
5415
+ sourceFile: relPath
5416
+ });
5417
+ }
5418
+ while ((match = extensionRegex.exec(cleaned)) !== null) {
5419
+ const isPublicExtension = (match[2] || "").trim() === "public";
5420
+ const name = match[3];
5421
+ const braceIdx = match.index + match[0].length - 1;
5422
+ const bodyEnd = matchBrace(cleaned, braceIdx);
5423
+ const surface = topLevelText(cleaned.slice(braceIdx + 1, bodyEnd - 1));
5424
+ const decl = {
5425
+ kind: "extension",
5426
+ name,
5427
+ properties: parseProperties(surface, isPublicExtension),
5428
+ methods: parseMethods(surface, isPublicExtension),
5429
+ initOverloads: parseInits(surface, isPublicExtension),
5430
+ sourceFile: relPath
5431
+ };
5432
+ if (decl.properties.length > 0 || decl.methods.length > 0 || decl.initOverloads.length > 0) types.push(decl);
5433
+ }
5434
+ const aliasRegex = /(?:public|open)\s+typealias\s+(\w+)(?:<[^>]*>)?\s*=\s*([^\n]+)/g;
5435
+ while ((match = aliasRegex.exec(cleaned)) !== null) typeAliases.push({
5436
+ name: match[1],
5437
+ value: match[2].trim(),
5438
+ sourceFile: relPath
5439
+ });
5440
+ return {
5441
+ types,
5442
+ enums,
5443
+ typeAliases
5444
+ };
5445
+ }
5446
+ //#endregion
5447
+ //#region src/compat/extractors/ios-surface.ts
5448
+ function mergeTypes(allTypes) {
5449
+ const byName = /* @__PURE__ */ new Map();
5450
+ for (const decl of allTypes) {
5451
+ let entry = byName.get(decl.name);
5452
+ if (!entry) {
5453
+ entry = {
5454
+ name: decl.name,
5455
+ declKind: null,
5456
+ properties: [],
5457
+ methods: [],
5458
+ initOverloads: [],
5459
+ sourceFile: decl.sourceFile
5460
+ };
5461
+ byName.set(decl.name, entry);
5462
+ }
5463
+ if (decl.kind !== "extension" && entry.declKind === null) {
5464
+ entry.declKind = decl.kind;
5465
+ entry.sourceFile = decl.sourceFile;
5466
+ }
5467
+ entry.properties.push(...decl.properties);
5468
+ entry.methods.push(...decl.methods);
5469
+ entry.initOverloads.push(...decl.initOverloads);
5470
+ }
5471
+ return [...byName.values()];
5472
+ }
5473
+ function buildSurface(allTypes, allEnums, allTypeAliases) {
5474
+ const classes = {};
5475
+ const interfaces = {};
5476
+ const typeAliases = {};
5477
+ const enums = {};
5478
+ const collector = new ExportCollector();
5479
+ for (const type of mergeTypes(allTypes)) {
5480
+ if (type.declKind === "struct" && type.methods.length === 0) {
5481
+ if (type.properties.length === 0) continue;
5482
+ const fields = {};
5483
+ for (const prop of type.properties) fields[prop.name] = {
5484
+ name: prop.name,
5485
+ type: prop.type,
5486
+ optional: prop.optional
5487
+ };
5488
+ interfaces[type.name] = {
5489
+ name: type.name,
5490
+ sourceFile: type.sourceFile,
5491
+ fields: sortRecord(fields),
5492
+ extends: []
5493
+ };
5494
+ collector.add(type.sourceFile, type.name);
5495
+ continue;
5496
+ }
5497
+ if (type.methods.length === 0 && type.properties.length === 0) continue;
5498
+ const methods = {};
5499
+ for (const method of type.methods) {
5500
+ const params = method.params.map((p) => ({
5501
+ name: p.name,
5502
+ type: p.type,
5503
+ optional: p.optional,
5504
+ passingStyle: "positional"
5505
+ }));
5506
+ if (!methods[method.name]) methods[method.name] = [];
5507
+ methods[method.name].push({
5508
+ name: method.name,
5509
+ params,
5510
+ returnType: method.returnType,
5511
+ async: method.async,
5512
+ isStatic: method.isStatic
5513
+ });
5514
+ }
5515
+ const properties = {};
5516
+ for (const prop of type.properties) properties[prop.name] = {
5517
+ name: prop.name,
5518
+ type: prop.type,
5519
+ readonly: prop.readonly
5520
+ };
5521
+ const constructorParams = (type.initOverloads[0] ?? []).map((p) => ({
5522
+ name: p.name,
5523
+ type: p.type,
5524
+ optional: p.optional,
5525
+ passingStyle: "positional"
5526
+ }));
5527
+ classes[type.name] = {
5528
+ name: type.name,
5529
+ sourceFile: type.sourceFile,
5530
+ methods: sortRecord(methods),
5531
+ properties: sortRecord(properties),
5532
+ constructorParams
5533
+ };
5534
+ collector.add(type.sourceFile, type.name);
5535
+ }
5536
+ for (const en of allEnums) {
5537
+ enums[en.name] = {
5538
+ name: en.name,
5539
+ sourceFile: en.sourceFile,
5540
+ members: sortRecord(en.members)
5541
+ };
5542
+ collector.add(en.sourceFile, en.name);
5543
+ }
5544
+ for (const ta of allTypeAliases) {
5545
+ typeAliases[ta.name] = {
5546
+ name: ta.name,
5547
+ sourceFile: ta.sourceFile,
5548
+ value: ta.value
5549
+ };
5550
+ collector.add(ta.sourceFile, ta.name);
5551
+ }
5552
+ return {
5553
+ classes: sortRecord(classes),
5554
+ interfaces: sortRecord(interfaces),
5555
+ typeAliases: sortRecord(typeAliases),
5556
+ enums: sortRecord(enums),
5557
+ exports: sortRecord(collector.toRecord())
5558
+ };
5559
+ }
5560
+ //#endregion
5561
+ //#region src/compat/extractors/ios.ts
5562
+ /**
5563
+ * Swift (iOS) API surface extractor.
5564
+ *
5565
+ * Walks `.swift` files (excluding tests, Package.swift, and build
5566
+ * directories), parses public structs, classes, actors, extensions, enums,
5567
+ * and type aliases, then builds an `ApiSurface`.
5568
+ *
5569
+ * Parser: `ios-parser.ts` — string-aware regex Swift source analysis
5570
+ * Surface: `ios-surface.ts` — ApiSurface construction
5571
+ */
5572
+ const PRIMITIVES = [
5573
+ "String",
5574
+ "Int",
5575
+ "Int32",
5576
+ "Int64",
5577
+ "Double",
5578
+ "Float",
5579
+ "Bool",
5580
+ "Void",
5581
+ "Data",
5582
+ "Date",
5583
+ "URL",
5584
+ "UUID"
5585
+ ];
5586
+ /** Unwrap `[Element]` and `[Key: Value]` sugar; returns the element/value type. */
5587
+ function unwrapBrackets(type) {
5588
+ const bracketMatch = type.match(/^\[(.+)\]$/);
5589
+ if (!bracketMatch) return type;
5590
+ const inner = bracketMatch[1].trim();
5591
+ const colonIdx = inner.indexOf(":");
5592
+ return colonIdx === -1 ? inner : inner.slice(colonIdx + 1).trim();
5593
+ }
5594
+ const iosExtractor = {
5595
+ language: "ios",
5596
+ hints: {
5597
+ stripNullable(type) {
5598
+ if (type.endsWith("?")) return type.slice(0, -1);
5599
+ return null;
5600
+ },
5601
+ isNullableOnlyDifference(a, b) {
5602
+ return defaultIsNullableOnlyDifference(this, a, b);
5603
+ },
5604
+ isUnionReorder(_a, _b) {
5605
+ return false;
5606
+ },
5607
+ isGenericTypeParam(type) {
5608
+ return /^[A-Z]$/.test(type) || /^T[A-Z][a-zA-Z]*$/.test(type);
5609
+ },
5610
+ isExtractionArtifact(type) {
5611
+ return [
5612
+ "Any",
5613
+ "Any?",
5614
+ "AnyObject",
5615
+ "AnyCodable",
5616
+ "AnyCodable?"
5617
+ ].includes(type);
5618
+ },
5619
+ tolerateCategoryMismatch: true,
5620
+ extractReturnTypeName(returnType) {
5621
+ let inner = returnType.trim();
5622
+ if (inner.endsWith("?")) inner = inner.slice(0, -1);
5623
+ inner = unwrapBrackets(inner);
5624
+ if (inner.endsWith("?")) inner = inner.slice(0, -1);
5625
+ const pageMatch = inner.match(/^Page<(.+)>$/);
5626
+ if (pageMatch) inner = pageMatch[1];
5627
+ if (PRIMITIVES.includes(inner)) return null;
5628
+ return inner;
5629
+ },
5630
+ extractParamTypeName(paramType) {
5631
+ let inner = paramType.trim();
5632
+ if (inner.endsWith("?")) inner = inner.slice(0, -1);
5633
+ inner = unwrapBrackets(inner);
5634
+ if (inner.endsWith("?")) inner = inner.slice(0, -1);
5635
+ if (PRIMITIVES.includes(inner)) return null;
5636
+ return inner;
5637
+ },
5638
+ propertyMatchesClass(propertyName, className) {
5639
+ return propertyName.toLowerCase() === className.toLowerCase();
5640
+ },
5641
+ derivedModelNames(modelName) {
5642
+ return [`${modelName}Response`];
5643
+ }
5644
+ },
5645
+ async extractSnapshot(sdkPath) {
5646
+ return apiSurfaceToSnapshot(await this.extract(sdkPath));
5647
+ },
5648
+ async extract(sdkPath) {
5649
+ const swiftFiles = walkSwiftFiles(sdkPath);
5650
+ if (swiftFiles.length === 0) throw new ExtractorError(`No .swift files found in ${sdkPath}`, `Ensure the --sdk-path argument points to a Swift package root containing .swift source files.`);
5651
+ const allTypes = [];
5652
+ const allEnums = [];
5653
+ const allTypeAliases = [];
5654
+ for (const filePath of swiftFiles) {
5655
+ const parsed = parseSwiftFile(filePath, sdkPath);
5656
+ allTypes.push(...parsed.types);
5657
+ allEnums.push(...parsed.enums);
5658
+ allTypeAliases.push(...parsed.typeAliases);
5659
+ }
5660
+ const { classes, interfaces, typeAliases, enums, exports } = buildSurface(allTypes, allEnums, allTypeAliases);
5661
+ return {
5662
+ language: "ios",
5663
+ extractedFrom: sdkPath,
5664
+ extractedAt: (/* @__PURE__ */ new Date()).toISOString(),
5665
+ classes,
5666
+ interfaces,
5667
+ typeAliases,
5668
+ enums,
5669
+ exports
5670
+ };
5671
+ }
5672
+ };
5673
+ //#endregion
5674
+ export { ALL_LANGUAGE_IDS, COMPAT_SCHEMA_VERSION, apiSurfaceToSnapshot, applyApprovals, buildConceptualRollup, buildOverlayLookup, classifyAddedSymbol, classifySymbolChanges, defaultSeverityForCategory, diffSnapshots, diffSurfaces, dotnetExtractor, elixirExtractor, filterSurface, formatConceptualSummary, formatHumanSummary, generateConceptualReport, generateReport, getDefaultPolicy, getExtractor, goExtractor, highestSeverity, iosExtractor, isCompatibleSchemaVersion, isPatchableChange, kotlinExtractor, matchApproval, mergePolicy, nodeExtractor, nodeHints, patchOverlay, phpExtractor, pythonExtractor, registerExtractor, resolveHints, rubyExtractor, rustExtractor, severityMeetsThreshold, specDerivedEnumValues, specDerivedFieldPaths, specDerivedHttpKeys, specDerivedMethodPaths, specDerivedNames, summarizeChanges, summarizeConceptualChanges, unapprovedChanges, validateApproval, validateApprovals, validateSnapshot };
5022
5675
 
5023
5676
  //# sourceMappingURL=index.mjs.map