swagger-ts-generator
Version:
Given a swagger.json file, generates a number of TypeScript files which can be used as models and model-driven forms in Angular 2 (and above)
770 lines (769 loc) • 33.1 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateModelTSFiles = void 0;
const util = require('util');
const fs_1 = require("fs");
const lodash_1 = require("lodash");
const path_1 = require("path");
const types_1 = require("./types");
const utils_1 = require("./utils");
const TS_SUFFIX = '.ts';
const MODEL_SUFFIX = '.model';
const MODEL_FILE_SUFFIX = `${MODEL_SUFFIX}${TS_SUFFIX}`;
const ROOT_NAMESPACE = 'root';
// const BASE_TYPE_WAIT_FOR_SECOND_PASS = 'wait-for-second-pass';
function generateModelTSFiles(swagger, options) {
utils_1.log('generating models...');
const folder = path_1.normalize(options.modelFolder);
// generate fixed file with non-standard validators for validation rules which can be defined in the swagger file
if (options.generateValidatorFile) {
generateTSValidations(folder, options);
}
// generate fixed file with the BaseModel class
generateTSBaseModel(folder, options);
// get type definitions from swagger
const typeCollection = getTypeDefinitions(swagger, options, MODEL_SUFFIX, MODEL_FILE_SUFFIX);
// console.log('typeCollection', util.inspect(typeCollection, false, null, true));
// group types per namespace
const namespaceGroups = getNamespaceGroups(typeCollection, options);
// console.log('namespaceGroups', namespaceGroups);
// generate model files
generateTSModels(namespaceGroups, folder, options);
// generate subTypeFactory
generateSubTypeFactory(namespaceGroups, folder, options);
}
exports.generateModelTSFiles = generateModelTSFiles;
function generateTSValidations(folder, options) {
if (!options.generateClasses)
return;
const outputFileName = path_1.join(folder, options.validatorsFileName);
const data = {};
const template = utils_1.readAndCompileTemplateFile(options.templates.validators);
const result = template(data);
utils_1.ensureFolder(folder);
const isChanged = utils_1.writeFileIfContentsIsChanged(outputFileName, result);
if (isChanged) {
utils_1.log(`generated ${outputFileName}`);
}
}
function generateTSBaseModel(folder, options) {
if (!options.generateClasses)
return;
const outputFileName = path_1.join(folder, options.baseModelFileName);
const data = {
subTypePropertyName: options.subTypePropertyName
};
const template = utils_1.readAndCompileTemplateFile(options.templates.baseModel);
const result = template(data);
utils_1.ensureFolder(folder);
const isChanged = utils_1.writeFileIfContentsIsChanged(outputFileName, result);
if (isChanged) {
utils_1.log(`generated ${outputFileName}`);
}
}
function getTypeDefinitions(swagger, options, suffix, fileSuffix) {
let typeCollection = new Array();
// console.log('typesToFilter', options.typesToFilter);
// // sort the definitions so subTypes are on top
// // console.log('swagger.components.schemas', swagger.components.schemas);
// console.log('----------------------------------------------');
// // _(object).toPairs().sortBy(0).fromPairs().value();
// swagger.components.schemas = _(swagger.components.schemas).toPairs().sortBy(0, [
// item => {
// console.log(item, 'isSubType', getIsSubType(item))
// return getIsSubType(item)
// }
// ]).fromPairs().value();
// // console.log('sorted swagger.components.schemas', swagger.components.schemas);
// console.log('----------------------------------------------');
lodash_1.forEach(swagger.components.schemas, (item, key) => {
if (!utils_1.isInTypesToFilter(item, key, options)) {
let type = getTypeDefinition(swagger, typeCollection, item, key, options, suffix, fileSuffix);
if (type) {
typeCollection.push(type);
}
}
});
// second pass: fill baseTypes that are still null
// (if the swagger is generated by SpringFox, the definitions might be sorted by propertyName
// so baseTypes are not on the top. In that case, baseTypes might not have been found when
// finding a subtype)
fillMissingBaseTypes(swagger, typeCollection, options, suffix, fileSuffix);
// fill types of the properties
fillPropertyTypes(swagger, typeCollection, options, suffix, fileSuffix);
// filter on unique types
typeCollection = lodash_1.uniqBy(typeCollection, 'typeName');
return typeCollection;
}
function getTypeDefinition(swagger, typeCollection, item, key, options, suffix, fileSuffix) {
// filter enum types (these are generated by the enumGenerator)
let isEnumType = getIsEnumType(item);
if (isEnumType) {
return undefined;
}
let required = item.required || [];
let namespace = getNamespace(key, options, true);
let fullNamespace = getNamespace(key, options, false);
let typeName = getTypeName(key, options);
if (getIsGenericType(typeName)) {
typeName = convertGenericToGenericT(typeName);
}
let fullTypeName = fullNamespace ? `${fullNamespace}.${typeName}` : typeName;
let pathToRoot = utils_1.getPathToRoot(namespace);
let importFile = getImportFile(typeName, namespace, pathToRoot, suffix);
let properties = options.sortModelProperties
? utils_1.getSortedObjectProperties(item.properties)
: item.properties;
let baseType = undefined;
let baseImportFile = undefined;
let isSubType = getIsSubType(item);
let hasSubTypeProperty = isSubType || getHasSubTypeProperty(properties, options);
if (isSubType) {
baseType = getBaseType(typeName, typeCollection, item, options, false);
// baseType might not be in the typeCollection yet
// in that case, a second pass will be done with method fillMissingBaseTypes
if (baseType) {
// set that the baseType is a baseType
baseType.isBaseType = true;
// determine baseImportFile
baseImportFile = getImportFile(baseType.typeName, baseType.namespace, pathToRoot, suffix);
required = getSubTypeRequired(item);
properties = getSubTypeProperties(item, baseType);
}
}
let type = new types_1.Type({
fileName: getFileName(key, options, fileSuffix),
typeName: typeName,
namespace: namespace,
fullNamespace: fullNamespace,
fullTypeName: fullTypeName,
isSubType: isSubType,
hasSubTypeProperty: hasSubTypeProperty,
importFile: importFile,
isBaseType: false,
baseType: baseType,
baseImportFile: baseImportFile,
path: utils_1.convertNamespaceToPath(namespace),
pathToRoot: pathToRoot,
properties: []
});
fillTypeProperties(swagger, type, baseType, required, properties, item, key, options, suffix, fileSuffix);
return type;
}
function fillMissingBaseTypes(swagger, typeCollection, options, suffix, fileSuffix) {
// console.log('-------------------> In fillMissingBaseTypes <---------------------------')
lodash_1.forEach(swagger.components.schemas, (item, key) => {
let isSubType = getIsSubType(item);
let type = findTypeInTypeCollection(typeCollection, key);
if (isSubType && !type.baseType) {
let namespace = getNamespace(key, options, true);
let pathToRoot = utils_1.getPathToRoot(namespace);
let baseType = getBaseType(key, typeCollection, item, options, true);
let baseImportFile;
if (baseType) {
// set that the baseType is a baseType
baseType.isBaseType = true;
// determine baseImportFile
baseImportFile = getImportFile(baseType.typeName, baseType.namespace, pathToRoot, suffix);
}
let required = getSubTypeRequired(item);
let properties = getSubTypeProperties(item, baseType);
type.baseType = baseType;
type.baseImportFile = baseImportFile;
fillTypeProperties(swagger, type, baseType, required, properties, item, key, options, suffix, fileSuffix);
}
});
}
function fillPropertyTypes(swagger, typeCollection, options, suffix, fileSuffix) {
const missingTypes = new Array();
lodash_1.forEach(typeCollection, (type, typeKey) => {
lodash_1.forEach(type.properties, (property, propertyKey) => {
const propertyType = findTypesInTypeCollection(typeCollection, property.typeName, property.isUnionType, property.unionTypeNames);
property.type = propertyType;
const hasMissingTypes = lodash_1.isNil(propertyType) || (lodash_1.isArray(propertyType) && lodash_1.some(propertyType, item => lodash_1.isNil(item)));
if (hasMissingTypes && !property.isEnum && property.isComplexType) {
let isMissingType = true;
let missingTypeName = property.typeName;
if (property.isArrayComplexType) {
const arrayPropertyType = findTypesInTypeCollection(typeCollection, property.arrayTypeName, property.isArrayUnionType, property.unionTypeNames);
isMissingType =
lodash_1.isNil(arrayPropertyType) ||
(lodash_1.isArray(arrayPropertyType) && lodash_1.some(arrayPropertyType, item => lodash_1.isNil(item)));
missingTypeName = property.arrayTypeName;
}
else if (property.isArray) {
isMissingType = false;
}
if (isMissingType) {
missingTypes.push(missingTypeName);
// console.error(property);
}
}
});
});
for (const missingType of lodash_1.uniq(missingTypes)) {
utils_1.logError(`type ${missingType} not found`);
}
}
function fillTypeProperties(swagger, type, baseType, required, properties, item, key, options, suffix, fileSuffix) {
type.properties = [];
lodash_1.forEach(properties, (item, key) => {
let property = getTypePropertyDefinition(swagger, type, baseType, required, item, key, options, suffix, fileSuffix);
type.properties.push(property);
});
}
function getTypePropertyDefinition(swagger, type, baseType, required, item, key, options, suffix, fileSuffix) {
const staticFieldName = `${lodash_1.snakeCase(key).toUpperCase()}_FIELD_NAME`;
let isRefType = !!item.$ref || !!item.oneOf;
let isArray = item.type == 'array';
let isEnum = (item.type == 'string' && !!item.enum) ||
(isArray && item.items && item.items.type == 'string' && !!item.items.enum) ||
((isRefType || isArray) && getIsEnumRefType(swagger, item, isArray));
// enum ref types are not handles as model types (they are handled in the enumGenerator)
if (isEnum) {
isRefType = false;
}
let propertyType = getPropertyType(item, key, options, isEnum);
let isComplexType = isRefType || isArray; // new this one in constructor
let hasImportTypes = isRefType || (isArray && (item.items.$ref || item.items.oneOf) && !isEnum);
// console.log('type', type, '\nbaseType', baseType, '\nitem', item, '\npropertyType', propertyType);
let importTypes = hasImportTypes
? getImportTypes(propertyType.typeName, propertyType.isUnionType, propertyType.unionTypeNames, isArray)
: undefined;
let importFiles = hasImportTypes
? getImportFiles(importTypes, propertyType.namespace, type.pathToRoot, suffix)
: undefined;
let importTypeIsPropertyType = lodash_1.first(importTypes) === type.typeName;
let hasUniqueImportTypes = hasImportTypes && !importTypeIsPropertyType && getHasUniqueImportTypes(importTypes, baseType, type.properties); // import this type
let validators = getTypePropertyValidatorDefinitions(required, item, key, propertyType.typeName, isEnum);
let hasValidation = lodash_1.keys(validators.validation).length > 0;
let importEnumType = isEnum ? removeGenericArray(propertyType.typeName, isArray) : undefined;
let isUniqueImportEnumType = isEnum && getIsUniqueImportEnumType(importEnumType, type.properties); // import this enumType
let property = new types_1.TypeProperty({
name: key,
staticFieldName: staticFieldName,
type: null,
typeName: propertyType.typeName,
interfaceTypeName: propertyType.interfaceTypeName,
isUnionType: propertyType.isUnionType,
unionTypeNames: propertyType.unionTypeNames,
unionInterfaceTypeNames: propertyType.unionInterfaceTypeNames,
namespace: propertyType.namespace,
description: item.description,
hasValidation,
isComplexType,
hasImportTypes,
hasUniqueImportTypes,
importTypes,
importFiles,
isEnum,
enum: item.enum,
isUniqueImportEnumType,
importEnumType,
isArray,
isArrayComplexType: propertyType.isArrayComplexType,
arrayTypeName: propertyType.arrayTypeName,
arrayInterfaceTypeName: propertyType.arrayInterfaceTypeName,
validators
});
return property;
}
function getTypePropertyValidatorDefinitions(required, item, key, typeName, isEnum) {
let isRequired = lodash_1.indexOf(required, key) !== -1;
// console.log('key=', key, 'typeName', typeName, 'item=', item, 'enum=', item.enum);
let validators = {
validation: {},
validatorArray: []
};
if (isRequired) {
validators.validation.required = isRequired;
validators.validatorArray.push('Validators.required');
}
if (lodash_1.has(item, 'minimum')) {
validators.validation.minimum = item.minimum;
validators.validatorArray.push(`minValueValidator(${item.minimum})`);
}
if (lodash_1.has(item, 'maximum')) {
validators.validation.maximum = item.maximum;
validators.validatorArray.push(`maxValueValidator(${item.maximum})`);
}
if (isEnum) {
validators.validation.enum = `'${item.enum}'`;
validators.validatorArray.push(`enumValidator(${typeName})`);
}
if (lodash_1.has(item, 'minLength')) {
validators.validation.minLength = item.minLength;
validators.validatorArray.push(`Validators.minLength(${item.minLength})`);
}
if (lodash_1.has(item, 'maxLength')) {
validators.validation.maxLength = item.maxLength;
validators.validatorArray.push(`Validators.maxLength(${item.maxLength})`);
}
if (lodash_1.has(item, 'pattern')) {
validators.validation.pattern = `'${item.pattern}'`;
validators.validatorArray.push(`Validators.pattern('${item.pattern}')`);
}
return validators;
}
function getHasUniqueImportTypes(importTypes, baseType, typeProperties) {
let baseTypeName = baseType ? baseType.typeName : undefined;
if (lodash_1.every(importTypes, item => item === baseTypeName)) {
return false;
}
// return !some(typeProperties, property => {
// return property.importTypes === currentTypeName;
// });
return true;
}
function getIsUniqueImportEnumType(currentTypeName, typeProperties) {
return !lodash_1.some(typeProperties, property => {
return property.importEnumType === currentTypeName;
});
}
function getTypeNameWithoutNamespacePrefixesToRemove(key, options) {
if (!options.namespacePrefixesToRemove) {
return key;
}
let namespaces = options.namespacePrefixesToRemove;
namespaces.forEach(item => {
key = key.replace(item, '');
if (key[0] === '.') {
key = key.substring(1);
}
});
return key;
}
function getPropertyType(item, name, options, isEnum) {
let result = {
typeName: '',
interfaceTypeName: '',
isUnionType: false,
unionTypeNames: undefined,
unionInterfaceTypeNames: undefined,
namespace: '',
fullNamespace: undefined,
isArrayComplexType: false,
arrayTypeName: undefined,
arrayInterfaceTypeName: undefined
};
if (item.type) {
result.typeName = item.type;
if (item.type == 'integer') {
result.typeName = 'number';
}
if (item.type == 'string' && item.format == 'date') {
result.typeName = 'Date';
}
if (item.type == 'string' && item.format == 'date-time') {
result.typeName = 'Date';
}
if (item.type == 'string' && item.enum) {
result.typeName = `${name}`;
}
result.interfaceTypeName = result.typeName;
if (item.type == 'array' && item.items) {
let arrayPropType = getPropertyType(item.items, name, options, isEnum);
result.typeName = `Array<${getTypeNameOrUnionTypeName(arrayPropType.isUnionType, arrayPropType.unionTypeNames, arrayPropType.typeName)}>`;
result.interfaceTypeName = `Array<${getTypeNameOrUnionTypeName(arrayPropType.isUnionType, arrayPropType.unionInterfaceTypeNames, arrayPropType.interfaceTypeName)}>`;
result.namespace = arrayPropType.namespace;
result.isArrayComplexType = !isEnum ? !!item.items.$ref || !!item.items.oneOf : false;
result.arrayTypeName = arrayPropType.typeName;
result.arrayInterfaceTypeName = arrayPropType.interfaceTypeName;
result.isUnionType = arrayPropType.isUnionType;
result.unionTypeNames = arrayPropType.unionTypeNames;
result.unionInterfaceTypeNames = arrayPropType.unionInterfaceTypeNames;
}
// // description may contain an overrule type for enums, eg /** type CoverType */
// if (hasTypeFromDescription(item.description)) {
// result.typeName = lowerFirst(getTypeFromDescription(item.description));
// // fix enum array with overrule type
// if (item.type == 'array' && item.items) {
// result.arrayTypeName = result.typeName;
// result.typeName = `Array<${result.typeName}>`;
// }
// }
return result;
}
if (item.$ref) {
const { typeName, interfaceTypeName, namespace, fullNamespace } = getRefTypeProperties(item.$ref, options, isEnum);
result = Object.assign(Object.assign({}, result), { typeName, interfaceTypeName, namespace, fullNamespace });
return result;
}
if (item.oneOf) {
const unionTypeNames = [];
const unionInterfaceTypeNames = [];
let namespace;
let fullNamespace;
item.oneOf.map(oneOfItem => {
const { typeName, interfaceTypeName, namespace, fullNamespace } = getRefTypeProperties(oneOfItem.$ref, options, isEnum);
unionTypeNames.push(typeName);
unionInterfaceTypeNames.push(interfaceTypeName);
});
result = Object.assign(Object.assign({}, result), { typeName: getTypeNameOrUnionTypeName(true, unionTypeNames, null), interfaceTypeName: getTypeNameOrUnionTypeName(true, unionInterfaceTypeNames, null), isUnionType: true, unionTypeNames,
unionInterfaceTypeNames,
namespace,
fullNamespace });
// console.log('getPropertyType with item.oneOf', result);
return result;
}
}
function getRefTypeProperties(ref, options, isEnum) {
// console.log('getRefTypeProperties ref', ref);
let type = removeDefinitionsRef(ref);
let typeName = getTypeName(type, options);
const interfaceTypeName = isEnum ? typeName : `I${typeName}`;
const namespace = getNamespace(type, options, true);
const fullNamespace = getNamespace(type, options, false);
// TODO add more C# primitive types
if (getIsGenericType(typeName)) {
let genericTType = getGenericTType(typeName);
if (genericTType && genericTType === 'System.DateTime') {
typeName = typeName.replace(genericTType, 'Date');
}
}
return { typeName, interfaceTypeName, namespace, fullNamespace };
}
function removeDefinitionsRef(value) {
let result = value.replace('#/components/schemas/', '');
return result;
}
function getTypeNameOrUnionTypeName(isUnionType, unionTypeNames, typeName) {
return isUnionType ? unionTypeNames.join(' | ') : typeName;
}
function getFileName(type, options, fileSuffix) {
let typeName = removeGenericTType(getTypeName(type, options));
return `${lodash_1.kebabCase(typeName)}${fileSuffix}`;
}
function getTypeName(type, options) {
let typeName;
if (getIsGenericType(type)) {
let startGenericT = type.indexOf('[');
let startGenericType = type.lastIndexOf('.', startGenericT) + 1;
typeName = type.substring(startGenericType);
typeName = convertGenericTypeName(typeName);
typeName = getTypeNameWithoutSuffixesToRemove(typeName, options);
}
else {
typeName = type.split('.').pop();
typeName = getTypeNameWithoutSuffixesToRemove(typeName, options);
// C# Object affects Typescript Object - fix this
if (typeName === 'Object') {
typeName = 'SystemObject';
}
//classNameSuffixesToRemove
}
return lodash_1.upperFirst(typeName);
}
function getTypeNameWithoutSuffixesToRemove(typeName, options) {
if (!options.typeNameSuffixesToRemove) {
return typeName;
}
let typeNameSuffixesToRemove = options.typeNameSuffixesToRemove;
typeNameSuffixesToRemove.forEach(item => {
if (lodash_1.endsWith(typeName, item)) {
typeName = typeName.slice(0, -item.length);
}
});
return typeName;
}
function getIsGenericType(type) {
return type.indexOf('[') !== -1 || type.indexOf('<') !== -1;
}
/**
* NullableOrEmpty<System.Date> -> System.Data
*/
function getGenericTType(type) {
if (getIsGenericType(type)) {
return /\<(.*)\>/.exec(type)[1];
}
return undefined;
}
/**
* NullableOrEmpty<System.Date> -> NullableOrEmpty
*/
function removeGenericTType(type) {
if (getIsGenericType(type)) {
type = type.substring(0, type.indexOf('<'));
}
return type;
}
/**
* NullableOrEmpty[System.Date] -> NullableOrEmpty<System.Date>
*/
function convertGenericTypeName(typeName) {
return typeName.replace('[', '<').replace(']', '>');
}
/**
* NullableOrEmpty<System.Date> -> NullableOrEmpty<T>
*/
function convertGenericToGenericT(typeName) {
return typeName.replace(/\<.*\>/, '<T>');
}
function getIsSubType(item) {
return item.allOf !== undefined;
}
function getHasSubTypeProperty(properties, options) {
return lodash_1.has(properties, options.subTypePropertyName);
}
function getBaseType(subTypeName, typeCollection, item, options, logErrorForMissingBaseType) {
// TODO how about more than one baseType?
let type = removeDefinitionsRef(item.allOf[0].$ref);
let typeName = getTypeName(type, options);
//let namespace = getNamespace(type, options);
let baseType = findTypeInTypeCollection(typeCollection, typeName);
// console.log('---------------------')
// console.log('getBaseType superTypeName', superTypeName, 'type', type, /*'item', item,*/ 'typeName', typeName, 'baseType', baseType ? baseType.typeName : null, /*'typeCollection', typeCollection*/ )
if (!baseType && logErrorForMissingBaseType) {
utils_1.logError(`baseType ${typeName} of ${subTypeName} not found`);
}
return baseType;
}
function findTypesInTypeCollection(typeCollection, typeName, isUnionType, unionTypeNames) {
if (isUnionType) {
return unionTypeNames.map(item => findTypeInTypeCollection(typeCollection, item));
}
return findTypeInTypeCollection(typeCollection, typeName);
}
function findTypeInTypeCollection(typeCollection, typeName) {
let result = lodash_1.find(typeCollection, type => {
return type.typeName === typeName;
//return type.typeName === typeName && type.namespace === namespace;
});
return result;
}
function getSubTypeProperties(item, baseType) {
// TODO strip properties which are defined in the baseType?
if (!lodash_1.isEmpty(item.allOf) && item.allOf.length > 1) {
return item.allOf[1].properties;
}
return {};
}
function getSubTypeRequired(item) {
if (!lodash_1.isEmpty(item.allOf) && item.allOf.length > 1) {
return item.allOf[1].required || [];
}
return [];
}
function getIsEnumType(item) {
return !!(item && item.enum);
}
function getIsEnumRefType(swagger, item, isArray) {
let refItemName;
if (isArray) {
if (item.items.$ref) {
// "perilTypesIncluded": {
// "type": "array",
// "items": {
// "$ref": "#/components/schemas/PerilTypeIncluded"
// }
// },
refItemName = removeDefinitionsRef(item.items.$ref);
}
}
else if (item.oneOf) {
// "partyRoleInClaim": {
// "type": "array",
// "items": {
// "oneOf": [
// {
// "$ref": "#/components/schemas/Claimant"
// },
// {
// "$ref": "#/components/schemas/Claimee"
// }
// ]
// }
// },
const firstOneOf = lodash_1.first(item.oneOf);
refItemName = removeDefinitionsRef(firstOneOf.$ref);
}
else {
// "riskLocationSupraentity": {
// "$ref": "#/components/schemas/LocationSupraentity",
// "description": "type LocationSupraentity "
// },
refItemName = removeDefinitionsRef(item.$ref);
}
let refItem = swagger.components.schemas[refItemName];
return getIsEnumType(refItem);
}
function getNamespace(type, options, removePrefix) {
let typeName = removePrefix ? getTypeNameWithoutNamespacePrefixesToRemove(type, options) : type;
if (getIsGenericType(typeName)) {
let first = typeName.substring(0, typeName.indexOf('['));
typeName = first + first.substring(typeName.indexOf(']'));
}
let parts = typeName.split('.');
parts.pop();
return parts.join('.');
}
function getImportTypes(type, isUnionType, unionTypeNames, isArray) {
if (isUnionType) {
return unionTypeNames;
}
if (isArray) {
let result = removeGenericArray(type, isArray);
return [result];
}
type = removeGenericTType(type);
return [type];
}
function removeGenericArray(type, isArray) {
if (isArray) {
let result = type.replace('Array<', '').replace('>', '');
return result;
}
return type;
}
function getImportFiles(importTypes, namespace, pathToRoot, suffix) {
return importTypes.map(item => getImportFile(item, namespace, pathToRoot, suffix));
}
function getImportFile(importType, namespace, pathToRoot, suffix) {
let importPath = `${lodash_1.kebabCase(importType)}${suffix}`;
if (namespace) {
let namespacePath = utils_1.convertNamespaceToPath(namespace);
importPath = `${namespacePath}/${importPath}`;
}
return (pathToRoot + importPath).toLocaleLowerCase();
}
function getNamespaceGroups(typeCollection, options) {
let namespaces = {
[ROOT_NAMESPACE]: []
};
for (let i = 0; i < typeCollection.length; ++i) {
let type = typeCollection[i];
let namespace = type.namespace || ROOT_NAMESPACE;
if (excludeNamespace(namespace, options.exclude)) {
continue;
}
if (!namespaces[namespace]) {
namespaces[namespace] = [];
}
namespaces[namespace].push(type);
}
return namespaces;
}
function excludeNamespace(namespace, excludeOptions) {
if (!excludeOptions || !excludeOptions.length) {
return false;
}
for (const excludeCheck of excludeOptions) {
if ((excludeCheck instanceof RegExp && excludeCheck.test(namespace)) ||
~namespace.indexOf(excludeCheck)) {
return true;
}
}
return false;
}
function generateTSModels(namespaceGroups, folder, options) {
let data = {
generateClasses: options.generateClasses,
hasComplexType: false,
validatorFileName: utils_1.removeExtension(options.validatorsFileName),
baseModelFileName: utils_1.removeExtension(options.baseModelFileName),
subTypeFactoryFileName: utils_1.removeExtension(options.subTypeFactoryFileName),
moduleName: options.modelModuleName,
enumModuleName: options.enumModuleName,
enumRef: options.enumRef,
subTypePropertyName: options.subTypePropertyName,
subTypePropertyConstantName: lodash_1.snakeCase(options.subTypePropertyName).toUpperCase(),
type: undefined
};
// console.log(data);
let template = utils_1.readAndCompileTemplateFile(options.templates.models);
utils_1.ensureFolder(folder);
for (let namespace in namespaceGroups) {
let typeCol = namespaceGroups[namespace];
let firstType = typeCol[0] ||
{
namespace: ''
};
let namespacePath = utils_1.convertNamespaceToPath(firstType.namespace);
let typeFolder = `${folder}${namespacePath}`;
let folderParts = namespacePath.split('/');
let prevParts = folder;
folderParts.forEach(part => {
prevParts += part + '/';
utils_1.ensureFolder(prevParts);
});
let nrGeneratedFiles = 0;
lodash_1.each(typeCol, type => {
let outputFileName = path_1.join(typeFolder, type.fileName);
data.type = type;
data.hasComplexType = type.properties.some(property => property.isComplexType);
let result = template(data, { allowProtoPropertiesByDefault: true });
let isChanged = utils_1.writeFileIfContentsIsChanged(outputFileName, result);
if (isChanged) {
nrGeneratedFiles++;
}
//fs.writeFileSync(outputFileName, result, { flag: 'w', encoding: utils.ENCODING });
});
utils_1.log(`generated ${nrGeneratedFiles} type${nrGeneratedFiles === 1 ? '' : 's'} in ${typeFolder}`);
removeFilesOfNonExistingTypes(typeCol, typeFolder, options, MODEL_FILE_SUFFIX);
}
let namespacePaths = Object.keys(namespaceGroups).map(namespace => {
return path_1.join(folder, utils_1.convertNamespaceToPath(namespace));
});
cleanFoldersForObsoleteFiles(folder, namespacePaths);
}
function cleanFoldersForObsoleteFiles(folder, namespacePaths) {
utils_1.getDirectories(folder).forEach(name => {
let folderPath = path_1.join(folder, name);
// TODO bij swagger-zib-v2 wordt de webapi/ZIB folder weggegooid !
let namespacePath = lodash_1.find(namespacePaths, path => {
return path.startsWith(folderPath);
});
if (!namespacePath) {
utils_1.removeFolder(folderPath);
utils_1.log(`removed obsolete folder ${name} in ${folder}`);
}
else {
cleanFoldersForObsoleteFiles(folderPath, namespacePaths);
}
});
}
function generateSubTypeFactory(namespaceGroups, folder, options) {
let data = {
subTypes: undefined,
subTypePropertyName: options.subTypePropertyName
};
let template = utils_1.readAndCompileTemplateFile(options.templates.subTypeFactory);
for (let key in namespaceGroups) {
data.subTypes = namespaceGroups[key].filter(type => {
return type.hasSubTypeProperty;
});
let namespacePath = namespaceGroups[key][0] ? namespaceGroups[key][0].path : '';
let outputFileName = path_1.join(folder, options.subTypeFactoryFileName);
let result = template(data);
let isChanged = utils_1.writeFileIfContentsIsChanged(outputFileName, result);
if (isChanged) {
utils_1.log(`generated ${outputFileName}`);
}
}
}
function addRootFixedFileNames(fileNames, options) {
let enumOutputFileName = path_1.normalize(options.enumTSFile.split('/').pop());
fileNames.splice(0, 0, utils_1.removeExtension(enumOutputFileName));
if (options.generateClasses) {
let validatorsOutputFileName = path_1.normalize(options.validatorsFileName);
fileNames.splice(0, 0, utils_1.removeExtension(validatorsOutputFileName));
}
}
function removeFilesOfNonExistingTypes(typeCollection, folder, options, suffix) {
// remove files of types which are no longer defined in typeCollection
let counter = 0;
let files = fs_1.readdirSync(folder);
lodash_1.each(files, file => {
if (lodash_1.endsWith(file, suffix) &&
!lodash_1.find(typeCollection, type => {
return type.fileName == file;
})) {
counter++;
fs_1.unlinkSync(path_1.join(folder, file));
utils_1.log(`removed ${file} in ${folder}`);
}
});
if (counter > 0) {
utils_1.log(`removed ${counter} types in ${folder}`);
}
}
;