@set2333/upload-script-helpers
Version:
Helper library for upload scripts
529 lines (424 loc) • 15 kB
Markdown
# Upload Scripts Helpers
Набор утилит для загрузки и обработки данных для дальнейшей обработки в Pentaho.
## Установка
```bash
npm install @set2333/upload-script-helpers
```
## Требования
- Node.js >= 12.0.0
## Быстрый старт
```typescript
import {
EmailManager,
FileManager,
Logger,
ParserXLS,
Validator,
ApiManager,
JsonMapper
} from '@set2333/upload-script-helpers'
// Создание логгера
const logger = new Logger({
displayTypes: ['console', { type: 'file', options: { logFile: 'app.log' } }]
})
// Управление файлами
const fileManager = new FileManager({
workDirectory: './work-dir',
logger
})
// Работа с API
const apiManager = new ApiManager({
baseUrl: 'https://api.example.com',
headers: { 'Authorization': 'Bearer token' }
})
// Получение данных
const apiData = await apiManager.fetch({ page: 1, limit: 100 })
// Сохранение данных
fileManager.saveJSONFile(apiData, 'api-response.json')
```
## Модули
### Logger
Система логирования с поддержкой консоли и файлов.
**Опции:**
- `messageTypes` - типы сообщений для логирования: `['log', 'warn', 'error']`
- `displayTypes` - способы вывода: `['console']` или `[{ type: 'file', options: { logFile: 'app.log', logDir: './logs' } }]`
**Методы:**
- `log(message: string, ...args: unknown[])` - обычное сообщение
- `warn(message: string, ...args: unknown[])` - предупреждение
- `error(message: string, ...args: unknown[])` - ошибка
- `start(message: string)` - начало процесса с временной меткой
- `end(message: string)` - конец процесса с временной меткой
- `duration(processName: string)` - длительность процесса
**Пример:**
```typescript
const logger = new Logger({
displayTypes: [
'console',
{ type: 'file', options: { logFile: 'app.log', logDir: './logs' } }
]
})
logger.start('Обработка данных')
logger.log('Загружаем файл...')
logger.warn('Файл большой, это может занять время')
logger.duration('Обработка данных')
logger.end('Обработка завершена')
```
### FileManager
Управление файлами и рабочими директориями.
**Опции:**
- `workDirectory` (string) - путь к рабочей директории
- `logger` (ILogger | null) - логгер для вывода сообщений
**Методы:**
- `saveJSONFile(data: unknown, fileName: string)` - сохранение JSON файла
- `saveAttachment(attachmentData: Buffer, fileName: string)` - сохранение вложения
**Пример:**
```typescript
const fileManager = new FileManager({
workDirectory: './work-dir',
logger
})
// Сохранение JSON данных
const userData = { users: [{ name: 'John', age: 30 }] }
fileManager.saveJSONFile(userData, 'users.json')
// Сохранение вложения из email
const attachmentBuffer = Buffer.from('file content')
fileManager.saveAttachment(attachmentBuffer, 'document.xlsx')
```
### EmailManager
Работа с email через IMAP и SMTP.
**Опции:**
- `credentials` - данные для подключения к почтовому серверу
- `searchRules` - правила поиска писем
- `logger` - логгер для вывода сообщений
**Методы:**
- `connect()` - подключение к серверу
- `disconnect()` - отключение от сервера
- `getEmails()` - получение писем с вложениями
- `sendEmail(options)` - отправка письма
**Пример:**
```typescript
const emailManager = new EmailManager({
credentials: {
host: 'imap.gmail.com',
port: 993,
user: 'your-email@gmail.com',
pass: 'your-password',
smtpHost: 'smtp.gmail.com',
smtpPort: 587,
smtpUser: 'your-email@gmail.com',
smtpPass: 'your-password'
},
searchRules: {
since: '2024-01-01',
before: '2024-12-31',
attachmentMask: /\.xlsx$/
},
logger
})
await emailManager.connect()
const emails = await emailManager.getEmails()
for (const email of emails) {
fileManager.saveAttachment(email.buffer, email.attachment)
}
await emailManager.sendEmail({
to: 'recipient@example.com',
subject: 'Обработка завершена',
text: 'Данные успешно обработаны'
})
await emailManager.disconnect()
```
### ParserXLS
Парсинг Excel файлов (.xlsx).
**Опции:**
- `data` - Buffer с данными Excel файла
- `fileName` - имя файла
- `usedSheet` - название листа для парсинга
- `logger` - логгер для вывода сообщений
**Методы:**
- `getColumnNames()` - получение названий колонок
- `parse(options)` - парсинг данных в объекты
**Пример:**
```typescript
const parser = new ParserXLS({
data: excelBuffer,
fileName: 'data.xlsx',
usedSheet: 'Sheet1',
logger
})
// Получение названий колонок
const columns = parser.getColumnNames()
console.log('Колонки:', columns)
// Парсинг данных
const parsedData = await parser.parse({
fieldNames: ['name', 'age', 'email', null], // null игнорирует колонку
initDataRow: (fileName) => ({
source: fileName,
processed: false
})
})
console.log('Данные:', parsedData)
```
### Validator
Валидация Excel файлов перед обработкой.
**Опции:**
- `validationRules` - массив правил валидации
- `usedSheet` - название листа для валидации
- `logger` - логгер для вывода сообщений
**Типы правил:**
- `sheetExists` - проверка существования листа
- `sheetHasData` - проверка наличия данных
- `columnHasName` - проверка названия колонки
- `columnHasType` - проверка типа данных в колонке
**Пример:**
```typescript
const validator = new Validator({
validationRules: [
{ type: 'sheetExists' },
{ type: 'sheetHasData' },
{ type: 'columnHasName', options: [0, 'Name'] },
{ type: 'columnHasType', options: [1, 'number'] }
],
usedSheet: 'Sheet1',
logger
})
const errors = await validator.validate(excelBuffer)
if (errors) {
console.error('Ошибки валидации:', errors)
} else {
console.log('Файл прошел валидацию')
}
```
### ApiManager
Работа с HTTP API.
**Опции:**
- `baseUrl` - базовый URL API
- `headers` - заголовки запросов
- `method` - HTTP метод (по умолчанию GET)
- `logger` - логгер для вывода сообщений
**Методы:**
- `fetch(params?)` - выполнение HTTP запроса
**Пример:**
```typescript
const apiManager = new ApiManager({
baseUrl: 'https://api.example.com',
headers: {
'Authorization': 'Bearer your-token',
'Content-Type': 'application/json'
},
method: 'GET',
logger
})
// GET запрос с параметрами
const data = await apiManager.fetch({
page: 1,
limit: 100,
search: 'test'
})
// POST запрос (изменяем метод)
apiManager['method'] = 'POST'
const result = await apiManager.fetch({ name: 'New Item' })
```
### JsonMapper
Преобразование JSON данных.
**Опции:**
- `nameRules` - правила переименования полей
- `valueRules` - правила преобразования значений
- `excludeRules` - поля для исключения
- `dataExpansion` - функция для расширения данных
**Методы:**
- `map(data)` - преобразование данных
**Пример:**
```typescript
const jsonMapper = new JsonMapper({
nameRules: {
'user_name': 'name',
'user_age': 'age'
},
valueRules: {
'age': (value) => Number(value),
'email': (value) => String(value).toLowerCase()
},
excludeRules: ['password', 'secret'],
dataExpansion: (data) => ({
...data,
processedAt: new Date().toISOString()
})
})
const originalData = {
user_name: 'John',
user_age: '30',
email: 'JOHN@EXAMPLE.COM',
password: 'secret123'
}
const mappedData = jsonMapper.map(originalData)
console.log(mappedData)
// { name: 'John', age: 30, email: 'john@example.com', processedAt: '2024-01-01T12:00:00.000Z' }
```
## Полный пример использования
Пример скрипта, который получает данные из email, валидирует Excel файлы, парсит их и сохраняет результат:
```typescript
import {
EmailManager,
FileManager,
Logger,
ParserXLS,
Validator,
JsonMapper
} from '@set2333/upload-script-helpers'
async function processEmailAttachments() {
const logger = new Logger({
displayTypes: ['console', { type: 'file', options: { logFile: 'process.log' } }]
})
const fileManager = new FileManager({
workDirectory: './processed-data',
logger
})
const emailManager = new EmailManager({
credentials: {
host: 'imap.gmail.com',
port: 993,
user: process.env.EMAIL_USER!,
pass: process.env.EMAIL_PASS!,
smtpHost: 'smtp.gmail.com',
smtpPort: 587,
smtpUser: process.env.EMAIL_USER!,
smtpPass: process.env.EMAIL_PASS!
},
searchRules: {
since: '2024-01-01',
before: '2024-12-31',
attachmentMask: /\.xlsx$/
},
logger
})
const validator = new Validator({
validationRules: [
{ type: 'sheetExists' },
{ type: 'sheetHasData' },
{ type: 'columnHasName', options: [0, 'Name'] },
{ type: 'columnHasType', options: [1, 'number'] }
],
usedSheet: 'Data',
logger
})
const jsonMapper = new JsonMapper({
nameRules: {
'Name': 'name',
'Age': 'age',
'Email': 'email'
},
valueRules: {
'age': (value) => Number(value),
'email': (value) => String(value).toLowerCase()
},
dataExpansion: (data) => ({
...data,
processedAt: new Date().toISOString(),
source: 'email-attachment'
})
})
try {
logger.start('Обработка email вложений')
await emailManager.connect()
const emails = await emailManager.getEmails()
logger.log(`Найдено писем с вложениями: ${emails.length}`)
for (const email of emails) {
logger.log(`Обрабатываем файл: ${email.attachment}`)
// Валидация файла
const validationErrors = await validator.validate(email.buffer)
if (validationErrors) {
logger.error(`Файл ${email.attachment} не прошел валидацию:`, validationErrors)
continue
}
// Парсинг Excel файла
const parser = new ParserXLS({
data: email.buffer,
fileName: email.attachment,
usedSheet: 'Data',
logger
})
const parsedData = await parser.parse({
fieldNames: ['name', 'age', 'email']
})
// Преобразование данных
const mappedData = parsedData.map(row => jsonMapper.map(row))
// Сохранение результата
const resultFileName = `processed_${email.attachment.replace('.xlsx', '.json')}`
fileManager.saveJSONFile(mappedData, resultFileName)
logger.log(`Файл ${email.attachment} успешно обработан`)
}
await emailManager.sendEmail({
to: 'admin@example.com',
subject: 'Обработка завершена',
text: `Обработано файлов: ${emails.length}`
})
await emailManager.disconnect()
logger.end('Обработка email вложений')
} catch (error) {
logger.error('Ошибка при обработке:', error)
throw error
}
}
// Запуск скрипта
processEmailAttachments().catch(console.error)
```
## Готовый к использованию пакет
Пакет поставляется уже скомпилированным и готовым к использованию:
- `dist/index.js` - CommonJS версия (минифицированная)
- `dist/index.mjs` - ES модули версия (минифицированная)
- `dist/index.d.ts` - TypeScript типы
## Разработка
```bash
# Установка зависимостей
npm install
# Сборка
npm run build
# Разработка с отслеживанием изменений
npm run dev
# Проверка типов
npm run typecheck
# Запуск тестов
npm test
# Запуск тестов один раз
npm run test:run
# Проверка линтера
npm run lint
# Автоисправление ошибок линтера
npm run lint:fix
# Запуск pre-commit проверок
npm run pre-commit
# Запуск pre-publish проверок
npm run pre-publish
```
## Git хуки
Проект использует Husky для автоматических проверок:
### Pre-commit хук
Автоматически запускается перед каждым коммитом:
- Исправляет ошибки ESLint в измененных файлах
- Проверяет типы TypeScript
- Запускает `lint-staged`
### Pre-publish хук
Автоматически запускается перед публикацией:
- Проверяет код линтером
- Проверяет типы TypeScript
- Запускает все тесты
- Собирает проект
Хуки настроены в `.husky/` директории и автоматически устанавливаются при `npm install`.
## Публикация
```bash
# Публикация с поднятием patch версии (1.0.0 -> 1.0.1)
npm run publish:patch
# Публикация с поднятием minor версии (1.0.0 -> 1.1.0)
npm run publish:minor
# Публикация с поднятием major версии (1.0.0 -> 2.0.0)
npm run publish:major
```
Скрипт автоматически:
- Поднимает версию в package.json
- Собирает проект
- Публикует в npm
> **Примечание**: Git команды убраны из скрипта. Версию нужно обновлять в git вручную.
## Поддерживаемые форматы
- CommonJS (`require`)
- ES модули (`import`)
- TypeScript типы