export type AugmenterMap = { [ keyword ] : string [ ] ; } ; export class DataAugmenter { private readonly KEYWORD_PATTERN = /(\[([^\[\]\(\)]*?)\])(?:[^\(]|$)/ ; constructor ( readonly augmenter , readonly entities ) { } augment ( sentences ) { return sentences . map ( s => this . augmentSentence ( s ) ) . reduce ( ( augmentedSentences , augmentations ) => augmentedSentences . concat ( augmentations ) , [ ] ) ; } private augmentSentence ( sentence ) { const finalSentences = [ ] ; let unprocessedSentences = [ sentence ] ; while ( unprocessedSentences . length > 0 ) { const processedSentence = unprocessedSentences . pop ( ) ; const variations = this . generateVariations ( processedSentence ) ; if ( variations . length == 0 ) { finalSentences . push ( processedSentence ) ; } else { unprocessedSentences = unprocessedSentences . concat ( variations ) ; } } return finalSentences ; } private generateVariations ( sentence ) { const match = this . KEYWORD_PATTERN . exec ( sentence ) ; if ( match ) { const start = match . index ; const definition = match [ 1 ] ; const keyword = match [ 2 ] ; if ( keyword in this . augmenter ) { return this . augmenter [ keyword ] . map ( word => this . createVariation ( sentence , word , start , definition , keyword ) ) ; } else { throw new Error ( `Unable to augment the data. Undefined keyword '${ keyword }'` ) ; } } return [ ] ; } private createVariation ( sentence , word , start , definition , keyword ) { return sentence . slice ( 0 , start ) . concat ( this . entities . includes ( keyword ) ? `[${ word }](${ keyword })` : word , sentence . slice ( start + definition . length ) ) ; } }