Skip to content

Commit

Permalink
Restructure TypeScript Node generation into separate files (PHNX-1041) (
Browse files Browse the repository at this point in the history
  • Loading branch information
gbrown-ce authored and jmini committed Jul 3, 2018
1 parent 7a7e221 commit 960412a
Show file tree
Hide file tree
Showing 51 changed files with 4,819 additions and 8,542 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@

import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.parser.util.SchemaTypeUtil;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.*;
import org.openapitools.codegen.SupportingFile;
import org.openapitools.codegen.utils.ModelUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.*;

public class TypeScriptNodeClientCodegen extends AbstractTypeScriptClientCodegen {
private static final Logger LOGGER = LoggerFactory.getLogger(TypeScriptNodeClientCodegen.class);
Expand All @@ -41,18 +41,24 @@ public class TypeScriptNodeClientCodegen extends AbstractTypeScriptClientCodegen
protected String npmName = null;
protected String npmVersion = "1.0.0";
protected String npmRepository = null;
protected String apiSuffix = "Api";

public TypeScriptNodeClientCodegen() {
super();

typeMapping.put("file", "Buffer");
languageSpecificPrimitives.add("Buffer");

// clear import mapping (from default generator) as TS does not use it
// at the moment
importMapping.clear();

outputFolder = "generated-code/typescript-node";
embeddedTemplateDir = templateDir = "typescript-node";
modelTemplateFiles.put("model.mustache", ".ts");
apiTemplateFiles.put("api-single.mustache", ".ts");
modelPackage = "model";
apiPackage = "api";

this.cliOptions.add(new CliOption(NPM_NAME, "The name under which you want to publish generated npm package"));
this.cliOptions.add(new CliOption(NPM_VERSION, "The version of your npm package"));
Expand Down Expand Up @@ -86,6 +92,101 @@ public String getTypeDeclaration(Schema p) {
}
return super.getTypeDeclaration(p);
}

@Override
public String toApiName(String name) {
if (name.length() == 0) {
return "Default" + apiSuffix;
}
return initialCaps(name) + apiSuffix;
}

@Override
public String toApiFilename(String name) {
if (name.length() == 0) {
return "default" + apiSuffix;
}
return camelize(name, true) + apiSuffix;
}

@Override
public String toApiImport(String name) {
return apiPackage() + "/" + toApiFilename(name);
}

@Override
public String toModelFilename(String name) {
return camelize(toModelName(name), true);
}

@Override
public String toModelImport(String name) {
return modelPackage() + "/" + toModelFilename(name);
}

@Override
public Map<String, Object> postProcessAllModels(Map<String, Object> objs) {
Map<String, Object> result = super.postProcessAllModels(objs);

for (Map.Entry<String, Object> entry : result.entrySet()) {
Map<String, Object> inner = (Map<String, Object>) entry.getValue();
List<Map<String, Object>> models = (List<Map<String, Object>>) inner.get("models");
for (Map<String, Object> mo : models) {
CodegenModel cm = (CodegenModel) mo.get("model");

// Add additional filename information for imports
mo.put("tsImports", toTsImports(cm, cm.imports));
}
}
return result;
}

private List<Map<String, String>> toTsImports(CodegenModel cm, Set<String> imports) {
List<Map<String, String>> tsImports = new ArrayList<>();
for (String im : imports) {
if (!im.equals(cm.classname)) {
HashMap<String, String> tsImport = new HashMap<>();
tsImport.put("classname", im);
tsImport.put("filename", toModelFilename(im));
tsImports.add(tsImport);
}
}
return tsImports;
}

@Override
public Map<String, Object> postProcessOperations(Map<String, Object> operations) {
Map<String, Object> objs = (Map<String, Object>) operations.get("operations");

// The api.mustache template requires all of the auth methods for the whole api
// Loop over all the operations and pick out each unique auth method
Map<String, CodegenSecurity> authMethodsMap = new HashMap<>();
for (CodegenOperation op : (List<CodegenOperation>) objs.get("operation")) {
if(op.hasAuthMethods){
for(CodegenSecurity sec : op.authMethods){
authMethodsMap.put(sec.name, sec);
}
}
}

// If there wer any auth methods specified add them to the operations context
if (!authMethodsMap.isEmpty()) {
operations.put("authMethods", authMethodsMap.values());
operations.put("hasAuthMethods", true);
}

// Add filename information for api imports
objs.put("apiFilename", getApiFilenameFromClassname(objs.get("classname").toString()));

// Add additional filename information for model imports in the apis
List<Map<String, Object>> imports = (List<Map<String, Object>>) operations.get("imports");
for (Map<String, Object> im : imports) {
im.put("filename", im.get("import"));
im.put("classname", getModelnameFromModelFilename(im.get("filename").toString()));
}

return operations;
}

public void setNpmName(String npmName) {
this.npmName = npmName;
Expand All @@ -110,10 +211,12 @@ public void setNpmRepository(String npmRepository) {
@Override
public void processOpts() {
super.processOpts();
supportingFiles.add(new SupportingFile("api.mustache", null, "api.ts"));
supportingFiles.add(new SupportingFile("models.mustache", modelPackage().replace('.', File.separatorChar), "models.ts"));
supportingFiles.add(new SupportingFile("api-all.mustache", apiPackage().replace('.', File.separatorChar), "apis.ts"));
supportingFiles.add(new SupportingFile("api.mustache", getIndexDirectory(), "api.ts"));
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
supportingFiles.add(new SupportingFile("gitignore", "", ".gitignore"));

if (additionalProperties.containsKey(NPM_NAME)) {
addNpmPackageGeneration();
}
Expand Down Expand Up @@ -141,9 +244,57 @@ private void addNpmPackageGeneration() {
supportingFiles.add(new SupportingFile("package.mustache", getPackageRootDirectory(), "package.json"));
supportingFiles.add(new SupportingFile("tsconfig.mustache", getPackageRootDirectory(), "tsconfig.json"));
}

private String getIndexDirectory() {
String indexPackage = modelPackage.substring(0, Math.max(0, modelPackage.lastIndexOf('.')));
return indexPackage.replace('.', File.separatorChar);
}

// The purpose of this override and associated methods is to allow for automatic conversion
// from 'file' type to the built in node 'Buffer' type
@Override
public String getSchemaType(Schema p) {
String openAPIType = super.getSchemaType(p);
if (isLanguagePrimitive(openAPIType) || isLanguageGenericType(openAPIType)) {
return openAPIType;
}
applyLocalTypeMapping(openAPIType);
return openAPIType;
}

private String applyLocalTypeMapping(String type) {
if (typeMapping.containsKey(type)) {
type = typeMapping.get(type);
}
return type;
}

private boolean isLanguagePrimitive(String type) {
return languageSpecificPrimitives.contains(type);
}

// Determines if the given type is a generic/templated type (ie. ArrayList<String>)
private boolean isLanguageGenericType(String type) {
for (String genericType : languageGenericTypes) {
if (type.startsWith(genericType + "<")) {
return true;
}
}
return false;
}

private String getPackageRootDirectory() {
String indexPackage = modelPackage.substring(0, Math.max(0, modelPackage.lastIndexOf('.')));
return indexPackage.replace('.', File.separatorChar);
}

private String getApiFilenameFromClassname(String classname) {
String name = classname.substring(0, classname.length() - apiSuffix.length());
return toApiFilename(name);
}

private String getModelnameFromModelFilename(String filename) {
String name = filename.substring((modelPackage() + File.separator).length());
return camelize(name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{{#apiInfo}}
{{#apis}}
{{#operations}}
export * from './{{ classFilename }}';
import { {{ classname }} } from './{{ classFilename }}';
{{/operations}}
{{#withInterfaces}}
export * from './{{ classFilename }}Interface'
{{/withInterfaces}}
{{/apis}}
export const APIS = [{{#apis}}{{#operations}}{{ classname }}{{/operations}}{{^-last}}, {{/-last}}{{/apis}}];
{{/apiInfo}}
Loading

0 comments on commit 960412a

Please sign in to comment.