@@ -41,28 +41,37 @@ public ModelCompiler(Settings settings, TypeProcessor typeProcessor) {
4141 public TsModel javaToTypeScript (Model model ) {
4242 final SymbolTable symbolTable = new SymbolTable (settings );
4343 TsModel tsModel = processModel (symbolTable , model );
44+
45+ // dates
4446 tsModel = transformDates (symbolTable , tsModel );
45- if (settings .mapEnum == EnumMapping .asUnion || settings .mapEnum == EnumMapping .asInlineUnion ) {
47+
48+ // enums
49+ if (settings .mapEnum == null || settings .mapEnum == EnumMapping .asUnion || settings .mapEnum == EnumMapping .asInlineUnion ) {
4650 tsModel = transformEnumsToUnions (tsModel );
4751 }
4852 if (settings .mapEnum == EnumMapping .asInlineUnion ) {
4953 tsModel = inlineEnums (tsModel , symbolTable );
5054 }
51- symbolTable .resolveSymbolNames (settings );
55+
56+ // tagged unions
57+ tsModel = createAndUseTaggedUnions (symbolTable , tsModel );
58+
59+ symbolTable .resolveSymbolNames ();
5260 return tsModel ;
5361 }
5462
5563 public TsType javaToTypeScript (Type type ) {
56- final BeanModel beanModel = new BeanModel (Object .class , Object .class , Collections .<Type >emptyList (), Collections .singletonList (new PropertyModel ("property" , type , false , null , null )));
64+ final BeanModel beanModel = new BeanModel (Object .class , Object .class , null , null , null , Collections .<Type >emptyList (), Collections .singletonList (new PropertyModel ("property" , type , false , null , null )), null );
5765 final Model model = new Model (Collections .singletonList (beanModel ), Collections .<EnumModel <?>>emptyList ());
5866 final TsModel tsModel = javaToTypeScript (model );
5967 return tsModel .getBeans ().get (0 ).getProperties ().get (0 ).getTsType ();
6068 }
6169
6270 private TsModel processModel (SymbolTable symbolTable , Model model ) {
71+ final Map <Type , List <BeanModel >> children = createChildrenMap (model );
6372 final List <TsBeanModel > beans = new ArrayList <>();
6473 for (BeanModel bean : model .getBeans ()) {
65- beans .add (processBean (symbolTable , bean ));
74+ beans .add (processBean (symbolTable , children , bean ));
6675 }
6776 final List <TsEnumModel <?>> enums = new ArrayList <>();
6877 for (EnumModel <?> enumModel : model .getEnums ()) {
@@ -72,7 +81,21 @@ private TsModel processModel(SymbolTable symbolTable, Model model) {
7281 return new TsModel (beans , enums , typeAliases );
7382 }
7483
75- private TsBeanModel processBean (SymbolTable symbolTable , BeanModel bean ) {
84+ private Map <Type , List <BeanModel >> createChildrenMap (Model model ) {
85+ final Map <Type , List <BeanModel >> children = new LinkedHashMap <>();
86+ for (BeanModel bean : model .getBeans ()) {
87+ final Type parent = bean .getParent ();
88+ if (parent != null ) {
89+ if (!children .containsKey (parent )) {
90+ children .put (parent , new ArrayList <BeanModel >());
91+ }
92+ children .get (parent ).add (bean );
93+ }
94+ }
95+ return children ;
96+ }
97+
98+ private TsBeanModel processBean (SymbolTable symbolTable , Map <Type , List <BeanModel >> children , BeanModel bean ) {
7699 final TsType beanType = typeFromJava (symbolTable , bean .getOrigin ());
77100 TsType parentType = typeFromJava (symbolTable , bean .getParent ());
78101 if (parentType != null && parentType .equals (TsType .Any )) {
@@ -89,7 +112,43 @@ private TsBeanModel processBean(SymbolTable symbolTable, BeanModel bean) {
89112 for (PropertyModel property : bean .getProperties ()) {
90113 properties .add (processProperty (symbolTable , bean , property ));
91114 }
92- return new TsBeanModel (bean .getOrigin (), beanType , parentType , interfaces , properties , bean .getComments ());
115+
116+ if (bean .getDiscriminantProperty () != null && !containsProperty (properties , bean .getDiscriminantProperty ())) {
117+ final List <BeanModel > selfAndDescendants = getSelfAndDescendants (bean , children );
118+ final List <TsType .StringLiteralType > literals = new ArrayList <>();
119+ for (BeanModel descendant : selfAndDescendants ) {
120+ if (descendant .getDiscriminantLiteral () != null ) {
121+ literals .add (new TsType .StringLiteralType (descendant .getDiscriminantLiteral ()));
122+ }
123+ }
124+ final TsType discriminantType = literals .isEmpty ()
125+ ? TsType .String
126+ : new TsType .UnionType (literals );
127+ properties .add (0 , new TsPropertyModel (bean .getDiscriminantProperty (), discriminantType , null ));
128+ }
129+
130+ return new TsBeanModel (bean .getOrigin (), beanType , parentType , bean .getTaggedUnionClasses (), interfaces , properties , bean .getComments ());
131+ }
132+
133+ private static List <BeanModel > getSelfAndDescendants (BeanModel bean , Map <Type , List <BeanModel >> children ) {
134+ final List <BeanModel > descendants = new ArrayList <>();
135+ descendants .add (bean );
136+ final List <BeanModel > directDescendants = children .get (bean .getOrigin ());
137+ if (directDescendants != null ) {
138+ for (BeanModel descendant : directDescendants ) {
139+ descendants .addAll (getSelfAndDescendants (descendant , children ));
140+ }
141+ }
142+ return descendants ;
143+ }
144+
145+ private static boolean containsProperty (List <TsPropertyModel > properties , String propertyName ) {
146+ for (TsPropertyModel property : properties ) {
147+ if (property .getName ().equals (propertyName )) {
148+ return true ;
149+ }
150+ }
151+ return false ;
93152 }
94153
95154 private TsPropertyModel processProperty (SymbolTable symbolTable , BeanModel bean , PropertyModel property ) {
@@ -187,6 +246,46 @@ public TsType transform(TsType tsType) {
187246 return newTsModel .setTypeAliases (aliases );
188247 }
189248
249+ private TsModel createAndUseTaggedUnions (final SymbolTable symbolTable , TsModel tsModel ) {
250+ if (settings .disableTaggedUnions ) {
251+ return tsModel ;
252+ }
253+ // create tagged unions
254+ final LinkedHashSet <TsAliasModel > typeAliases = new LinkedHashSet <>(tsModel .getTypeAliases ());
255+ for (TsBeanModel bean : tsModel .getBeans ()) {
256+ if (bean .getTaggedUnionClasses () != null ) {
257+ if (bean .getName () instanceof TsType .ReferenceType ) {
258+ final TsType .ReferenceType unionName = new TsType .ReferenceType (symbolTable .getSymbol (bean .getOrigin (), "Union" ));
259+ final List <TsType > unionTypes = new ArrayList <>();
260+ for (Class <?> cls : bean .getTaggedUnionClasses ()) {
261+ final TsType type = new TsType .ReferenceType (symbolTable .getSymbol (cls ));
262+ unionTypes .add (type );
263+ }
264+ final TsType .UnionType union = new TsType .UnionType (unionTypes );
265+ typeAliases .add (new TsAliasModel (bean .getOrigin (), unionName , union , null ));
266+ }
267+ }
268+ }
269+ // use tagged unions
270+ final TsModel model = transformBeanPropertyTypes (tsModel , new TsType .Transformer () {
271+ @ Override
272+ public TsType transform (TsType tsType ) {
273+ if (tsType instanceof TsType .ReferenceType ) {
274+ final TsType .ReferenceType referenceType = (TsType .ReferenceType ) tsType ;
275+ if (!(referenceType instanceof TsType .GenericReferenceType )) {
276+ final Class <?> cls = symbolTable .getSymbolClass (referenceType .symbol );
277+ final Symbol unionSymbol = symbolTable .hasSymbol (cls , "Union" );
278+ if (unionSymbol != null ) {
279+ return new TsType .ReferenceType (unionSymbol );
280+ }
281+ }
282+ }
283+ return tsType ;
284+ }
285+ });
286+ return model .setTypeAliases (new ArrayList <>(typeAliases ));
287+ }
288+
190289 private static TsModel transformBeanPropertyTypes (TsModel tsModel , TsType .Transformer transformer ) {
191290 final List <TsBeanModel > newBeans = new ArrayList <>();
192291 for (TsBeanModel bean : tsModel .getBeans ()) {
@@ -195,7 +294,7 @@ private static TsModel transformBeanPropertyTypes(TsModel tsModel, TsType.Transf
195294 final TsType newType = TsType .transformTsType (property .getTsType (), transformer );
196295 newProperties .add (property .setTsType (newType ));
197296 }
198- newBeans .add (bean .setProperties (newProperties ));
297+ newBeans .add (bean .withProperties (newProperties ));
199298 }
200299 return tsModel .setBeans (newBeans );
201300 }
0 commit comments