UNPKG

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
"use strict"; 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}`); } }