@workos/oagen 0.14.0 → 0.15.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 +142 -32
- package/dist/cli/index.mjs.map +1 -1
- package/dist/compat/index.mjs +120 -7
- package/dist/compat/index.mjs.map +1 -1
- package/dist/differ-fdF9qogA.d.mts.map +1 -1
- package/dist/{overlay-DGcHh1KN.mjs → overlay-YkIApOxh.mjs} +143 -33
- package/dist/overlay-YkIApOxh.mjs.map +1 -0
- package/dist/verify/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/overlay-DGcHh1KN.mjs.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-DcUvm0KA.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-YkIApOxh.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";
|
|
@@ -701,6 +701,7 @@ function parseConstElement(constElement) {
|
|
|
701
701
|
}
|
|
702
702
|
function parseMethods$2(classBody) {
|
|
703
703
|
const methods = [];
|
|
704
|
+
const allPromotedProperties = [];
|
|
704
705
|
for (const child of classBody.namedChildren) {
|
|
705
706
|
if (child.type !== "method_declaration") continue;
|
|
706
707
|
const nameNode = child.childForFieldName("name");
|
|
@@ -710,10 +711,11 @@ function parseMethods$2(classBody) {
|
|
|
710
711
|
const visibility = getVisibility(child);
|
|
711
712
|
const isStatic = isStaticMethod(child);
|
|
712
713
|
const docInfo = findDocComment(child);
|
|
714
|
+
const promotedProperties = [];
|
|
713
715
|
const params = [];
|
|
714
716
|
const paramsList = child.childForFieldName("parameters");
|
|
715
717
|
if (paramsList) for (const paramNode of paramsList.namedChildren) {
|
|
716
|
-
if (paramNode.type !== "simple_parameter") continue;
|
|
718
|
+
if (paramNode.type !== "simple_parameter" && paramNode.type !== "property_promotion_parameter") continue;
|
|
717
719
|
const paramNameNode = paramNode.namedChildren.find((c) => c.type === "variable_name");
|
|
718
720
|
if (!paramNameNode) continue;
|
|
719
721
|
const paramName = paramNameNode.text.replace(/^\$/, "");
|
|
@@ -728,6 +730,14 @@ function parseMethods$2(classBody) {
|
|
|
728
730
|
type: paramType,
|
|
729
731
|
optional: hasDefault
|
|
730
732
|
});
|
|
733
|
+
if (paramNode.type === "property_promotion_parameter") {
|
|
734
|
+
const visibility = paramNode.namedChildren.find((c) => c.type === "visibility_modifier")?.text ?? "public";
|
|
735
|
+
promotedProperties.push({
|
|
736
|
+
name: paramName,
|
|
737
|
+
type: paramType,
|
|
738
|
+
visibility
|
|
739
|
+
});
|
|
740
|
+
}
|
|
731
741
|
}
|
|
732
742
|
let returnType = "";
|
|
733
743
|
const returnTypeNode = child.childForFieldName("return_type");
|
|
@@ -741,8 +751,12 @@ function parseMethods$2(classBody) {
|
|
|
741
751
|
params,
|
|
742
752
|
returnType
|
|
743
753
|
});
|
|
754
|
+
if (methodName === "__construct") allPromotedProperties.push(...promotedProperties);
|
|
744
755
|
}
|
|
745
|
-
return
|
|
756
|
+
return {
|
|
757
|
+
methods,
|
|
758
|
+
promotedProperties: allPromotedProperties
|
|
759
|
+
};
|
|
746
760
|
}
|
|
747
761
|
function parseProperties$1(classBody) {
|
|
748
762
|
const properties = [];
|
|
@@ -815,18 +829,19 @@ function parseClassDeclarations(tree, sourceFile, namespace) {
|
|
|
815
829
|
}
|
|
816
830
|
const bodyNode = node.childForFieldName("body");
|
|
817
831
|
if (!bodyNode) continue;
|
|
818
|
-
const methods = parseMethods$2(bodyNode);
|
|
832
|
+
const { methods, promotedProperties } = parseMethods$2(bodyNode);
|
|
819
833
|
const properties = parseProperties$1(bodyNode);
|
|
820
834
|
const constants = parseConstants(bodyNode);
|
|
821
835
|
const resourceAttributes = parseResourceAttributes(bodyNode);
|
|
822
836
|
const hasCustomConstructor = methods.some((m) => m.name === "constructFromResponse" && m.isStatic);
|
|
837
|
+
const allProperties = [...properties, ...promotedProperties];
|
|
823
838
|
classes.push({
|
|
824
839
|
name: nameNode.text,
|
|
825
840
|
namespace,
|
|
826
841
|
extends: extendsName,
|
|
827
842
|
isInterface: false,
|
|
828
843
|
methods,
|
|
829
|
-
properties,
|
|
844
|
+
properties: allProperties,
|
|
830
845
|
constants,
|
|
831
846
|
resourceAttributes,
|
|
832
847
|
hasCustomConstructor,
|
|
@@ -842,7 +857,7 @@ function parseInterfaceDeclarations(tree, sourceFile, namespace) {
|
|
|
842
857
|
if (!nameNode) continue;
|
|
843
858
|
const bodyNode = node.childForFieldName("body");
|
|
844
859
|
if (!bodyNode) continue;
|
|
845
|
-
const methods = parseMethods$2(bodyNode);
|
|
860
|
+
const { methods } = parseMethods$2(bodyNode);
|
|
846
861
|
interfaces.push({
|
|
847
862
|
name: nameNode.text,
|
|
848
863
|
namespace,
|
|
@@ -881,7 +896,7 @@ function parseEnumDeclarations(tree, sourceFile, namespace) {
|
|
|
881
896
|
value
|
|
882
897
|
});
|
|
883
898
|
}
|
|
884
|
-
const methods = parseMethods$2(bodyNode);
|
|
899
|
+
const { methods } = parseMethods$2(bodyNode);
|
|
885
900
|
enums.push({
|
|
886
901
|
name: nameNode.text,
|
|
887
902
|
namespace,
|
|
@@ -922,6 +937,27 @@ const DEFAULT_EXCEPTION_BASES$1 = ["Exception", "\\Exception"];
|
|
|
922
937
|
function isResourceClass(cls, resourceBases) {
|
|
923
938
|
return !!cls.extends && resourceBases.has(cls.extends) && cls.resourceAttributes.length > 0;
|
|
924
939
|
}
|
|
940
|
+
/**
|
|
941
|
+
* Check if a class is a "value object" — PHP 8 model class whose fields
|
|
942
|
+
* live on the constructor as promoted properties (`public Type $field`).
|
|
943
|
+
* Every model class generated by the WorkOS PHP emitter follows this
|
|
944
|
+
* shape: `readonly class Foo implements \JsonSerializable { use
|
|
945
|
+
* JsonSerializableTrait; public function __construct(public Type $field,
|
|
946
|
+
* …) {} }`. The parser collects promoted properties under
|
|
947
|
+
* `cls.properties` so any class with at least one public promoted
|
|
948
|
+
* property is a value object — the field set is its identity.
|
|
949
|
+
*
|
|
950
|
+
* Exception classes are explicitly excluded: an exception subclass that
|
|
951
|
+
* happens to declare a public property (e.g. `BaseRequestException` with
|
|
952
|
+
* a `$requestId` field) is still semantically an exception, not a model.
|
|
953
|
+
* The `isExceptionClass` check is performed by the caller so this stays
|
|
954
|
+
* a pure structural test.
|
|
955
|
+
*/
|
|
956
|
+
function isValueObjectClass(cls) {
|
|
957
|
+
if (cls.isInterface) return false;
|
|
958
|
+
if (cls.constants.length > 0) return false;
|
|
959
|
+
return cls.properties.some((p) => p.visibility === "public");
|
|
960
|
+
}
|
|
925
961
|
/** Check if a class is enum-like (only constants, no public methods). */
|
|
926
962
|
function isEnumClass(cls) {
|
|
927
963
|
if (cls.isInterface) return false;
|
|
@@ -972,6 +1008,23 @@ function buildSurface$6(allClasses, hints) {
|
|
|
972
1008
|
...cls.hasCustomConstructor ? { hasCustomConstructor: true } : {}
|
|
973
1009
|
};
|
|
974
1010
|
collector.add(cls.sourceFile, cls.name);
|
|
1011
|
+
} else if (isValueObjectClass(cls) && !isExceptionClass$1(cls, exceptionBases)) {
|
|
1012
|
+
const fields = {};
|
|
1013
|
+
for (const prop of cls.properties) {
|
|
1014
|
+
if (prop.visibility !== "public") continue;
|
|
1015
|
+
fields[prop.name] = {
|
|
1016
|
+
name: prop.name,
|
|
1017
|
+
type: prop.type,
|
|
1018
|
+
optional: false
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
interfaces[cls.name] = {
|
|
1022
|
+
name: cls.name,
|
|
1023
|
+
sourceFile: cls.sourceFile,
|
|
1024
|
+
fields,
|
|
1025
|
+
extends: cls.extends ? [cls.extends] : []
|
|
1026
|
+
};
|
|
1027
|
+
collector.add(cls.sourceFile, cls.name);
|
|
975
1028
|
} else if (isEnumClass(cls)) {
|
|
976
1029
|
const members = {};
|
|
977
1030
|
for (const constant of cls.constants) members[constant.name] = constant.value;
|
|
@@ -1520,6 +1573,20 @@ const DEFAULT_EXCEPTION_BASES = ["Exception", "BaseException"];
|
|
|
1520
1573
|
function hasBase(cls, bases) {
|
|
1521
1574
|
return cls.bases.some((b) => bases.has(b));
|
|
1522
1575
|
}
|
|
1576
|
+
/**
|
|
1577
|
+
* True when the class carries a `@dataclass` decorator (with or without
|
|
1578
|
+
* arguments — `@dataclass`, `@dataclass()`, `@dataclass(slots=True)`, etc.).
|
|
1579
|
+
*
|
|
1580
|
+
* Dataclasses are the canonical "data-shape" Python construct: their
|
|
1581
|
+
* structural identity is the field set, even when generated alongside
|
|
1582
|
+
* helper methods like `from_dict` / `to_dict`. Without this signal the
|
|
1583
|
+
* extractor categorizes them as plain method-bearing classes (category 5)
|
|
1584
|
+
* and loses the field info — which then prevents the compat differ from
|
|
1585
|
+
* recognizing renames structurally.
|
|
1586
|
+
*/
|
|
1587
|
+
function isDataclass(cls) {
|
|
1588
|
+
return cls.decorators.some((d) => /^dataclass(\s*\(.*\))?$/.test(d));
|
|
1589
|
+
}
|
|
1523
1590
|
/** Check if a class is a model class (inherits from BaseModel or configured model bases,
|
|
1524
1591
|
* transitively from another class that does). */
|
|
1525
1592
|
function isModelClass(cls, allClasses, modelBases) {
|
|
@@ -1701,6 +1768,22 @@ function buildSurface$5(parsedFiles, hints) {
|
|
|
1701
1768
|
collector.add(cls.sourceFile, cls.name);
|
|
1702
1769
|
continue;
|
|
1703
1770
|
}
|
|
1771
|
+
if (isDataclass(cls) && cls.fields.length > 0) {
|
|
1772
|
+
const fields = {};
|
|
1773
|
+
for (const field of cls.fields) fields[field.name] = {
|
|
1774
|
+
name: field.name,
|
|
1775
|
+
type: field.type,
|
|
1776
|
+
optional: field.hasDefault
|
|
1777
|
+
};
|
|
1778
|
+
interfaces[cls.name] = {
|
|
1779
|
+
name: cls.name,
|
|
1780
|
+
sourceFile: cls.sourceFile,
|
|
1781
|
+
fields: sortRecord(fields),
|
|
1782
|
+
extends: []
|
|
1783
|
+
};
|
|
1784
|
+
collector.add(cls.sourceFile, cls.name);
|
|
1785
|
+
continue;
|
|
1786
|
+
}
|
|
1704
1787
|
if (cls.methods.length > 0) {
|
|
1705
1788
|
const apiMethods = {};
|
|
1706
1789
|
const constructorParams = [];
|
|
@@ -2044,6 +2127,7 @@ function extractClasses(source) {
|
|
|
2044
2127
|
if (node.type !== "class") continue;
|
|
2045
2128
|
if (isInsideRanges(node.startPosition.row, serviceRanges)) continue;
|
|
2046
2129
|
if (node.descendantsOfType("singleton_class").length > 0) continue;
|
|
2130
|
+
if (isEnumShapedClass(node)) continue;
|
|
2047
2131
|
const nameNode = node.childForFieldName("name");
|
|
2048
2132
|
if (!nameNode) continue;
|
|
2049
2133
|
const className = nameNode.text;
|
|
@@ -2100,6 +2184,19 @@ function extractServiceModules(source) {
|
|
|
2100
2184
|
}
|
|
2101
2185
|
return services;
|
|
2102
2186
|
}
|
|
2187
|
+
/**
|
|
2188
|
+
* True when a `class` node looks like a Ruby enum: only constant
|
|
2189
|
+
* assignments, no methods, no attr_*, no singleton class. The
|
|
2190
|
+
* `extractEnumModules` pass picks these up; `extractClasses` skips
|
|
2191
|
+
* them to avoid double-emission. Shared so the two stay in sync.
|
|
2192
|
+
*/
|
|
2193
|
+
function isEnumShapedClass(classNode) {
|
|
2194
|
+
const bodyNode = classNode.childForFieldName("body");
|
|
2195
|
+
if (!bodyNode) return false;
|
|
2196
|
+
for (const c of bodyNode.namedChildren) if (c.type === "method" || c.type === "singleton_method" || c.type === "call") return false;
|
|
2197
|
+
const constants = extractEnumConstants(bodyNode);
|
|
2198
|
+
return Object.keys(constants).length >= 2;
|
|
2199
|
+
}
|
|
2103
2200
|
/** Extract enum-like modules (modules with string/number constants, no class << self). */
|
|
2104
2201
|
function extractEnumModules$1(source) {
|
|
2105
2202
|
const tree = safeParse(source);
|
|
@@ -2119,6 +2216,22 @@ function extractEnumModules$1(source) {
|
|
|
2119
2216
|
members: sortRecord(constants)
|
|
2120
2217
|
});
|
|
2121
2218
|
}
|
|
2219
|
+
for (const node of tree.rootNode.descendantsOfType("class")) {
|
|
2220
|
+
if (node.type !== "class") continue;
|
|
2221
|
+
if (isInsideRanges(node.startPosition.row, serviceRanges)) continue;
|
|
2222
|
+
if (node.descendantsOfType("singleton_class").length > 0) continue;
|
|
2223
|
+
const nameNode = node.childForFieldName("name");
|
|
2224
|
+
if (!nameNode) continue;
|
|
2225
|
+
const bodyNode = node.childForFieldName("body");
|
|
2226
|
+
if (!bodyNode) continue;
|
|
2227
|
+
if (bodyNode.namedChildren.some((c) => c.type === "method" || c.type === "singleton_method" || c.type === "call")) continue;
|
|
2228
|
+
const constants = extractEnumConstants(bodyNode);
|
|
2229
|
+
if (Object.keys(constants).length < 2) continue;
|
|
2230
|
+
enums.push({
|
|
2231
|
+
name: nameNode.text,
|
|
2232
|
+
members: sortRecord(constants)
|
|
2233
|
+
});
|
|
2234
|
+
}
|
|
2122
2235
|
return enums;
|
|
2123
2236
|
}
|
|
2124
2237
|
/** Extract autoload declarations to build the export map. */
|