diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java new file mode 100644 index 00000000000..76df02a6cae --- /dev/null +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java @@ -0,0 +1,587 @@ +/* + * Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech) + * Copyright 2018 SmartBear Software + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openapitools.codegen.languages; + +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.NumberSchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import org.apache.commons.lang3.StringUtils; +import org.openapitools.codegen.*; +import org.openapitools.codegen.utils.ModelUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.*; + +public class TypeScriptClientCodegen extends DefaultCodegen implements CodegenConfig { + private static final Logger LOGGER = LoggerFactory.getLogger(TypeScriptClientCodegen.class); + + private static final String X_DISCRIMINATOR_TYPE = "x-discriminator-value"; + private static final String UNDEFINED_VALUE = "undefined"; + + protected String modelPropertyNaming = "camelCase"; + protected boolean supportsES6 = true; + protected HashSet languageGenericTypes; + + public TypeScriptClientCodegen() { + super(); + + // clear import mapping (from default generator) as TS does not use it + // at the moment + importMapping.clear(); + outputFolder = "generated-code/typescript"; + embeddedTemplateDir = templateDir = "typescript"; + + supportsInheritance = true; + + // NOTE: TypeScript uses camel cased reserved words, while models are title cased. We don't want lowercase comparisons. + reservedWords.addAll(Arrays.asList( + // local variable names used in API methods (endpoints) + "varLocalPath", "queryParameters", "headerParams", "formParams", "useFormData", "varLocalDeferred", + "requestOptions", + // Typescript reserved words + "abstract", "await", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "debugger", "default", "delete", "do", "double", "else", "enum", "export", "extends", "false", "final", "finally", "float", "for", "function", "goto", "if", "implements", "import", "in", "instanceof", "int", "interface", "let", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "super", "switch", "synchronized", "this", "throw", "transient", "true", "try", "typeof", "var", "void", "volatile", "while", "with", "yield")); + + languageSpecificPrimitives = new HashSet<>(Arrays.asList( + "string", + "String", + "boolean", + "Boolean", + "Double", + "Integer", + "Long", + "Float", + "Object", + "Array", + "Date", + "number", + "any", + "File", + "Error", + "Map" + )); + + languageGenericTypes = new HashSet(Arrays.asList( + "Array" + )); + + instantiationTypes.put("array", "Array"); + + typeMapping = new HashMap(); + typeMapping.put("Array", "Array"); + typeMapping.put("array", "Array"); + typeMapping.put("List", "Array"); + typeMapping.put("boolean", "boolean"); + typeMapping.put("string", "string"); + typeMapping.put("int", "number"); + typeMapping.put("float", "number"); + typeMapping.put("number", "number"); + typeMapping.put("long", "number"); + typeMapping.put("short", "number"); + typeMapping.put("char", "string"); + typeMapping.put("double", "number"); + typeMapping.put("object", "any"); + typeMapping.put("integer", "number"); + typeMapping.put("Map", "any"); + typeMapping.put("date", "string"); + typeMapping.put("DateTime", "Date"); + typeMapping.put("binary", "any"); + typeMapping.put("File", "any"); + typeMapping.put("ByteArray", "string"); + typeMapping.put("UUID", "string"); + typeMapping.put("Error", "Error"); + + cliOptions.add(new CliOption(CodegenConstants.MODEL_PROPERTY_NAMING, CodegenConstants.MODEL_PROPERTY_NAMING_DESC).defaultValue("camelCase")); + cliOptions.add(new CliOption(CodegenConstants.SUPPORTS_ES6, CodegenConstants.SUPPORTS_ES6_DESC).defaultValue("false")); + // TODO: gen package.json? + + //Files for building our lib + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + supportingFiles.add(new SupportingFile("package.mustache", "", "package.json")); + supportingFiles.add(new SupportingFile("tsconfig.mustache", "", "tsconfig.json")); + supportingFiles.add(new SupportingFile("http" + File.separator + "http.mustache", "http", "http.ts")); + supportingFiles.add(new SupportingFile("http" + File.separator + "isomorphic-fetch.mustache", "http", "isomorphic-fetch.ts")); + } + + + @Override + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + @Override + public String escapeReservedWord(String name) { + if (this.reservedWordsMappings().containsKey(name)) { + return this.reservedWordsMappings().get(name); + } + return "_" + name; + } + + @Override + public String toParamName(String name) { + // should be the same as variable name + return toVarName(name); + } + + @Override + public String toVarName(String name) { + // sanitize name + name = sanitizeName(name); + + if ("_".equals(name)) { + name = "_u"; + } + + // if it's all uppper case, do nothing + if (name.matches("^[A-Z_]*$")) { + return name; + } + + name = getNameUsingModelPropertyNaming(name); + + // for reserved word or word starting with number, append _ + if (isReservedWord(name) || name.matches("^\\d.*")) { + name = escapeReservedWord(name); + } + + return name; + } + + @Override + public String toModelName(String name) { + name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. + + if (!StringUtils.isEmpty(modelNamePrefix)) { + name = modelNamePrefix + "_" + name; + } + + if (!StringUtils.isEmpty(modelNameSuffix)) { + name = name + "_" + modelNameSuffix; + } + + // model name cannot use reserved keyword, e.g. return + if (isReservedWord(name)) { + String modelName = camelize("model_" + name); + LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + modelName); + return modelName; + } + + // model name starts with number + if (name.matches("^\\d.*")) { + String modelName = camelize("model_" + name); // e.g. 200Response => Model200Response (after camelize) + LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + modelName); + return modelName; + } + + if (languageSpecificPrimitives.contains(name)) { + String modelName = camelize("model_" + name); + LOGGER.warn(name + " (model name matches existing language type) cannot be used as a model name. Renamed to " + modelName); + return modelName; + } + + // camelize the model name + // phone_number => PhoneNumber + return camelize(name); + } + + @Override + public String toModelFilename(String name) { + // should be the same as the model name + return toModelName(name); + } + + + @Override + protected String getParameterDataType(Parameter parameter, Schema p) { + // handle enums of various data types + Schema inner; + if (ModelUtils.isArraySchema(p)) { + ArraySchema mp1 = (ArraySchema) p; + inner = mp1.getItems(); + return this.getSchemaType(p) + "<" + this.getParameterDataType(parameter, inner) + ">"; + } else if (ModelUtils.isMapSchema(p)) { + inner = (Schema) p.getAdditionalProperties(); + return "{ [key: string]: " + this.getParameterDataType(parameter, inner) + "; }"; + } else if (ModelUtils.isStringSchema(p)) { + // Handle string enums + if (p.getEnum() != null) { + return enumValuesToEnumTypeUnion(p.getEnum(), "string"); + } + } else if (ModelUtils.isIntegerSchema(p)) { + // Handle integer enums + if (p.getEnum() != null) { + return numericEnumValuesToEnumTypeUnion(new ArrayList(p.getEnum())); + } + } else if (ModelUtils.isNumberSchema(p)) { + // Handle double enums + if (p.getEnum() != null) { + return numericEnumValuesToEnumTypeUnion(new ArrayList(p.getEnum())); + } + } + /* TODO revise the logic below + else if (ModelUtils.isDateSchema(p)) { + // Handle date enums + DateSchema sp = (DateSchema) p; + if (sp.getEnum() != null) { + return enumValuesToEnumTypeUnion(sp.getEnum(), "string"); + } + } else if (ModelUtils.isDateTimeSchema(p)) { + // Handle datetime enums + DateTimeSchema sp = (DateTimeSchema) p; + if (sp.getEnum() != null) { + return enumValuesToEnumTypeUnion(sp.getEnum(), "string"); + } + }*/ + return this.getTypeDeclaration(p); + } + + /** + * Converts a list of strings to a literal union for representing enum values as a type. + * Example output: 'available' | 'pending' | 'sold' + * + * @param values list of allowed enum values + * @param dataType either "string" or "number" + * @return a literal union for representing enum values as a type + */ + protected String enumValuesToEnumTypeUnion(List values, String dataType) { + StringBuilder b = new StringBuilder(); + boolean isFirst = true; + for (String value : values) { + if (!isFirst) { + b.append(" | "); + } + b.append(toEnumValue(value.toString(), dataType)); + isFirst = false; + } + return b.toString(); + } + + /** + * Converts a list of numbers to a literal union for representing enum values as a type. + * Example output: 3 | 9 | 55 + * + * @param values a list of numbers + * @return a literal union for representing enum values as a type + */ + protected String numericEnumValuesToEnumTypeUnion(List values) { + List stringValues = new ArrayList<>(); + for (Number value : values) { + stringValues.add(value.toString()); + } + return enumValuesToEnumTypeUnion(stringValues, "number"); + } + + @Override + public String toDefaultValue(Schema p) { + if (ModelUtils.isBooleanSchema(p)) { + return UNDEFINED_VALUE; + } else if (ModelUtils.isDateSchema(p)) { + return UNDEFINED_VALUE; + } else if (ModelUtils.isDateTimeSchema(p)) { + return UNDEFINED_VALUE; + } else if (ModelUtils.isNumberSchema(p)) { + if (p.getDefault() != null) { + return p.getDefault().toString(); + } + return UNDEFINED_VALUE; + } else if (ModelUtils.isIntegerSchema(p)) { + if (p.getDefault() != null) { + return p.getDefault().toString(); + } + return UNDEFINED_VALUE; + } else if (ModelUtils.isStringSchema(p)) { + if (p.getDefault() != null) { + return "'" + (String) p.getDefault() + "'"; + } + return UNDEFINED_VALUE; + } else { + return UNDEFINED_VALUE; + } + + } + + @Override + protected boolean isReservedWord(String word) { + // NOTE: This differs from super's implementation in that TypeScript does _not_ want case insensitive matching. + return reservedWords.contains(word); + } + + @Override + public String getSchemaType(Schema p) { + String openAPIType = super.getSchemaType(p); + String type = null; + if (typeMapping.containsKey(openAPIType)) { + type = typeMapping.get(openAPIType); + if (languageSpecificPrimitives.contains(type)) + return type; + } else + type = openAPIType; + return toModelName(type); + } + + @Override + public String toOperationId(String operationId) { + // throw exception if method name is empty + if (StringUtils.isEmpty(operationId)) { + throw new RuntimeException("Empty method name (operationId) not allowed"); + } + + // method name cannot use reserved keyword, e.g. return + // append _ at the beginning, e.g. _return + if (isReservedWord(operationId)) { + return escapeReservedWord(camelize(sanitizeName(operationId), true)); + } + + return camelize(sanitizeName(operationId), true); + } + + public void setModelPropertyNaming(String naming) { + if ("original".equals(naming) || "camelCase".equals(naming) || + "PascalCase".equals(naming) || "snake_case".equals(naming)) { + this.modelPropertyNaming = naming; + } else { + throw new IllegalArgumentException("Invalid model property naming '" + + naming + "'. Must be 'original', 'camelCase', " + + "'PascalCase' or 'snake_case'"); + } + } + + public String getModelPropertyNaming() { + return this.modelPropertyNaming; + } + + public String getNameUsingModelPropertyNaming(String name) { + switch (CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.valueOf(getModelPropertyNaming())) { + case original: + return name; + case camelCase: + return camelize(name, true); + case PascalCase: + return camelize(name); + case snake_case: + return underscore(name); + default: + throw new IllegalArgumentException("Invalid model property naming '" + + name + "'. Must be 'original', 'camelCase', " + + "'PascalCase' or 'snake_case'"); + } + + } + + @Override + public String toEnumValue(String value, String datatype) { + if ("number".equals(datatype)) { + return value; + } else { + return "\'" + escapeText(value) + "\'"; + } + } + + @Override + public String toEnumDefaultValue(String value, String datatype) { + return datatype + "_" + value; + } + + @Override + public String toEnumVarName(String name, String datatype) { + if (name.length() == 0) { + return "Empty"; + } + + // for symbol, e.g. $, # + if (getSymbolName(name) != null) { + return camelize(getSymbolName(name)); + } + + // number + if ("number".equals(datatype)) { + String varName = "NUMBER_" + name; + + varName = varName.replaceAll("-", "MINUS_"); + varName = varName.replaceAll("\\+", "PLUS_"); + varName = varName.replaceAll("\\.", "_DOT_"); + return varName; + } + + // string + String enumName = sanitizeName(name); + enumName = enumName.replaceFirst("^_", ""); + enumName = enumName.replaceFirst("_$", ""); + + // camelize the enum variable name + // ref: https://basarat.gitbooks.io/typescript/content/docs/enums.html + enumName = camelize(enumName); + + if (enumName.matches("\\d.*")) { // starts with number + return "_" + enumName; + } else { + return enumName; + } + } + + @Override + public String toEnumName(CodegenProperty property) { + String enumName = toModelName(property.name) + "Enum"; + + if (enumName.matches("\\d.*")) { // starts with number + return "_" + enumName; + } else { + return enumName; + } + } + + @Override + public Map postProcessModels(Map objs) { + // process enum in models + List models = (List) postProcessModelsEnum(objs).get("models"); + for (Object _mo : models) { + Map mo = (Map) _mo; + CodegenModel cm = (CodegenModel) mo.get("model"); + cm.imports = new TreeSet(cm.imports); + // name enum with model name, e.g. StatusEnum => Pet.StatusEnum + for (CodegenProperty var : cm.vars) { + if (Boolean.TRUE.equals(var.isEnum)) { + var.datatypeWithEnum = var.datatypeWithEnum.replace(var.enumName, cm.classname + "." + var.enumName); + } + } + if (cm.parent != null) { + for (CodegenProperty var : cm.allVars) { + if (Boolean.TRUE.equals(var.isEnum)) { + var.datatypeWithEnum = var.datatypeWithEnum + .replace(var.enumName, cm.classname + "." + var.enumName); + } + } + } + } + + return objs; + } + + @Override + public Map postProcessAllModels(Map objs) { + Map result = super.postProcessAllModels(objs); + + for (Map.Entry entry : result.entrySet()) { + Map inner = (Map) entry.getValue(); + List> models = (List>) inner.get("models"); + for (Map mo : models) { + CodegenModel cm = (CodegenModel) mo.get("model"); + if (cm.discriminator != null && cm.children != null) { + for (CodegenModel child : cm.children) { + this.setDiscriminatorValue(child, cm.discriminator.getPropertyName(), this.getDiscriminatorValue(child)); + } + } + } + } + return result; + } + + public void setSupportsES6(Boolean value) { + supportsES6 = value; + } + + public Boolean getSupportsES6() { + return supportsES6; + } + + private void setDiscriminatorValue(CodegenModel model, String baseName, String value) { + for (CodegenProperty prop : model.allVars) { + if (prop.baseName.equals(baseName)) { + prop.discriminatorValue = value; + } + } + if (model.children != null) { + final boolean newDiscriminator = model.discriminator != null; + for (CodegenModel child : model.children) { + this.setDiscriminatorValue(child, baseName, newDiscriminator ? value : this.getDiscriminatorValue(child)); + } + } + } + + private String getDiscriminatorValue(CodegenModel model) { + return model.vendorExtensions.containsKey(X_DISCRIMINATOR_TYPE) ? + (String) model.vendorExtensions.get(X_DISCRIMINATOR_TYPE) : model.classname; + } + + @Override + public String escapeQuotationMark(String input) { + // remove ', " to avoid code injection + return input.replace("\"", "").replace("'", ""); + } + + @Override + public String escapeUnsafeCharacters(String input) { + return input.replace("*/", "*_/").replace("/*", "/_*"); + } + + @Override + public String getName() { + return "typescript"; + } + + @Override + public String getHelp() { + return "Generates a TypeScript client library using Fetch API (beta)."; + } + + + @Override + public void processOpts() { + super.processOpts(); + + if (additionalProperties.containsKey(CodegenConstants.MODEL_PROPERTY_NAMING)) { + setModelPropertyNaming((String) additionalProperties.get(CodegenConstants.MODEL_PROPERTY_NAMING)); + } + + if (additionalProperties.containsKey(CodegenConstants.SUPPORTS_ES6)) { + setSupportsES6(Boolean.valueOf(additionalProperties.get(CodegenConstants.SUPPORTS_ES6).toString())); + additionalProperties.put("supportsES6", getSupportsES6()); + } + + // change package names + apiPackage = this.apiPackage + ".apis"; + modelPackage = this.modelPackage + ".models"; + testPackage = this.testPackage + ".tests"; + } + + @Override + public String getTypeDeclaration(Schema p) { + Schema inner; + if (ModelUtils.isArraySchema(p)) { + inner = ((ArraySchema) p).getItems(); + return this.getSchemaType(p) + "<" + this.getTypeDeclaration(inner) + ">"; + } else if (ModelUtils.isMapSchema(p)) { + inner = (Schema) p.getAdditionalProperties(); + return "{ [key: string]: " + this.getTypeDeclaration(inner) + "; }"; + } else if (ModelUtils.isFileSchema(p)) { + return "any"; + } else if (ModelUtils.isBinarySchema(p)) { + return "any"; + } else { + return super.getTypeDeclaration(p); + } + } + + @Override + protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Schema schema) { + codegenModel.additionalPropertiesType = getTypeDeclaration((Schema) schema.getAdditionalProperties()); + addImport(codegenModel, codegenModel.additionalPropertiesType); + } +} diff --git a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig index 8e2db93db51..893113e32ed 100644 --- a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig +++ b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig @@ -113,6 +113,7 @@ org.openapitools.codegen.languages.SwiftClientCodegen org.openapitools.codegen.languages.Swift3Codegen org.openapitools.codegen.languages.Swift4Codegen org.openapitools.codegen.languages.Swift5ClientCodegen +org.openapitools.codegen.languages.TypeScriptClientCodegen org.openapitools.codegen.languages.TypeScriptAngularClientCodegen org.openapitools.codegen.languages.TypeScriptAngularJsClientCodegen org.openapitools.codegen.languages.TypeScriptAureliaClientCodegen diff --git a/modules/openapi-generator/src/main/resources/typescript/README.mustache b/modules/openapi-generator/src/main/resources/typescript/README.mustache new file mode 100644 index 00000000000..ea786ff2cf6 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript/README.mustache @@ -0,0 +1 @@ +readme \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/typescript/http/http.mustache b/modules/openapi-generator/src/main/resources/typescript/http/http.mustache new file mode 100644 index 00000000000..f5bbf2df97d --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript/http/http.mustache @@ -0,0 +1,43 @@ +export enum HttpMethod { + GET = "GET", + HEAD = "HEAD", + POST = "POST", + PUT = "PUT", + DELETE = "DELETE", + CONNECT = "CONNECT", + OPTIONS = "OPTIONS", + TRACE = "TRACE", + PATCH = "PATCH" +} + +export class Request { + public headers: { [key: string]: string } = {}; + public body: string = ""; + + public constructor(public url: string, public httpMethod: HttpMethod) { + + } + + public addCookie(name: string, value: string): void { + if (!this.headers["Cookie"]) { + this.headers["Cookie"] = ""; + } + this.headers["Cookie"] += name + "=" + value + "; "; + } + + public setHeader(key: string, value: string): void { + this.headers[key] = value; + } +} + +export class Response { + + public constructor(public httpStatusCode: number, + public headers: { [key: string]: string }, public body: string) { + } + +} + +export interface HttpLibrary { + send(request: Request): Promise; +} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/typescript/http/isomorphic-fetch.mustache b/modules/openapi-generator/src/main/resources/typescript/http/isomorphic-fetch.mustache new file mode 100644 index 00000000000..69aaffd071e --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript/http/isomorphic-fetch.mustache @@ -0,0 +1,27 @@ +import {HttpLibrary, Request, Response} from './http'; +import * as e6p from 'es6-promise' +e6p.polyfill(); +import 'isomorphic-fetch'; + +export class IsomorphicFetchHttpLibrary implements HttpLibrary { + + public send(request: Request): Promise { + let method = request.httpMethod.toString(); + return fetch(request.url, { + method: method, + body: request.body, + headers: request.headers, + credentials: "same-origin" + }).then((resp) => { + // hack + let headers = (resp.headers as any)._headers; + for (let key in headers) { + headers[key] = (headers[key] as Array).join("; "); + } + + return resp.text().then((body) => { + return new Response(resp.status, headers, body) + }); + }); + } +} diff --git a/modules/openapi-generator/src/main/resources/typescript/package.mustache b/modules/openapi-generator/src/main/resources/typescript/package.mustache new file mode 100644 index 00000000000..327f133bceb --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript/package.mustache @@ -0,0 +1,33 @@ +{ + "name": "{{npmName}}", + "version": "{{npmVersion}}", + "description": "OpenAPI client for {{npmName}}", + "author": "OpenAPI-Generator Contributors", + "keywords": [ + "fetch", + "typescript", + "openapi-client", + "openapi-generator", + "{{npmName}}" + ], + "license": "Unlicense", + "main": "./dist/index.js", + "typings": "./dist/index.d.ts", + "scripts" : { + "build": "tsc", + "prepublishOnly": "npm run build" + }, + "dependencies": { + "es6-promise": "^4.2.4", + "isomorphic-fetch": "^2.2.1", + "@types/isomorphic-fetch": "0.0.34" + }, + "devDependencies": { + "typescript": "^2.9.2" + }{{#npmRepository}},{{/npmRepository}} +{{#npmRepository}} + "publishConfig":{ + "registry":"{{npmRepository}}" + } +{{/npmRepository}} +} diff --git a/modules/openapi-generator/src/main/resources/typescript/tsconfig.mustache b/modules/openapi-generator/src/main/resources/typescript/tsconfig.mustache new file mode 100644 index 00000000000..6223bc4d7cf --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript/tsconfig.mustache @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "strict": true, + /* Basic Options */ + "target": "{{#supportsES6}}es6{{/supportsES6}}{{^supportsES6}}es5{{/supportsES6}}", + "module": "{{#supportsES6}}es6{{/supportsES6}}{{^supportsES6}}commonjs{{/supportsES6}}", + "declaration": true, + + /* Additional Checks */ + "noUnusedLocals": true, /* Report errors on unused locals. */ + "noUnusedParameters": true, /* Report errors on unused parameters. */ + "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + "removeComments": true, + "sourceMap": true, + "outDir": "./dist", + "noLib": false, + "declaration": true, + "lib": [ "es6", "dom" ] + }, + "exclude": [ + "node_modules" + ], + "filesGlob": [ + "./**/*.ts", + ] + +} \ No newline at end of file