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)

185 lines (168 loc) 8.23 kB
"use strict"; let fs = require('fs'); let path = require('path'); let _ = require('lodash'); let utils = require('./utils'); module.exports = { generateEnumTSFile: generateEnumTSFile, generateEnumI18NHtmlFile: generateEnumI18NHtmlFile, generateEnumLanguageFiles: generateEnumLanguageFiles, } function generateEnumTSFile(swagger, options) { let outputFileName = path.normalize(options.enumTSFile); // get enum definitions from swagger let enumTypeCollection = getEnumDefinitions(swagger, options); generateTSEnums(enumTypeCollection, outputFileName, options) function generateTSEnums(enumTypeCollection, outputFileName, options) { let data = { moduleName: options.enumModuleName, generateClasses: options.generateClasses, enumTypeCollection: enumTypeCollection } let template = utils.readAndCompileTemplateFile('generate-enum-ts.hbs'); let result = template(data); let isChanged = utils.writeFileIfContentsIsChanged(outputFileName, result); if (isChanged) { utils.log(`generated ${enumTypeCollection.length} enums in ${outputFileName}`); } } } function generateEnumI18NHtmlFile(swagger, options) { let outputFileName = path.normalize(options.enumI18NHtmlFile); // get enum definitions from swagger let enumTypeCollection = getEnumDefinitions(swagger, options); generateI18NEnumsHtml(enumTypeCollection, outputFileName, options) function generateI18NEnumsHtml(enumTypeCollection, outputFileName, options) { let data = { enumTypeCollection: enumTypeCollection } let template = utils.readAndCompileTemplateFile('generate-enum-i18n-html.hbs'); let result = template(data); let isChanged = utils.writeFileIfContentsIsChanged(outputFileName, result); if (isChanged) { utils.log(`generated ${enumTypeCollection.length} enums in ${outputFileName}`); } } } function generateEnumLanguageFiles(swagger, options) { _.each(options.enumLanguageFiles, (outputFileName) => { outputFileName = path.normalize(outputFileName); // read contents of the current language file utils.ensureFile(outputFileName, '{}'); let enumLanguage = JSON.parse(fs.readFileSync(outputFileName, utils.ENCODING)); // get enum definitions from swagger let enumTypeCollection = getEnumDefinitions(swagger, options); // add new enum types/values to the enumLanguage (leave existing ones intact) let newValuesAdded = buildNewEnumLanguage(enumTypeCollection, enumLanguage); // generateEnumLanguageFile generateEnumLanguageFile(enumLanguage, outputFileName, newValuesAdded) }); function buildNewEnumLanguage(enumTypeCollection, enumLanguage) { let result = false; let currentEnumLanguage = _.clone(enumLanguage); let properties = _.keys(enumLanguage); _.map(properties, (property) => { _.unset(enumLanguage, property); }); _.forEach(enumTypeCollection, function (enumType) { enumLanguage[enumType.type] = '-------ENUM-TYPE-------'; _.forEach(enumType.valuesAndLabels, function (valueAndLabel, key) { if (!_.has(enumLanguage, valueAndLabel.value)) { if (_.has(currentEnumLanguage, valueAndLabel.value)) { enumLanguage[valueAndLabel.value] = currentEnumLanguage[valueAndLabel.value]; } else { enumLanguage[valueAndLabel.value] = valueAndLabel.label; result = true; } } }); }); return result; } function generateEnumLanguageFile(enumLanguage, outputFileName, newValuesAdded) { let message = newValuesAdded ? 'generated new enum values in' : 'nothing new'; utils.log(`${message} in ${outputFileName}`); let isChanged = utils.writeFileIfContentsIsChanged(outputFileName, JSON.stringify(enumLanguage, null, 2)); //fs.writeFileSync(outputFileName, JSON.stringify(enumLanguage, null, 2), utils.ENCODING); } } function getEnumDefinitions(swagger, options) { let enumTypeCollection = new Array(); filterEnumDefinitions(enumTypeCollection, swagger.definitions, options); // filter on unique types enumTypeCollection = _.uniq(enumTypeCollection, 'type'); // patch enumTypes which have the same values (to prevent non-unique consts in Go) enumTypeCollection = removeEnumTypesWithSameValues(enumTypeCollection); // sort on type if (options.sortEnumTypes) { enumTypeCollection = _.sortBy(enumTypeCollection, 'type'); } // console.log('enumTypeCollection', enumTypeCollection); return enumTypeCollection; } function filterEnumDefinitions(enumTypeCollection, node, options, enumArrayType) { _.forEach(node, function (item, key) { if (_.isObject(item) && (!utils.isInTypesToFilter(item, key, options))) { if (item.enum) { let type = enumArrayType ? enumArrayType : key; let values = item.enum; let enumType = { 'type': type, valuesAndLabels: getEnumValuesAndLabels(values) }; // description may contain an overrule type, eg /** type coverType */ if (utils.hasTypeFromDescription(item.description)) { enumType.type = _.lowerFirst(utils.getTypeFromDescription(item.description)); } // add string with joined values so enums with the same values can be detected enumType.joinedValues = values.join(';') // console.log(enumType); // console.log('----------------------'); enumTypeCollection.push(enumType) } else { // enum array's has enum definition one level below (under "items") let enumArrayType = undefined; if (item.type === 'array') { enumArrayType = key; if (utils.hasTypeFromDescription(item.description)) { enumArrayType = _.lowerFirst(utils.getTypeFromDescription(item.description)) } } filterEnumDefinitions(enumTypeCollection, item, options, enumArrayType); } } }); } function removeEnumTypesWithSameValues(enumTypeCollection) { const result = _.uniqBy(enumTypeCollection, element => { return element.type + element.joinedValues }); // console.log('#enumTypes with and without duplicates', enumTypeCollection.length, result.length); // console.log('======================> original <======================', enumTypeCollection); // console.log('======================> result <======================', result); return result; // // get enumTypes with duplicate enumValues // let groupped = _.groupBy(enumTypeCollection, (e) => { return e.joinedValues }); // var duplicates = _.uniqBy(_.flatten(_.filter(groupped, (g) => { return g.length > 1 })), element => { return element.type; }); // console.log('duplicates', JSON.stringify(duplicates)); // // prefix enumValue.pascalCaseValue with typeName to make sure the genertaed Go consts are unique // _.forEach(duplicates, (item, key) => { // // _.forEach(item.values, (value) => { // // value.pascalCaseValue = `${item.typeName}${value.pascalCaseValue}`; // // }); // }) // // console.log('enumTypeCollection', JSON.stringify(enumTypeCollection)); // return enumTypeCollection; } function getEnumValuesAndLabels(enumValues) { let result = new Array(); _.forEach(enumValues, (value, key) => { const valueAndLabel = { value: value, // only convert label when the value contains not only uppercase chars (only uppercase are considered codes like Country) label: _.upperCase(value) !== value ? _.startCase(value) : value } result.push(valueAndLabel); }); return result; }