/**
 * Copyright © 2019 Johnson & Johnson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ import path from 'path' ; import fs from 'fs-extra' ; import walkdir from 'walkdir' ; import flow from 'lodash/flow' ; import { Tree , TreeHO } from './type' ; import { treeHOPromiseFlow } from './promiseUtils' ; param key param value export const withDeepValue = ( key , value ) => ( tree ) : Tree => { const keys = typeof key === 'string' ? [ key ] : key ; if ( keys . length === 1 ) { return { ... tree , [ keys [ 0 ] ] : value } as Tree ; } const [ first , ... rest ] = keys ; if ( Object . keys ( tree ) . includes ( first ) ) { const subTree = tree [ first ] as Tree ; return { ... tree , [ first ] : withDeepValue ( rest , value ) ( subTree ) , } as Tree ; } return { ... tree , [ first ] : withDeepValue ( rest , value ) ( { } ) , } as Tree ; } ; type Resolve = ( a : TreeHO ) => void ; param startDir export const getTreeFromDir = ( startDir ) => ( new Promise ( ( resolve ) => { const updates = [ ] as TreeHO [ ] ; const walker = walkdir ( startDir , { follow_symlinks : true } ) ; walker . on ( 'file' , ( filePath ) => { const keys = path . relative ( startDir , filePath ) . split ( path . sep ) ; updates . push ( withDeepValue ( keys , filePath ) ) ; } ) ; walker . on ( 'end' , ( ) => { resolve ( flow ( ... updates ) ) ; } ) ; } ) ) ; param prePend export const prependPath = ( prePend ) => ( tree ) : Tree => ( Object . keys ( tree ) . reduce ( ( acc , key ) => { if ( typeof tree [ key ] === 'string' ) { return { [ key ] : path . join ( prePend , tree [ key ] as string ) , ... acc } as Tree ; } const subTree = prependPath ( prePend ) ( tree [ key ] as Tree ) ; return { [ key ] : subTree , ... acc } as Tree ; } , { } as Tree ) ) ; param newTree export const withTree = ( newTree ) => ( tree ) : Tree => ( Object . keys ( newTree ) . reduce ( ( acc , key ) => { if ( typeof newTree [ key ] === 'object' && typeof tree [ key ] === 'string' ) { const indexPath = tree [ key ] ; return { ... acc , [ key ] : withTree ( newTree [ key ] as Tree ) ( { 'README.md' : indexPath } ) } ; } if ( typeof newTree [ key ] === 'object' && typeof tree [ key ] === 'object' ) { return { ... acc , [ key ] : withTree ( newTree [ key ] as Tree ) ( tree [ key ] as Tree ) } ; } if ( typeof newTree [ key ] === 'object' && typeof tree [ key ] === 'undefined' ) { return { ... acc , [ key ] : newTree [ key ] } ; } if ( typeof newTree [ key ] === 'string' && typeof tree [ key ] === 'object' ) { return { ... acc , [ key ] : withTree ( { 'README.md' : newTree [ key ] } ) ( tree [ key ] as Tree ) } ; } return { ... acc , [ key ] : newTree [ key ] } ; } , tree as Tree ) ) ; param filePath export const withTreeFromFile = ( filePath ) : Promise < TreeHO > => { const dirPath = path . dirname ( filePath ) ; return fs . readJson ( filePath ) . then ( ( fileJSON ) => { const { _dir , ... rawTree } = fileJSON ; const updateTree = withTree ( prependPath ( dirPath ) ( rawTree ) ) ; if ( _dir ) { const docPath = path . join ( dirPath , _dir as string ) ; const promises = [ Promise . resolve ( updateTree ) , getTreeFromDir ( docPath ) , ] ; return treeHOPromiseFlow ( ... promises ) ; } return updateTree ; } ) ; } ; param tree export const getSimplePaths = ( tree ) : string [ ] => { const simplePathsList = [ ] ; const walkTree = ( tree1 ) => { Object . keys ( tree1 ) . forEach ( key => { const branch = tree1 [ key ] ; if ( typeof branch === 'object' ) { walkTree ( branch ) ; } else { simplePathsList . push ( branch ) ; } } ) ; } ; walkTree ( tree ) ; return simplePathsList ; } ; param pathsToDocs export const validatePaths = ( pathsToDocs ) => { pathsToDocs . forEach ( pathToDoc => { const defaultPath = path . resolve ( pathToDoc ) ; const nativePath = fs . realpathSync . native ( defaultPath ) ; if ( defaultPath !== nativePath ) { const errorMessage = `
        The file path specified in docs.json is not equal to the real file path.
        ${ defaultPath }
        !==
        ${ nativePath }
        Make sure the path is case-sensitively correct.
      ` ; throw new Error ( errorMessage ) ; } } ) ; } ;