import * as fs from 'fs' ; import * as path from 'path' ; import { escapeDoubleQuotesForCsv , escapeEndOfLineForCsv , unescapeEndOfLineFromCsv } from './utils/workspace-util' ; const { v4 : uuidv4 , validate : uuidValidate } = require ( 'uuid' ) ; /**
 * Comment structure
 *
 * **Attention!**
 * For every stored property added:
 * 1. Append it to CsvStructure.headers array.
 * 2. Add an entry to CsvStructure.defaults.
 * 3. Add an entry to CsvStructure.serializers (optional).
 * 4. Update createCommentFromObject() (optional).
 */ export interface CsvEntry { sha : string ; filename : string ; url : string ; lines : string ; title : string ; comment : string ; priority : number ; category : string ; additional : string ; code ? : string ; /** Unique identifier of the entry */ id : string ; /** Private state of the entry
     * 0 = public
     * 1 = private
     */ private : number ; } param object return export function createCommentFromObject ( object ) { if ( typeof object !== 'string' ) { object = JSON . stringify ( object ) ; } const comment = JSON . parse ( object ) as CsvEntry ; comment . id = CsvStructure . getDefaultValue ( 'id' ) ! ; return comment ; } /**
 * CSV file storage helpers
 */ export class CsvStructure { public static readonly separator = ',' ; /**
     * Columns stored in the CSV file
     *
     * **Attention!**
     * - Every new property of CsvEntry to be stored must be added to the end of the array.
     * - A deprecated stored property can't be removed from the array.
     */ private static readonly headers : string [ ] = [ 'sha' , 'filename' , 'url' , 'lines' , 'title' , 'comment' , 'priority' , 'category' , 'additional' , 'id' , 'private' , ] ; /**
     * Map of default property values builders
     *
     * **Attention!**
     * Any stored property added to CsvEntry **must** have a corresponding entry in this map.
     */ private static readonly defaults : Map < string , ( ) => any > = new Map ( [ [ 'id' , ( ) => uuidv4 ( ) ] , [ 'private' , ( ) => 0 ] , ] ) ; /**
     * Map of transformations to apply before storage
     *
     * **Attention!**
     * Any stored property added to CsvEntry **may** have a corresponding entry in this map.
     */ private static readonly serializers : Map < string , ( value : any ) => any > = new Map ( [ [ 'comment' , ( comment ) => ( comment ? escapeEndOfLineForCsv ( escapeDoubleQuotesForCsv ( comment ) ) : '' ) ] , [ 'title' , ( title ) => ( title ? escapeDoubleQuotesForCsv ( title ) : '' ) ] , [ 'priority' , ( priority ) => priority || 0 ] , [ 'additional' , ( additional ) => ( additional ? escapeDoubleQuotesForCsv ( additional ) : '' ) ] , [ 'category' , ( category ) => category || '' ] , [ 'private' , ( priv ) => priv || 0 ] , ] ) ; param comment param workspaceRoot return public static isValidComment ( comment , workspaceRoot = undefined ) { let isValid = comment && ( comment [ 'comment' ] ?. length ?? 0 ) > 0 && ( comment [ 'filename' ] ?. length ?? 0 ) > 0 && ( comment [ 'lines' ] ?. match ( /^(\d+:\d+-\d+:\d+)(\|(\d+:\d+-\d+:\d+))*$/gm ) ?? false ) && uuidValidate ( comment [ 'id' ] ?? '' ) ; if ( isValid && workspaceRoot ) { const filename = path . join ( workspaceRoot , comment [ 'filename' ] ) ; isValid &&= fs . existsSync ( filename ) ; } return isValid ; } /**
     * Get the header of a CSV file
     */ public static get headerLine ( ) : string { return CsvStructure . headers . join ( CsvStructure . separator ) ; } param column return public static getDefaultValue ( column ) { return CsvStructure . defaults . get ( column ) ?. ( ) ; } param comment return public static formatAsCsvLine ( comment ) { const dict = JSON . parse ( JSON . stringify ( comment ) ) ; let columns = [ ] ; for ( const property of CsvStructure . headers ) { let value = dict [ property ] ; value = CsvStructure . serializers . get ( property ) ?. ( dict [ property ] ) ?? value ; columns . push ( `"${ value ?? '' }"` ) ; } return columns . join ( CsvStructure . separator ) ; } param comment return public static finalizeParse ( comment ) { comment . comment = unescapeEndOfLineFromCsv ( comment . comment ) ; comment . priority = Number ( comment . priority ) ; comment . private = Number ( comment . private ) ; return comment ; } }