@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.
- package/dist/cli/index.mjs +20 -1
- package/dist/cli/index.mjs.map +1 -1
- package/dist/compat/index.d.mts +6 -3
- package/dist/compat/index.d.mts.map +1 -1
- package/dist/compat/index.mjs +693 -40
- package/dist/compat/index.mjs.map +1 -1
- package/dist/{differ-HVvbbyUV.d.mts → differ-BoYl2n6Y.d.mts} +2 -2
- package/dist/{differ-HVvbbyUV.d.mts.map → differ-BoYl2n6Y.d.mts.map} +1 -1
- package/dist/index.d.mts +35 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +39 -1
- package/dist/index.mjs.map +1 -1
- package/dist/{overlay-DcvsIx5P.mjs → overlay-jsSkFJ2g.mjs} +21 -2
- package/dist/overlay-jsSkFJ2g.mjs.map +1 -0
- package/dist/{types-owWZiSwD.d.mts → types-CIAqYpcV.d.mts} +11 -3
- package/dist/types-CIAqYpcV.d.mts.map +1 -0
- package/dist/verify/index.d.mts +2 -2
- package/dist/verify/index.mjs +1 -1
- package/docs/agents/emitters.md +17 -0
- package/examples/reference-emitter/src/generators/client.ts +5 -1
- package/examples/reference-emitter/src/generators/models.ts +3 -2
- package/examples/reference-emitter/src/generators/resources.ts +2 -2
- package/package.json +1 -1
- package/skills/check-emitter-parity/SKILL.md +11 -0
- package/dist/overlay-DcvsIx5P.mjs.map +0 -1
- package/dist/types-owWZiSwD.d.mts.map +0 -1
package/dist/compat/index.mjs
CHANGED
|
@@ -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-
|
|
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$
|
|
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$
|
|
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$
|
|
834
|
-
const properties = parseProperties$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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
|
-
|
|
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
|