import is from '@sindresorhus/is' ; import { load } from 'js-yaml' ; import { logger } from '../../logger' ; import { regEx } from '../../util/regex' ; import { getDep } from '../dockerfile/extract' ; import type { PackageFile } from '../types' ; import type { DockerComposeConfig } from './types' ; class LineMapper { private imageLines : { line : string ; lineNumber : number ; used : boolean ; } [ ] ; constructor ( content , filter ) { this . imageLines = [ ... content . split ( '\n' ) . entries ( ) ] . filter ( ( entry ) => filter . test ( entry [ 1 ] ) ) . map ( ( [ lineNumber , line ] ) => ( { lineNumber , line , used : false } ) ) ; } pluckLineNumber ( imageName ) { const lineMeta = this . imageLines . find ( ( { line , used } ) => ! used && line . includes ( imageName ) ) ; if ( ! lineMeta ) { return null ; } lineMeta . used = true ; return lineMeta . lineNumber ; } } export function extractPackageFile ( content , fileName ? ) { logger . debug ( 'docker-compose.extractPackageFile()' ) ; let config ; try { config = load ( content , { json : true } ) as DockerComposeConfig ; if ( ! config ) { logger . debug ( { fileName } , 'Null config when parsing Docker Compose content' ) ; return null ; } if ( typeof config !== 'object' ) { logger . debug ( { fileName , type : typeof config } , 'Unexpected type for Docker Compose content' ) ; return null ; } } catch ( err ) { logger . debug ( { err } , 'err' ) ; logger . debug ( { fileName } , 'Parsing Docker Compose config YAML' ) ; return null ; } try { const lineMapper = new LineMapper ( content , regEx ( /^\s*image:/ ) ) ; const services = config . services || config ; const deps = Object . values ( services || { } ) . filter ( ( service ) => is . string ( service ?. image ) && ! service ?. build ) . map ( ( service ) => { const dep = getDep ( service . image ) ; const lineNumber = lineMapper . pluckLineNumber ( service . image ) ; if ( ! lineNumber ) { return null ; } return dep ; } ) . filter ( Boolean ) ; logger . trace ( { deps } , 'Docker Compose image' ) ; return { deps } ; } catch ( err ) { logger . warn ( { fileName , content , err } , 'Error extracting Docker Compose file' ) ; return null ; } }