import toposort from 'toposort' ; import { Link , Directory , Node , FileIndex } from '../models' ; export type MillOpts = Record < string , string > ; export type MillFunction = ( mill : string , opts : MillOpts , form : any , headers : { [ k ] : string ; } ) => Promise < FileIndex > ; export default class SchemaMiller { static sortLinksByDependency ( links ) { const linkAndDepends = Object . entries ( links ) . map ( ( [ name , link ] ) => { const pair = [ name , link . use ] ; return pair ; } ) ; const sorted = [ ... toposort ( linkAndDepends ) ] . reverse ( ) ; return ( sorted . filter ( ( name ) => { return name !== ':file' ; } ) . map ( ( name ) => ( { name , link : links [ name ] } ) ) ) ; } static normalizeOptions ( info ) { const opts = info . opts || { } ; opts . plaintext = ( info . plaintext || false ) . toString ( ) ; opts . pin = ( info . pin || false ) . toString ( ) ; return opts ; } static resolveDependency ( method , payloadsByName ) { let use ; if ( method . use && method . use !== ':file' ) { use = ( method . use . length === 46 && method . use . startsWith ( 'Qm' ) ) ? method . use : payloadsByName . files [ method . use ] . hash ; } const resolvedMethod = { ... method } ; resolvedMethod . use = use || '' ; return resolvedMethod ; } static async mill ( payload , node , remoteMill ) { const dir = { files : { } } ; if ( node . mill ) { const normal = SchemaMiller . normalizeOptions ( node ) ; const resolved = SchemaMiller . resolveDependency ( normal , dir ) ; let form ; if ( resolved . use ) { form = undefined ; } else if ( typeof payload === 'function' ) { form = payload ( ) ; } else { form = payload ; } const file = await remoteMill ( node . mill , resolved , form , { } ) ; dir . files [ ':single' ] = file ; } else if ( node . links ) { const steps = SchemaMiller . sortLinksByDependency ( node . links ) ; for ( const step of steps ) { let form ; const normal = SchemaMiller . normalizeOptions ( step . link || { } ) ; const resolved = SchemaMiller . resolveDependency ( normal , dir ) ; if ( resolved . use ) { form = undefined ; } else if ( typeof payload === 'function' ) { form = payload ( ) ; } else { form = payload ; } const file = await remoteMill ( step . link . mill , resolved , form , { } ) ; dir . files [ step . name ] = file ; } } return dir ; } }