• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IgniteUI / igniteui-angular / 20961384596

13 Jan 2026 02:57PM UTC coverage: 91.53%. First build
20961384596

Pull #16746

github

web-flow
Merge c83357fa2 into 44f1ec7c9
Pull Request #16746: fix(csv): export summaries - master

14290 of 16840 branches covered (84.86%)

22 of 23 new or added lines in 2 files covered. (95.65%)

28701 of 31357 relevant lines covered (91.53%)

34857.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.24
/projects/igniteui-angular/grids/core/src/services/csv/char-separated-value-data.ts
1
import { ExportUtilities } from '../exporter-common/export-utilities';
2
import { IColumnInfo } from '../exporter-common/base-export-service';
3
import { yieldingLoop } from 'igniteui-angular/core';
4

5
/**
6
 * @hidden
7
 */
8
export class CharSeparatedValueData {
9
    private _headerRecord = '';
86✔
10
    private _dataRecords = '';
86✔
11
    private _eor = '\r\n';
86✔
12
    private _delimiter;
13
    private _escapeCharacters = ['\r', '\n', '\r\n'];
86✔
14
    private _delimiterLength = 1;
86✔
15
    private _isSpecialData = false;
86✔
16

17
    constructor(private _data: any[], valueDelimiter: string, private columns: IColumnInfo[] = [])  {
86✔
18
        this.setDelimiter(valueDelimiter);
86✔
19
    }
20

21
    public prepareData(key?: any[]) {
22
        if (!this._data || this._data.length === 0) {
9✔
23
            return '';
1✔
24
        }
25
        let keys = [];
8✔
26
        if (key){
8!
27
            keys = key;
×
28
        }else {
29
            keys = ExportUtilities.getKeysFromData(this._data);
8✔
30
        }
31

32
        if (keys.length === 0) {
8!
33
            return '';
×
34
        }
35

36
        this._isSpecialData = ExportUtilities.isSpecialData(this._data[0]);
8✔
37
        this._escapeCharacters.push(this._delimiter);
8✔
38

39
        this._headerRecord = this.processHeaderRecord(keys, this._data.length);
8✔
40
        this._dataRecords = this.processDataRecords(this._data, keys);
8✔
41

42
        return this._headerRecord + this._dataRecords;
8✔
43
    }
44

45
    public prepareDataAsync(done: (result: string) => void, alwaysExportHeaders: boolean = true) {
×
46
        const columns = this.columns?.filter(c => !c.skip)
205✔
47
                        .sort((a, b) => a.startIndex - b.startIndex)
161✔
48
                        .sort((a, b) => a.pinnedIndex - b.pinnedIndex);
161✔
49
        const keys = columns && columns.length ? columns.map(c => c.field) : ExportUtilities.getKeysFromData(this._data);
199✔
50

51
        if (this._data && this._data.length > 0) {
77✔
52
            this._isSpecialData = ExportUtilities.isSpecialData(this._data[0]);
71✔
53
        }
54
        this._escapeCharacters.push(this._delimiter);
77✔
55

56
        const headers = columns && columns.length ?
77✔
57
                        columns.map(c => c.header ?? c.field) :
199!
58
                        keys;
59

60
        this._headerRecord = this.processHeaderRecord(headers, this._data.length);
77✔
61
        if (keys.length === 0 || ((!this._data || this._data.length === 0) && keys.length === 0)) {
77✔
62
            // If alwaysExportHeaders is true and we have headers, export headers only
63
            if (alwaysExportHeaders && headers && headers.length > 0) {
8!
NEW
64
                done(this._headerRecord);
×
65
            } else {
66
                done('');
8✔
67
            }
68
        } else {
69
            this.processDataRecordsAsync(this._data, keys, (dr) => {
69✔
70
                done(this._headerRecord + dr);
69✔
71
            });
72
        }
73
    }
74

75
    private processField(value, escapeChars): string {
76
        let safeValue = ExportUtilities.hasValue(value) ? String(value) : '';
1,758✔
77
        if (escapeChars.some((v) => safeValue.includes(v))) {
7,017✔
78
            safeValue = `"${safeValue}"`;
16✔
79
        }
80
        return safeValue + this._delimiter;
1,758✔
81
    }
82

83
    private processHeaderRecord(keys, dataLength): string {
84
        let recordData = '';
85✔
85
        for (const keyName of keys) {
85✔
86
            recordData += this.processField(keyName, this._escapeCharacters);
214✔
87
        }
88

89
        const result = recordData.slice(0, -this._delimiterLength);
85✔
90

91
        return dataLength > 0 ? result + this._eor : result;
85✔
92
    }
93

94
    private processRecord(record, keys): string {
95
        const recordData = new Array(keys.length);
496✔
96
        for (let index = 0; index < keys.length; index++) {
496✔
97
            const value = (record[keys[index]] !== undefined) ? record[keys[index]] : this._isSpecialData ? record : '';
1,544✔
98
            recordData[index] = this.processField(value, this._escapeCharacters);
1,544✔
99
        }
100

101
        return recordData.join('').slice(0, -this._delimiterLength) + this._eor;
496✔
102
    }
103

104
    private processDataRecords(currentData, keys) {
105
        const dataRecords = new Array(currentData.length);
8✔
106

107
        for (let i = 0; i < currentData.length; i++) {
8✔
108
            const row = currentData[i];
18✔
109
            dataRecords[i] = this.processRecord(row, keys);
18✔
110
        }
111

112
        return dataRecords.join('');
8✔
113
    }
114

115
    private processDataRecordsAsync(currentData, keys, done: (result: string) => void) {
116
        const dataRecords = new Array(currentData.length);
69✔
117

118
        yieldingLoop(currentData.length, 1000,
69✔
119
            (i) => {
120
                const row = currentData[i];
478✔
121
                dataRecords[i] = this.processRecord(row, keys);
478✔
122
            },
123
            () => {
124
                done(dataRecords.join(''));
69✔
125
            });
126
    }
127

128
    private setDelimiter(value) {
129
        this._delimiter = value;
86✔
130
        this._delimiterLength = value.length;
86✔
131
    }
132
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc