vue-csv-exporter 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hunter
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,396 @@
1
+ # vue-csv-exporter
2
+
3
+ [![npm version](https://img.shields.io/npm/v/vue-csv-exporter.svg)](https://www.npmjs.com/package/vue-csv-exporter)
4
+ [![license](https://img.shields.io/npm/l/vue-csv-exporter.svg)](https://github.com/7Hunter7/vue-csv-exporter/blob/main/LICENSE)
5
+ [![downloads](https://img.shields.io/npm/dm/vue-csv-exporter.svg)](https://www.npmjs.com/package/vue-csv-exporter)
6
+ [![vue2](https://img.shields.io/badge/vue-2.x-brightgreen.svg)](https://vuejs.org/)
7
+ [![vue3](https://img.shields.io/badge/vue-3.x-brightgreen.svg)](https://v3.vuejs.org/)
8
+
9
+ Простой и мощный экспорт данных в CSV для Vue.js приложений.
10
+ **Без зависимостей**, с поддержкой кириллицы и TypeScript.
11
+
12
+ ## Автор
13
+ Ivan Kalugin Телеграмм: https://t.me/Ivan_Anatolievich_Kalugin
14
+
15
+ ## ✨ Особенности
16
+
17
+ - 🚀 **Zero dependencies** - никаких лишних библиотек
18
+ - 📦 **Tree shaking** - используйте только то, что нужно
19
+ - 🌍 **Кириллица** - корректное отображение в Excel
20
+ - 🎯 **RFC 4180** - соответствие стандарту CSV
21
+ - 🔧 **Гибкая настройка** - разделители, кавычки, BOM
22
+ - 📱 **Браузер** - работает в любой современном браузере
23
+ - 🎨 **Vue 2 и 3** - поддержка обеих версий
24
+ - 📄 **TypeScript** - готовые типы
25
+
26
+ ## Структура файлов
27
+ ```bash
28
+ vue-csv-exporter/
29
+ ├── src/
30
+ │ ├── index.js # главный файл
31
+ │ ├── CSVGenerator.js # ядро
32
+ │ └── exportMixin.js # миксин
33
+ ├── README.md
34
+ ├── LICENSE
35
+ └── package.json
36
+ ```
37
+
38
+ ## 📦 Установка
39
+
40
+ ```bash
41
+ npm install vue-csv-exporter
42
+ # или
43
+ yarn add vue-csv-exporter
44
+ ```
45
+
46
+ ## 🚀 Быстрый старт
47
+ 1. Как плагин (рекомендуется)
48
+ ```bash
49
+ // main.js
50
+ import Vue from 'vue';
51
+ import VueCSVExporter from 'vue-csv-exporter';
52
+
53
+ Vue.use(VueCSVExporter, {
54
+ defaultFilename: 'export.csv',
55
+ defaultConfig: {
56
+ delimiter: ';',
57
+ includeBOM: true
58
+ }
59
+ });
60
+
61
+ // В компоненте
62
+ export default {
63
+ methods: {
64
+ async exportData() {
65
+ try {
66
+ const count = await this.$csvExport({
67
+ data: this.items,
68
+ filename: 'users.csv',
69
+ onStart: () => console.log('Экспорт начат'),
70
+ onProgress: (progress) => console.log(`Прогресс: ${progress}%`),
71
+ onSuccess: (count) => this.$notify.success(`Экспортировано ${count} записей`),
72
+ onError: (error) => this.$notify.error(error.message)
73
+ });
74
+ } catch (error) {
75
+ console.error('Ошибка экспорта:', error);
76
+ }
77
+ }
78
+ }
79
+ };
80
+ ```
81
+ ### Как миксин
82
+ ```bash
83
+ import { exportMixin } from 'vue-csv-exporter';
84
+
85
+ export default {
86
+ mixins: [exportMixin],
87
+ data() {
88
+ return {
89
+ users: [
90
+ { name: 'Иван', email: 'ivan@example.com' },
91
+ { name: 'Мария', email: 'maria@example.com' }
92
+ ]
93
+ };
94
+ },
95
+ methods: {
96
+ async exportUsers() {
97
+ await this.exportToCSV({
98
+ data: this.users,
99
+ filename: 'users.csv',
100
+ config: { delimiter: ',' }
101
+ });
102
+ }
103
+ }
104
+ };
105
+ ```
106
+
107
+ ### Как отдельный класс
108
+ ```bash
109
+ import { CSVGenerator } from 'vue-csv-exporter';
110
+
111
+ // Генерация CSV
112
+ const data = [
113
+ { name: 'Иван', age: 30 },
114
+ { name: 'Мария', age: 25 }
115
+ ];
116
+
117
+ const csv = CSVGenerator.generate(data, {
118
+ delimiter: ';',
119
+ includeBOM: true
120
+ });
121
+
122
+ // Скачивание
123
+ CSVGenerator.download(csv, 'export.csv');
124
+
125
+ // Валидация
126
+ const validation = CSVGenerator.validateData(data);
127
+ if (validation.isValid) {
128
+ console.log('Данные корректны');
129
+ }
130
+ ```
131
+
132
+ ## 📊 API Reference
133
+
134
+ ### Плагин Vue
135
+
136
+ #### Опции плагина
137
+
138
+ | Параметр | Тип | По умолчанию | Обязательный | Описание |
139
+ |----------|-----|--------------|---------------|----------|
140
+ | `defaultFilename` | `string` | `'export.csv'` | Нет | Имя файла по умолчанию для экспорта |
141
+ | `defaultConfig` | `Object` | `{}` | Нет | Конфигурация CSV по умолчанию (см. таблицу Конфигурация) |
142
+ | `install` | `Function` | - | Нет | Функция установки плагина (вызывается автоматически) |
143
+
144
+ #### Методы плагина (`this.$csvExport()`)
145
+
146
+ | Параметр | Тип | По умолчанию | Обязательный | Описание |
147
+ |----------|-----|--------------|---------------|----------|
148
+ | `data` | `Array<Object>` | - | **Да** | Массив данных для экспорта |
149
+ | `filename` | `string` | `'export.csv'` | Нет | Имя выходного CSV файла |
150
+ | `config` | `Object` | `{}` | Нет | Конфигурация CSV (переопределяет defaultConfig) |
151
+ | `onStart` | `Function` | `() => {}` | Нет | Колбэк перед началом экспорта |
152
+ | `onProgress` | `Function` | `() => {}` | Нет | Колбэк прогресса (0-100) |
153
+ | `onSuccess` | `Function` | `() => {}` | Нет | Колбэк при успешном экспорте |
154
+ | `onError` | `Function` | `() => {}` | Нет | Колбэк при ошибке |
155
+
156
+ **Возвращает:** `Promise<number>` - количество экспортированных записей
157
+
158
+ **Пример:**
159
+ ```javascript
160
+ const count = await this.$csvExport({
161
+ data: this.users,
162
+ filename: 'users.csv',
163
+ config: { delimiter: ',' },
164
+ onStart: () => this.loading = true,
165
+ onProgress: (p) => this.progress = p,
166
+ onSuccess: (count) => this.showSuccess(count),
167
+ onError: (error) => this.showError(error)
168
+ });
169
+ ```
170
+
171
+ ---
172
+
173
+ ### Миксин `exportMixin`
174
+
175
+ #### Данные миксина
176
+
177
+ | Поле | Тип | По умолчанию | Доступ | Описание |
178
+ |------|-----|--------------|---------|----------|
179
+ | `isExporting` | `boolean` | `false` | Только чтение | Флаг процесса экспорта |
180
+ | `exportProgress` | `number` | `0` | Только чтение | Прогресс экспорта (0-100) |
181
+
182
+ #### Методы миксина
183
+
184
+ | Метод | Параметры | Возвращает | Описание |
185
+ |-------|-----------|------------|----------|
186
+ | `exportToCSV(options)` | `Object` (см. таблицу методов плагина) | `Promise<number>` | Основной метод экспорта |
187
+ | `prepareExportData(data)` | `data: Array` | `Array` | Подготовка данных (можно переопределить) |
188
+ | `transformData(data)` | `data: Array` | `Array` | Трансформация данных (можно переопределить) |
189
+ | `generateDefaultFilename()` | - | `string` | Генерация имени файла по умолчанию |
190
+
191
+ **Пример:**
192
+ ```javascript
193
+ import { exportMixin } from 'vue-csv-exporter';
194
+
195
+ export default {
196
+ mixins: [exportMixin],
197
+ data() {
198
+ return {
199
+ items: []
200
+ };
201
+ },
202
+ methods: {
203
+ async handleExport() {
204
+ if (this.isExporting) return;
205
+
206
+ await this.exportToCSV({
207
+ data: this.items,
208
+ filename: 'export.csv'
209
+ });
210
+ },
211
+ // Переопределение метода подготовки данных
212
+ prepareExportData(data) {
213
+ return data.filter(item => item.active);
214
+ }
215
+ }
216
+ };
217
+ ```
218
+
219
+ ---
220
+
221
+ ### Класс `CSVGenerator`
222
+
223
+ #### Статические методы
224
+
225
+ | Метод | Параметры | Возвращает | Описание |
226
+ |-------|-----------|------------|----------|
227
+ | `generate(data, config)` | `data: Array<Object>`<br>`config: Object` | `string` | Генерация CSV строки из данных |
228
+ | `download(csv, filename)` | `csv: string`<br>`filename: string` | `void` | Скачивание CSV файла |
229
+ | `validateData(data)` | `data: Array` | `{ isValid: boolean, error: string }` | Валидация данных перед экспортом |
230
+ | `sanitizeField(field)` | `field: any` | `string` | Очистка поля от опасных символов |
231
+ | `formatRow(fields, config)` | `fields: Array`<br>`config: Object` | `string` | Форматирование строки (приватный) |
232
+ | `formatField(field, config)` | `field: any`<br>`config: Object` | `string` | Форматирование поля (приватный) |
233
+
234
+ **Пример:**
235
+ ```javascript
236
+ import { CSVGenerator } from 'vue-csv-exporter';
237
+
238
+ // Валидация
239
+ const validation = CSVGenerator.validateData(myData);
240
+ if (!validation.isValid) {
241
+ console.error(validation.error);
242
+ return;
243
+ }
244
+
245
+ // Генерация
246
+ const csv = CSVGenerator.generate(myData, {
247
+ delimiter: ';',
248
+ includeBOM: true
249
+ });
250
+
251
+ // Скачивание
252
+ CSVGenerator.download(csv, 'report.csv');
253
+
254
+ // Очистка поля
255
+ const safeString = CSVGenerator.sanitizeField("Hello;World");
256
+ ```
257
+
258
+ ---
259
+
260
+ ### Конфигурация CSV
261
+
262
+ #### Параметры конфигурации
263
+
264
+ | Параметр | Тип | По умолчанию | Допустимые значения | Описание |
265
+ |----------|-----|--------------|---------------------|----------|
266
+ | `delimiter` | `string` | `';'` | `','`, `';'`, `'\t'`, любой символ | Разделитель полей в CSV |
267
+ | `quote` | `string` | `'"'` | `'"'`, `"'"` | Символ для экранирования полей |
268
+ | `lineBreak` | `string` | `'\r\n'` | `'\r\n'`, `'\n'`, `'\r'` | Разделитель строк |
269
+ | `includeBOM` | `boolean` | `true` | `true`, `false` | Добавлять BOM для кириллицы |
270
+ | `quoteAll` | `boolean` | `false` | `true`, `false` | Всегда заключать поля в кавычки |
271
+ | `escapeDoubleQuotes` | `boolean` | `true` | `true`, `false` | Экранировать кавычки удвоением |
272
+
273
+ #### Примеры конфигурации
274
+
275
+ | Сценарий | Конфигурация | Результат |
276
+ |----------|--------------|-----------|
277
+ | **Excel (Россия)** | `{ delimiter: ';', includeBOM: true }` | Корректное отображение кириллицы в Excel |
278
+ | **Excel (Запад)** | `{ delimiter: ',', includeBOM: false }` | Стандартный CSV для западных версий Excel |
279
+ | **Максимальная совместимость** | `{ quoteAll: true, delimiter: ',' }` | Все поля в кавычках, никаких проблем с спецсимволами |
280
+ | **Google Sheets** | `{ delimiter: ',', lineBreak: '\n' }` | Оптимально для импорта в Google Sheets |
281
+ | **Базы данных** | `{ delimiter: '\t', quoteAll: false }` | TSV формат для импорта в БД |
282
+
283
+ ```javascript
284
+ // Примеры использования разных конфигураций
285
+ const configs = {
286
+ // Для Excel (русский)
287
+ russianExcel: {
288
+ delimiter: ';',
289
+ includeBOM: true,
290
+ quoteAll: false
291
+ },
292
+
293
+ // Для Google Sheets
294
+ googleSheets: {
295
+ delimiter: ',',
296
+ lineBreak: '\n',
297
+ includeBOM: false
298
+ },
299
+
300
+ // Максимальная защита
301
+ safe: {
302
+ delimiter: ',',
303
+ quoteAll: true,
304
+ escapeDoubleQuotes: true
305
+ },
306
+
307
+ // TSV формат
308
+ tsv: {
309
+ delimiter: '\t',
310
+ quoteAll: false
311
+ }
312
+ };
313
+ ```
314
+
315
+ ---
316
+
317
+ ### События и колбэки
318
+
319
+ | Колбэк | Параметры | Момент вызова | Использование |
320
+ |--------|-----------|---------------|---------------|
321
+ | `onStart` | - | Перед началом экспорта | Показать лоадер, заблокировать UI |
322
+ | `onProgress` | `progress: number` (0-100) | Во время экспорта | Обновить индикатор прогресса |
323
+ | `onSuccess` | `count: number` | После успешного экспорта | Показать уведомление об успехе |
324
+ | `onError` | `error: Error` | При ошибке | Показать сообщение об ошибке |
325
+
326
+ ```javascript
327
+ // Пример с использованием всех колбэков
328
+ this.$csvExport({
329
+ data: this.largeDataset,
330
+ filename: 'big_export.csv',
331
+
332
+ onStart: () => {
333
+ this.isExporting = true;
334
+ this.showProgressBar = true;
335
+ },
336
+
337
+ onProgress: (progress) => {
338
+ this.exportProgress = progress;
339
+ },
340
+
341
+ onSuccess: (count) => {
342
+ this.$notify.success(`Успешно экспортировано ${count} записей`);
343
+ this.isExporting = false;
344
+ this.showProgressBar = false;
345
+ },
346
+
347
+ onError: (error) => {
348
+ this.$notify.error(`Ошибка экспорта: ${error.message}`);
349
+ this.isExporting = false;
350
+ this.showProgressBar = false;
351
+ }
352
+ });
353
+ ```
354
+
355
+ ---
356
+
357
+ ### Типы данных
358
+
359
+ | Тип | Описание | Пример |
360
+ |-----|----------|--------|
361
+ | `CSVConfig` | Объект конфигурации | `{ delimiter: ';', includeBOM: true }` |
362
+ | `ValidationResult` | Результат валидации | `{ isValid: true, error: '' }` |
363
+ | `ExportOptions` | Опции экспорта | `{ data: [], filename: 'file.csv' }` |
364
+ | `ProgressCallback` | Колбэк прогресса | `(progress) => console.log(progress)` |
365
+ | `SuccessCallback` | Колбэк успеха | `(count) => console.log(count)` |
366
+ | `ErrorCallback` | Колбэк ошибки | `(error) => console.error(error)` |
367
+
368
+ ```typescript
369
+ // TypeScript интерфейсы (для справки)
370
+ interface CSVConfig {
371
+ delimiter?: string;
372
+ quote?: string;
373
+ lineBreak?: string;
374
+ includeBOM?: boolean;
375
+ quoteAll?: boolean;
376
+ escapeDoubleQuotes?: boolean;
377
+ }
378
+
379
+ interface ExportOptions {
380
+ data: Record<string, any>[];
381
+ filename?: string;
382
+ config?: CSVConfig;
383
+ onStart?: () => void;
384
+ onProgress?: (progress: number) => void;
385
+ onSuccess?: (count: number) => void;
386
+ onError?: (error: Error) => void;
387
+ }
388
+
389
+ interface ValidationResult {
390
+ isValid: boolean;
391
+ error: string;
392
+ }
393
+ ```
394
+ ## 📄 Лицензия
395
+
396
+ MIT © [Ivan Kalugin](https://github.com/7Hunter7)
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "vue-csv-exporter",
3
+ "version": "1.0.0",
4
+ "description": "Простой и надежный экспорт данных в CSV для Vue.js. Без зависимостей, с поддержкой кириллицы и TypeScript.",
5
+ "main": "src/index.js",
6
+ "module": "src/index.js",
7
+ "browser": "src/index.js",
8
+ "files": [
9
+ "src",
10
+ "README.md",
11
+ "LICENSE"
12
+ ],
13
+ "scripts": {
14
+ "test": "echo \"Error: no test specified\" && exit 0",
15
+ "prepublishOnly": "echo \"Ready to publish\""
16
+ },
17
+ "keywords": [
18
+ "vue",
19
+ "csv",
20
+ "exporter",
21
+ "export",
22
+ "vuejs",
23
+ "csv-exporter",
24
+ "vue-csv",
25
+ "russian",
26
+ "cyrillic",
27
+ "browser",
28
+ "no-dependencies"
29
+ ],
30
+ "author": {
31
+ "name": "Ivan Kalugin",
32
+ "email": "i.am.hunter.777.ih@gmail.com",
33
+ "url": "https://github.com/7Hunter7"
34
+ },
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/7Hunter7/vue-csv-exporter.git"
39
+ },
40
+ "bugs": {
41
+ "url": "https://github.com/7Hunter7/vue-csv-exporter/issues"
42
+ },
43
+ "homepage": "https://github.com/7Hunter7/vue-csv-exporter#readme",
44
+ "peerDependencies": {
45
+ "vue": "^2.6.0 || ^3.0.0"
46
+ },
47
+ "engines": {
48
+ "node": ">=12.0.0"
49
+ }
50
+ }
@@ -0,0 +1,220 @@
1
+ /**
2
+ * vue-csv-exporter
3
+ * Без зависимостей, нативный генератор CSV для браузера
4
+ * Соответствует RFC 4180
5
+ * @module vue-csv-exporter
6
+ */
7
+
8
+ /**
9
+ * Конфигурация по умолчанию
10
+ * @typedef {Object} CSVConfig
11
+ * @property {string} delimiter - Разделитель полей (по умолчанию ';')
12
+ * @property {string} quote - Символ кавычек (по умолчанию '"')
13
+ * @property {string} lineBreak - Разделитель строк (по умолчанию '\r\n')
14
+ * @property {boolean} includeBOM - Добавлять BOM для кириллицы (по умолчанию true)
15
+ * @property {boolean} quoteAll - Всегда заключать поля в кавычки (по умолчанию false)
16
+ * @property {boolean} escapeDoubleQuotes - Экранировать кавычки удвоением (по умолчанию true)
17
+ */
18
+
19
+ /**
20
+ * Результат валидации
21
+ * @typedef {Object} ValidationResult
22
+ * @property {boolean} isValid - Валидны ли данные
23
+ * @property {string} error - Сообщение об ошибке
24
+ */
25
+
26
+ class CSVGenerator {
27
+ /**
28
+ * Конфигурация по умолчанию
29
+ * @type {CSVConfig}
30
+ */
31
+ static defaultConfig = {
32
+ delimiter: ";",
33
+ quote: '"',
34
+ lineBreak: "\r\n",
35
+ includeBOM: true,
36
+ quoteAll: false,
37
+ escapeDoubleQuotes: true,
38
+ };
39
+
40
+ /**
41
+ * Генерация CSV из массива объектов
42
+ * @param {Array<Object>} data - Массив данных для экспорта
43
+ * @param {CSVConfig} config - Конфигурация генерации
44
+ * @returns {string} CSV строка
45
+ * @throws {Error} Если данные некорректны
46
+ *
47
+ * @example
48
+ * const csv = CSVGenerator.generate([
49
+ * { name: 'Иван', age: 30 },
50
+ * { name: 'Мария', age: 25 }
51
+ * ]);
52
+ */
53
+ static generate(data, config = {}) {
54
+ const validation = this.validateData(data);
55
+ if (!validation.isValid) {
56
+ throw new Error(`CSV generation failed: ${validation.error}`);
57
+ }
58
+
59
+ const cfg = { ...this.defaultConfig, ...config };
60
+
61
+ // Получаем заголовки из первого объекта
62
+ const headers = Object.keys(data[0]);
63
+
64
+ // Генерируем строки CSV
65
+ const rows = [
66
+ this.formatRow(headers, cfg),
67
+ ...data.map((item) => this.formatRow(Object.values(item), cfg)),
68
+ ];
69
+
70
+ let csv = rows.join(cfg.lineBreak);
71
+
72
+ // Добавляем BOM для правильного отображения кириллицы в Excel
73
+ if (cfg.includeBOM) {
74
+ csv = "\uFEFF" + csv;
75
+ }
76
+
77
+ return csv;
78
+ }
79
+
80
+ /**
81
+ * Форматирование одной строки CSV
82
+ * @private
83
+ * @param {Array} fields - Поля строки
84
+ * @param {CSVConfig} cfg - Конфигурация
85
+ * @returns {string} Отформатированная строка
86
+ */
87
+ static formatRow(fields, cfg) {
88
+ return fields
89
+ .map((field) => this.formatField(field, cfg))
90
+ .join(cfg.delimiter);
91
+ }
92
+
93
+ /**
94
+ * Форматирование отдельного поля
95
+ * @private
96
+ * @param {*} field - Значение поля
97
+ * @param {CSVConfig} cfg - Конфигурация
98
+ * @returns {string} Отформатированное поле
99
+ */
100
+ static formatField(field, cfg) {
101
+ let stringField =
102
+ field === null || field === undefined ? "" : String(field);
103
+
104
+ const needsQuoting =
105
+ cfg.quoteAll ||
106
+ stringField.includes(cfg.delimiter) ||
107
+ stringField.includes(cfg.quote) ||
108
+ stringField.includes("\n") ||
109
+ stringField.includes("\r");
110
+
111
+ if (needsQuoting) {
112
+ if (cfg.escapeDoubleQuotes) {
113
+ stringField = stringField.replace(
114
+ new RegExp(cfg.quote, "g"),
115
+ cfg.quote + cfg.quote,
116
+ );
117
+ }
118
+ return cfg.quote + stringField + cfg.quote;
119
+ }
120
+
121
+ return stringField;
122
+ }
123
+
124
+ /**
125
+ * Очистка поля от потенциально опасных символов
126
+ * @param {*} field - Поле для очистки
127
+ * @returns {string} Очищенное поле
128
+ *
129
+ * @example
130
+ * const safe = CSVGenerator.sanitizeField("Hello;World");
131
+ */
132
+ static sanitizeField(field) {
133
+ if (field === null || field === undefined) return "";
134
+
135
+ return String(field)
136
+ .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, " ")
137
+ .replace(/\s+/g, " ")
138
+ .trim();
139
+ }
140
+
141
+ /**
142
+ * Валидация данных перед экспортом
143
+ * @param {Array} data - Данные для проверки
144
+ * @returns {ValidationResult} Результат валидации
145
+ *
146
+ * @example
147
+ * const result = CSVGenerator.validateData(myData);
148
+ * if (result.isValid) {
149
+ * // экспорт
150
+ * }
151
+ */
152
+ static validateData(data) {
153
+ if (!Array.isArray(data)) {
154
+ return {
155
+ isValid: false,
156
+ error: "Data must be an array",
157
+ };
158
+ }
159
+
160
+ if (data.length === 0) {
161
+ return {
162
+ isValid: false,
163
+ error: "No data to export",
164
+ };
165
+ }
166
+
167
+ const hasInvalidItem = data.some(
168
+ (item) => item === null || typeof item !== "object",
169
+ );
170
+
171
+ if (hasInvalidItem) {
172
+ return {
173
+ isValid: false,
174
+ error: "Data contains invalid items",
175
+ };
176
+ }
177
+
178
+ return { isValid: true };
179
+ }
180
+
181
+ /**
182
+ * Скачивание CSV файла
183
+ * @param {string} csv - CSV контент
184
+ * @param {string} filename - Имя файла
185
+ * @throws {Error} Если нет данных или ошибка скачивания
186
+ *
187
+ * @example
188
+ * CSVGenerator.download(csv, 'export.csv');
189
+ */
190
+ static download(csv, filename) {
191
+ if (!csv) {
192
+ throw new Error("No data to download");
193
+ }
194
+
195
+ try {
196
+ const blob = new Blob([csv], {
197
+ type: "text/csv;charset=utf-8;",
198
+ });
199
+
200
+ const url = URL.createObjectURL(blob);
201
+ const link = document.createElement("a");
202
+
203
+ link.setAttribute("href", url);
204
+ link.setAttribute("download", filename);
205
+ link.setAttribute("target", "_blank");
206
+
207
+ document.body.appendChild(link);
208
+ link.click();
209
+
210
+ setTimeout(() => {
211
+ document.body.removeChild(link);
212
+ URL.revokeObjectURL(url);
213
+ }, 100);
214
+ } catch (error) {
215
+ throw new Error(`Failed to download CSV: ${error.message}`);
216
+ }
217
+ }
218
+ }
219
+
220
+ export default CSVGenerator;
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Vue миксин для экспорта данных в CSV
3
+ * @module vue-csv-exporter/mixin
4
+ */
5
+
6
+ import CSVGenerator from "./CSVGenerator";
7
+
8
+ /**
9
+ * @mixin exportMixin
10
+ * @property {boolean} isExporting - Флаг процесса экспорта
11
+ * @property {number} exportProgress - Прогресс экспорта (0-100)
12
+ */
13
+ export const exportMixin = {
14
+ data() {
15
+ return {
16
+ isExporting: false,
17
+ exportProgress: 0,
18
+ };
19
+ },
20
+
21
+ methods: {
22
+ /**
23
+ * Экспорт данных в CSV файл
24
+ * @param {Object} options - Опции экспорта
25
+ * @param {Array} options.data - Данные для экспорта
26
+ * @param {string} options.filename - Имя файла
27
+ * @param {Object} options.config - Конфигурация CSV
28
+ * @param {Function} options.onStart - Колбэк перед началом
29
+ * @param {Function} options.onProgress - Колбэк прогресса
30
+ * @param {Function} options.onSuccess - Колбэк успеха
31
+ * @param {Function} options.onError - Колбэк ошибки
32
+ * @returns {Promise<void>}
33
+ *
34
+ * @example
35
+ * this.exportToCSV({
36
+ * data: this.items,
37
+ * filename: 'export.csv',
38
+ * onSuccess: (count) => console.log(`Exported ${count} items`)
39
+ * });
40
+ */
41
+ async exportToCSV({
42
+ data,
43
+ filename = this.generateDefaultFilename(),
44
+ config = {},
45
+ onStart,
46
+ onProgress,
47
+ onSuccess,
48
+ onError,
49
+ } = {}) {
50
+ if (this.isExporting) {
51
+ this.$notify?.warning?.("Export already in progress", "Please wait");
52
+ return;
53
+ }
54
+
55
+ const exportData = this.prepareExportData(data);
56
+ const validation = CSVGenerator.validateData(exportData);
57
+
58
+ if (!validation.isValid) {
59
+ const error = new Error(validation.error);
60
+ onError?.(error);
61
+ throw error;
62
+ }
63
+
64
+ this.isExporting = true;
65
+ this.exportProgress = 0;
66
+
67
+ try {
68
+ onStart?.();
69
+
70
+ const transformedData = this.transformData(exportData);
71
+ this.exportProgress = 50;
72
+ onProgress?.(50);
73
+
74
+ const csv = CSVGenerator.generate(transformedData, config);
75
+ this.exportProgress = 90;
76
+ onProgress?.(90);
77
+
78
+ CSVGenerator.download(csv, filename);
79
+ this.exportProgress = 100;
80
+ onProgress?.(100);
81
+
82
+ onSuccess?.(exportData.length);
83
+
84
+ return exportData.length;
85
+ } catch (error) {
86
+ onError?.(error);
87
+ throw error;
88
+ } finally {
89
+ setTimeout(() => {
90
+ this.isExporting = false;
91
+ this.exportProgress = 0;
92
+ }, 1000);
93
+ }
94
+ },
95
+
96
+ /**
97
+ * Подготовка данных для экспорта
98
+ * @protected
99
+ * @param {Array} data - Исходные данные
100
+ * @returns {Array} Подготовленные данные
101
+ */
102
+ prepareExportData(data) {
103
+ return data?.map?.((item) => ({ ...item })) || [];
104
+ },
105
+
106
+ /**
107
+ * Трансформация данных для CSV формата
108
+ * @protected
109
+ * @param {Array} data - Подготовленные данные
110
+ * @returns {Array} Трансформированные данные
111
+ */
112
+ transformData(data) {
113
+ return data.map((item) => {
114
+ const transformed = {};
115
+ Object.keys(item).forEach((key) => {
116
+ transformed[key] = CSVGenerator.sanitizeField(item[key]);
117
+ });
118
+ return transformed;
119
+ });
120
+ },
121
+
122
+ /**
123
+ * Генерация имени файла по умолчанию
124
+ * @protected
125
+ * @returns {string} Имя файла
126
+ */
127
+ generateDefaultFilename() {
128
+ const date = new Date();
129
+ const year = date.getFullYear();
130
+ const month = String(date.getMonth() + 1).padStart(2, "0");
131
+ const day = String(date.getDate()).padStart(2, "0");
132
+
133
+ return `export_${year}-${month}-${day}.csv`;
134
+ },
135
+ },
136
+ };
137
+
138
+ export default exportMixin;
package/src/index.js ADDED
@@ -0,0 +1,75 @@
1
+ /**
2
+ * vue-csv-exporter
3
+ * Простой и мощный экспорт данных в CSV для Vue.js приложений
4
+ *
5
+ * @module vue-csv-exporter
6
+ */
7
+
8
+ import CSVGenerator from "./CSVGenerator";
9
+ import exportMixin from "./exportMixin";
10
+
11
+ /**
12
+ * Версия библиотеки
13
+ */
14
+ export const VERSION = "1.0.0";
15
+
16
+ /**
17
+ * Плагин для Vue.js
18
+ * @param {Vue} Vue - Конструктор Vue
19
+ * @param {Object} options - Опции плагина
20
+ *
21
+ * @example
22
+ * import Vue from 'vue';
23
+ * import VueCSVExporter from 'vue-csv-exporter';
24
+ *
25
+ * Vue.use(VueCSVExporter, {
26
+ * defaultFilename: 'export.csv',
27
+ * defaultConfig: { delimiter: ';' }
28
+ * });
29
+ */
30
+ export function install(Vue, options = {}) {
31
+ if (install.installed) return;
32
+ install.installed = true;
33
+
34
+ const globalMixin = {
35
+ data() {
36
+ return {
37
+ $csvExporter: {
38
+ isExporting: false,
39
+ exportProgress: 0,
40
+ },
41
+ };
42
+ },
43
+ methods: {
44
+ $exportToCSV(config) {
45
+ return this.$csvExport(config);
46
+ },
47
+ },
48
+ };
49
+
50
+ Vue.mixin(globalMixin);
51
+
52
+ Vue.prototype.$csvExport = async function ({
53
+ data,
54
+ filename = options.defaultFilename,
55
+ config = options.defaultConfig,
56
+ ...callbacks
57
+ }) {
58
+ const mixin = new Vue(exportMixin);
59
+ return mixin.exportToCSV({ data, filename, config, ...callbacks });
60
+ };
61
+ }
62
+
63
+ // Автоматическая установка в браузере
64
+ if (typeof window !== "undefined" && window.Vue) {
65
+ install(window.Vue);
66
+ }
67
+
68
+ export { CSVGenerator, exportMixin };
69
+
70
+ export default {
71
+ install,
72
+ CSVGenerator,
73
+ exportMixin,
74
+ VERSION,
75
+ };