2929import org .openapitools .codegen .utils .ModelUtils ;
3030import org .slf4j .Logger ;
3131import org .slf4j .LoggerFactory ;
32+ import java .lang .Exception ;
3233
3334import java .io .File ;
3435import java .util .*;
3536
3637import static org .openapitools .codegen .utils .StringUtils .camelize ;
38+ import static org .openapitools .codegen .utils .StringUtils .underscore ;
3739
3840public abstract class AbstractFSharpCodegen extends DefaultCodegen implements CodegenConfig {
3941
@@ -246,11 +248,6 @@ public void processOpts() {
246248 additionalProperties .put (CodegenConstants .PACKAGE_NAME , packageName );
247249 }
248250
249- if (additionalProperties .containsKey (CodegenConstants .INVOKER_PACKAGE )) {
250- LOGGER .warn (String .format (Locale .ROOT , "%s is not used by F# generators. Please use %s" ,
251- CodegenConstants .INVOKER_PACKAGE , CodegenConstants .PACKAGE_NAME ));
252- }
253-
254251 // {{packageTitle}}
255252 if (additionalProperties .containsKey (CodegenConstants .PACKAGE_TITLE )) {
256253 setPackageTitle ((String ) additionalProperties .get (CodegenConstants .PACKAGE_TITLE ));
@@ -300,32 +297,8 @@ public void processOpts() {
300297 additionalProperties .put (CodegenConstants .USE_DATETIME_OFFSET , useDateTimeOffsetFlag );
301298 }
302299
303- if (additionalProperties .containsKey (CodegenConstants .USE_COLLECTION )) {
304- setUseCollection (convertPropertyToBooleanAndWriteBack (CodegenConstants .USE_COLLECTION ));
305- } else {
306- additionalProperties .put (CodegenConstants .USE_COLLECTION , useCollection );
307- }
308-
309- if (additionalProperties .containsKey (CodegenConstants .RETURN_ICOLLECTION )) {
310- setReturnICollection (convertPropertyToBooleanAndWriteBack (CodegenConstants .RETURN_ICOLLECTION ));
311- } else {
312- additionalProperties .put (CodegenConstants .RETURN_ICOLLECTION , returnICollection );
313- }
314-
315- if (additionalProperties .containsKey (CodegenConstants .NETCORE_PROJECT_FILE )) {
316- setNetCoreProjectFileFlag (convertPropertyToBooleanAndWriteBack (CodegenConstants .NETCORE_PROJECT_FILE ));
317- } else {
318- additionalProperties .put (CodegenConstants .NETCORE_PROJECT_FILE , netCoreProjectFileFlag );
319- }
320-
321- if (additionalProperties .containsKey (CodegenConstants .INTERFACE_PREFIX )) {
322- String useInterfacePrefix = additionalProperties .get (CodegenConstants .INTERFACE_PREFIX ).toString ();
323- if ("false" .equals (useInterfacePrefix .toLowerCase (Locale .ROOT ))) {
324- setInterfacePrefix ("" );
325- } else if (!"true" .equals (useInterfacePrefix .toLowerCase (Locale .ROOT ))) {
326- // NOTE: if user passes "true" explicitly, we use the default I- prefix. The other supported case here is a custom prefix.
327- setInterfacePrefix (sanitizeName (useInterfacePrefix ));
328- }
300+ if (additionalProperties .containsKey (CodegenConstants .MODEL_PROPERTY_NAMING )) {
301+ setModelPropertyNaming ((String ) additionalProperties .get (CodegenConstants .MODEL_PROPERTY_NAMING ));
329302 }
330303
331304 // This either updates additionalProperties with the above fixes, or sets the default if the option was not specified.
@@ -372,65 +345,49 @@ public Map<String, Object> postProcessAllModels(Map<String, Object> objs) {
372345 }
373346
374347 /*
375- * F# does not allow forward declarations, so files must be imported in the correct order.
376- * Output of CodeGen models must therefore bein dependency order (rather than alphabetical order, which seems to be the default).
377- * We achieve this by creating a comparator to check whether the first model contains any properties of the comparison model's type
378- * This could probably be made more efficient if absolutely needed.
379- */
348+ * F# does not allow forward declarations, so files must be imported in the correct order.
349+ * Output of CodeGen models must therefore bein dependency order (rather than alphabetical order, which seems to be the default).
350+ * This could probably be made more efficient if absolutely needed.
351+ */
380352 @ SuppressWarnings ({"unchecked" })
381- public Map <String , Object > postProcessDependencyOrders (final Map <String , Object > objs ) {
382- Comparator <String > comparator = new Comparator <String >() {
383- @ Override
384- public int compare (String key1 , String key2 ) {
385- // Get the corresponding models
386- CodegenModel model1 = ModelUtils .getModelByName (key1 , objs );
387- CodegenModel model2 = ModelUtils .getModelByName (key2 , objs );
388-
389- List <String > complexVars1 = new ArrayList <String >();
390- List <String > complexVars2 = new ArrayList <String >();
391-
392- for (CodegenProperty prop : model1 .vars ) {
393- if (prop .complexType != null )
394- complexVars1 .add (prop .complexType );
395- }
396- for (CodegenProperty prop : model2 .vars ) {
397- if (prop .complexType != null )
398- complexVars2 .add (prop .complexType );
399- }
400-
401- // if first has complex vars and second has none, first is greater
402- if (complexVars1 .size () > 0 && complexVars2 .size () == 0 )
403- return 1 ;
404-
405- // if second has complex vars and first has none, first is lesser
406- if (complexVars1 .size () == 0 && complexVars2 .size () > 0 )
407- return -1 ;
408-
409- // if first has complex var that matches the second's key, first is greater
410- if (complexVars1 .contains (key2 ))
411- return 1 ;
412-
413- // if second has complex var that matches the first's key, first is lesser
414- if (complexVars2 .contains (key1 ))
415- return -1 ;
416-
417- // if none of the above, don't care
418- return 0 ;
419-
420- }
421- };
422- PriorityQueue <String > queue = new PriorityQueue <String >(objs .size (), comparator );
423- for (Object k : objs .keySet ()) {
424- queue .add (k .toString ());
353+ public Map <String ,Object > postProcessDependencyOrders (final Map <String , Object > objs ) {
354+
355+ Map <String ,Set <String >> dependencies = new HashMap <String ,Set <String >>();
356+
357+ List <String > classNames = new ArrayList <String >();
358+
359+ for (String k : objs .keySet ()) {
360+ CodegenModel model = ModelUtils .getModelByName (k , objs );
361+ if (model == null || model .classname == null ) {
362+ throw new RuntimeException ("Null model encountered" );
425363 }
426-
427- Map <String , Object > sorted = new LinkedHashMap <String , Object >();
428-
429- while (queue .size () > 0 ) {
430- String key = queue .poll ();
431- sorted .put (key , objs .get (key ));
364+ dependencies .put (model .classname , model .imports );
365+
366+ classNames .add (model .classname );
367+ }
368+
369+ Object [] sortedKeys = classNames .toArray ();
370+
371+ for (int i1 = 0 ; i1 < sortedKeys .length ; i1 ++) {
372+ String k1 = sortedKeys [i1 ].toString ();
373+ for (int i2 = i1 + 1 ; i2 < sortedKeys .length ; i2 ++) {
374+ String k2 = sortedKeys [i2 ].toString ();
375+ if (dependencies .get (k2 ).contains (k1 )) {
376+ sortedKeys [i2 ] = k1 ;
377+ sortedKeys [i1 ] = k2 ;
378+ i1 = -1 ;
379+ break ;
380+ }
432381 }
433- return sorted ;
382+ }
383+
384+ Map <String ,Object > sorted = new LinkedHashMap <String ,Object >();
385+ for (int i = sortedKeys .length - 1 ; i >= 0 ; i --) {
386+ Object k = sortedKeys [i ];
387+ sorted .put (k .toString (), objs .get (k ));
388+ }
389+
390+ return sorted ;
434391 }
435392
436393 /**
@@ -684,6 +641,39 @@ public String toOperationId(String operationId) {
684641 return camelize (sanitizeName (operationId ));
685642 }
686643
644+ public String getModelPropertyNaming () {
645+ return this .modelPropertyNaming ;
646+ }
647+
648+ public void setModelPropertyNaming (String naming ) {
649+ if ("original" .equals (naming ) || "camelCase" .equals (naming ) ||
650+ "PascalCase" .equals (naming ) || "snake_case" .equals (naming )) {
651+ this .modelPropertyNaming = naming ;
652+ } else {
653+ throw new IllegalArgumentException ("Invalid model property naming '" +
654+ naming + "'. Must be 'original', 'camelCase', " +
655+ "'PascalCase' or 'snake_case'" );
656+ }
657+ }
658+
659+
660+ public String getNameUsingModelPropertyNaming (String name ) {
661+ switch (CodegenConstants .MODEL_PROPERTY_NAMING_TYPE .valueOf (getModelPropertyNaming ())) {
662+ case original :
663+ return name ;
664+ case camelCase :
665+ return camelize (name , true );
666+ case PascalCase :
667+ return camelize (name );
668+ case snake_case :
669+ return underscore (name );
670+ default :
671+ throw new IllegalArgumentException ("Invalid model property naming '" +
672+ name + "'. Must be 'original', 'camelCase', " +
673+ "'PascalCase' or 'snake_case'" );
674+ }
675+ }
676+
687677 @ Override
688678 public String toVarName (String name ) {
689679 // sanitize name
@@ -694,9 +684,8 @@ public String toVarName(String name) {
694684 return name ;
695685 }
696686
697- // camelize the variable name
698- // pet_id => PetId
699- name = camelize (name );
687+ name = getNameUsingModelPropertyNaming (name );
688+
700689 // for reserved word or word starting with number, append _
701690 if (isReservedWord (name ) || name .matches ("^\\ d.*" )) {
702691 name = escapeReservedWord (name );
0 commit comments