import { readFileSync } from 'fs' ; import { normalize } from 'path' ; import { each , clone , keys , map , unset , forEach , has , sortBy , isObject , lowerFirst , uniqBy , upperCase , startCase } from 'lodash' ; import { Swagger , SwaggerSchemas , SwaggerSchema } from '../bootstrap/swagger' ; import { GeneratorOptions } from '../bootstrap/options' ; import { ENCODING , readAndCompileTemplateFile , writeFileIfContentsIsChanged , log , ensureFile , isInTypesToFilter } from './utils' ; interface EnumType { type : string ; valuesAndLabels : EnumTypeValueAndLabel [ ] ; joinedValues : string ; } interface EnumTypeValueAndLabel { value : string ; label : string ; } export function generateEnumTSFile ( swagger , options ) { log ( 'generating enums...' ) ; let outputFileName = normalize ( options . enumTSFile ) ; 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 = readAndCompileTemplateFile ( options . templates . enum ) ; let result = template ( data ) ; let isChanged = writeFileIfContentsIsChanged ( outputFileName , result ) ; if ( isChanged ) { log ( `generated ${ enumTypeCollection . length }  enums in ${ outputFileName }` ) ; } } } export function generateEnumI18NHtmlFile ( swagger , options ) { let outputFileName = normalize ( options . enumI18NHtmlFile ) ; let enumTypeCollection = getEnumDefinitions ( swagger , options ) ; generateI18NEnumsHtml ( enumTypeCollection , outputFileName , options ) ; function generateI18NEnumsHtml ( enumTypeCollection , outputFileName , options ) { let data = { enumTypeCollection } ; let template = readAndCompileTemplateFile ( options . templates . enumLanguage ) ; let result = template ( data ) ; let isChanged = writeFileIfContentsIsChanged ( outputFileName , result ) ; if ( isChanged ) { log ( `generated ${ enumTypeCollection . length }  enums in ${ outputFileName }` ) ; } } } export function generateEnumLanguageFiles ( swagger , options ) { each ( options . enumLanguageFiles , outputFileName => { outputFileName = normalize ( outputFileName ) ; ensureFile ( outputFileName , '{}' ) ; let enumLanguage = JSON . parse ( readFileSync ( outputFileName , ENCODING ) ) ; let enumTypeCollection = getEnumDefinitions ( swagger , options ) ; let newValuesAdded = buildNewEnumLanguage ( enumTypeCollection , enumLanguage ) ; 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' ; log ( `${ message } in ${ outputFileName }` ) ; let isChanged = writeFileIfContentsIsChanged ( outputFileName , JSON . stringify ( enumLanguage , null , 2 ) ) ; } } function getEnumDefinitions ( swagger , options ) { let enumTypeCollection = new Array ( ) ; filterEnumDefinitions ( enumTypeCollection , swagger . components . schemas , options ) ; enumTypeCollection = uniqBy ( enumTypeCollection , 'type' ) ; enumTypeCollection = removeEnumTypesWithSameValues ( enumTypeCollection ) ; if ( options . sortEnumTypes ) { enumTypeCollection = sortBy ( enumTypeCollection , 'type' ) ; } return enumTypeCollection ; } function filterEnumDefinitions ( enumTypeCollection , node , options , enumArrayType ? ) { forEach ( node , ( item , key ) => { const itemDef = item as SwaggerSchema ; if ( isObject ( itemDef ) && ! isInTypesToFilter ( itemDef , key , options ) ) { if ( itemDef . enum ) { let type = enumArrayType ? enumArrayType : key ; let values = itemDef . enum ; let enumType = { type , valuesAndLabels : getEnumValuesAndLabels ( values , options ) , joinedValues : undefined } ; enumType . joinedValues = values . join ( ';' ) ; enumTypeCollection . push ( enumType ) ; } else { let enumArrayType = undefined ; if ( itemDef . type === 'array' ) { enumArrayType = key ; } filterEnumDefinitions ( enumTypeCollection , itemDef , options , enumArrayType ) ; } } } ) ; } function removeEnumTypesWithSameValues ( enumTypeCollection ) { const result = uniqBy ( enumTypeCollection , element => { return element . type + element . joinedValues ; } ) ; return result ; } function getEnumValuesAndLabels ( enumValues , options ) { let result = new Array ( ) ; forEach ( enumValues , value => { const valueAndLabel = { value , label : upperCase ( value ) === value && value . length <= 3 ? value : startCase ( value . toLowerCase ( ) ) } ; result . push ( valueAndLabel ) ; } ) ; if ( options . sortEnumTypes ) { result = sortBy ( result , 'value' ) ; } return result ; }