import { IYamlItem , IYamlApiFile , IYamlSyntax , IYamlReferenceSpec , IYamlReference } from '../yaml/IYamlApiFile' ; import { PackageYamlModel , EnumYamlModel , TypeAliasYamlModel , TypeYamlModel , FieldYamlModel , FunctionYamlModel , CommonYamlModel } from '../yaml/ISDPYamlFile' ; import path from 'path' ; import { FileSystem , Encoding , NewlineKind } from '@rushstack/node-core-library' ; import yaml = require ( 'js-yaml' ) ; export function convertUDPYamlToSDP ( folderPath ) { convert ( folderPath , folderPath ) ; } function convert ( inputPath , outputPath ) { console . log ( ) ; if ( ! FileSystem . exists ( inputPath ) ) { console . error ( `input path: ${ inputPath } is not exist` ) ; return ; } FileSystem . readFolderItemNames ( inputPath ) . forEach ( ( name ) => { const fpath = path . join ( inputPath , name ) ; if ( FileSystem . getStatistics ( fpath ) . isFile ( ) ) { if ( ! name . endsWith ( '.yml' ) ) { return ; } const yamlContent = FileSystem . readFile ( fpath , { encoding : Encoding . Utf8 } ) ; const isLegacyYaml = yamlContent . startsWith ( '### YamlMime:UniversalReference' ) ; if ( ! isLegacyYaml ) { return ; } console . log ( `convert file ${ fpath } from udp to sdp` ) ; const file = yaml . safeLoad ( yamlContent ) as IYamlApiFile ; const result = convertToSDP ( file ) ; if ( result && result . model ) { const stringified = `### YamlMime:TS${ result . type }\n${ yaml . safeDump ( result . model , { lineWidth : 120 } ) }` ; FileSystem . writeFile ( `${ outputPath }/${ name }` , stringified , { convertLineEndings : NewlineKind . CrLf , ensureFolderExists : true } ) ; } else { console . log ( 'not target file ' , fpath ) ; } } else { convert ( fpath , path . join ( outputPath , name ) ) ; } } ) ; } function convertToPackageSDP ( transfomredClass ) { const element = transfomredClass . items [ 0 ] ; const packageModel = { uid : element . uid , name : element . name ! , type : 'package' } ; if ( element . summary ) { packageModel . summary = element . summary ; } else { packageModel . summary = '' ; } if ( element . children ) { element . children . forEach ( ( child ) => { if ( child . endsWith ( ':class' ) ) { assignPackageModelFields ( packageModel , 'classes' , child ) ; } else if ( child . endsWith ( ':interface' ) ) { assignPackageModelFields ( packageModel , 'interfaces' , child ) ; } else if ( child . endsWith ( ':enum' ) ) { assignPackageModelFields ( packageModel , 'enums' , child ) ; } else if ( child . endsWith ( ':type' ) ) { } else { } } ) ; } for ( let i = 1 ; i < transfomredClass . items . length ; i ++ ) { const ele = transfomredClass . items [ i ] ; switch ( ele . type ) { case 'typealias' : break ; case 'function' : if ( ! packageModel . functions ) { packageModel . functions = [ ] ; } packageModel . functions . push ( convertToFunctionSDP ( ele , element . uid , transfomredClass ) ) ; break ; default : console . log ( '[warning] not applied type(package): ' , ele . type ) ; } } return packageModel ; } function assignPackageModelFields ( packageModel , name , uid ) { if ( ! packageModel [ name ] ) { packageModel [ name ] = [ ] ; } packageModel [ name ] ! . push ( uid ) ; } function convertToSDP ( transfomredClass ) { const element = transfomredClass . items [ 0 ] ; switch ( element . type ) { case 'class' : case 'interface' : return { model : convertToTypeSDP ( transfomredClass , element . type === 'class' ) , type : 'Type' } ; case 'enum' : if ( transfomredClass . items . length < 2 ) { console . log ( `[warning] enum ${ element . uid }/${ element . name } does not have fields` ) ; return undefined ; } return { model : convertToEnumSDP ( transfomredClass ) , type : 'Enum' } ; case 'typealias' : return { model : convertToTypeAliasSDP ( element , transfomredClass ) , type : 'TypeAlias' } ; case 'package' : return { model : convertToPackageSDP ( transfomredClass ) , type : 'Package' } ; default : console . log ( 'not applied type: ' , element . type ) ; return undefined ; } } function convertToEnumSDP ( transfomredClass ) { const element = transfomredClass . items [ 0 ] ; const fields = [ ] ; for ( let i = 1 ; i < transfomredClass . items . length ; i ++ ) { const ele = transfomredClass . items [ i ] ; const field = { name : ele . name ! , uid : ele . uid , package : element . package ! } ; if ( ele . summary ) { field . summary = ele . summary ; } else { field . summary = '' ; } if ( ele . numericValue ) { field . value = ele . numericValue ; } fields . push ( field ) ; } const result = { ... convertCommonYamlModel ( element , element . package ! , transfomredClass ) , fields : fields } ; return result ; } function convertToTypeAliasSDP ( element , transfomredClass ) { const result = { ... convertCommonYamlModel ( element , element . package ! , transfomredClass ) } as TypeAliasYamlModel ; if ( element . syntax ) { result . syntax = element . syntax . content ! ; } return result ; } function convertToTypeSDP ( transfomredClass , isClass ) { const element = transfomredClass . items [ 0 ] ; const constructors = [ ] ; const properties = [ ] ; const methods = [ ] ; const events = [ ] ; for ( let i = 1 ; i < transfomredClass . items . length ; i ++ ) { const ele = transfomredClass . items [ i ] ; const item = convertCommonYamlModel ( ele , element . package ! , transfomredClass ) ; if ( ele . type === 'constructor' ) { if ( isClass ) { constructors . push ( item ) ; } } else if ( ele . type === 'property' ) { properties . push ( item ) ; } else if ( ele . type === 'method' ) { methods . push ( item ) ; } else if ( ele . type === 'event' ) { events . push ( item ) ; } else { console . log ( `[warning] ${ ele . uid }#${ ele . name } is not applied sub type ${ ele . type } for type yaml` ) ; } } const result = { ... convertCommonYamlModel ( element , element . package ! , transfomredClass ) , type : isClass ? 'class' : 'interface' } ; delete result . syntax ; if ( constructors . length > 0 ) { result . constructors = constructors ; } if ( properties . length > 0 ) { result . properties = properties ; } if ( methods . length > 0 ) { result . methods = methods ; } if ( events . length > 0 ) { result . events = events ; } if ( element . extends && element . extends . length > 0 ) { result . extends = convertSelfTypeToXref ( element . extends [ 0 ] as string , transfomredClass ) ; } return result ; } function convertToFunctionSDP ( element , packageName , transfomredClass ) { const model = convertCommonYamlModel ( element , packageName , transfomredClass ) ; delete model . fullName ; return model ; } function convertCommonYamlModel ( element , packageName , transfomredClass ) { const result = { name : element . name ! , uid : element . uid , package : packageName } ; if ( element . fullName ) { result . fullName = element . fullName ; } if ( element . summary ) { result . summary = element . summary ; } else { result . summary = '' ; } if ( element . remarks ) { result . remarks = element . remarks ; } else { result . remarks = '' ; } if ( element . example ) { result . example = element . example ; } else { result . example = [ ] ; } result . isPreview = element . isPreview ; if ( ! result . isPreview ) { result . isPreview = false ; } if ( element . deprecated ) { result . isDeprecated = true ; result . customDeprecatedMessage = element . deprecated . content ; } else { result . isDeprecated = false ; } if ( element . syntax ) { result . syntax = { } ; const syntax = element . syntax ; result . syntax . content = syntax . content ; if ( syntax . parameters && syntax . parameters . length > 0 ) { syntax . parameters ?. forEach ( ( it ) => { delete it . optional ; delete it . defaultValue ; } ) ; result . syntax . parameters = syntax . parameters . map ( ( it ) => { return { ... it , id : it . id ! , type : convertSelfTypeToXref ( escapeMarkdown ( it . type ! [ 0 ] as string ) , transfomredClass ) } ; } ) ; } if ( syntax . return ) { result . syntax . return = { ... syntax . return , type : convertSelfTypeToXref ( escapeMarkdown ( syntax . return . type ! [ 0 ] as string ) , transfomredClass ) } ; } } return result ; } function escapeMarkdown ( name ) { const markdownLinkRegEx = /^\s*(\[.+\]):(.+)/g ; return name . replace ( markdownLinkRegEx , `$1\\:$2` ) ; } function convertSelfTypeToXref ( name , transfomredClass ) { let result = name ; if ( result . endsWith ( ':complex' ) ) { const specs = transfomredClass . references ?. find ( ( item ) => { return item . uid === name ; } ) ?. [ 'spec.typeScript' ] ; if ( specs && specs . length > 0 ) { result = '' ; for ( const spec of specs ) { if ( spec . uid && ! spec . uid . startsWith ( '!' ) ) { result += spec . uid ; } else { result += spec . name ; } } } } else if ( result . startsWith ( '!' ) ) { const ref = transfomredClass . references ?. find ( ( item ) => { return item . uid === name ; } ) ; if ( ref && ref . name ) { result = ref . name ; } } result = result . replace ( /</g , '&lt;' ) . replace ( />/g , '&gt;' ) ; const uidRegEx = /(@?[\w\d\-/!~\.]+\:[\w\d\-\(/]+)/g ; return result . replace ( uidRegEx , `<xref uid="$1" />` ) ; }