import { join , sep } from 'path' ; import { readdirSync } from 'fs' ; import Page from './page' ; import { Nuxtent } from '../../types/index' ; import { logger } from '../utils' ; const { max , min } = Math ; description export class export default class Database { public dirPath = '' ; public pagesMap : Map < string , Page > ; public pagesArr : Page [ ] ; public permalink : string ; param { Nuxtent . Config . Build } build param { string } build . contentDir param { string } build . ignorePrefix param { string } dirName param { Nuxtent . Config . Content } dirOpts memberOf constructor ( build , dirName , dirOpts ) { this . dirPath = join ( build . contentDir , dirName ) ; this . permalink = dirOpts . permalink ; const fileStore = new Map ( ) ; const createMap = ( { index , fileName , section , } ) => { const filePath = join ( build . contentDir , dirName , section , fileName ) ; const meta = { index , fileName , section , dirName , filePath } ; return new Page ( meta , dirOpts ) ; } ; param name function canProcesFile ( name ) { const fileTest = new RegExp ( `\.(${ build . contentExtensions . join ( '|' ) }$)` ) ; return ( name . search ( fileTest ) !== - 1 && ! name . startsWith ( build . ignorePrefix ) ) ; } const globAndApply = ( dirPath , nestedPath = sep ) : Nuxtent . FileStore => { const stats = readdirSync ( dirPath , { withFileTypes : true , } ) . reverse ( ) ; stats . forEach ( ( stat , index ) => { const statPath = join ( dirPath , stat . name ) ; if ( stat . isFile ( ) && canProcesFile ( stat . name ) ) { const fileData = { dirName : dirPath , fileName : stat . name , filePath : statPath , index , section : nestedPath , } ; const page = createMap ( fileData ) ; fileStore . set ( page . permalink , page ) ; } else if ( stat . isDirectory ( ) ) { globAndApply ( statPath , join ( nestedPath , stat . name ) ) ; } } ) ; return fileStore ; } ; this . pagesMap = globAndApply ( this . dirPath ) ; if ( dirOpts . breadcrumbs === true ) { this . loadBreadcrumbs ( dirOpts . page ) ; } this . pagesArr = [ ... this . pagesMap . values ( ) ] ; } param { string } permalink public returns { boolean } public exists ( permalink ) { return this . pagesMap . has ( permalink ) ; } param permalink param query returns public find ( permalink , query ) { const page = this . pagesMap . get ( permalink ) ; if ( page ) { return page . create ( query ) ; } return null ; } param onlyArg param query returns public findOnly ( onlyArg , query ) { if ( typeof onlyArg === 'string' ) { onlyArg = onlyArg . split ( ',' ) ; } const [ startIndex , endIndex ] = onlyArg ; let currIndex = typeof startIndex === 'number' ? startIndex : max ( 0 , parseInt ( startIndex , 10 ) ) ; if ( Number . isNaN ( currIndex ) ) { currIndex = 0 ; } const finalIndex = endIndex !== undefined ? min ( typeof endIndex === 'number' ? endIndex : parseInt ( endIndex , 10 ) , this . pagesArr . length - 1 ) : null ; if ( ! finalIndex ) { return [ this . pagesArr [ currIndex ] . create ( query ) ] ; } const pages = [ ] ; if ( finalIndex ) { while ( currIndex <= finalIndex ) { pages . push ( this . pagesArr [ currIndex ] ) ; currIndex ++ ; } } return pages . map ( page => page . create ( query ) ) ; } param { string } betweenStr param { any } query returns { NuxtentPageData [ ] } public findBetween ( betweenStr , query ) { const [ currPermalink , numStr1 , numStr2 ] = betweenStr . split ( ',' ) ; if ( ! this . pagesMap . has ( currPermalink ) ) { return [ ] ; } const page = this . pagesMap . get ( currPermalink ) ; if ( ! page ) { return [ ] ; } const currPage = page . create ( query ) ; if ( ! currPage . meta ) { logger . warn ( 'You should not exclude meta when querying between' ) ; return [ ] ; } const { index } = currPage . meta ; const total = this . pagesArr . length - 1 ; const num1 = parseInt ( numStr1 || '0' , 10 ) ; const num2 = numStr2 !== undefined ? parseInt ( numStr2 , 10 ) : null ; if ( num1 === 0 && num2 === 0 ) { return [ currPage ] ; } let beforeRange ; if ( num1 === 0 ) { beforeRange = [ ] ; } else { beforeRange = [ max ( 0 , index - num1 ) , max ( min ( index - 1 , total ) , 0 ) ] ; } let afterRange ; if ( num2 === 0 || ( ! num2 && num1 === 0 ) ) { afterRange = [ ] ; } else { afterRange = [ min ( index + 1 , total ) , min ( index + ( num2 || num1 ) , total ) ] ; } const beforePages = this . findOnly ( beforeRange , query ) ; const afterPages = this . findOnly ( afterRange , query ) ; return [ currPage , ... beforePages , ... afterPages ] ; } param query returns public findAll ( query ) { return this . pagesArr . map ( page => page . create ( query ) ) ; } description param { string } dirPage private returns { void } memberOf protected loadBreadcrumbs ( dirPage ) { const target = dirPage . split ( '/' ) . slice ( 0 , - 1 ) . join ( '/' ) ; for ( const page of this . pagesMap . values ( ) ) { const hops = page . permalink . substr ( target . length + 1 ) . split ( '/' ) ; const breadcrumbs = [ ] ; for ( let i = 0 ; i < hops . length ; i ++ ) { let crumb = target ; for ( let j = 0 ; j < i ; j ++ ) { crumb += '/' + hops [ j ] ; } if ( crumb !== target ) { const crumbPage = this . pagesMap . get ( crumb ) ; if ( crumbPage ) { breadcrumbs . push ( { frontMatter : crumbPage . attributes , permalink : crumb , } ) ; } } } if ( breadcrumbs . length > 0 ) { page . breadcrumbs = breadcrumbs ; this . pagesMap . set ( page . permalink , page ) ; } } } }