package cz.habarta.typescript.generator.maven;
import cz.habarta.typescript.generator.*;
import java.io.*;
import java.net.*;
import java.util.*;
import org.apache.maven.artifact.*;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugins.annotations.*;
import org.apache.maven.project.MavenProject;
/**
* Generates TypeScript declaration file from specified java classes.
* For more information see README and Wiki on GitHub.
*/
@Mojo(name = "generate", defaultPhase = LifecyclePhase.PROCESS_CLASSES, requiresDependencyResolution = ResolutionScope.COMPILE)
public class GenerateMojo extends AbstractMojo {
/**
* Path and name of generated TypeScript file.
*/
@Parameter
private File outputFile;
/**
* Output file format, can be 'declarationFile' (.d.ts) or 'implementationFile' (.ts).
* Setting this parameter to 'implementationFile' allows to generate runnable TypeScript code.
* Default value is 'declarationFile'.
*/
@Parameter
private TypeScriptFileType outputFileType;
/**
* Kind of generated TypeScript output, allowed values are 'global', 'module' or 'ambientModule'.
* Value 'global' means that declarations will be in global scope or namespace (no module).
* Value 'module' means that generated file will contain top-level 'export' declarations.
* Value 'ambientModule' means that generated declarations will be wrapped in 'declare module "mod" { }' declaration.
* Required parameter.
* For more information see Wiki page 'http://vojtechhabarta.github.io/typescript-generator/doc/ModulesAndNamespaces.html'.
*/
@Parameter(required = true)
private TypeScriptOutputKind outputKind;
/**
* Name of generated ambient module.
* Used when 'outputKind' is set to 'ambientModule'.
*/
@Parameter
private String module;
/**
* Generates specified namespace. Not recommended to combine with modules. Default is no namespace.
*/
@Parameter
private String namespace;
/**
* Generates TypeScript namespaces from Java packages. Default is false.
*/
@Parameter
private boolean mapPackagesToNamespaces;
/**
* Turns proper module into UMD (Universal Module Definition) with specified namespace.
* Only applicable to declaration files.
*/
@Parameter
private String umdNamespace;
/**
* JSON classes to process.
*/
@Parameter
private List<String> classes;
/**
* JSON classes to process specified using glob patterns
* so it is possible to specify package or class name suffix.
* Glob patterns support two wildcards:
* Single "*" wildcard matches any character except for "." and "$".
* Double "**" wildcard matches any character.
* For more information and examples see Wiki page 'https://github.com/vojtechhabarta/typescript-generator/wiki/Class-Names-Glob-Patterns'.
*/
@Parameter
private List<String> classPatterns;
/**
* Scans specified JAX-RS {@link javax.ws.rs.core.Application} for JSON classes to process.
* Parameter contains fully-qualified class name.
* It is possible to exclude particular REST resource classes using {@link #excludeClasses} parameter.
*/
@Parameter
private String classesFromJaxrsApplication;
/**
* Scans JAX-RS resources for JSON classes to process.
* It is possible to exclude particular REST resource classes using {@link #excludeClasses} parameter.
*/
@Parameter
private boolean classesFromAutomaticJaxrsApplication;
/**
* List of classes excluded from processing.
*/
@Parameter
private List<String> excludeClasses;
/**
* Excluded classes specified using glob patterns.
*/
@Parameter
private List<String> excludeClassPatterns;
/**
* If this list is not empty then TypeScript will only be generated for
* methods with one of the annotations defined in this list
*/
@Parameter
private List<String> includePropertyAnnotations;
/**
* Library used in JSON classes.
* Supported values are
* 'jackson1' (annotations from 'org.codehaus.jackson.annotate' package),
* 'jackson2' (annotations from 'com.fasterxml.jackson.annotation' package),
* 'jaxb' (annotations from 'javax.xml.bind.annotation' package).
* Required parameter, recommended value is 'jackson2'.
*/
@Parameter(required = true)
private JsonLibrary jsonLibrary;
/**
* If true declared properties will be optional.
*/
@Parameter
private boolean declarePropertiesAsOptional;
/**
* If true declared properties will be <code>readonly</code>.
*/
@Parameter
private boolean declarePropertiesAsReadOnly;
/**
* Prefix which will be removed from names of classes, interfaces, enums.
* For example if set to "Json" then mapping for "JsonData" will be "Data".
*/
@Parameter
private String removeTypeNamePrefix;
/**
* Suffix which will be removed from names of classes, interfaces, enums.
* For example if set to "JSON" then mapping for "DataJSON" will be "Data".
*/
@Parameter
private String removeTypeNameSuffix;
/**
* Prefix which will be added to names of classes, interfaces, enums.
* For example if set to "I" then mapping for "Data" will be "IData".
*/
@Parameter
private String addTypeNamePrefix;
/**
* Suffix which will be added to names of classes, interfaces, enums.
* For example if set to "Data" then mapping for "Person" will be "PersonData".
*/
@Parameter
private String addTypeNameSuffix;
/**
* Specifies custom TypeScript names for Java classes.
* Multiple mappings can be specified, each using this format: "javaClassName:typescriptName".
* This takes precedence over other naming settings.
*/
@Parameter
private List<String> customTypeNaming;
/**
* Specifies JavaScript function for getting custom TypeScript names for Java classes.
* Function can return undefined if default name should be used.
* Function signature: <code>function getName(className: string, classSimpleName: string): string | null | undefined;</code>
* Example function: <code>function(name, simpleName) { if (name.startsWith('cz.')) return 'Test' + simpleName; }</code>
*/
@Parameter
private String customTypeNamingFunction;
/**
* List of files which will be referenced using triple-slash directive: /// <reference path="file" />.
* This can be used with "customTypeMappings" to provide needed TypeScript types.
*/
@Parameter
private List<String> referencedFiles;
/**
* List of import declarations which will be added to generated output.
* This can be used with "customTypeMappings" to provide needed TypeScript types.
*/
@Parameter
private List<String> importDeclarations;
/**
* List of custom mappings.
* Each item specifies TypeScript type which will be used for particular Java class.
* Item format is: "javaClass:typescriptType".
* For example mapping "ZonedDateTime" to "string" would be added as "java.time.ZonedDateTime:string".
*/
@Parameter
private List<String> customTypeMappings;
/**
* Specifies how {@link java.util.Date} will be mapped.
* Supported values are 'asDate', 'asNumber', 'asString'.
* Default value is 'asDate'.
*/
@Parameter
private DateMapping mapDate;
/**
* Specifies how enums will be mapped.
* Supported values are 'asUnion', 'asInlineUnion', 'asNumberBasedEnum'.
* Default value is 'asUnion'.
* Value 'asUnion' creates type alias to union of string enum values.
* Value 'asInlineUnion' creates union of enum values on places where the enum is used.
* Value 'asNumberBasedEnum' creates enum of named number values.
*/
@Parameter
private EnumMapping mapEnum;
/**
* Specifies whether classes will be mapped to classes or interfaces.
* Supported values are 'asInterfaces', 'asClasses'.
* Default value is 'asInterfaces'.
* Value 'asClasses' can only be used in implementation files (.ts).
*/
@Parameter
private ClassMapping mapClasses;
/**
* If true tagged unions will not be generated for Jackson 2 polymorphic types.
*/
@Parameter
private boolean disableTaggedUnions;
/**
* If true Swagger annotations will not be used.
*/
@Parameter
private boolean ignoreSwaggerAnnotations;
/**
* If true interface for JAX-RS REST application will be generated.
*/
@Parameter
private boolean generateJaxrsApplicationInterface;
/**
* If true client for JAX-RS REST application will be generated.
*/
@Parameter
private boolean generateJaxrsApplicationClient;
/**
* Specifies how JAX-RS REST operations will be grouped into objects.
* Supported values are 'singleObject', 'perResource', 'byAnnotation'.
* Default value is 'singleObject'.
* Value 'singleObject' means that one object with all operations will be generated.
* Value 'perResource' means that for each root resource one object will be generated.
* Value 'byAnnotation' means that operations will be grouped by annotation specified using <code>jaxrsNamespacingAnnotation</code>.
*/
@Parameter
private JaxrsNamespacing jaxrsNamespacing;
/**
* Specifies annotation used for grouping JAX-RS REST operations.
* Format is <code>annotationClass#annotationElement</code> where
* annotationClass is fully-qualified class name and annotationElement is element name and defaults to 'value'.
* Examples:
* <code>io.swagger.annotations.Api</code>,
* <code>io.swagger.annotations.Api#value</code>
*/
@Parameter
private String jaxrsNamespacingAnnotation;
/**
* Specifies HTTP response type in JAXRS application.
* Default value is <code>Promise<R></code> which means data object returned asynchronously.
* This parameter is useful for example when underlying HTTP response object (like <code>XMLHttpRequest</code> or <code>AxiosPromise</code>)
* is returned instead of actual response data.
*/
@Parameter
private String restResponseType;
/**
* Specifies HTTP request options type in JAXRS application.
* By default no <code>options</code> parameter is generated.
* Useful when passing additional parameters to underlying HTTP request method (like jQuery ajax settings or <code>AxiosRequestConfig</code>).
* Can be specific (for example <code>AxiosRequestConfig</code>) or generic (for example <code><O></code>).
*/
@Parameter
private String restOptionsType;
/**
* Specifies custom class implementing {@link cz.habarta.typescript.generator.TypeProcessor}.
* This allows to customize how Java types are mapped to TypeScript.
* For example it is possible to implement TypeProcessor
* for {@link com.google.common.base.Optional} from guava or for Java 8 date/time classes.
*/
@Parameter
private String customTypeProcessor;
/**
* If true TypeScript declarations (interfaces, properties) will be sorted alphabetically.
*/
@Parameter
private boolean sortDeclarations;
/**
* If true TypeScript type declarations (interfaces) will be sorted alphabetically.
*/
@Parameter
private boolean sortTypeDeclarations;
/**
* If true generated file will not contain comment at the top.
* By default there is a comment with timestamp and typescript-generator version.
* So it might be useful to suppress this comment if the file is in source control and is regenerated in build.
*/
@Parameter
private boolean noFileComment;
/**
* List of Javadoc XML files to search for documentation comments.
* These files should be created using "com.github.markusbernhardt.xmldoclet.XmlDoclet" (com.github.markusbernhardt:xml-doclet).
* Javadoc comments are added to output declarations as JSDoc comments.
* For more information see Wiki page 'https://github.com/vojtechhabarta/typescript-generator/wiki/Javadoc'.
*/
@Parameter
private List<File> javadocXmlFiles;
/**
* List of extensions specified as fully qualified class name.
* Known extensions:
* cz.habarta.typescript.generator.ext.TypeGuardsForJackson2PolymorphismExtension
*/
@Parameter
private List<String> extensions;
/**
* The presence of any annotation in this list on a JSON property will cause
* the typescript-generator to treat that property as optional when generating
* the corresponding TypeScript interface.
* Example optional annotation: @javax.annotation.Nullable
*/
@Parameter
private List<String> optionalAnnotations;
/**
* If true NPM package.json will be generated.
* Only applicable when 'outputKind' is set to 'module'.
* NPM package name and version can be specified using 'npmName' and 'npmVersion' parameters.
*/
@Parameter
private boolean generateNpmPackageJson;
/**
* Specifies NPM package name.
* Only applicable when 'generateNpmPackageJson' parameter is 'true'.
* Default value is <code>${project.artifactId}</code>.
*/
@Parameter
private String npmName;
/**
* Specifies NPM package version.
* Only applicable when 'generateNpmPackageJson' parameter is 'true'.
* Default value is <code>1.0.0</code>.
*/
@Parameter
private String npmVersion;
/**
* Specifies how strings will be quoted.
* Supported values are 'doubleQuotes', 'singleQuotes'.
* Default value is 'doubleQuotes'.
*/
@Parameter
private StringQuotes stringQuotes;
/**
* Display warnings when bean serializer is not found.
*/
@Parameter(defaultValue = "true")
private boolean displaySerializerWarning;
/**
* Turns off Jackson2 automatic module discovery.
*/
@Parameter
private boolean disableJackson2ModuleDiscovery;
@Parameter(defaultValue = "${project}", readonly = true, required = true)
private MavenProject project;
@Parameter(defaultValue = "${project.build.directory}", readonly = true, required = true)
private String projectBuildDirectory;
@Override
public void execute() {
try {
TypeScriptGenerator.printVersion();
// class loader
final List<URL> urls = new ArrayList<>();
for (String element : project.getCompileClasspathElements()) {
urls.add(new File(element).toURI().toURL());
}
final URLClassLoader classLoader = new URLClassLoader(urls.toArray(new URL[0]), Thread.currentThread().getContextClassLoader());
// Settings
final Settings settings = new Settings();
if (outputFileType != null) {
settings.outputFileType = outputFileType;
}
settings.outputKind = outputKind;
settings.module = module;
settings.namespace = namespace;
settings.mapPackagesToNamespaces = mapPackagesToNamespaces;
settings.umdNamespace = umdNamespace;
settings.setExcludeFilter(excludeClasses, excludeClassPatterns);
settings.jsonLibrary = jsonLibrary;
settings.declarePropertiesAsOptional = declarePropertiesAsOptional;
settings.declarePropertiesAsReadOnly = declarePropertiesAsReadOnly;
settings.removeTypeNamePrefix = removeTypeNamePrefix;
settings.removeTypeNameSuffix = removeTypeNameSuffix;
settings.addTypeNamePrefix = addTypeNamePrefix;
settings.addTypeNameSuffix = addTypeNameSuffix;
settings.customTypeNaming = Settings.convertToMap(customTypeNaming);
settings.customTypeNamingFunction = customTypeNamingFunction;
settings.referencedFiles = referencedFiles;
settings.importDeclarations = importDeclarations;
settings.customTypeMappings = Settings.convertToMap(customTypeMappings);
settings.mapDate = mapDate;
settings.mapEnum = mapEnum;
settings.mapClasses = mapClasses;
settings.disableTaggedUnions = disableTaggedUnions;
settings.ignoreSwaggerAnnotations = ignoreSwaggerAnnotations;
settings.generateJaxrsApplicationInterface = generateJaxrsApplicationInterface;
settings.generateJaxrsApplicationClient = generateJaxrsApplicationClient;
settings.jaxrsNamespacing = jaxrsNamespacing;
settings.setJaxrsNamespacingAnnotation(classLoader, jaxrsNamespacingAnnotation);
settings.restResponseType = restResponseType;
settings.setRestOptionsType(restOptionsType);
settings.loadCustomTypeProcessor(classLoader, customTypeProcessor);
settings.sortDeclarations = sortDeclarations;
settings.sortTypeDeclarations = sortTypeDeclarations;
settings.noFileComment = noFileComment;
settings.javadocXmlFiles = javadocXmlFiles;
settings.loadExtensions(classLoader, extensions);
settings.loadIncludePropertyAnnotations(classLoader, includePropertyAnnotations);
settings.loadOptionalAnnotations(classLoader, optionalAnnotations);
settings.generateNpmPackageJson = generateNpmPackageJson;
settings.npmName = npmName == null && generateNpmPackageJson ? project.getArtifactId() : npmName;
settings.npmVersion = npmVersion == null && generateNpmPackageJson ? settings.getDefaultNpmVersion() : npmVersion;
settings.setStringQuotes(stringQuotes);
settings.displaySerializerWarning = displaySerializerWarning;
settings.disableJackson2ModuleDiscovery = disableJackson2ModuleDiscovery;
settings.classLoader = classLoader;
final File output = outputFile != null
? outputFile
: new File(new File(projectBuildDirectory, "typescript-generator"), project.getArtifactId() + settings.getExtension());
settings.validateFileName(output);
// TypeScriptGenerator
new TypeScriptGenerator(settings).generateTypeScript(
Input.fromClassNamesAndJaxrsApplication(classes, classPatterns, classesFromJaxrsApplication, classesFromAutomaticJaxrsApplication, settings.getExcludeFilter(), classLoader),
Output.to(output)
);
} catch (DependencyResolutionRequiredException | IOException e) {
throw new RuntimeException(e);
}
}
}