Compare commits
No commits in common. "master" and "master" have entirely different histories.
18
config.js
18
config.js
@ -7,6 +7,16 @@
|
|||||||
// Тело модуля
|
// Тело модуля
|
||||||
//------------
|
//------------
|
||||||
|
|
||||||
|
//Переменные окружения
|
||||||
|
/*
|
||||||
|
Только для СУБД Oracle.
|
||||||
|
1. NODE_ORACLE_DB_THIN_MODE - Установите значение "1", чтобы использовать режим "тонкого клиента" (Thin-режим)
|
||||||
|
при подключении к БД (не требует установки Oracle Client).
|
||||||
|
2. ORACLE_CLIENT_LIB_DIR - Путь к директории с библиотеками Oracle Client,
|
||||||
|
используется только для работы в режиме "толстого клиента" (Thick-режим), если значение не указано,
|
||||||
|
то будет использоваться значение из переменной операционной системы PATH.
|
||||||
|
*/
|
||||||
|
|
||||||
//Общие параметры
|
//Общие параметры
|
||||||
let common = {
|
let common = {
|
||||||
//Наименование сервера приложений
|
//Наименование сервера приложений
|
||||||
@ -14,7 +24,7 @@ let common = {
|
|||||||
//Версия сервера приложений
|
//Версия сервера приложений
|
||||||
sVersion: "8.5.6.1",
|
sVersion: "8.5.6.1",
|
||||||
//Релиз сервера приложений
|
//Релиз сервера приложений
|
||||||
sRelease: "2026.04.29",
|
sRelease: "2026.02.10",
|
||||||
//Таймаут останова сервера (мс)
|
//Таймаут останова сервера (мс)
|
||||||
nTerminateTimeout: 60000,
|
nTerminateTimeout: 60000,
|
||||||
//Контролировать версию Системы
|
//Контролировать версию Системы
|
||||||
@ -34,11 +44,7 @@ let dbConnect = {
|
|||||||
//Наименование сервера приложений в сессии БД
|
//Наименование сервера приложений в сессии БД
|
||||||
sSessionAppName: "PARUS$ExchangeServer",
|
sSessionAppName: "PARUS$ExchangeServer",
|
||||||
//Подключаемый модуль обслуживания БД (низкоуровневые функции работы с СУБД)
|
//Подключаемый модуль обслуживания БД (низкоуровневые функции работы с СУБД)
|
||||||
sConnectorModule: "parus_oracle_db.js",
|
sConnectorModule: "parus_oracle_db.js"
|
||||||
//Применение "тонкого" (Thin) или "толстого" (Thick) режима подключения (false - Thick-режим - работа через установленного клиента СУБД Oracle, true - Thin-режим - не требует установки клиента СУБД Oracle, допустим только для Oracle >= 12.1)
|
|
||||||
bOraUseThinMode: false,
|
|
||||||
//Путь к домашней директории Oracle Client (только для Thick-режима подключения к СУБД Oracle, если значение не указано, то будет использоваться значение из переменной окружения "PATH" ОС)
|
|
||||||
sOraClient: ""
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//Параметры обработки очереди исходящих сообщений
|
//Параметры обработки очереди исходящих сообщений
|
||||||
|
|||||||
@ -118,6 +118,7 @@ class ParusAppServer {
|
|||||||
await this.logger.info(
|
await this.logger.info(
|
||||||
`Обработчик очереди входящих сообщений запущен (порт - ${nPort}, доступные IP - ${sHost === "0.0.0.0" ? getIPs().join("; ") : sHost})`
|
`Обработчик очереди входящих сообщений запущен (порт - ${nPort}, доступные IP - ${sHost === "0.0.0.0" ? getIPs().join("; ") : sHost})`
|
||||||
);
|
);
|
||||||
|
//Запускаем
|
||||||
//Запускаем модуль отправки уведомлений
|
//Запускаем модуль отправки уведомлений
|
||||||
await this.logger.info("Запуск модуля отправки уведомлений...");
|
await this.logger.info("Запуск модуля отправки уведомлений...");
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -540,35 +540,6 @@ class DBConnector extends EventEmitter {
|
|||||||
throw new ServerError(SERR_DB_EXECUTE, "Нет подключения к БД");
|
throw new ServerError(SERR_DB_EXECUTE, "Нет подключения к БД");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Установить признак "В работе" позиции очереди
|
|
||||||
async setInProgress(prms) {
|
|
||||||
if (this.bConnected) {
|
|
||||||
//Проверяем структуру переданных параметров
|
|
||||||
let sCheckResult = validateObject(
|
|
||||||
prms,
|
|
||||||
prmsDBConnectorSchema.setInProgress,
|
|
||||||
`Параметры функции установки признака "В работе" позиции очереди`
|
|
||||||
);
|
|
||||||
//Если структура объекта в норме
|
|
||||||
if (!sCheckResult) {
|
|
||||||
//Подготовим параметры
|
|
||||||
let setInProgressData = deepClone(prms);
|
|
||||||
setInProgressData.connection = this.connection;
|
|
||||||
try {
|
|
||||||
//Исполняем действие в БД
|
|
||||||
await this.connector.setInProgress(setInProgressData);
|
|
||||||
//Успешно - возвращаем ничего
|
|
||||||
return;
|
|
||||||
} catch (e) {
|
|
||||||
throw new ServerError(SERR_DB_EXECUTE, e.message);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new ServerError(SERR_OBJECT_BAD_INTERFACE, sCheckResult);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new ServerError(SERR_DB_EXECUTE, "Нет подключения к БД");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Считать очередную порцию исходящих сообщений
|
//Считать очередную порцию исходящих сообщений
|
||||||
async getOutgoing(prms) {
|
async getOutgoing(prms) {
|
||||||
if (this.bConnected) {
|
if (this.bConnected) {
|
||||||
|
|||||||
1129
core/http_client.js
1129
core/http_client.js
File diff suppressed because it is too large
Load Diff
@ -173,18 +173,15 @@ class OutQueue extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Останов обработчика
|
//Останов обработчика
|
||||||
async stopQueueProcessor(prms) {
|
stopQueueProcessor(prms) {
|
||||||
//Проверяем структуру переданного объекта для останова обработчика
|
//Проверяем структуру переданного объекта для останова обработчика
|
||||||
let sCheckResult = validateObject(prms, prmsOutQueueSchema.stopQueueProcessor, "Параметры функции останова обработчика сообщения очереди");
|
let sCheckResult = validateObject(prms, prmsOutQueueSchema.stopQueueProcessor, "Параметры функции останова обработчика сообщения очереди");
|
||||||
//Если структура объекта в норме
|
//Если структура объекта в норме
|
||||||
if (!sCheckResult) {
|
if (!sCheckResult) {
|
||||||
//Удаляем идентификатор позиции очереди из списка обрабатываемых
|
//Удаляем идентификатор позиции очереди из списка обрабатываемых
|
||||||
this.rmInProgress({ nQueueId: prms.nQueueId });
|
this.rmInProgress({ nQueueId: prms.nQueueId });
|
||||||
//Сбрасываем признак "В работе" позиции очереди
|
//Завершаем дочерний процесс обработчика
|
||||||
await this.dbConn.setInProgress({
|
prms.proc.kill();
|
||||||
nQueueId: prms.nQueueId,
|
|
||||||
nInProgress: objQueueSchema.NQUEUE_IN_PROGRESS_NO
|
|
||||||
});
|
|
||||||
//Увеличиваем количество доступных обработчиков
|
//Увеличиваем количество доступных обработчиков
|
||||||
this.nWorkersLeft++;
|
this.nWorkersLeft++;
|
||||||
} else {
|
} else {
|
||||||
@ -298,8 +295,7 @@ class OutQueue extends EventEmitter {
|
|||||||
if (prms.queue.nExecState == objQueueSchema.NQUEUE_EXEC_STATE_ERR) await this.notifyMessageProcessError(prms);
|
if (prms.queue.nExecState == objQueueSchema.NQUEUE_EXEC_STATE_ERR) await this.notifyMessageProcessError(prms);
|
||||||
//Останавливаем обработчик и инкрементируем флаг их доступного количества
|
//Останавливаем обработчик и инкрементируем флаг их доступного количества
|
||||||
try {
|
try {
|
||||||
//Завершаем дочерний процесс обработчика
|
this.stopQueueProcessor({ nQueueId: prms.queue.nId, proc });
|
||||||
proc.kill();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//Отразим в протоколе ошибку останова
|
//Отразим в протоколе ошибку останова
|
||||||
await self.logger.error(`Ошибка останова обработчика исходящего сообщения: ${makeErrorText(e)}`, {
|
await self.logger.error(`Ошибка останова обработчика исходящего сообщения: ${makeErrorText(e)}`, {
|
||||||
@ -329,8 +325,7 @@ class OutQueue extends EventEmitter {
|
|||||||
if (prms.queue.nExecState == objQueueSchema.NQUEUE_EXEC_STATE_ERR) await this.notifyMessageProcessError(prms);
|
if (prms.queue.nExecState == objQueueSchema.NQUEUE_EXEC_STATE_ERR) await this.notifyMessageProcessError(prms);
|
||||||
//Останавливаем обработчик и инкрементируем флаг их доступного количества
|
//Останавливаем обработчик и инкрементируем флаг их доступного количества
|
||||||
try {
|
try {
|
||||||
//Завершаем дочерний процесс обработчика
|
this.stopQueueProcessor({ nQueueId: prms.queue.nId, proc });
|
||||||
proc.kill();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//Отразим в протоколе ошибку останова
|
//Отразим в протоколе ошибку останова
|
||||||
await self.logger.error(`Ошибка останова обработчика исходящего сообщения: ${makeErrorText(e)}`, {
|
await self.logger.error(`Ошибка останова обработчика исходящего сообщения: ${makeErrorText(e)}`, {
|
||||||
@ -339,17 +334,7 @@ class OutQueue extends EventEmitter {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
//Перехват останова обработчика
|
//Перехват останова обработчика
|
||||||
proc.on("exit", async code => {
|
proc.on("exit", code => {});
|
||||||
try {
|
|
||||||
//Завершаем процесс обработки сообщения
|
|
||||||
this.stopQueueProcessor({ nQueueId: prms.queue.nId });
|
|
||||||
} catch (e) {
|
|
||||||
//Отразим в протоколе ошибку останова
|
|
||||||
await self.logger.error(`Ошибка останова обработчика исходящего сообщения: ${makeErrorText(e)}`, {
|
|
||||||
nQueueId: prms.queue.nId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
//Запускаем обработчик
|
//Запускаем обработчик
|
||||||
this.startQueueProcessor({ queue: prms.queue, proc });
|
this.startQueueProcessor({ queue: prms.queue, proc });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,9 +30,8 @@ const { SPROTOCOL_HTTP, SPROTOCOL_KAFKA } = require("../models/obj_service"); //
|
|||||||
|
|
||||||
//Глубокое клонирование
|
//Глубокое клонирование
|
||||||
const deepClone = value => {
|
const deepClone = value => {
|
||||||
//Буфер для фиксации "клонированных" элементов исходного объекта
|
//Клонируем объект в зависимости от его типа, сохраняя прототипы
|
||||||
const seen = new WeakMap();
|
const seen = new WeakMap();
|
||||||
//Функция рекурсивного клонирования (разбирает тип полученного значения и в зависимости от него выполняет клонирование, сохраняя прототипы)
|
|
||||||
const clone = val => {
|
const clone = val => {
|
||||||
//Примитивы и функции возвращаем как есть
|
//Примитивы и функции возвращаем как есть
|
||||||
if (val === null || typeof val !== "object") return val;
|
if (val === null || typeof val !== "object") return val;
|
||||||
@ -105,12 +104,10 @@ const deepClone = value => {
|
|||||||
});
|
});
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
//Выполняем копирование рекурсивно с верхнего уровня
|
|
||||||
try {
|
try {
|
||||||
//Возвращаем что получилось
|
|
||||||
return clone(value);
|
return clone(value);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//В случае непредвиденной ошибки формируем исключение
|
//В случае непредвиденной ошибки формируем информативное исключение
|
||||||
const err = new Error("Ошибка глубокого копирования объекта");
|
const err = new Error("Ошибка глубокого копирования объекта");
|
||||||
err.originalError = e;
|
err.originalError = e;
|
||||||
throw err;
|
throw err;
|
||||||
@ -410,33 +407,30 @@ const getNowString = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Глубокое слияние объектов
|
//Глубокое слияние объектов
|
||||||
const deepMerge = (...sources) => {
|
function deepMerge(...sources) {
|
||||||
//Проверка на простой объект (не имеет специального поведения или прототипа)
|
|
||||||
const isPlainObject = value => Object.prototype.toString.call(value) === "[object Object]";
|
const isPlainObject = value => Object.prototype.toString.call(value) === "[object Object]";
|
||||||
//Клоникарование значения
|
|
||||||
const cloneValue = value => deepClone(value);
|
const cloneValue = value => {
|
||||||
//Буфер для результата
|
return deepClone(value);
|
||||||
|
};
|
||||||
|
|
||||||
const target = {};
|
const target = {};
|
||||||
//Обходим входные параметры по очереди
|
|
||||||
for (const source of sources) {
|
for (const source of sources) {
|
||||||
//Пропускаем непростые объекты - сливать можем только простые
|
|
||||||
if (!isPlainObject(source)) continue;
|
if (!isPlainObject(source)) continue;
|
||||||
//Обходим пары "ключ-значение"
|
|
||||||
for (const [key, value] of Object.entries(source)) {
|
for (const [key, value] of Object.entries(source)) {
|
||||||
//Если значение ключа - объект
|
|
||||||
if (isPlainObject(value)) {
|
if (isPlainObject(value)) {
|
||||||
//Сливаем рекурсивно
|
|
||||||
if (!isPlainObject(target[key])) target[key] = {};
|
if (!isPlainObject(target[key])) target[key] = {};
|
||||||
target[key] = deepMerge(target[key], value);
|
target[key] = deepMerge(target[key], value);
|
||||||
} else {
|
} else {
|
||||||
//Примитивы - просто клонируем
|
|
||||||
target[key] = cloneValue(value);
|
target[key] = cloneValue(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Возвращаем собранный буфер, содержащий все слитые воедино объекты-параметры
|
|
||||||
return target;
|
return target;
|
||||||
};
|
}
|
||||||
|
|
||||||
//Глубокое копирование объекта
|
//Глубокое копирование объекта
|
||||||
const deepCopyObject = obj => JSON.parse(JSON.stringify(obj));
|
const deepCopyObject = obj => JSON.parse(JSON.stringify(obj));
|
||||||
@ -515,31 +509,27 @@ const getURLProtocol = sURL => {
|
|||||||
|
|
||||||
//Обёртывание промиса в таймаут исполнения
|
//Обёртывание промиса в таймаут исполнения
|
||||||
const wrapPromiseTimeout = (timeout, executor) => {
|
const wrapPromiseTimeout = (timeout, executor) => {
|
||||||
//Проверяем входные параметры - должен быть указан ненулевой таймаут и функция-исполнитель промиса
|
|
||||||
if (!timeout || typeof executor !== "function") {
|
if (!timeout || typeof executor !== "function") {
|
||||||
//Разрешаем сразу, не ожидая
|
|
||||||
return executor ? executor() : Promise.resolve();
|
return executor ? executor() : Promise.resolve();
|
||||||
}
|
}
|
||||||
//Параметры прошли проверку, создаем экхемпляр контроллера прерывания асинхронного процесса
|
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
//Подготовим объект для выбрасывания ошибки
|
|
||||||
const sMessage = `Истёк интервал ожидания (${timeout} мс) завершения асинхронного процесса.`;
|
const sMessage = `Истёк интервал ожидания (${timeout} мс) завершения асинхронного процесса.`;
|
||||||
const timeoutError = new Error(sMessage);
|
const timeoutError = new Error(sMessage);
|
||||||
timeoutError.error = sMessage;
|
timeoutError.error = sMessage;
|
||||||
//Буфер для идентификатора таймера
|
|
||||||
let timeoutPid;
|
let timeoutPid;
|
||||||
//Создаём промис с взведенным таумером на у казанный таймаут, промис будет "отклонён" по истечении таймера, но перед этим контроллер прерывания выдаст "сигнал" на отмену осинхронного процесса
|
|
||||||
const timeoutPromise = new Promise((_, reject) => {
|
const timeoutPromise = new Promise((_, reject) => {
|
||||||
timeoutPid = setTimeout(() => {
|
timeoutPid = setTimeout(() => {
|
||||||
controller.abort(timeoutError);
|
controller.abort(timeoutError);
|
||||||
reject(timeoutError);
|
reject(timeoutError);
|
||||||
}, timeout);
|
}, timeout);
|
||||||
});
|
});
|
||||||
//Создаём промис с функцией-исполнителем асинхронного процесса
|
|
||||||
const taskPromise = Promise.resolve(executor(controller.signal));
|
const taskPromise = Promise.resolve(executor(controller.signal));
|
||||||
//Запускаем оба промиса в режиме "гонка" - кто "быстрее" исполнится
|
|
||||||
return Promise.race([taskPromise, timeoutPromise]).finally(() => {
|
return Promise.race([taskPromise, timeoutPromise]).finally(() => {
|
||||||
//В любом случае не забываем зачистить взведённый таймер
|
|
||||||
if (timeoutPid) clearTimeout(timeoutPid);
|
if (timeoutPid) clearTimeout(timeoutPid);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
8
index.js
8
index.js
@ -23,13 +23,7 @@ let appSrv = new app.ParusAppServer(); //Экземпляр сервера пр
|
|||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
|
||||||
//Разрешение на TLS (Transport Layer Security) без авторизации
|
//Разрешение на TLS (Transport Layer Security) без авторизации
|
||||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = cfg?.outGoing?.bValidateSSL === false ? "0" : "1";
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = cfg.outGoing.bValidateSSL === false ? "0" : "1";
|
||||||
|
|
||||||
//Включение "Токого режима" для Oracle
|
|
||||||
process.env.NODE_ORACLE_DB_THIN_MODE = cfg?.dbConnect?.bOraUseThinMode === true ? "1" : "0";
|
|
||||||
|
|
||||||
//Путь к клиентским библиотекам для Oracle
|
|
||||||
process.env.ORACLE_CLIENT_LIB_DIR = cfg?.dbConnect?.sOraClient || "";
|
|
||||||
|
|
||||||
//Обработка события "выход" жизненного цикла процесса
|
//Обработка события "выход" жизненного цикла процесса
|
||||||
process.on("exit", code => {
|
process.on("exit", code => {
|
||||||
|
|||||||
@ -189,24 +189,6 @@ const dbConnect = new Schema({
|
|||||||
type: path => `Наименование подключаемого модуля обслуживания БД (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
type: path => `Наименование подключаемого модуля обслуживания БД (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
||||||
required: path => `Не указано наименование подключаемого модуля обслуживания БД (${path})`
|
required: path => `Не указано наименование подключаемого модуля обслуживания БД (${path})`
|
||||||
}
|
}
|
||||||
},
|
|
||||||
//Признак применения "тонкого" (Thin) или "толстого" (Thick) режима подключения к БД
|
|
||||||
bOraUseThinMode: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true,
|
|
||||||
message: {
|
|
||||||
type: path => `Признак режима подключения (Thin/Thick) к БД (${path}) имеет некорректный тип данных (ожидалось - Boolean)`,
|
|
||||||
required: path => `Не указан признак режима подключения (Thin/Thick) к БД (${path})`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
//Путь к домашней директории Oracle Client
|
|
||||||
sOraClient: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
message: {
|
|
||||||
type: path => `Путь к домашней директории Oracle Client (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
|
||||||
required: path => `Не указан путь к домашней директории Oracle Client (${path})`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -33,10 +33,6 @@ const SQUEUE_EXEC_STATE_DB_ERR = "DB_ERR"; //Ошибка обработки С
|
|||||||
const SQUEUE_EXEC_STATE_OK = "OK"; //Обработано успешно (строковый код)
|
const SQUEUE_EXEC_STATE_OK = "OK"; //Обработано успешно (строковый код)
|
||||||
const SQUEUE_EXEC_STATE_ERR = "ERR"; //Обработано с ошибками (строковый код)
|
const SQUEUE_EXEC_STATE_ERR = "ERR"; //Обработано с ошибками (строковый код)
|
||||||
|
|
||||||
//Значения признака "В работе" сообщения очереди обмена
|
|
||||||
const NQUEUE_IN_PROGRESS_NO = 0; //Не в работе
|
|
||||||
const NQUEUE_IN_PROGRESS_YES = 1; //В работе
|
|
||||||
|
|
||||||
//Коды результатов исполнения обработчика сообщения
|
//Коды результатов исполнения обработчика сообщения
|
||||||
const SPRC_RESP_RESULT_OK = "OK"; //Обработано успешно
|
const SPRC_RESP_RESULT_OK = "OK"; //Обработано успешно
|
||||||
const SPRC_RESP_RESULT_ERR = "ERR"; //Ошибка обработки
|
const SPRC_RESP_RESULT_ERR = "ERR"; //Ошибка обработки
|
||||||
@ -74,8 +70,6 @@ exports.SPRC_RESP_RESULT_ERR = SPRC_RESP_RESULT_ERR;
|
|||||||
exports.SPRC_RESP_RESULT_UNAUTH = SPRC_RESP_RESULT_UNAUTH;
|
exports.SPRC_RESP_RESULT_UNAUTH = SPRC_RESP_RESULT_UNAUTH;
|
||||||
exports.NQUEUE_RESET_DATA_NO = NQUEUE_RESET_DATA_NO;
|
exports.NQUEUE_RESET_DATA_NO = NQUEUE_RESET_DATA_NO;
|
||||||
exports.NQUEUE_RESET_DATA_YES = NQUEUE_RESET_DATA_YES;
|
exports.NQUEUE_RESET_DATA_YES = NQUEUE_RESET_DATA_YES;
|
||||||
exports.NQUEUE_IN_PROGRESS_NO = NQUEUE_IN_PROGRESS_NO;
|
|
||||||
exports.NQUEUE_IN_PROGRESS_YES = NQUEUE_IN_PROGRESS_YES;
|
|
||||||
|
|
||||||
//Схема валидации сообщения очереди обмена
|
//Схема валидации сообщения очереди обмена
|
||||||
exports.Queue = new Schema({
|
exports.Queue = new Schema({
|
||||||
@ -84,7 +78,8 @@ exports.Queue = new Schema({
|
|||||||
type: Number,
|
type: Number,
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Идентификатор сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Number)`,
|
type: path =>
|
||||||
|
`Идентификатор сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Number)`,
|
||||||
required: path => `Не указан идентификатор сообщения очереди обмена (${path})`
|
required: path => `Не указан идентификатор сообщения очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -93,7 +88,8 @@ exports.Queue = new Schema({
|
|||||||
type: Date,
|
type: Date,
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Дата постановки сообщения в очередь обмена (${path}) имеет некорректный тип данных (ожидалось - Date)`,
|
type: path =>
|
||||||
|
`Дата постановки сообщения в очередь обмена (${path}) имеет некорректный тип данных (ожидалось - Date)`,
|
||||||
required: path => `Не указана дата постановки сообщения в очередь обмена (${path})`
|
required: path => `Не указана дата постановки сообщения в очередь обмена (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -112,7 +108,8 @@ exports.Queue = new Schema({
|
|||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Пользователь, поставивший сообщение в очередь обмена (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
type: path =>
|
||||||
|
`Пользователь, поставивший сообщение в очередь обмена (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
||||||
required: path => `Не указан пользователь, поставивший сообщение в очередь обмена (${path})`
|
required: path => `Не указан пользователь, поставивший сообщение в очередь обмена (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -121,7 +118,8 @@ exports.Queue = new Schema({
|
|||||||
type: Number,
|
type: Number,
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Идентификатор сервиса-обработчика сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Number)`,
|
type: path =>
|
||||||
|
`Идентификатор сервиса-обработчика сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Number)`,
|
||||||
required: path => `Не указан идентификатор сервиса-обработчика сообщения очереди обмена (${path})`
|
required: path => `Не указан идентификатор сервиса-обработчика сообщения очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -130,7 +128,8 @@ exports.Queue = new Schema({
|
|||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Код сервиса-обработчика сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
type: path =>
|
||||||
|
`Код сервиса-обработчика сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
||||||
required: path => `Не указан код сервиса-обработчика сообщения очереди обмена (${path})`
|
required: path => `Не указан код сервиса-обработчика сообщения очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -149,7 +148,8 @@ exports.Queue = new Schema({
|
|||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Код функции сервиса-обработчика сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
type: path =>
|
||||||
|
`Код функции сервиса-обработчика сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
||||||
required: path => `Не указан код функции сервиса-обработчика сообщения очереди обмена (${path})`
|
required: path => `Не указан код функции сервиса-обработчика сообщения очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -158,7 +158,8 @@ exports.Queue = new Schema({
|
|||||||
type: Date,
|
type: Date,
|
||||||
required: false,
|
required: false,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Дата обработки сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Date)`,
|
type: path =>
|
||||||
|
`Дата обработки сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Date)`,
|
||||||
required: path => `Не указана дата обработки сообщения очереди обмена (${path})`
|
required: path => `Не указана дата обработки сообщения очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -177,7 +178,8 @@ exports.Queue = new Schema({
|
|||||||
type: Number,
|
type: Number,
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Количество попыток обработки сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Number)`,
|
type: path =>
|
||||||
|
`Количество попыток обработки сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Number)`,
|
||||||
required: path => `Не указано количество попыток обработки сообщения очереди обмена (${path})`
|
required: path => `Не указано количество попыток обработки сообщения очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -207,7 +209,8 @@ exports.Queue = new Schema({
|
|||||||
],
|
],
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Состояние обработки сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Number)`,
|
type: path =>
|
||||||
|
`Состояние обработки сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Number)`,
|
||||||
enum: path => `Значение состояния обработки сообщения очереди обмена (${path}) не поддерживается`,
|
enum: path => `Значение состояния обработки сообщения очереди обмена (${path}) не поддерживается`,
|
||||||
required: path => `Не указано состояние обработки сообщения очереди обмена (${path})`
|
required: path => `Не указано состояние обработки сообщения очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
@ -228,8 +231,10 @@ exports.Queue = new Schema({
|
|||||||
],
|
],
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Строковый код состояния обработки сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
type: path =>
|
||||||
enum: path => `Значение строкового кода состояния обработки сообщения очереди обмена (${path}) не поддерживается`,
|
`Строковый код состояния обработки сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
||||||
|
enum: path =>
|
||||||
|
`Значение строкового кода состояния обработки сообщения очереди обмена (${path}) не поддерживается`,
|
||||||
required: path => `Не указан строковый код состояния обработки сообщения очереди обмена (${path})`
|
required: path => `Не указан строковый код состояния обработки сообщения очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -238,7 +243,8 @@ exports.Queue = new Schema({
|
|||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Информация от обработчика сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
type: path =>
|
||||||
|
`Информация от обработчика сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
||||||
required: path => `Не указана информация от обработчика сообщения очереди обмена (${path})`
|
required: path => `Не указана информация от обработчика сообщения очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -247,7 +253,8 @@ exports.Queue = new Schema({
|
|||||||
type: Number,
|
type: Number,
|
||||||
required: false,
|
required: false,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Идентификатор связанного сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Number)`,
|
type: path =>
|
||||||
|
`Идентификатор связанного сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Number)`,
|
||||||
required: path => `Не указан идентификатор связанного сообщения очереди обмена (${path})`
|
required: path => `Не указан идентификатор связанного сообщения очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -256,7 +263,8 @@ exports.Queue = new Schema({
|
|||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Параметры сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - String)`,
|
type: path =>
|
||||||
|
`Параметры сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - String)`,
|
||||||
required: path => `Не указаны параметры сообщения очереди обмена (${path})`
|
required: path => `Не указаны параметры сообщения очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -265,7 +273,8 @@ exports.Queue = new Schema({
|
|||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Параметры ответа на сообщение очереди обмена (${path}) имеют некорректный тип данных (ожидалось - String)`,
|
type: path =>
|
||||||
|
`Параметры ответа на сообщение очереди обмена (${path}) имеют некорректный тип данных (ожидалось - String)`,
|
||||||
required: path => `Не указаны параметры ответа на сообщение очереди обмена (${path})`
|
required: path => `Не указаны параметры ответа на сообщение очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -274,7 +283,8 @@ exports.Queue = new Schema({
|
|||||||
type: Number,
|
type: Number,
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Приоритет в очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Number)`,
|
type: path =>
|
||||||
|
`Приоритет в очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Number)`,
|
||||||
required: path => `Не указан приоритет в очереди обмена (${path})`
|
required: path => `Не указан приоритет в очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -287,7 +297,8 @@ exports.QueueMsg = new Schema({
|
|||||||
type: Buffer,
|
type: Buffer,
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Данные сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - Buffer)`,
|
type: path =>
|
||||||
|
`Данные сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - Buffer)`,
|
||||||
required: path => `Не указаны данные сообщения очереди обмена (${path})`
|
required: path => `Не указаны данные сообщения очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -300,7 +311,8 @@ exports.QueueResp = new Schema({
|
|||||||
type: Buffer,
|
type: Buffer,
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Данные ответа сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - Buffer)`,
|
type: path =>
|
||||||
|
`Данные ответа сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - Buffer)`,
|
||||||
required: path => `Не указаны данные ответа сообщения очереди обмена (${path})`
|
required: path => `Не указаны данные ответа сообщения очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,7 +326,8 @@ exports.QueuePrcResult = new Schema({
|
|||||||
enum: [SPRC_RESP_RESULT_OK, SPRC_RESP_RESULT_ERR, SPRC_RESP_RESULT_UNAUTH],
|
enum: [SPRC_RESP_RESULT_OK, SPRC_RESP_RESULT_ERR, SPRC_RESP_RESULT_UNAUTH],
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Состояние обработки сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
type: path =>
|
||||||
|
`Состояние обработки сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
||||||
enum: path => `Значение состояния обработки сообщения очереди обмена (${path}) не поддерживается`,
|
enum: path => `Значение состояния обработки сообщения очереди обмена (${path}) не поддерживается`,
|
||||||
required: path => `Не указано состояние обработки сообщения очереди обмена (${path})`
|
required: path => `Не указано состояние обработки сообщения очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
@ -324,7 +337,8 @@ exports.QueuePrcResult = new Schema({
|
|||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Параметры ответа на сообщение очереди обмена (${path}) имеют некорректный тип данных (ожидалось - String)`,
|
type: path =>
|
||||||
|
`Параметры ответа на сообщение очереди обмена (${path}) имеют некорректный тип данных (ожидалось - String)`,
|
||||||
required: path => `Не указаны параметры ответа на сообщение очереди обмена (${path})`
|
required: path => `Не указаны параметры ответа на сообщение очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -333,7 +347,8 @@ exports.QueuePrcResult = new Schema({
|
|||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Информация от обработчика сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
type: path =>
|
||||||
|
`Информация от обработчика сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
||||||
required: path => `Не указана информация от обработчика сообщения очереди обмена (${path})`
|
required: path => `Не указана информация от обработчика сообщения очереди обмена (${path})`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,9 +22,7 @@ const {
|
|||||||
NQUEUE_EXEC_STATE_OK,
|
NQUEUE_EXEC_STATE_OK,
|
||||||
NQUEUE_EXEC_STATE_ERR,
|
NQUEUE_EXEC_STATE_ERR,
|
||||||
NQUEUE_RESET_DATA_NO,
|
NQUEUE_RESET_DATA_NO,
|
||||||
NQUEUE_RESET_DATA_YES,
|
NQUEUE_RESET_DATA_YES
|
||||||
NQUEUE_IN_PROGRESS_NO,
|
|
||||||
NQUEUE_IN_PROGRESS_YES
|
|
||||||
} = require("./obj_queue"); //Схемы валидации сообщения очереди обмена
|
} = require("./obj_queue"); //Схемы валидации сообщения очереди обмена
|
||||||
|
|
||||||
//----------
|
//----------
|
||||||
@ -330,29 +328,6 @@ exports.putQueue = new Schema({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//Схема валидации параметров функции установки признака "В работе" позиции очереди
|
|
||||||
exports.setInProgress = new Schema({
|
|
||||||
//Идентификатор позиции очереди
|
|
||||||
nQueueId: {
|
|
||||||
type: Number,
|
|
||||||
required: true,
|
|
||||||
message: {
|
|
||||||
type: path => `Идентификатор позиции очереди (${path}) имеет некорректный тип данных (ожидалось - Number)`,
|
|
||||||
required: path => `Не указан идентификатор позиции очереди (${path})`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
nInProgress: {
|
|
||||||
type: Number,
|
|
||||||
enum: [NQUEUE_IN_PROGRESS_NO, NQUEUE_IN_PROGRESS_YES],
|
|
||||||
required: true,
|
|
||||||
message: {
|
|
||||||
type: path => `Признак "В работе" (${path}) имеет некорректный тип данных (ожидалось - Number)`,
|
|
||||||
enum: path => `Значение признака "В работе" (${path}) не поддерживается`,
|
|
||||||
required: path => `Не указано значение признака "В работе" (${path})`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//Схема валидации параметров функции считывания исходящих сообщений
|
//Схема валидации параметров функции считывания исходящих сообщений
|
||||||
exports.getOutgoing = new Schema({
|
exports.getOutgoing = new Schema({
|
||||||
//Количество считываемых сообщений очереди
|
//Количество считываемых сообщений очереди
|
||||||
|
|||||||
@ -42,7 +42,8 @@ exports.OutQueue = new Schema({
|
|||||||
type: DBConnector,
|
type: DBConnector,
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Объект для взаимодействия с БД (${path}) имеет некорректный тип данных (ожидалось - DBConnector)`,
|
type: path =>
|
||||||
|
`Объект для взаимодействия с БД (${path}) имеет некорректный тип данных (ожидалось - DBConnector)`,
|
||||||
required: path => `Не указан объект для взаимодействия с БД (${path})`
|
required: path => `Не указан объект для взаимодействия с БД (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -51,7 +52,8 @@ exports.OutQueue = new Schema({
|
|||||||
type: Logger,
|
type: Logger,
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Объект для протоколирования работы (${path}) имеет некорректный тип данных (ожидалось - Logger)`,
|
type: path =>
|
||||||
|
`Объект для протоколирования работы (${path}) имеет некорректный тип данных (ожидалось - Logger)`,
|
||||||
required: path => `Не указаны объект для протоколирования работы (${path})`
|
required: path => `Не указаны объект для протоколирования работы (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -60,7 +62,8 @@ exports.OutQueue = new Schema({
|
|||||||
type: Notifier,
|
type: Notifier,
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
type: path => `Объект для рассылки уведомлений (${path}) имеет некорректный тип данных (ожидалось - Notifier)`,
|
type: path =>
|
||||||
|
`Объект для рассылки уведомлений (${path}) имеет некорректный тип данных (ожидалось - Notifier)`,
|
||||||
required: path => `Не указан объект для рассылки уведомлений (${path})`
|
required: path => `Не указан объект для рассылки уведомлений (${path})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -129,7 +132,8 @@ exports.startQueueProcessor = new Schema({
|
|||||||
use: { validateChildProcess },
|
use: { validateChildProcess },
|
||||||
required: true,
|
required: true,
|
||||||
message: {
|
message: {
|
||||||
validateChildProcess: path => `Процесс обработчика (${path}) имеет некорректный тип данных (ожидалось - ChildProcess)`,
|
validateChildProcess: path =>
|
||||||
|
`Процесс обработчика (${path}) имеет некорректный тип данных (ожидалось - ChildProcess)`,
|
||||||
required: path => `Не указан процесс обработчика (${path})`
|
required: path => `Не указан процесс обработчика (${path})`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,6 +149,16 @@ exports.stopQueueProcessor = new Schema({
|
|||||||
type: path => `Идентификатор сообщения (${path}) имеет некорректный тип данных (ожидалось - Number)`,
|
type: path => `Идентификатор сообщения (${path}) имеет некорректный тип данных (ожидалось - Number)`,
|
||||||
required: path => `Не указан идентификатор сообщения (${path})`
|
required: path => `Не указан идентификатор сообщения (${path})`
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
//Процесс обработчика
|
||||||
|
proc: {
|
||||||
|
use: { validateChildProcess },
|
||||||
|
required: true,
|
||||||
|
message: {
|
||||||
|
validateChildProcess: path =>
|
||||||
|
`Процесс обработчика (${path}) имеет некорректный тип данных (ожидалось - ChildProcess)`,
|
||||||
|
required: path => `Не указан процесс обработчика (${path})`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@ const sax = require("./node_modules/sax"); //Событийный XML-парсе
|
|||||||
|
|
||||||
//Инициализируем Thick-режим до любых подключений к БД
|
//Инициализируем Thick-режим до любых подключений к БД
|
||||||
try {
|
try {
|
||||||
if (typeof oracledb.initOracleClient === "function" && !(process.env.NODE_ORACLE_DB_THIN_MODE === "1")) {
|
if (typeof oracledb.initOracleClient === "function" && !(process.env.NODE_ORACLE_DB_THIN_MODE === 1)) {
|
||||||
const libDir = process.env.ORACLE_CLIENT_LIB_DIR;
|
const libDir = process.env.ORACLE_CLIENT_LIB_DIR;
|
||||||
if (libDir) {
|
if (libDir) {
|
||||||
oracledb.initOracleClient({ libDir });
|
oracledb.initOracleClient({ libDir });
|
||||||
|
|||||||
@ -16,7 +16,7 @@ const { makeErrorText } = require("../core/utils"); //Вспомогательн
|
|||||||
|
|
||||||
//Инициализируем Thick-режим до любых подключений к БД
|
//Инициализируем Thick-режим до любых подключений к БД
|
||||||
try {
|
try {
|
||||||
if (typeof oracledb.initOracleClient === "function" && !(process.env.NODE_ORACLE_DB_THIN_MODE === "1")) {
|
if (typeof oracledb.initOracleClient === "function" && !(process.env.NODE_ORACLE_DB_THIN_MODE === 1)) {
|
||||||
const libDir = process.env.ORACLE_CLIENT_LIB_DIR;
|
const libDir = process.env.ORACLE_CLIENT_LIB_DIR;
|
||||||
if (libDir) {
|
if (libDir) {
|
||||||
oracledb.initOracleClient({ libDir });
|
oracledb.initOracleClient({ libDir });
|
||||||
@ -203,10 +203,9 @@ const clearServer = async prms => {
|
|||||||
|
|
||||||
//Подключение к БД
|
//Подключение к БД
|
||||||
const connect = async prms => {
|
const connect = async prms => {
|
||||||
let pool = null;
|
|
||||||
try {
|
try {
|
||||||
//Создаем пул подключения
|
//Создаем пул подключения
|
||||||
pool = await oracledb.createPool({
|
let pool = await oracledb.createPool({
|
||||||
user: prms.sUser,
|
user: prms.sUser,
|
||||||
password: prms.sPassword,
|
password: prms.sPassword,
|
||||||
connectString: prms.sConnectString,
|
connectString: prms.sConnectString,
|
||||||
@ -230,15 +229,8 @@ const connect = async prms => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//Проверяем доступность пула
|
|
||||||
let tstConn = await pool.getConnection();
|
|
||||||
await tstConn.close();
|
|
||||||
//Всё ок - возвращяем его
|
|
||||||
return pool;
|
return pool;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//Закрываем пул, если успели открыть
|
|
||||||
if (pool) pool.close(NPOOL_DRAIN_TIME);
|
|
||||||
//Возвращаем ошибку
|
|
||||||
throw new Error(e.message);
|
throw new Error(e.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -412,18 +404,6 @@ const putQueue = async prms => {
|
|||||||
return queueData.RCQUEUE[0];
|
return queueData.RCQUEUE[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
//Установка признака "В работе" в сообщении очереди
|
|
||||||
const setInProgress = async prms => {
|
|
||||||
await executeStored({
|
|
||||||
connection: prms.connection,
|
|
||||||
sName: "PKG_EXS.QUEUE_IN_PROGRESS_SET",
|
|
||||||
inPrms: {
|
|
||||||
NEXSQUEUE: prms.nQueueId,
|
|
||||||
NIN_PROGRESS: prms.nInProgress
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//Считывание очередной порции исходящих сообщений из очереди
|
//Считывание очередной порции исходящих сообщений из очереди
|
||||||
const getQueueOutgoing = async prms => {
|
const getQueueOutgoing = async prms => {
|
||||||
let queueOutgoingData = await executeStored({
|
let queueOutgoingData = await executeStored({
|
||||||
@ -578,7 +558,6 @@ exports.getServiceExpiredQueueInfo = getServiceExpiredQueueInfo;
|
|||||||
exports.log = log;
|
exports.log = log;
|
||||||
exports.getQueue = getQueue;
|
exports.getQueue = getQueue;
|
||||||
exports.putQueue = putQueue;
|
exports.putQueue = putQueue;
|
||||||
exports.setInProgress = setInProgress;
|
|
||||||
exports.getQueueOutgoing = getQueueOutgoing;
|
exports.getQueueOutgoing = getQueueOutgoing;
|
||||||
exports.setQueueState = setQueueState;
|
exports.setQueueState = setQueueState;
|
||||||
exports.getQueueMsg = getQueueMsg;
|
exports.getQueueMsg = getQueueMsg;
|
||||||
|
|||||||
@ -373,18 +373,6 @@ const putQueue = async prms => {
|
|||||||
return queueData.RCQUEUE[0];
|
return queueData.RCQUEUE[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
//Установка признака "В работе" в сообщении очереди
|
|
||||||
const setInProgress = async prms => {
|
|
||||||
await executeStored({
|
|
||||||
connection: prms.connection,
|
|
||||||
sName: "PKG_EXS$QUEUE_IN_PROGRESS_SET",
|
|
||||||
inPrms: {
|
|
||||||
NEXSQUEUE: prms.nQueueId,
|
|
||||||
NIN_PROGRESS: prms.nInProgress
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//Считывание очередной порции исходящих сообщений из очереди
|
//Считывание очередной порции исходящих сообщений из очереди
|
||||||
const getQueueOutgoing = async prms => {
|
const getQueueOutgoing = async prms => {
|
||||||
let queueOutgoingData = await executeStored({
|
let queueOutgoingData = await executeStored({
|
||||||
@ -539,7 +527,6 @@ exports.getServiceExpiredQueueInfo = getServiceExpiredQueueInfo;
|
|||||||
exports.log = log;
|
exports.log = log;
|
||||||
exports.getQueue = getQueue;
|
exports.getQueue = getQueue;
|
||||||
exports.putQueue = putQueue;
|
exports.putQueue = putQueue;
|
||||||
exports.setInProgress = setInProgress;
|
|
||||||
exports.getQueueOutgoing = getQueueOutgoing;
|
exports.getQueueOutgoing = getQueueOutgoing;
|
||||||
exports.setQueueState = setQueueState;
|
exports.setQueueState = setQueueState;
|
||||||
exports.getQueueMsg = getQueueMsg;
|
exports.getQueueMsg = getQueueMsg;
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
const xml2js = require("xml2js"); //Конвертация XML в JSON и JSON в XML
|
const xml2js = require("xml2js"); //Конвертация XML в JSON и JSON в XML
|
||||||
const { httpRequest } = require("../core/http_client"); //Работа с HTTP/HTTPS запросами
|
const { httpRequest } = require("../core/http_client"); //Работа с HTTP/HTTPS запросами
|
||||||
const { SMCHD_STORAGE_SYSTEM, NCTX_EXP } = require("./sbis_config"); //Параметры работы расширения
|
const { SMCHD_STORAGE_SYSTEM, NCTX_EXP } = require("./sbis_config"); //Система хранения МЧД
|
||||||
|
|
||||||
//---------------------
|
//---------------------
|
||||||
// Глобальные константы
|
// Глобальные константы
|
||||||
|
|||||||
878
modules/shp.js
878
modules/shp.js
@ -1,878 +0,0 @@
|
|||||||
/*
|
|
||||||
Сервис интеграции ПП Парус 8 с WEB API
|
|
||||||
Дополнительный модуль: Sheet Parser (SHP)
|
|
||||||
*/
|
|
||||||
|
|
||||||
//------------------------------
|
|
||||||
// Подключение внешних библиотек
|
|
||||||
//------------------------------
|
|
||||||
|
|
||||||
const xml2js = require("xml2js"); //Конвертация XML в JSON и JSON в XML
|
|
||||||
const XLSX = require("./shp_utils/node_modules/xlsx"); //Парсер табличных данных
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
// Глобальные константы
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
//Количество строк, загружаемых за одно обращение к серверу
|
|
||||||
const NIMPORT_BUFF_LEN = 500;
|
|
||||||
|
|
||||||
//Форматы файлов данных */
|
|
||||||
const NSHPFL_FORMAT_XLS = 0; //MS Excel (xls, xlsx)
|
|
||||||
const NSHPFL_FORMAT_ODS = 1; //OpenDocument Spreadsheet (ods)
|
|
||||||
const NSHPFL_FORMAT_CSV = 2; //Comma-Separated Values (csv)
|
|
||||||
const NSHPFL_FORMAT_DBF = 3; //Database File (dbf)
|
|
||||||
|
|
||||||
//Кодировки файлов данных */
|
|
||||||
const NSHPFL_ENC_DEFAULT = 0; //По умолчанию
|
|
||||||
const NSHPFL_ENC_WIN1251 = 1; //Windows-1251
|
|
||||||
const NSHPFL_ENC_UTF8 = 2; //UTF-8
|
|
||||||
|
|
||||||
//------------------------
|
|
||||||
// Вспомогательные функции
|
|
||||||
//------------------------
|
|
||||||
|
|
||||||
//Разбор XML (обёртка для async/await)
|
|
||||||
const parseXML = ({ sXML, options }) => {
|
|
||||||
//Возвращаем промис для использования async/await
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
//Разбираем XML
|
|
||||||
xml2js.parseString(sXML, options, (err, result) => {
|
|
||||||
//Если при разборе возникла ошибка
|
|
||||||
if (err) reject(err);
|
|
||||||
//Если всё успешно - возвращаем результат
|
|
||||||
else resolve(result);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//Конвертация в XML
|
|
||||||
const toXML = ({ rootName, data, headless = false }) => {
|
|
||||||
//Формируем XML
|
|
||||||
const builder = new xml2js.Builder({ rootName, headless });
|
|
||||||
return builder.buildObject(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Получение текстового представления ячейки
|
|
||||||
const getCellText = cl => {
|
|
||||||
//Если ячейки нет - возвращаем пустую строку
|
|
||||||
if (!cl) return "";
|
|
||||||
//Если есть значение v - берём его
|
|
||||||
if (cl.v !== null && cl.v !== undefined) return String(cl.v);
|
|
||||||
//Если есть форматированное значение w - берём его
|
|
||||||
if (cl.w !== null && cl.w !== undefined) return String(cl.w);
|
|
||||||
//Если значений нет - возвращаем пустую строку
|
|
||||||
return "";
|
|
||||||
};
|
|
||||||
|
|
||||||
//Построение индекса колонок по заголовкам (имя заголовка -> номер колонки)
|
|
||||||
const buildHeadersIndex = ({ sheet, sheetData, nHeaderLineNo }) => {
|
|
||||||
//Если листа нет - индекса заголовков нет
|
|
||||||
if (!sheet) return null;
|
|
||||||
//Если данных листа нет - индекса заголовков нет
|
|
||||||
if (!Array.isArray(sheetData) || sheetData.length === 0) return null;
|
|
||||||
//Номер строки заголовков должен быть валидным (1..)
|
|
||||||
const nHdrLine = Number.isFinite(nHeaderLineNo) && nHeaderLineNo > 0 ? nHeaderLineNo : null;
|
|
||||||
//Если номер строки заголовков невалиден - индекса заголовков нет
|
|
||||||
if (!nHdrLine) return null;
|
|
||||||
//Строка заголовков
|
|
||||||
const headerRow = sheetData[nHdrLine - 1] || [];
|
|
||||||
//Если строки заголовков нет - индекса заголовков нет
|
|
||||||
if (!Array.isArray(headerRow) || headerRow.length === 0) return null;
|
|
||||||
//Создаём резолвер объединённых ячеек
|
|
||||||
const { resolveCell } = createMergedCellResolver(sheet);
|
|
||||||
//Результат индекса
|
|
||||||
const idx = new Map();
|
|
||||||
//Обходим все колонки строки заголовков
|
|
||||||
for (let c = 0; c < headerRow.length; c++) {
|
|
||||||
//Номер колонки
|
|
||||||
const colNo = c + 1;
|
|
||||||
//Резолвим ячейку заголовка
|
|
||||||
const cl = resolveCell(nHdrLine - 1, c, (headerRow || [])[c]);
|
|
||||||
//Текст заголовка
|
|
||||||
const sName = getCellText(cl).trim();
|
|
||||||
//Пустые заголовки не индексируем
|
|
||||||
if (!sName) continue;
|
|
||||||
//Ключ заголовка
|
|
||||||
const key = sName.toUpperCase();
|
|
||||||
//Если такой заголовок уже есть - не перезаписываем
|
|
||||||
if (idx.has(key)) continue;
|
|
||||||
//Сохраняем номер колонки
|
|
||||||
idx.set(key, colNo);
|
|
||||||
}
|
|
||||||
//Если индекс пустой - возвращаем null
|
|
||||||
if (idx.size === 0) return null;
|
|
||||||
//Возвращаем индекс
|
|
||||||
return idx;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Формирование XML заголовков таблицы
|
|
||||||
const buildTableHeadersXML = ({ workbook, sSheetName, aColumns, nColumnsCount, nHeaderLineNo }) => {
|
|
||||||
//Если книги нет - заголовки построить нельзя
|
|
||||||
if (!workbook) return null;
|
|
||||||
//Если имя листа не задано - заголовки построить нельзя
|
|
||||||
if (!sSheetName) return null;
|
|
||||||
//Получаем лист
|
|
||||||
const sheet = workbook.Sheets?.[sSheetName] || null;
|
|
||||||
//Если листа нет - заголовки построить нельзя
|
|
||||||
if (!sheet) return null;
|
|
||||||
//Dense-данные листа (строки/ячейки)
|
|
||||||
const sheetData = sheet?.["!data"] || [];
|
|
||||||
//Если данных нет - заголовки построить нельзя
|
|
||||||
if (!Array.isArray(sheetData) || sheetData.length === 0) return null;
|
|
||||||
//Номер строки заголовков должен быть валидным (1..)
|
|
||||||
const nHdrLine = Number.isFinite(nHeaderLineNo) && nHeaderLineNo > 0 ? nHeaderLineNo : 1;
|
|
||||||
//Получаем строку заголовков
|
|
||||||
const headerRow = sheetData[nHdrLine - 1] || [];
|
|
||||||
//Создаём резолвер объединённых ячеек
|
|
||||||
const { hasMerges, resolveCell } = createMergedCellResolver(sheet);
|
|
||||||
//Нормализуем количество колонок таблицы
|
|
||||||
const nCols = Number.isFinite(nColumnsCount) && nColumnsCount > 0 ? nColumnsCount : 0;
|
|
||||||
//Если колонок нет - формируем пустой RHEADERS
|
|
||||||
if (!nCols) return toXML({ rootName: "RHEADERS", data: {}, headless: true });
|
|
||||||
//Список заголовков (RHEADER)
|
|
||||||
const rHeaders = [];
|
|
||||||
//Если задан список колонок
|
|
||||||
if (Array.isArray(aColumns) && aColumns.length > 0) {
|
|
||||||
//Обходим все выбранные колонки в заданном порядке
|
|
||||||
for (let i = 0; i < aColumns.length; i++) {
|
|
||||||
//Номер исходной колонки
|
|
||||||
const colNo = aColumns[i];
|
|
||||||
//Если номер колонки невалиден - пропускаем
|
|
||||||
if (!Number.isFinite(colNo) || colNo < 1) continue;
|
|
||||||
//Резолвим ячейку заголовка
|
|
||||||
const cl = resolveCell(nHdrLine - 1, colNo - 1, (headerRow || [])[colNo - 1]);
|
|
||||||
//Текст заголовка
|
|
||||||
const sName = getCellText(cl).trim();
|
|
||||||
//Добавляем RHEADER
|
|
||||||
rHeaders.push({ NCOLUMN: colNo, SCOLUMN: sName });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Иначе - заголовки строим по фактическому набору колонок (1..nCols)
|
|
||||||
else {
|
|
||||||
//Определяем количество колонок в строке заголовков
|
|
||||||
const nHeaderRowCols = hasMerges ? nCols : (headerRow || []).length;
|
|
||||||
const nIter = Math.max(nCols, nHeaderRowCols, 0);
|
|
||||||
//Обходим колонки 1..nIter
|
|
||||||
for (let c = 0; c < nIter; c++) {
|
|
||||||
//Номер колонки
|
|
||||||
const colNo = c + 1;
|
|
||||||
//Резолвим ячейку заголовка
|
|
||||||
const cl = resolveCell(nHdrLine - 1, c, (headerRow || [])[c]);
|
|
||||||
//Текст заголовка
|
|
||||||
const sName = getCellText(cl).trim();
|
|
||||||
//Добавляем RHEADER
|
|
||||||
rHeaders.push({ NCOLUMN: colNo, SCOLUMN: sName });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Собираем XML заголовков
|
|
||||||
return toXML({
|
|
||||||
rootName: "RHEADERS",
|
|
||||||
data: {
|
|
||||||
...(rHeaders.length > 0 ? { RHEADER: rHeaders } : {})
|
|
||||||
},
|
|
||||||
headless: true
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//Преобразование "одиночное значение | массив | undefined" -> массив
|
|
||||||
const toArray = value => {
|
|
||||||
//Если значения нет - возвращаем пустой массив
|
|
||||||
if (!value) return [];
|
|
||||||
//Если уже массив - возвращаем как есть, иначе оборачиваем
|
|
||||||
return Array.isArray(value) ? value : [value];
|
|
||||||
};
|
|
||||||
|
|
||||||
//Разбор параметров выполнения SHP (clOptions: XML -> JSON)
|
|
||||||
const parseShpOptionsXML = async sOptionsXML => {
|
|
||||||
//Если параметр отсутствует или не строка - параметров выполнения нет
|
|
||||||
if (!sOptionsXML || !(sOptionsXML instanceof String || typeof sOptionsXML === "string")) return null;
|
|
||||||
//Если строка пустая - параметров выполнения нет
|
|
||||||
if (!String(sOptionsXML).trim()) return null;
|
|
||||||
//Результат парсинга XML
|
|
||||||
let parseRes = null;
|
|
||||||
try {
|
|
||||||
//Парсим XML
|
|
||||||
parseRes = await parseXML({
|
|
||||||
sXML: sOptionsXML,
|
|
||||||
options: {
|
|
||||||
explicitArray: false,
|
|
||||||
mergeAttrs: true,
|
|
||||||
valueProcessors: [xml2js.processors.parseNumbers, xml2js.processors.parseBooleans]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
//Ошибка разбора параметров выполнения
|
|
||||||
throw new Error(`Ошибка разбора XML параметров выполнения: ${e.message || e}`);
|
|
||||||
}
|
|
||||||
//Корневой элемент параметров выполнения
|
|
||||||
const root = parseRes?.OPTIONS || null;
|
|
||||||
//Если корня нет - параметров выполнения нет
|
|
||||||
if (!root) return null;
|
|
||||||
//OPTION может быть одиночным объектом или массивом
|
|
||||||
const options = toArray(root.OPTION).filter(Boolean);
|
|
||||||
//Возвращаем нормализованный объект
|
|
||||||
return { options };
|
|
||||||
};
|
|
||||||
|
|
||||||
//Преобразование номера/имени колонки в число (A->1, B->2, AA->27, ...)
|
|
||||||
const normalizeColumn = value => {
|
|
||||||
//Если значение отсутствует - возвращаем null
|
|
||||||
if (value === null || value === undefined) return null;
|
|
||||||
//Приводим к строке и убираем пробелы
|
|
||||||
const sVal = String(value).trim();
|
|
||||||
//Пустое значение - нечего нормализовать
|
|
||||||
if (!sVal) return null;
|
|
||||||
//Если это число в строковом представлении
|
|
||||||
if (/^\d+$/.test(sVal)) {
|
|
||||||
//Преобразуем в число
|
|
||||||
const n = parseInt(sVal, 10);
|
|
||||||
//Колонки начинаются с 1
|
|
||||||
return Number.isFinite(n) && n > 0 ? n : null;
|
|
||||||
}
|
|
||||||
//Приводим буквы к верхнему регистру
|
|
||||||
const s = sVal.toUpperCase();
|
|
||||||
//Ожидаем только латинские буквы (A..Z)
|
|
||||||
if (!/^[A-Z]+$/.test(s)) return null;
|
|
||||||
//Результат в десятичном виде
|
|
||||||
let n = 0;
|
|
||||||
//Переводим base-26 представление в десятичное
|
|
||||||
for (let i = 0; i < s.length; i++) {
|
|
||||||
//A=1 ... Z=26
|
|
||||||
n = n * 26 + (s.charCodeAt(i) - 64);
|
|
||||||
}
|
|
||||||
//Возвращаем результат, если он валиден
|
|
||||||
return n > 0 ? n : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Преобразование имени/номера колонки в число с учётом заголовков
|
|
||||||
const normalizeColumnWithHeaders = ({ value, headersIndex }) => {
|
|
||||||
//Если значение отсутствует - возвращаем null
|
|
||||||
if (value === null || value === undefined) return null;
|
|
||||||
//Приводим к строке и убираем пробелы
|
|
||||||
const sVal = String(value).trim();
|
|
||||||
//Пустое значение - нечего нормализовать
|
|
||||||
if (!sVal) return null;
|
|
||||||
//Если задан индекс заголовков - сначала ищем по нему
|
|
||||||
if (headersIndex && headersIndex instanceof Map) {
|
|
||||||
//Ключ поиска
|
|
||||||
const key = sVal.toUpperCase();
|
|
||||||
//Пробуем найти колонку по заголовку
|
|
||||||
const nByHdr = headersIndex.get(key);
|
|
||||||
//Если нашли валидный номер - возвращаем
|
|
||||||
if (Number.isFinite(nByHdr) && nByHdr > 0) return nByHdr;
|
|
||||||
}
|
|
||||||
//Если по заголовку не нашли - преобразуем имя колонки в число
|
|
||||||
return normalizeColumn(sVal);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Формирование списка индексов (1..max) по описанию (RANGE/ENUM/COUNT)
|
|
||||||
const buildIndexList = ({ selector, nMax, normalizeItem, getDefaultFrom }) => {
|
|
||||||
//Нормализуем максимум
|
|
||||||
const nMaxSafe = Number.isFinite(nMax) && nMax > 0 ? nMax : 0;
|
|
||||||
//Если селектора нет или максимум не задан - считаем что фильтра нет
|
|
||||||
if (!selector || !nMaxSafe) return null;
|
|
||||||
//Тип выборки (RANGE/ENUM/COUNT)
|
|
||||||
const sType = String(selector.SADDRESS_TYPE || "")
|
|
||||||
.trim()
|
|
||||||
.toUpperCase();
|
|
||||||
//Если тип не задан - считаем что фильтра нет
|
|
||||||
if (!sType) return null;
|
|
||||||
//Добавление уникальных значений в множество
|
|
||||||
const pushUnique = (set, value) => {
|
|
||||||
//Должно быть число
|
|
||||||
if (!Number.isFinite(value)) return;
|
|
||||||
//Должно попадать в диапазон 1..nMaxSafe
|
|
||||||
if (value < 1 || value > nMaxSafe) return;
|
|
||||||
//Добавляем уникально
|
|
||||||
set.add(value);
|
|
||||||
};
|
|
||||||
//Множество для уникальных значений
|
|
||||||
const res = new Set();
|
|
||||||
//Адрес-диапазон
|
|
||||||
if (sType === "RANGE") {
|
|
||||||
//Узел диапазона
|
|
||||||
const range = selector.RADDRESS_RANGE || null;
|
|
||||||
//Начало диапазона обязательно
|
|
||||||
const nFrom = normalizeItem?.(range?.SVALUE_FROM);
|
|
||||||
//Если начала нет - фильтр считаем некорректным
|
|
||||||
if (!Number.isFinite(nFrom) || nFrom < 1) return null;
|
|
||||||
//Конец диапазона опционален
|
|
||||||
let nTo = normalizeItem?.(range?.SVALUE_TO);
|
|
||||||
//Если конец не указан - берём до конца
|
|
||||||
if (!Number.isFinite(nTo) || nTo < nFrom) nTo = nMaxSafe;
|
|
||||||
//Заполняем диапазон
|
|
||||||
for (let i = nFrom; i <= Math.min(nTo, nMaxSafe); i++) pushUnique(res, i);
|
|
||||||
//Возвращаем отсортированный список
|
|
||||||
return Array.from(res).sort((a, b) => a - b);
|
|
||||||
}
|
|
||||||
//Адрес-перечисление
|
|
||||||
if (sType === "ENUM") {
|
|
||||||
//Узел перечисления
|
|
||||||
const en = selector.RADDRESS_ENUM || null;
|
|
||||||
//Значение может быть одиночным значением или массивом
|
|
||||||
for (const v of toArray(en?.SVALUE)) pushUnique(res, normalizeItem?.(v));
|
|
||||||
//Возвращаем отсортированный список
|
|
||||||
return Array.from(res).sort((a, b) => a - b);
|
|
||||||
}
|
|
||||||
//Адрес-количество
|
|
||||||
if (sType === "COUNT") {
|
|
||||||
//Узел количества
|
|
||||||
const cnt = selector.RADDRESS_COUNT || null;
|
|
||||||
//Количество берём из SVALUE
|
|
||||||
const nCount = parseInt(String(cnt?.SVALUE ?? "").trim(), 10);
|
|
||||||
//Количество должно быть > 0
|
|
||||||
if (!Number.isFinite(nCount) || nCount <= 0) return null;
|
|
||||||
//Признак, что старт задан явно
|
|
||||||
const bHasFrom = cnt?.SVALUE_FROM !== null && cnt?.SVALUE_FROM !== undefined && String(cnt?.SVALUE_FROM).trim() !== "";
|
|
||||||
//Старт опционален (если не задан - берём вычисляемое значение, иначе 1)
|
|
||||||
const nFromRaw = bHasFrom ? normalizeItem?.(cnt?.SVALUE_FROM) : (getDefaultFrom?.() ?? 1);
|
|
||||||
//Если старт некорректен - начинаем с 1
|
|
||||||
const nFromSafe = Number.isFinite(nFromRaw) && nFromRaw > 0 ? nFromRaw : 1;
|
|
||||||
//Добавляем нужное количество индексов
|
|
||||||
for (let i = nFromSafe; i < nFromSafe + nCount; i++) pushUnique(res, i);
|
|
||||||
//Возвращаем отсортированный список
|
|
||||||
return Array.from(res).sort((a, b) => a - b);
|
|
||||||
}
|
|
||||||
//Неизвестный тип
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Формирование списка всех индексов (1..nMax)
|
|
||||||
const buildAllIndexList = ({ nMax }) => {
|
|
||||||
//Нормализуем максимум
|
|
||||||
const nMaxSafe = Number.isFinite(nMax) && nMax > 0 ? nMax : 0;
|
|
||||||
//Если максимум некорректен - возвращаем пустой список
|
|
||||||
if (!nMaxSafe) return [];
|
|
||||||
//Создаём массив нужной длины
|
|
||||||
const res = new Array(nMaxSafe);
|
|
||||||
//Заполняем индексами
|
|
||||||
for (let i = 0; i < nMaxSafe; i++) res[i] = i + 1;
|
|
||||||
//Возвращаем результат
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Проверка наличия данных в листе
|
|
||||||
const isSheetNotEmpty = ({ workbook, sSheetName }) =>
|
|
||||||
//Лист не пустой, если есть dense-данные и они содержат хотя бы одну строку
|
|
||||||
Array.isArray(workbook?.Sheets[sSheetName]?.["!data"]) && workbook?.Sheets[sSheetName]?.["!data"].length > 0;
|
|
||||||
|
|
||||||
//Подсчёт предельного количества столбцов в листе
|
|
||||||
const getSheetColumnsCount = ({ workbook, sSheetName }) => {
|
|
||||||
//Получаем dense-данные листа
|
|
||||||
const rows = workbook?.Sheets?.[sSheetName]?.["!data"];
|
|
||||||
//Если данных нет - возвращаем 0
|
|
||||||
if (!Array.isArray(rows) || rows.length === 0) return 0;
|
|
||||||
//Возвращаем максимальную длину строки (количество колонок)
|
|
||||||
return rows.reduce((cnt, curRow) => Math.max(cnt, (curRow || []).length), 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Проверка, что ячейка содержит данные (v/w)
|
|
||||||
const isCellHasData = cl => {
|
|
||||||
//Если ячейки нет - данных нет
|
|
||||||
if (!cl) return false;
|
|
||||||
//Если есть значение v - проверяем его на пустоту
|
|
||||||
if (cl.v !== null && cl.v !== undefined && String(cl.v) !== "") return true;
|
|
||||||
//Если есть текстовое значение w - проверяем его на пустоту
|
|
||||||
if (cl.w !== null && cl.w !== undefined && String(cl.w) !== "") return true;
|
|
||||||
//Данных нет
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Поиск первой строки, где есть данные
|
|
||||||
const getFirstDataLineNo = ({ sheetData }) => {
|
|
||||||
//Если данных листа нет - возвращаем 1
|
|
||||||
if (!Array.isArray(sheetData) || sheetData.length === 0) return 1;
|
|
||||||
//Обходим строки сверху вниз
|
|
||||||
for (let r = 0; r < sheetData.length; r++) {
|
|
||||||
//Строка листа (массив ячеек)
|
|
||||||
const row = sheetData[r] || [];
|
|
||||||
//Обходим ячейки строки
|
|
||||||
for (let c = 0; c < row.length; c++) {
|
|
||||||
//Если нашли данные - возвращаем номер строки
|
|
||||||
if (isCellHasData(row[c])) return r + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Если данных не нашли - возвращаем 1
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Поиск первой колонки, где есть данные
|
|
||||||
const getFirstDataColumnNo = ({ sheetData }) => {
|
|
||||||
//Если данных листа нет - возвращаем 1
|
|
||||||
if (!Array.isArray(sheetData) || sheetData.length === 0) return 1;
|
|
||||||
//Минимальный индекс колонки с данными
|
|
||||||
let minCol = null;
|
|
||||||
//Обходим строки
|
|
||||||
for (let r = 0; r < sheetData.length; r++) {
|
|
||||||
//Строка листа (массив ячеек)
|
|
||||||
const row = sheetData[r] || [];
|
|
||||||
//Обходим ячейки строки
|
|
||||||
for (let c = 0; c < row.length; c++) {
|
|
||||||
//Если данных нет - пропускаем
|
|
||||||
if (!isCellHasData(row[c])) continue;
|
|
||||||
//Фиксируем минимальную колонку с данными
|
|
||||||
minCol = minCol === null ? c : Math.min(minCol, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Если данных не нашли - возвращаем 1
|
|
||||||
if (minCol === null) return 1;
|
|
||||||
//Возвращаем номер колонки
|
|
||||||
return minCol + 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Построение таблиц для импорта по параметрам выполнения
|
|
||||||
const buildDataTablesByOptions = ({ workbook, nShpFileRn, options, sDataSheetName, bIgnoreSheetName, bHasHeaders }) => {
|
|
||||||
//Результирующий список таблиц
|
|
||||||
const res = [];
|
|
||||||
//Обходим все OPTION
|
|
||||||
for (const opt of toArray(options)) {
|
|
||||||
//Имя листа, к которому относится параметр
|
|
||||||
const sSheetName = String(opt?.SSHEET || "").trim();
|
|
||||||
//Если имя листа не задано - пропускаем
|
|
||||||
if (!sSheetName) continue;
|
|
||||||
//Если лист пустой - пропускаем
|
|
||||||
if (!isSheetNotEmpty({ workbook, sSheetName: bIgnoreSheetName ? sDataSheetName : sSheetName })) continue;
|
|
||||||
//Список таблиц для данного параметра
|
|
||||||
const rTables = toArray(opt?.RTABLES?.RTABLE);
|
|
||||||
//Если таблицы не указаны - пропускаем
|
|
||||||
if (rTables.length === 0) continue;
|
|
||||||
//Фактическое количество колонок листа
|
|
||||||
const nColumnsCountRaw = getSheetColumnsCount({ workbook, sSheetName: bIgnoreSheetName ? sDataSheetName : sSheetName });
|
|
||||||
//Фактическое количество строк листа
|
|
||||||
const nLinesCountRaw = (workbook.Sheets[bIgnoreSheetName ? sDataSheetName : sSheetName]["!data"] || []).length;
|
|
||||||
//Обходим описанные таблицы
|
|
||||||
for (const rt of rTables) {
|
|
||||||
//Имя таблицы
|
|
||||||
const sTableName = rt?.SNAME ? String(rt.SNAME).trim() : null;
|
|
||||||
//Лист, откуда берём данные
|
|
||||||
const sheet = workbook?.Sheets?.[bIgnoreSheetName ? sDataSheetName : sSheetName] || null;
|
|
||||||
//Dense-данные листа
|
|
||||||
const sheetData = sheet?.["!data"] || [];
|
|
||||||
//Номер строки заголовков
|
|
||||||
const nHeaderLineNo = bHasHeaders ? getFirstDataLineNo({ sheetData }) : null;
|
|
||||||
//Индекс заголовков
|
|
||||||
const headersIndex = bHasHeaders ? buildHeadersIndex({ sheet, sheetData, nHeaderLineNo }) : null;
|
|
||||||
//Формируем список колонок по описателю
|
|
||||||
const aCols = buildIndexList({
|
|
||||||
selector: rt?.RCOLUMNS || null,
|
|
||||||
nMax: nColumnsCountRaw,
|
|
||||||
normalizeItem: v => normalizeColumnWithHeaders({ value: v, headersIndex }),
|
|
||||||
getDefaultFrom: () => getFirstDataColumnNo({ sheetData })
|
|
||||||
});
|
|
||||||
//Формируем список строк по описателю
|
|
||||||
const aLines = buildIndexList({
|
|
||||||
selector: rt?.RLINES || null,
|
|
||||||
nMax: nLinesCountRaw,
|
|
||||||
normalizeItem: v => {
|
|
||||||
//Если значения нет - не нормализуем
|
|
||||||
if (v === null || v === undefined) return null;
|
|
||||||
//Парсим строку как число
|
|
||||||
const n = parseInt(String(v).trim(), 10);
|
|
||||||
//Индекс строки должен быть положительным
|
|
||||||
return Number.isFinite(n) && n > 0 ? n : null;
|
|
||||||
},
|
|
||||||
getDefaultFrom: () => getFirstDataLineNo({ sheetData })
|
|
||||||
});
|
|
||||||
//Добавляем описание таблицы в результат
|
|
||||||
res.push({
|
|
||||||
sSheetName,
|
|
||||||
sDataSheetName: bIgnoreSheetName ? sDataSheetName : sSheetName,
|
|
||||||
sTableName,
|
|
||||||
nShpFileRn,
|
|
||||||
aColumns: aCols,
|
|
||||||
aLines
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Возвращаем список таблиц
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Преобразование значения ячейки в формат импорта
|
|
||||||
const makeImportCell = ({ cl, n }) => {
|
|
||||||
//Нормализуем номер колонки (1..)
|
|
||||||
const nCol = Number.isFinite(n) && n > 0 ? n : null;
|
|
||||||
//Если ячейки нет - пишем пустую ячейку
|
|
||||||
if (!cl) return { $: { t: "z", n: nCol }, v: null };
|
|
||||||
//Тип ячейки
|
|
||||||
const t = cl.t || "z";
|
|
||||||
//Значение ячейки (даты приводим к ISO-строке)
|
|
||||||
const v = (t === "d" ? cl.v?.toISOString?.() : cl.v) || cl.w || null;
|
|
||||||
//Возвращаем формат ячейки для импорта
|
|
||||||
return { $: { t, n: nCol }, v };
|
|
||||||
};
|
|
||||||
|
|
||||||
//Резолвер значений для объединённых ячеек
|
|
||||||
const createMergedCellResolver = sheet => {
|
|
||||||
//Считываем описания объединений ячеек (если они есть)
|
|
||||||
const merges = Array.isArray(sheet?.["!merges"]) ? sheet["!merges"] : [];
|
|
||||||
//Если объединений нет - возвращаем быстрый резолвер без дополнительной логики
|
|
||||||
if (merges.length === 0) {
|
|
||||||
return {
|
|
||||||
hasMerges: false,
|
|
||||||
resolveCell: (_r, _c, cell) => cell || null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
//Создаём индекс объединений по строкам
|
|
||||||
const byRow = new Map();
|
|
||||||
//Обходим все описания объединений
|
|
||||||
for (const m of merges) {
|
|
||||||
//Начальная координата диапазона объединения
|
|
||||||
const s = m?.s;
|
|
||||||
//Конечная координата диапазона объединения
|
|
||||||
const e = m?.e;
|
|
||||||
//Если координат нет - пропускаем элемент
|
|
||||||
if (!s || !e) continue;
|
|
||||||
//Нормализуем начало по строкам
|
|
||||||
const rFrom = Math.min(s.r ?? 0, e.r ?? 0);
|
|
||||||
//Нормализуем конец по строкам
|
|
||||||
const rTo = Math.max(s.r ?? 0, e.r ?? 0);
|
|
||||||
//Нормализуем начало по колонкам
|
|
||||||
const cFrom = Math.min(s.c ?? 0, e.c ?? 0);
|
|
||||||
//Нормализуем конец по колонкам
|
|
||||||
const cTo = Math.max(s.c ?? 0, e.c ?? 0);
|
|
||||||
//Проверяем валидность нормализованных координат
|
|
||||||
const bOk = Number.isFinite(rFrom) && Number.isFinite(rTo) && Number.isFinite(cFrom) && Number.isFinite(cTo);
|
|
||||||
//Если координаты невалидны - пропускаем объединение
|
|
||||||
if (!bOk) continue;
|
|
||||||
//Индексируем объединение по всем строкам диапазона
|
|
||||||
for (let r = rFrom; r <= rTo; r++) {
|
|
||||||
//Текущий список объединений по строке (если уже есть)
|
|
||||||
const arr = byRow.get(r);
|
|
||||||
//Сохраняем диапазон и “ведущую” ячейку
|
|
||||||
const item = { rFrom, rTo, cFrom, cTo, rLead: rFrom, cLead: cFrom };
|
|
||||||
//Если массив по строке уже существует - добавляем
|
|
||||||
if (arr) arr.push(item);
|
|
||||||
//Иначе создаём новый список по строке
|
|
||||||
else byRow.set(r, [item]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Получаем dense-данные листа (для доступа к “ведущей” ячейке)
|
|
||||||
const data = sheet?.["!data"] || [];
|
|
||||||
//Возвращаем резолвер с поддержкой объединений
|
|
||||||
return {
|
|
||||||
hasMerges: true,
|
|
||||||
resolveCell: (r, c, cell) => {
|
|
||||||
//Если ячейка уже есть - возвращаем её без изменений
|
|
||||||
if (cell) return cell;
|
|
||||||
//Получаем список объединений для текущей строки
|
|
||||||
const rowMerges = byRow.get(r);
|
|
||||||
//Если объединений в этой строке нет - возвращаем null
|
|
||||||
if (!rowMerges || rowMerges.length === 0) return null;
|
|
||||||
//Проверяем попадание колонки в один из диапазонов объединений
|
|
||||||
for (const m of rowMerges) {
|
|
||||||
//Если колонка вне диапазона - проверяем следующее объединение
|
|
||||||
if (c < m.cFrom || c > m.cTo) continue;
|
|
||||||
//Возвращаем “ведущую” ячейку диапазона
|
|
||||||
return (data[m.rLead] || [])[m.cLead] || null;
|
|
||||||
}
|
|
||||||
//Если не попали ни в одно объединение - возвращаем null
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------
|
|
||||||
// Тело модуля
|
|
||||||
//------------
|
|
||||||
|
|
||||||
//Обработчик "До"
|
|
||||||
const importBefore = async ({ queue, dbConn }) => {
|
|
||||||
//Если задано тело сообщения
|
|
||||||
if (queue.blMsg) {
|
|
||||||
//В теле должен быть рег. номер файла данных (EXSEXTSHPFL)
|
|
||||||
const nShpFileRn = parseInt(queue.blMsg.toString(), 10);
|
|
||||||
//Если там рег. номер (число)
|
|
||||||
if (!isNaN(nShpFileRn)) {
|
|
||||||
//Читаем по нему запись файла данных
|
|
||||||
const shpFileData = await dbConn.executeStored({
|
|
||||||
connection: dbConn.connection,
|
|
||||||
sName: "PKG_EXS_EXT_SHP.FILE_GET",
|
|
||||||
inPrms: { NEXSEXTSHPFL: nShpFileRn },
|
|
||||||
outPrms: { RFILE: dbConn.connector.DT_CURSOR }
|
|
||||||
});
|
|
||||||
//Если запись найдена
|
|
||||||
if (shpFileData.RFILE.length === 1) {
|
|
||||||
//Разбираем её
|
|
||||||
try {
|
|
||||||
//Признак наличия заголовков
|
|
||||||
const bHasHeaders = String(shpFileData.RFILE[0]?.nHasHeaders ?? "0").trim() === "1";
|
|
||||||
//Формат файла данных
|
|
||||||
const nFileFormat = shpFileData.RFILE[0]?.nFormat;
|
|
||||||
//Заголовки формируем только для CSV/DBF и только если они есть
|
|
||||||
const bNeedSendHeaders = bHasHeaders && [NSHPFL_FORMAT_CSV, NSHPFL_FORMAT_DBF].includes(nFileFormat);
|
|
||||||
//Объект рабочей книги
|
|
||||||
let workbook = null;
|
|
||||||
try {
|
|
||||||
//Кодировка файла данных
|
|
||||||
const nEnc = shpFileData.RFILE[0].nEnc;
|
|
||||||
//Кодовая страница (параметры чтения XLSX)
|
|
||||||
const cp = {};
|
|
||||||
//Байты файла данных
|
|
||||||
let blData = shpFileData.RFILE[0].blFileData;
|
|
||||||
//Если это CSV
|
|
||||||
if (nFileFormat === NSHPFL_FORMAT_CSV) {
|
|
||||||
//Если указана Win-1251 - перекодируем CSV в UTF-8
|
|
||||||
if (nEnc === NSHPFL_ENC_WIN1251) {
|
|
||||||
//Декодируем исходные байты как windows-1251
|
|
||||||
const s = new TextDecoder("windows-1251").decode(blData);
|
|
||||||
//Преобразуем строку обратно в байты UTF-8
|
|
||||||
blData = Buffer.from(s);
|
|
||||||
}
|
|
||||||
//Задаём codepage UTF-8
|
|
||||||
cp.codepage = 65001;
|
|
||||||
}
|
|
||||||
//Если это DBF
|
|
||||||
else if (nFileFormat === NSHPFL_FORMAT_DBF) {
|
|
||||||
//Если указана Win-1251
|
|
||||||
if (nEnc === NSHPFL_ENC_WIN1251)
|
|
||||||
//Задаём codepage 1251
|
|
||||||
cp.codepage = 1251;
|
|
||||||
else
|
|
||||||
//Задаём codepage UTF-8
|
|
||||||
cp.codepage = 65001;
|
|
||||||
}
|
|
||||||
//Выполняем парсинг
|
|
||||||
workbook = XLSX.read(blData, { dense: true, cellDates: true, ...cp });
|
|
||||||
} catch (e) {
|
|
||||||
//Ошибка чтения/парсинга файла данных
|
|
||||||
throw new Error(`Ошибка разбора файла данных: ${e.message}`);
|
|
||||||
}
|
|
||||||
//Если есть сведения о листахх
|
|
||||||
if (workbook && workbook?.SheetNames?.length > 0) {
|
|
||||||
//Признак формата, где листов фактически нет (csv/dbf) или их не нужно учитывать
|
|
||||||
const bIgnoreSheetName = ![NSHPFL_FORMAT_XLS, NSHPFL_FORMAT_ODS].includes(nFileFormat);
|
|
||||||
//Имя листа с данными (для csv/dbf используем первый лист книги)
|
|
||||||
const sDataSheetName = workbook.SheetNames[0];
|
|
||||||
//Разбор параметров выполнения (если есть)
|
|
||||||
const shpOptions = await parseShpOptionsXML(shpFileData.RFILE[0]?.clOptions);
|
|
||||||
//Определим буфер для хранения таблиц файла данных
|
|
||||||
const dataTables = [];
|
|
||||||
//Формирование списка таблиц для импорта
|
|
||||||
const tablesSpec = shpOptions
|
|
||||||
? buildDataTablesByOptions({
|
|
||||||
workbook,
|
|
||||||
nShpFileRn,
|
|
||||||
options: shpOptions.options,
|
|
||||||
sDataSheetName,
|
|
||||||
bIgnoreSheetName,
|
|
||||||
bHasHeaders
|
|
||||||
})
|
|
||||||
: (bIgnoreSheetName
|
|
||||||
? [sDataSheetName]
|
|
||||||
: workbook.SheetNames.filter(sSheetName => isSheetNotEmpty({ workbook, sSheetName }))
|
|
||||||
).map(sSheetName => ({
|
|
||||||
sSheetName,
|
|
||||||
sDataSheetName: bIgnoreSheetName ? sDataSheetName : sSheetName,
|
|
||||||
sTableName: null,
|
|
||||||
nShpFileRn,
|
|
||||||
aColumns: null,
|
|
||||||
aLines: null
|
|
||||||
}));
|
|
||||||
//Регистрируем таблицы на сервере
|
|
||||||
for (const tbl of tablesSpec) {
|
|
||||||
//Считаем фактическое количество колонок листа
|
|
||||||
const nColumnsCountRaw = getSheetColumnsCount({ workbook, sSheetName: tbl.sDataSheetName || tbl.sSheetName });
|
|
||||||
//Считаем фактическое количество строк листа
|
|
||||||
const nLinesCountRaw = (workbook.Sheets[tbl.sDataSheetName || tbl.sSheetName]["!data"] || []).length;
|
|
||||||
//Список колонок (или null - значит все)
|
|
||||||
const aColumns = Array.isArray(tbl.aColumns) ? tbl.aColumns : null;
|
|
||||||
//Список строк (или null - значит все)
|
|
||||||
const aLines = Array.isArray(tbl.aLines) ? tbl.aLines : null;
|
|
||||||
//Количество колонок для описания таблицы
|
|
||||||
const nColumnsCount = aColumns ? aColumns.length : nColumnsCountRaw;
|
|
||||||
//Определяем лист, с которого читаем данные
|
|
||||||
const sDataSheetName = tbl.sDataSheetName || tbl.sSheetName;
|
|
||||||
//Dense-данные листа
|
|
||||||
const sheetData = workbook?.Sheets?.[sDataSheetName]?.["!data"] || [];
|
|
||||||
//Номер строки заголовков (если заголовки нужны - берём первую строку с данными, иначе null)
|
|
||||||
const nHeaderLineNo = bNeedSendHeaders ? getFirstDataLineNo({ sheetData }) : null;
|
|
||||||
//Количество строк для описания таблицы
|
|
||||||
const nLinesCount = (() => {
|
|
||||||
//Если заголовков нет - количество строк
|
|
||||||
const nRaw = aLines ? aLines.length : nLinesCountRaw;
|
|
||||||
//Если заголовки не требуются - возвращаем как есть
|
|
||||||
if (!bNeedSendHeaders) return nRaw;
|
|
||||||
//Если строк нет - нечего исключать
|
|
||||||
if (!Number.isFinite(nRaw) || nRaw <= 0) return nRaw;
|
|
||||||
//Если номер заголовка невалиден
|
|
||||||
if (!Number.isFinite(nHeaderLineNo) || nHeaderLineNo <= 0) return nRaw;
|
|
||||||
//Если выбран конкретный список строк - исключаем заголовок только если он туда попал
|
|
||||||
if (aLines) return aLines.includes(nHeaderLineNo) ? Math.max(nRaw - 1, 0) : nRaw;
|
|
||||||
//Если строки не фильтруются - заголовок считаем частью данных листа и исключаем его
|
|
||||||
return nHeaderLineNo <= nLinesCountRaw ? Math.max(nRaw - 1, 0) : nRaw;
|
|
||||||
})();
|
|
||||||
//Формируем XML заголовков (только если требуется отправка заголовков)
|
|
||||||
const sHeadersXML = bNeedSendHeaders
|
|
||||||
? buildTableHeadersXML({
|
|
||||||
workbook,
|
|
||||||
sSheetName: sDataSheetName,
|
|
||||||
aColumns,
|
|
||||||
nColumnsCount,
|
|
||||||
nHeaderLineNo
|
|
||||||
})
|
|
||||||
: null;
|
|
||||||
try {
|
|
||||||
//Создаём таблицу в БД
|
|
||||||
const shpFileDataTable = await dbConn.executeStored({
|
|
||||||
connection: dbConn.connection,
|
|
||||||
sName: "PKG_EXS_EXT_SHP.FILE_TABLE_ADD",
|
|
||||||
inPrms: {
|
|
||||||
NEXSEXTSHPFL: nShpFileRn,
|
|
||||||
SSHEET: tbl.sSheetName,
|
|
||||||
STBL: tbl.sTableName,
|
|
||||||
NCOLS: nColumnsCount,
|
|
||||||
...(sHeadersXML ? { CHEADERS: sHeadersXML } : {}),
|
|
||||||
NLINES: nLinesCount
|
|
||||||
},
|
|
||||||
outPrms: { NEXSEXTSHPFLTB: dbConn.connector.DT_NUMBER }
|
|
||||||
});
|
|
||||||
//Сохраняем данные таблицы для дальнейшей загрузки строк
|
|
||||||
dataTables.push({
|
|
||||||
sSheetName: tbl.sSheetName,
|
|
||||||
sDataSheetName: tbl.sDataSheetName || tbl.sSheetName,
|
|
||||||
sTableName: tbl.sTableName,
|
|
||||||
nTableRn: shpFileDataTable.NEXSEXTSHPFLTB,
|
|
||||||
nColumnsCount,
|
|
||||||
nLinesCount,
|
|
||||||
aColumns,
|
|
||||||
aLines,
|
|
||||||
nHeaderLineNo
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
//Ошибка регистрации таблицы
|
|
||||||
throw new Error(
|
|
||||||
`Ошибка сохранения описания таблицы "${tbl.sTableName || "<НЕ УКАЗАНА>"}" листа "${tbl.sSheetName || "<НЕ УКАЗАН>"}": ${e.message}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Теперь загружаем таблицы - обходим их последовательно
|
|
||||||
for (const dataTable of dataTables) {
|
|
||||||
//Буфер строк для порционной загрузки
|
|
||||||
let impBuff = [];
|
|
||||||
//Сброс буфера
|
|
||||||
const flushBuff = async () => {
|
|
||||||
//Если буфер пуст - нечего сохранять
|
|
||||||
if (impBuff.length === 0) return;
|
|
||||||
//Преобразуем буфер в XML
|
|
||||||
let sXML = null;
|
|
||||||
try {
|
|
||||||
//Сборка XML для порции строк
|
|
||||||
sXML = toXML({ rootName: "lines", data: impBuff });
|
|
||||||
} catch (e) {
|
|
||||||
//Ошибка сборки XML
|
|
||||||
throw new Error(`Ошибка преобразования буфера в XML: ${e.message}.`);
|
|
||||||
}
|
|
||||||
//Сохраняем на сервере
|
|
||||||
const nLineFrom = impBuff[0].line.$.n;
|
|
||||||
const nLineTo = impBuff[impBuff.length - 1].line.$.n;
|
|
||||||
try {
|
|
||||||
//Сохраняем порцию строк в БД
|
|
||||||
await dbConn.executeStored({
|
|
||||||
connection: dbConn.connection,
|
|
||||||
sName: "PKG_EXS_EXT_SHP.FILE_TABLE_LINE_ADD",
|
|
||||||
inPrms: {
|
|
||||||
NEXSEXTSHPFLTB: dataTable.nTableRn,
|
|
||||||
NLN_FROM: nLineFrom,
|
|
||||||
NLN_TO: nLineTo,
|
|
||||||
BDT: Buffer.from(sXML)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
//Ошибка сохранения порции строк
|
|
||||||
throw new Error(
|
|
||||||
`Ошибка сохранения строк (c ${nLineFrom} - по ${nLineTo}) таблицы "${dataTable.sTableName || "<НЕ УКАЗАНА>"}" листа "${dataTable.sSheetName || "<НЕ УКАЗАН>"}": ${e.message}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
//Очищаем буфер после успешной отправки
|
|
||||||
impBuff = [];
|
|
||||||
};
|
|
||||||
//Получаем объект листа
|
|
||||||
const sheet = workbook.Sheets[dataTable.sDataSheetName || dataTable.sSheetName];
|
|
||||||
//Получаем dense-данные листа (строки/ячейки)
|
|
||||||
const sheetData = sheet?.["!data"] || [];
|
|
||||||
//Создаём резолвер объединённых ячеек
|
|
||||||
const { hasMerges, resolveCell } = createMergedCellResolver(sheet);
|
|
||||||
//Формируем список строк (или берём все)
|
|
||||||
const aLines = dataTable.aLines ? dataTable.aLines : buildAllIndexList({ nMax: sheetData.length });
|
|
||||||
//Список колонок (или null - значит все)
|
|
||||||
const aColumns = dataTable.aColumns;
|
|
||||||
//Предыдущая строка для контроля непрерывности (NLN_FROM/NLN_TO)
|
|
||||||
let prevLineNo = null;
|
|
||||||
for (const lineNo of aLines) {
|
|
||||||
//Защита от невалидных индексов
|
|
||||||
if (!Number.isFinite(lineNo) || lineNo < 1 || lineNo > sheetData.length) continue;
|
|
||||||
//Если это строка заголовков - не отправляем её как данные
|
|
||||||
if (Number.isFinite(dataTable.nHeaderLineNo) && lineNo === dataTable.nHeaderLineNo) continue;
|
|
||||||
//Если есть разрыв диапазона строк - сбрасываем буфер (важно для NLN_FROM/NLN_TO)
|
|
||||||
if (prevLineNo !== null && lineNo !== prevLineNo + 1) await flushBuff();
|
|
||||||
//Получаем строку листа
|
|
||||||
const sheetLine = sheetData[lineNo - 1] || [];
|
|
||||||
//Формируем ячейки строки с учётом фильтра колонок и объединений
|
|
||||||
const cells = aColumns
|
|
||||||
? aColumns.map(colNo =>
|
|
||||||
//Для выбранной колонки получаем ячейку (с учётом объединения) и приводим к формату импорта
|
|
||||||
makeImportCell({
|
|
||||||
//Резолвим ячейку по исходной колонке
|
|
||||||
cl: resolveCell(lineNo - 1, colNo - 1, (sheetLine || [])[colNo - 1]),
|
|
||||||
//Пишем номер исходной колонки
|
|
||||||
n: colNo
|
|
||||||
})
|
|
||||||
)
|
|
||||||
: (() => {
|
|
||||||
//Определяем количество колонок для строки (в режиме объединений берём из описания таблицы)
|
|
||||||
const nCols = hasMerges ? dataTable.nColumnsCount : (sheetLine || []).length;
|
|
||||||
//Готовим массив ячеек нужной длины
|
|
||||||
const res = new Array(nCols);
|
|
||||||
//Обходим все колонки строки
|
|
||||||
for (let c = 0; c < nCols; c++) {
|
|
||||||
//Резолвим ячейку (с учётом объединения) и приводим к формату импорта
|
|
||||||
res[c] = makeImportCell({
|
|
||||||
//Резолвим ячейку по исходной колонке
|
|
||||||
cl: resolveCell(lineNo - 1, c, (sheetLine || [])[c]),
|
|
||||||
//Пишем номер исходной колонки
|
|
||||||
n: c + 1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
//Возвращаем массив ячеек строки
|
|
||||||
return res;
|
|
||||||
})();
|
|
||||||
//Добавляем строку в буфер импорта
|
|
||||||
impBuff.push({
|
|
||||||
line: {
|
|
||||||
$: { n: lineNo },
|
|
||||||
cell: cells
|
|
||||||
}
|
|
||||||
});
|
|
||||||
//Запоминаем предыдущую строку
|
|
||||||
prevLineNo = lineNo;
|
|
||||||
//Если набрали порцию - отправляем
|
|
||||||
if (impBuff.length === NIMPORT_BUFF_LEN) await flushBuff();
|
|
||||||
}
|
|
||||||
//Сохраняем остаток буфера
|
|
||||||
await flushBuff();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
//Любая ошибка импорта
|
|
||||||
throw new Error(e.message || "Неожиданная ошибка.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Не нашли запись файла данных
|
|
||||||
else throw new Error("Файл данных не определен.");
|
|
||||||
}
|
|
||||||
//Не смогли считать рег. номер из тела сообщения
|
|
||||||
else throw new Error("Некорректный идентификатор файла данных для разбора.");
|
|
||||||
}
|
|
||||||
//Тело сообщения не задано
|
|
||||||
else throw new Error("Нет данных для разбора.");
|
|
||||||
//Обработку закончили - продолжать не надо, мы всё сделали в обработчике
|
|
||||||
return { bStopPropagation: true };
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------------
|
|
||||||
// Интерфейс модуля
|
|
||||||
//-----------------
|
|
||||||
|
|
||||||
exports.importBefore = importBefore;
|
|
||||||
16
modules/shp_utils/node_modules/.bin/xlsx
generated
vendored
16
modules/shp_utils/node_modules/.bin/xlsx
generated
vendored
@ -1,16 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
||||||
|
|
||||||
case `uname` in
|
|
||||||
*CYGWIN*|*MINGW*|*MSYS*)
|
|
||||||
if command -v cygpath > /dev/null 2>&1; then
|
|
||||||
basedir=`cygpath -w "$basedir"`
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [ -x "$basedir/node" ]; then
|
|
||||||
exec "$basedir/node" "$basedir/../xlsx/bin/xlsx.njs" "$@"
|
|
||||||
else
|
|
||||||
exec node "$basedir/../xlsx/bin/xlsx.njs" "$@"
|
|
||||||
fi
|
|
||||||
17
modules/shp_utils/node_modules/.bin/xlsx.cmd
generated
vendored
17
modules/shp_utils/node_modules/.bin/xlsx.cmd
generated
vendored
@ -1,17 +0,0 @@
|
|||||||
@ECHO off
|
|
||||||
GOTO start
|
|
||||||
:find_dp0
|
|
||||||
SET dp0=%~dp0
|
|
||||||
EXIT /b
|
|
||||||
:start
|
|
||||||
SETLOCAL
|
|
||||||
CALL :find_dp0
|
|
||||||
|
|
||||||
IF EXIST "%dp0%\node.exe" (
|
|
||||||
SET "_prog=%dp0%\node.exe"
|
|
||||||
) ELSE (
|
|
||||||
SET "_prog=node"
|
|
||||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
|
||||||
)
|
|
||||||
|
|
||||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\xlsx\bin\xlsx.njs" %*
|
|
||||||
28
modules/shp_utils/node_modules/.bin/xlsx.ps1
generated
vendored
28
modules/shp_utils/node_modules/.bin/xlsx.ps1
generated
vendored
@ -1,28 +0,0 @@
|
|||||||
#!/usr/bin/env pwsh
|
|
||||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
|
||||||
|
|
||||||
$exe=""
|
|
||||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
|
||||||
# Fix case when both the Windows and Linux builds of Node
|
|
||||||
# are installed in the same directory
|
|
||||||
$exe=".exe"
|
|
||||||
}
|
|
||||||
$ret=0
|
|
||||||
if (Test-Path "$basedir/node$exe") {
|
|
||||||
# Support pipeline input
|
|
||||||
if ($MyInvocation.ExpectingInput) {
|
|
||||||
$input | & "$basedir/node$exe" "$basedir/../xlsx/bin/xlsx.njs" $args
|
|
||||||
} else {
|
|
||||||
& "$basedir/node$exe" "$basedir/../xlsx/bin/xlsx.njs" $args
|
|
||||||
}
|
|
||||||
$ret=$LASTEXITCODE
|
|
||||||
} else {
|
|
||||||
# Support pipeline input
|
|
||||||
if ($MyInvocation.ExpectingInput) {
|
|
||||||
$input | & "node$exe" "$basedir/../xlsx/bin/xlsx.njs" $args
|
|
||||||
} else {
|
|
||||||
& "node$exe" "$basedir/../xlsx/bin/xlsx.njs" $args
|
|
||||||
}
|
|
||||||
$ret=$LASTEXITCODE
|
|
||||||
}
|
|
||||||
exit $ret
|
|
||||||
19
modules/shp_utils/node_modules/.package-lock.json
generated
vendored
19
modules/shp_utils/node_modules/.package-lock.json
generated
vendored
@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "shp_utils",
|
|
||||||
"lockfileVersion": 3,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {
|
|
||||||
"node_modules/xlsx": {
|
|
||||||
"version": "0.20.3",
|
|
||||||
"resolved": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
|
|
||||||
"integrity": "sha512-oLDq3jw7AcLqKWH2AhCpVTZl8mf6X2YReP+Neh0SJUzV/BdZYjth94tG5toiMB1PPrYtxOCfaoUCkvtuH+3AJA==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"bin": {
|
|
||||||
"xlsx": "bin/xlsx.njs"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.8"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
361
modules/shp_utils/node_modules/xlsx/CHANGELOG.md
generated
vendored
361
modules/shp_utils/node_modules/xlsx/CHANGELOG.md
generated
vendored
@ -1,361 +0,0 @@
|
|||||||
# CHANGELOG
|
|
||||||
|
|
||||||
This log is intended to keep track of backwards-incompatible changes, including
|
|
||||||
but not limited to API changes and file location changes. Minor behavioral
|
|
||||||
changes may not be included if they are not expected to break existing code.
|
|
||||||
|
|
||||||
## v0.20.3
|
|
||||||
|
|
||||||
* Correct parsing of NUMBERS and ODS merge cells (h/t @s-ashwin)
|
|
||||||
* More precise treatment of infinite and NaN values
|
|
||||||
* XLML Streaming Write
|
|
||||||
* Parse `Int8Array` objects (for compatibility with JS engines in Java)
|
|
||||||
* CSV Export only quote leading ID (h/t @lako12)
|
|
||||||
|
|
||||||
## v0.20.2
|
|
||||||
|
|
||||||
* Reworked parsing methods to avoid slow regexes (CVE-2024-22363)
|
|
||||||
* HTML properly encode data-v attribute
|
|
||||||
* SYLK read and write error cells
|
|
||||||
|
|
||||||
## v0.20.1
|
|
||||||
|
|
||||||
* `init` use packaged test files to work around GitHub breaking changes
|
|
||||||
* SSF date code rounding to 15 decimal digits (h/t @davidtamaki)
|
|
||||||
* `sheet_to_json` force UTC interpretation for formatted strings (h/t @Blanay)
|
|
||||||
* QPW extract result of string formula
|
|
||||||
* XLSX parse non-compliant merge cell expressions
|
|
||||||
* NUMBERS correctly handle rows omitted from official exports
|
|
||||||
* DBF parse empty logical field (h/t @Roman91)
|
|
||||||
* `dense` option added to types
|
|
||||||
* package.json add mini and core scripts to export map (h/t @stof)
|
|
||||||
|
|
||||||
## v0.20.0
|
|
||||||
|
|
||||||
* Use UTC interpretation of Date objects for date cells (potentially breaking)
|
|
||||||
* API functions support UTC and local time value interpretations
|
|
||||||
* Export `NaN` values to `#NUM!` and infinite values to `#DIV/0!`
|
|
||||||
|
|
||||||
## v0.19.3
|
|
||||||
|
|
||||||
* XLSX Ensure comment address is valid (h/t @slonser)
|
|
||||||
* Enforce Excel worksheet name restrictions
|
|
||||||
* Fixed "Prototype Pollution" vulnerability (CVE-2023-30533)
|
|
||||||
|
|
||||||
## v0.19.2
|
|
||||||
|
|
||||||
* XLSX proper decoding of hyperlinks (h/t @tw-yaxu)
|
|
||||||
* XLSX ignore unexpected attributes in rich text (h/t @colin4)
|
|
||||||
* `sheet_to_json` type fix (h/t @chsdwn)
|
|
||||||
|
|
||||||
## v0.19.1
|
|
||||||
|
|
||||||
* Fixed types issue in strict mode (h/t @younes-io)
|
|
||||||
* Numbers 12.2 parsing skip ActivityStream.iwa
|
|
||||||
|
|
||||||
## v0.19.0
|
|
||||||
|
|
||||||
* XLSX export hyperlinks compatible with google sheets (h/t Evan Bovie)
|
|
||||||
* NUMBERS export multiple sheets, full worksheet range
|
|
||||||
* formalized `dense` mode
|
|
||||||
|
|
||||||
## v0.18.12
|
|
||||||
|
|
||||||
* `package.json` added types in `exports` structure
|
|
||||||
* uncapped NUMBERS single-sheet single-table export
|
|
||||||
* DBF export records using supported codepages
|
|
||||||
|
|
||||||
## v0.18.11
|
|
||||||
|
|
||||||
* Base64 input ignore data URI wrapper
|
|
||||||
* Parse ZIP files that use ZIP64 extended information field
|
|
||||||
* More precise handling of time-only values
|
|
||||||
* Threaded Comment fallback text for older Excel
|
|
||||||
|
|
||||||
## v0.18.10
|
|
||||||
|
|
||||||
* `exports` field in package.json to satiate ViteJS and newer tooling
|
|
||||||
* JSC (Safari / Bun) perf, see <https://bugs.webkit.org/show_bug.cgi?id=243148>
|
|
||||||
* workbook `bookType` property to denote the origin format when parsed from file
|
|
||||||
* XLSX force export of stub cells with number formats when `sheetStubs` is set
|
|
||||||
|
|
||||||
## v0.18.9
|
|
||||||
|
|
||||||
* XLSX / ODS write defined names
|
|
||||||
* sync defined names to AutoFilter setting on export
|
|
||||||
* 1904 date system setting properly roundtripped
|
|
||||||
* ODS read/write number formats
|
|
||||||
|
|
||||||
## v0.18.8
|
|
||||||
|
|
||||||
* Plaintext parsing of dateless meridien time values (`1:23:45 PM`)
|
|
||||||
* Legacy format (SYLK / WK# / Multiplan) minutiae
|
|
||||||
|
|
||||||
## v0.18.7
|
|
||||||
|
|
||||||
* Normalized handling of `\r` and `\n` newline characters
|
|
||||||
|
|
||||||
## v0.18.6
|
|
||||||
|
|
||||||
* Removed all npm dependencies
|
|
||||||
* Auto-correct bad Google Sheets format `d.m`
|
|
||||||
* NUMBERS write merge cells, cells up to column "ALL"
|
|
||||||
|
|
||||||
## v0.18.5
|
|
||||||
|
|
||||||
* Enabled `sideEffects: false` in package.json
|
|
||||||
* Basic NUMBERS write support
|
|
||||||
|
|
||||||
## v0.18.4
|
|
||||||
|
|
||||||
* CSV output omits trailing record separator
|
|
||||||
* Properly terminate NodeJS Streams
|
|
||||||
* DBF preserve column types on import and use when applicable on export
|
|
||||||
|
|
||||||
## v0.18.3
|
|
||||||
|
|
||||||
* Removed references to `require` and `process` in browser builds
|
|
||||||
|
|
||||||
## v0.18.2
|
|
||||||
|
|
||||||
* Hotfix for unicode processing of XLSX exports
|
|
||||||
|
|
||||||
## v0.18.1
|
|
||||||
|
|
||||||
* Removed Node ESM build script and folded into standard ESM build
|
|
||||||
* Removed undocumented aliases including `make_formulae` and `get_formulae`
|
|
||||||
|
|
||||||
## v0.18.0
|
|
||||||
|
|
||||||
* Browser scripts only expose `XLSX` variable
|
|
||||||
* Module no longer ships with `dist/jszip.js` browser script
|
|
||||||
|
|
||||||
## v0.17.4
|
|
||||||
|
|
||||||
* CLI script moved to `xlsx-cli` package
|
|
||||||
|
|
||||||
## v0.17.3
|
|
||||||
|
|
||||||
* `window.XLSX` explicit assignment to satiate LWC
|
|
||||||
* CSV Proper formatting of errors
|
|
||||||
* HTML emit data-\* attributes
|
|
||||||
|
|
||||||
## v0.17.2
|
|
||||||
|
|
||||||
* Browser and Node optional ESM support
|
|
||||||
* DSV correct handling of bare quotes (h/t @bgamrat)
|
|
||||||
|
|
||||||
## v0.17.1
|
|
||||||
|
|
||||||
* `XLSB` writer uses short cell form when viable
|
|
||||||
|
|
||||||
## 0.17.0:
|
|
||||||
|
|
||||||
* mini build includes ODS parse/write support
|
|
||||||
* DBF explicitly cap worksheet to 1<<20 rows
|
|
||||||
* XLS throw errors on truncated records
|
|
||||||
|
|
||||||
## v0.16.2
|
|
||||||
|
|
||||||
* Disabled `PRN` parsing by default (better support for CSV without delimeters)
|
|
||||||
|
|
||||||
## v0.16.1
|
|
||||||
|
|
||||||
* skip empty custom property tags if data is absent (fixes DocSecurity issue)
|
|
||||||
* HTML output add raw value, type, number format
|
|
||||||
* DOM parse look for `v` / `t` / `z` attributes when determining value
|
|
||||||
* double quotes in properties escaped using `_x0022_`
|
|
||||||
* changed AMD structure for NetSuite and other RequireJS implementations
|
|
||||||
- `encode_cell` and `decode_cell` do not rely on `encode_col` / `decode_col`
|
|
||||||
|
|
||||||
## v0.16.0
|
|
||||||
|
|
||||||
* Date handling changed
|
|
||||||
* XLML certain tag tests are now case insensitive
|
|
||||||
* Fixed potentially vulnerable regular expressions
|
|
||||||
|
|
||||||
## v0.15.6
|
|
||||||
|
|
||||||
* CFB prevent infinite loop
|
|
||||||
* ODS empty cells marked as stub (type "z")
|
|
||||||
* `cellStyles` option implies `sheetStubs`
|
|
||||||
|
|
||||||
## v0.15.5
|
|
||||||
|
|
||||||
* `sheets` parse option to specify which sheets to parse
|
|
||||||
|
|
||||||
## v0.15.4
|
|
||||||
|
|
||||||
* AOA utilities properly preserve number formats
|
|
||||||
* Number formats captured in stub cells
|
|
||||||
|
|
||||||
## v0.15.3
|
|
||||||
|
|
||||||
* Properties and Custom Properties properly XML-encoded
|
|
||||||
|
|
||||||
## v0.15.2
|
|
||||||
|
|
||||||
- `sheet_get_cell` utility function
|
|
||||||
- `sheet_to_json` explicitly support `null` as alias for default behavior
|
|
||||||
- `encode_col` throw on negative column index
|
|
||||||
- HTML properly handle whitespace around tags in a run
|
|
||||||
- HTML use `id` option on write
|
|
||||||
- Files starting with `0x09` followed by a display character are now TSV files
|
|
||||||
- XLS parse references col/row indices mod by the correct number for BIFF ver
|
|
||||||
- XLSX comments moved to avoid overlapping cell
|
|
||||||
- XLSB outline level
|
|
||||||
- AutoFilter update `_FilterDatabase` defined name on write
|
|
||||||
- XLML skip CDATA blocks
|
|
||||||
|
|
||||||
## v0.15.1 (2019-08-14)
|
|
||||||
|
|
||||||
* XLSX ignore XML artifacts
|
|
||||||
* HTML capture and persist merges
|
|
||||||
|
|
||||||
## v0.15.0
|
|
||||||
|
|
||||||
* `dist/xlsx.mini.min.js` mini build with XLSX read/write and some utilities
|
|
||||||
* Removed legacy conversion utility functions
|
|
||||||
|
|
||||||
## v0.14.5
|
|
||||||
|
|
||||||
* XLS PtgNameX lookup
|
|
||||||
* XLS always create stub cells for blank cells with comments
|
|
||||||
|
|
||||||
|
|
||||||
## v0.14.4
|
|
||||||
|
|
||||||
* Better treatment of `skipHidden` in CSV output
|
|
||||||
* Ignore CLSID in XLS
|
|
||||||
* SYLK 7-bit character encoding
|
|
||||||
* SYLK and DBF codepage support
|
|
||||||
|
|
||||||
## v0.14.3
|
|
||||||
|
|
||||||
* Proper shifting of addresses in Shared Formulae
|
|
||||||
|
|
||||||
## v0.14.2
|
|
||||||
|
|
||||||
* Proper XML encoding of comments
|
|
||||||
|
|
||||||
## v0.14.1
|
|
||||||
|
|
||||||
* raw cell objects can be passed to `sheet_add_aoa`
|
|
||||||
* `_FilterDatabase` fix for AutoFilter-related crashes
|
|
||||||
* `stream.to_json` doesn't end up accidentally scanning to max row
|
|
||||||
|
|
||||||
## 0.14.0 (2018-09-06)
|
|
||||||
|
|
||||||
* `sheet_to_json` default flipped to `raw: true`
|
|
||||||
|
|
||||||
## 0.13.5 (2018-08-25)
|
|
||||||
|
|
||||||
* HTML output generates `<br/>` instead of encoded newline character
|
|
||||||
|
|
||||||
## 0.13.2 (2018-07-08)
|
|
||||||
|
|
||||||
* Buffer.from shim replaced, will not be defined in node `<=0.12`
|
|
||||||
|
|
||||||
## 0.13.0 (2018-06-01)
|
|
||||||
|
|
||||||
* Library reshaped to support AMD out of the box
|
|
||||||
|
|
||||||
## 0.12.11 (2018-04-27)
|
|
||||||
|
|
||||||
* XLS/XLSX/XLSB range truncation (errors in `WTF` mode)
|
|
||||||
|
|
||||||
## 0.12.4 (2018-03-04)
|
|
||||||
|
|
||||||
* `JSZip` renamed to `JSZipSync`
|
|
||||||
|
|
||||||
## 0.12.0 (2018-02-08)
|
|
||||||
|
|
||||||
* Extendscript target script in NPM package
|
|
||||||
|
|
||||||
## 0.11.19 (2018-02-03)
|
|
||||||
|
|
||||||
* Error on empty workbook
|
|
||||||
|
|
||||||
## 0.11.16 (2017-12-30)
|
|
||||||
|
|
||||||
* XLS ANSI/CP separation
|
|
||||||
* 'array' write type and ArrayBuffer processing
|
|
||||||
|
|
||||||
## 0.11.6 (2017-10-16)
|
|
||||||
|
|
||||||
* Semicolon-delimited files are detected
|
|
||||||
|
|
||||||
## 0.11.5 (2017-09-30)
|
|
||||||
|
|
||||||
* Bower main script shifted to full version
|
|
||||||
* 'binary' / 'string' encoding
|
|
||||||
|
|
||||||
## 0.11.3 (2017-08-19)
|
|
||||||
|
|
||||||
* XLS cell ixfe/XF removed
|
|
||||||
|
|
||||||
## 0.11.0 (2017-07-31)
|
|
||||||
|
|
||||||
* Strip `require` statements from minified version
|
|
||||||
* minifier mangler enabled
|
|
||||||
|
|
||||||
## 0.10.9 (2017-07-28)
|
|
||||||
|
|
||||||
* XLML/HTML resolution logic looks further into the data stream to decide type
|
|
||||||
* Errors thrown on suspected RTF files
|
|
||||||
|
|
||||||
## 0.10.5 (2017-06-09)
|
|
||||||
|
|
||||||
* HTML Table output header/footer should not include `<table>` tag
|
|
||||||
|
|
||||||
## 0.10.2 (2017-05-16)
|
|
||||||
|
|
||||||
* Dates are converted to numbers by default (set `cellDates:true` to emit Dates)
|
|
||||||
* Module does not export CFB
|
|
||||||
|
|
||||||
## 0.9.10 (2017-04-08)
|
|
||||||
|
|
||||||
* `--perf` renamed to `--read-only`
|
|
||||||
|
|
||||||
## 0.9.9 (2017-04-03)
|
|
||||||
|
|
||||||
* default output format changed to XLSB
|
|
||||||
* comment text line endings are now normalized
|
|
||||||
* errors thrown on write when worksheets have invalid names
|
|
||||||
|
|
||||||
## 0.9.7 (2017-03-28)
|
|
||||||
|
|
||||||
* XLS legacy `!range` field removed
|
|
||||||
* Hyperlink tooltip is stored in the `Tooltip` field
|
|
||||||
|
|
||||||
## 0.9.6 (2017-03-25)
|
|
||||||
|
|
||||||
* `sheet_to_json` now passes `null` values when `raw` is set to `true`
|
|
||||||
* `sheet_to_json` treats `null` stub cells as values in conjunction with `raw`
|
|
||||||
|
|
||||||
## 0.9.5 (2017-03-22)
|
|
||||||
|
|
||||||
* `cellDates` affects parsing in non-XLSX formats
|
|
||||||
|
|
||||||
## 0.9.3 (2017-03-15)
|
|
||||||
|
|
||||||
* XLML property names are more closely mapped to the XLSX equivalent
|
|
||||||
* Stub cells are now cell type `z`
|
|
||||||
|
|
||||||
## 0.9.2 (2017-03-13)
|
|
||||||
|
|
||||||
* Removed stale TypeScript definition files. Flowtype comments are used in the
|
|
||||||
`xlsx.flow.js` source and stripped to produce `xlsx.js`.
|
|
||||||
* sed usage reworked to support GNU sed in-place form. BSD sed seems to work,
|
|
||||||
but the build script has not been tested on other sed variants:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ sed -i.ext [...] # GNU
|
|
||||||
$ sed -i .ext [...] # bsd
|
|
||||||
```
|
|
||||||
|
|
||||||
## 0.9.0 (2017-03-09)
|
|
||||||
|
|
||||||
* Removed ods.js source. The xlsx.js source absorbed the ODS logic and exposes
|
|
||||||
the ODS variable, so projects should remove references to ods.js
|
|
||||||
|
|
||||||
201
modules/shp_utils/node_modules/xlsx/LICENSE
generated
vendored
201
modules/shp_utils/node_modules/xlsx/LICENSE
generated
vendored
@ -1,201 +0,0 @@
|
|||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright (C) 2012-present SheetJS LLC
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
41
modules/shp_utils/node_modules/xlsx/README.md
generated
vendored
41
modules/shp_utils/node_modules/xlsx/README.md
generated
vendored
@ -1,41 +0,0 @@
|
|||||||
# [SheetJS](https://sheetjs.com)
|
|
||||||
|
|
||||||
The SheetJS Community Edition offers battle-tested open-source solutions for
|
|
||||||
extracting useful data from almost any complex spreadsheet and generating new
|
|
||||||
spreadsheets that will work with legacy and modern software alike.
|
|
||||||
|
|
||||||
[SheetJS Pro](https://sheetjs.com/pro) offers solutions beyond data processing:
|
|
||||||
Edit complex templates with ease; let out your inner Picasso with styling; make
|
|
||||||
custom sheets with images/graphs/PivotTables; evaluate formula expressions and
|
|
||||||
port calculations to web apps; automate common spreadsheet tasks, and much more!
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
- [API and Usage Documentation](https://docs.sheetjs.com)
|
|
||||||
|
|
||||||
- [Downloadable Scripts and Modules](https://cdn.sheetjs.com)
|
|
||||||
|
|
||||||
## Constellation
|
|
||||||
|
|
||||||
- <https://oss.sheetjs.com/notes/>: File Format Notes
|
|
||||||
|
|
||||||
- [`ssf`](packages/ssf): Format data using ECMA-376 spreadsheet format codes
|
|
||||||
|
|
||||||
- [`xlsx-cli`](packages/xlsx-cli): NodeJS command-line tool for processing files
|
|
||||||
|
|
||||||
- [`cfb`](https://git.sheetjs.com/SheetJS/js-cfb): Container (OLE/ZIP) file
|
|
||||||
processing library
|
|
||||||
|
|
||||||
- [`codepage`](https://git.sheetjs.com/SheetJS/js-codepage): Legacy text
|
|
||||||
encodings for XLS and other legacy spreadsheet formats
|
|
||||||
|
|
||||||
- [`dta`](packages/dta): Stata DTA file processor
|
|
||||||
|
|
||||||
- [`test_files`](https://github.com/sheetjs/test_files): Test files and various
|
|
||||||
plaintext baselines.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
Please consult the attached LICENSE file for details. All rights not explicitly
|
|
||||||
granted by the Apache 2.0 License are reserved by the Original Author.
|
|
||||||
|
|
||||||
310
modules/shp_utils/node_modules/xlsx/bin/xlsx.njs
generated
vendored
310
modules/shp_utils/node_modules/xlsx/bin/xlsx.njs
generated
vendored
@ -1,310 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
|
||||||
/* eslint-env node */
|
|
||||||
/* vim: set ts=2 ft=javascript: */
|
|
||||||
var n = "xlsx";
|
|
||||||
var X = require('../');
|
|
||||||
try { X = require('../xlsx.flow'); } catch(e) {}
|
|
||||||
try { require('exit-on-epipe'); } catch(e) {}
|
|
||||||
var fs = require('fs'), program;
|
|
||||||
try { program = require('commander'); } catch(e) {
|
|
||||||
[
|
|
||||||
"The `xlsx` command line tool is deprecated in favor of `xlsx-cli`.",
|
|
||||||
"",
|
|
||||||
"For new versions of node, we recommend using `npx`:",
|
|
||||||
" $ npx xlsx-cli --help",
|
|
||||||
"",
|
|
||||||
"For older versions of node, explicitly install `xlsx-cli` globally:",
|
|
||||||
" $ npm i -g xlsx-cli",
|
|
||||||
" $ xlsx-cli --help"
|
|
||||||
].forEach(function(m) { console.error(m); });
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
program
|
|
||||||
.version(X.version)
|
|
||||||
.usage('[options] <file> [sheetname]')
|
|
||||||
.option('-f, --file <file>', 'use specified workbook')
|
|
||||||
.option('-s, --sheet <sheet>', 'print specified sheet (default first sheet)')
|
|
||||||
.option('-N, --sheet-index <idx>', 'use specified sheet index (0-based)')
|
|
||||||
.option('-p, --password <pw>', 'if file is encrypted, try with specified pw')
|
|
||||||
.option('-l, --list-sheets', 'list sheet names and exit')
|
|
||||||
.option('-o, --output <file>', 'output to specified file')
|
|
||||||
|
|
||||||
.option('-B, --xlsb', 'emit XLSB to <sheetname> or <file>.xlsb')
|
|
||||||
.option('-M, --xlsm', 'emit XLSM to <sheetname> or <file>.xlsm')
|
|
||||||
.option('-X, --xlsx', 'emit XLSX to <sheetname> or <file>.xlsx')
|
|
||||||
.option('-I, --xlam', 'emit XLAM to <sheetname> or <file>.xlam')
|
|
||||||
.option('-Y, --ods', 'emit ODS to <sheetname> or <file>.ods')
|
|
||||||
.option('-8, --xls', 'emit XLS to <sheetname> or <file>.xls (BIFF8)')
|
|
||||||
.option('-5, --biff5','emit XLS to <sheetname> or <file>.xls (BIFF5)')
|
|
||||||
.option('-4, --biff4','emit XLS to <sheetname> or <file>.xls (BIFF4)')
|
|
||||||
.option('-3, --biff3','emit XLS to <sheetname> or <file>.xls (BIFF3)')
|
|
||||||
.option('-2, --biff2','emit XLS to <sheetname> or <file>.xls (BIFF2)')
|
|
||||||
.option('-i, --xla', 'emit XLA to <sheetname> or <file>.xla')
|
|
||||||
.option('-6, --xlml', 'emit SSML to <sheetname> or <file>.xls (2003 XML)')
|
|
||||||
.option('-T, --fods', 'emit FODS to <sheetname> or <file>.fods (Flat ODS)')
|
|
||||||
.option('--wk3', 'emit WK3 to <sheetname> or <file>.txt (Lotus WK3)')
|
|
||||||
.option('--numbers', 'emit NUMBERS to <sheetname> or <file>.numbers')
|
|
||||||
|
|
||||||
.option('-S, --formulae', 'emit list of values and formulae')
|
|
||||||
.option('-j, --json', 'emit formatted JSON (all fields text)')
|
|
||||||
.option('-J, --raw-js', 'emit raw JS object (raw numbers)')
|
|
||||||
.option('-A, --arrays', 'emit rows as JS objects (raw numbers)')
|
|
||||||
.option('-H, --html', 'emit HTML to <sheetname> or <file>.html')
|
|
||||||
.option('-D, --dif', 'emit DIF to <sheetname> or <file>.dif (Lotus DIF)')
|
|
||||||
.option('-U, --dbf', 'emit DBF to <sheetname> or <file>.dbf (MSVFP DBF)')
|
|
||||||
.option('-K, --sylk', 'emit SYLK to <sheetname> or <file>.slk (Excel SYLK)')
|
|
||||||
.option('-P, --prn', 'emit PRN to <sheetname> or <file>.prn (Lotus PRN)')
|
|
||||||
.option('-E, --eth', 'emit ETH to <sheetname> or <file>.eth (Ethercalc)')
|
|
||||||
.option('-t, --txt', 'emit TXT to <sheetname> or <file>.txt (UTF-8 TSV)')
|
|
||||||
.option('-r, --rtf', 'emit RTF to <sheetname> or <file>.txt (Table RTF)')
|
|
||||||
.option('--wk1', 'emit WK1 to <sheetname> or <file>.txt (Lotus WK1)')
|
|
||||||
.option('-z, --dump', 'dump internal representation as JSON')
|
|
||||||
.option('--props', 'dump workbook properties as CSV')
|
|
||||||
|
|
||||||
.option('-F, --field-sep <sep>', 'CSV field separator', ",")
|
|
||||||
.option('-R, --row-sep <sep>', 'CSV row separator', "\n")
|
|
||||||
.option('-n, --sheet-rows <num>', 'Number of rows to process (0=all rows)')
|
|
||||||
.option('--codepage <cp>', 'default to specified codepage when ambiguous')
|
|
||||||
.option('--req <module>', 'require module before processing')
|
|
||||||
.option('--sst', 'generate shared string table for XLS* formats')
|
|
||||||
.option('--compress', 'use compression when writing XLSX/M/B and ODS')
|
|
||||||
.option('--read', 'read but do not generate output')
|
|
||||||
.option('--book', 'for single-sheet formats, emit a file per worksheet')
|
|
||||||
.option('--all', 'parse everything; write as much as possible')
|
|
||||||
.option('--dev', 'development mode')
|
|
||||||
.option('--sparse', 'sparse mode')
|
|
||||||
.option('-q, --quiet', 'quiet mode');
|
|
||||||
|
|
||||||
program.on('--help', function() {
|
|
||||||
console.log(' Default output format is CSV');
|
|
||||||
console.log(' Support email: dev@sheetjs.com');
|
|
||||||
console.log(' Web Demo: http://oss.sheetjs.com/js-'+n+'/');
|
|
||||||
});
|
|
||||||
|
|
||||||
/* flag, bookType, default ext */
|
|
||||||
var workbook_formats = [
|
|
||||||
['xlsx', 'xlsx', 'xlsx'],
|
|
||||||
['xlsm', 'xlsm', 'xlsm'],
|
|
||||||
['xlam', 'xlam', 'xlam'],
|
|
||||||
['xlsb', 'xlsb', 'xlsb'],
|
|
||||||
['xls', 'xls', 'xls'],
|
|
||||||
['xla', 'xla', 'xla'],
|
|
||||||
['biff5', 'biff5', 'xls'],
|
|
||||||
['numbers', 'numbers', 'numbers'],
|
|
||||||
['ods', 'ods', 'ods'],
|
|
||||||
['fods', 'fods', 'fods'],
|
|
||||||
['wk3', 'wk3', 'wk3']
|
|
||||||
];
|
|
||||||
var wb_formats_2 = [
|
|
||||||
['xlml', 'xlml', 'xls']
|
|
||||||
];
|
|
||||||
program.parse(process.argv);
|
|
||||||
|
|
||||||
var filename = '', sheetname = '';
|
|
||||||
if(program.args[0]) {
|
|
||||||
filename = program.args[0];
|
|
||||||
if(program.args[1]) sheetname = program.args[1];
|
|
||||||
}
|
|
||||||
if(program.sheet) sheetname = program.sheet;
|
|
||||||
if(program.file) filename = program.file;
|
|
||||||
|
|
||||||
if(!filename) {
|
|
||||||
console.error(n + ": must specify a filename");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
if(!fs.existsSync(filename)) {
|
|
||||||
console.error(n + ": " + filename + ": No such file or directory");
|
|
||||||
process.exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(program.req) program.req.split(",").forEach(function(r) {
|
|
||||||
require((fs.existsSync(r) || fs.existsSync(r + '.js')) ? require('path').resolve(r) : r);
|
|
||||||
});
|
|
||||||
|
|
||||||
var opts = {}, wb/*:?Workbook*/;
|
|
||||||
if(program.listSheets) opts.bookSheets = true;
|
|
||||||
if(program.sheetRows) opts.sheetRows = program.sheetRows;
|
|
||||||
if(program.password) opts.password = program.password;
|
|
||||||
var seen = false;
|
|
||||||
function wb_fmt() {
|
|
||||||
seen = true;
|
|
||||||
opts.cellFormula = true;
|
|
||||||
opts.cellNF = true;
|
|
||||||
opts.xlfn = true;
|
|
||||||
if(program.output) sheetname = program.output;
|
|
||||||
}
|
|
||||||
function isfmt(m/*:string*/)/*:boolean*/ {
|
|
||||||
if(!program.output) return false;
|
|
||||||
var t = m.charAt(0) === "." ? m : "." + m;
|
|
||||||
return program.output.slice(-t.length) === t;
|
|
||||||
}
|
|
||||||
workbook_formats.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) { wb_fmt(); } });
|
|
||||||
wb_formats_2.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) { wb_fmt(); } });
|
|
||||||
if(seen) {
|
|
||||||
} else if(program.formulae) opts.cellFormula = true;
|
|
||||||
else opts.cellFormula = false;
|
|
||||||
|
|
||||||
var wopts = ({WTF:opts.WTF, bookSST:program.sst}/*:any*/);
|
|
||||||
if(program.compress) wopts.compression = true;
|
|
||||||
|
|
||||||
if(program.all) {
|
|
||||||
opts.cellFormula = true;
|
|
||||||
opts.bookVBA = true;
|
|
||||||
opts.cellNF = true;
|
|
||||||
opts.cellHTML = true;
|
|
||||||
opts.cellStyles = true;
|
|
||||||
opts.sheetStubs = true;
|
|
||||||
opts.cellDates = true;
|
|
||||||
wopts.cellFormula = true;
|
|
||||||
wopts.cellStyles = true;
|
|
||||||
wopts.sheetStubs = true;
|
|
||||||
wopts.bookVBA = true;
|
|
||||||
}
|
|
||||||
if(program.sparse) opts.dense = false; else opts.dense = true;
|
|
||||||
if(program.codepage) opts.codepage = +program.codepage;
|
|
||||||
|
|
||||||
if(program.dev) {
|
|
||||||
opts.WTF = true;
|
|
||||||
wb = X.readFile(filename, opts);
|
|
||||||
} else try {
|
|
||||||
wb = X.readFile(filename, opts);
|
|
||||||
} catch(e) {
|
|
||||||
var msg = (program.quiet) ? "" : n + ": error parsing ";
|
|
||||||
msg += filename + ": " + e;
|
|
||||||
console.error(msg);
|
|
||||||
process.exit(3);
|
|
||||||
}
|
|
||||||
if(program.read) process.exit(0);
|
|
||||||
if(!wb) { console.error(n + ": error parsing " + filename + ": empty workbook"); process.exit(0); }
|
|
||||||
/*:: if(!wb) throw new Error("unreachable"); */
|
|
||||||
if(program.listSheets) {
|
|
||||||
console.log((wb.SheetNames||[]).join("\n"));
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
if(program.dump) {
|
|
||||||
console.log(JSON.stringify(wb));
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
if(program.props) {
|
|
||||||
if(wb) dump_props(wb);
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* full workbook formats */
|
|
||||||
workbook_formats.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) {
|
|
||||||
wopts.bookType = m[1];
|
|
||||||
if(wopts.bookType == "numbers") try {
|
|
||||||
var XLSX_ZAHL = require("../dist/xlsx.zahl");
|
|
||||||
wopts.numbers = XLSX_ZAHL;
|
|
||||||
} catch(e) {}
|
|
||||||
if(wb) X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts);
|
|
||||||
process.exit(0);
|
|
||||||
} });
|
|
||||||
|
|
||||||
wb_formats_2.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) {
|
|
||||||
wopts.bookType = m[1];
|
|
||||||
if(wb) X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts);
|
|
||||||
process.exit(0);
|
|
||||||
} });
|
|
||||||
|
|
||||||
var target_sheet = sheetname || '';
|
|
||||||
if(target_sheet === '') {
|
|
||||||
if(+program.sheetIndex < (wb.SheetNames||[]).length) target_sheet = wb.SheetNames[+program.sheetIndex];
|
|
||||||
else target_sheet = (wb.SheetNames||[""])[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
var ws;
|
|
||||||
try {
|
|
||||||
ws = wb.Sheets[target_sheet];
|
|
||||||
if(!ws) {
|
|
||||||
console.error("Sheet " + target_sheet + " cannot be found");
|
|
||||||
process.exit(3);
|
|
||||||
}
|
|
||||||
} catch(e) {
|
|
||||||
console.error(n + ": error parsing "+filename+" "+target_sheet+": " + e);
|
|
||||||
process.exit(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!program.quiet && !program.book) console.error(target_sheet);
|
|
||||||
|
|
||||||
/* single worksheet file formats */
|
|
||||||
[
|
|
||||||
['biff2', '.xls'],
|
|
||||||
['biff3', '.xls'],
|
|
||||||
['biff4', '.xls'],
|
|
||||||
['sylk', '.slk'],
|
|
||||||
['html', '.html'],
|
|
||||||
['prn', '.prn'],
|
|
||||||
['eth', '.eth'],
|
|
||||||
['rtf', '.rtf'],
|
|
||||||
['txt', '.txt'],
|
|
||||||
['dbf', '.dbf'],
|
|
||||||
['wk1', '.wk1'],
|
|
||||||
['dif', '.dif']
|
|
||||||
].forEach(function(m) { if(program[m[0]] || isfmt(m[1])) {
|
|
||||||
wopts.bookType = m[0];
|
|
||||||
if(program.book) {
|
|
||||||
/*:: if(wb == null) throw new Error("Unreachable"); */
|
|
||||||
wb.SheetNames.forEach(function(n, i) {
|
|
||||||
wopts.sheet = n;
|
|
||||||
X.writeFile(wb, (program.output || sheetname || filename || "") + m[1] + "." + i, wopts);
|
|
||||||
});
|
|
||||||
} else X.writeFile(wb, program.output || sheetname || ((filename || "") + m[1]), wopts);
|
|
||||||
process.exit(0);
|
|
||||||
} });
|
|
||||||
|
|
||||||
function outit(o, fn) { if(fn) fs.writeFileSync(fn, o); else console.log(o); }
|
|
||||||
|
|
||||||
function doit(cb) {
|
|
||||||
/*:: if(!wb) throw new Error("unreachable"); */
|
|
||||||
if(program.book) wb.SheetNames.forEach(function(n, i) {
|
|
||||||
/*:: if(!wb) throw new Error("unreachable"); */
|
|
||||||
outit(cb(wb.Sheets[n]), (program.output || sheetname || filename) + "." + i);
|
|
||||||
});
|
|
||||||
else outit(cb(ws), program.output);
|
|
||||||
}
|
|
||||||
|
|
||||||
var jso = {};
|
|
||||||
switch(true) {
|
|
||||||
case program.formulae:
|
|
||||||
doit(function(ws) { return X.utils.sheet_to_formulae(ws).join("\n"); });
|
|
||||||
break;
|
|
||||||
|
|
||||||
case program.arrays: jso.header = 1;
|
|
||||||
/* falls through */
|
|
||||||
case program.rawJs: jso.raw = true;
|
|
||||||
/* falls through */
|
|
||||||
case program.json:
|
|
||||||
doit(function(ws) { return JSON.stringify(X.utils.sheet_to_json(ws,jso)); });
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if(!program.book) {
|
|
||||||
var stream = X.stream.to_csv(ws, {FS:program.fieldSep||",", RS:program.rowSep||"\n"});
|
|
||||||
if(program.output) stream.pipe(fs.createWriteStream(program.output));
|
|
||||||
else stream.pipe(process.stdout);
|
|
||||||
} else doit(function(ws) { return X.utils.sheet_to_csv(ws,{FS:program.fieldSep, RS:program.rowSep}); });
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
function dump_props(wb/*:Workbook*/) {
|
|
||||||
var propaoa = [];
|
|
||||||
if(Object.assign && Object.entries) propaoa = Object.entries(Object.assign({}, wb.Props, wb.Custprops));
|
|
||||||
else {
|
|
||||||
var Keys/*:: :Array<string> = []*/, pi;
|
|
||||||
if(wb.Props) {
|
|
||||||
Keys = Object.keys(wb.Props);
|
|
||||||
for(pi = 0; pi < Keys.length; ++pi) {
|
|
||||||
if(Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(wb.Custprops) {
|
|
||||||
Keys = Object.keys(wb.Custprops);
|
|
||||||
for(pi = 0; pi < Keys.length; ++pi) {
|
|
||||||
if(Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log(X.utils.sheet_to_csv(X.utils.aoa_to_sheet(propaoa)));
|
|
||||||
}
|
|
||||||
22
modules/shp_utils/node_modules/xlsx/bower.json
generated
vendored
22
modules/shp_utils/node_modules/xlsx/bower.json
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "js-xlsx",
|
|
||||||
"homepage": "https://github.com/SheetJS/js-xlsx",
|
|
||||||
"main": ["xlsx.js"],
|
|
||||||
"ignore": [
|
|
||||||
"bin",
|
|
||||||
"bits",
|
|
||||||
"misc",
|
|
||||||
"**/.*"
|
|
||||||
],
|
|
||||||
"keywords": [
|
|
||||||
"excel",
|
|
||||||
"xls",
|
|
||||||
"xml",
|
|
||||||
"xlsx",
|
|
||||||
"xlsm",
|
|
||||||
"xlsb",
|
|
||||||
"ods",
|
|
||||||
"js-xls",
|
|
||||||
"js-xlsx"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
201
modules/shp_utils/node_modules/xlsx/dist/LICENSE
generated
vendored
201
modules/shp_utils/node_modules/xlsx/dist/LICENSE
generated
vendored
@ -1,201 +0,0 @@
|
|||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright (C) 2012-present SheetJS LLC
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
39
modules/shp_utils/node_modules/xlsx/dist/cpexcel.d.ts
generated
vendored
39
modules/shp_utils/node_modules/xlsx/dist/cpexcel.d.ts
generated
vendored
@ -1,39 +0,0 @@
|
|||||||
/* codepage.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
|
||||||
// TypeScript Version: 2.2
|
|
||||||
|
|
||||||
/** Codepage index type (integer or string representation) */
|
|
||||||
export type CP$Index = number | string;
|
|
||||||
|
|
||||||
/* Individual codepage converter */
|
|
||||||
export interface CP$Conv {
|
|
||||||
enc: {[n: string]: number; };
|
|
||||||
dec: {[n: number]: string; };
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Encode input type (string, array of characters, Buffer) */
|
|
||||||
export type CP$String = string | string[] | Uint8Array;
|
|
||||||
|
|
||||||
/** Encode output / decode input type */
|
|
||||||
export type CP$Data = string | number[] | Uint8Array;
|
|
||||||
|
|
||||||
/** General utilities */
|
|
||||||
export interface CP$Utils {
|
|
||||||
decode(cp: CP$Index, data: CP$Data): string;
|
|
||||||
encode(cp: CP$Index, data: CP$String, opts?: any): CP$Data;
|
|
||||||
hascp(n: number): boolean;
|
|
||||||
magic: {[cp: string]: string};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* note: TS cannot export top-level indexer, hence default workaround */
|
|
||||||
export interface CP$Module {
|
|
||||||
/** Version string */
|
|
||||||
version: string;
|
|
||||||
|
|
||||||
/** Utility Functions */
|
|
||||||
utils: CP$Utils;
|
|
||||||
|
|
||||||
/** Codepage Converters */
|
|
||||||
[cp: number]: CP$Conv;
|
|
||||||
}
|
|
||||||
export const cptable: CP$Module;
|
|
||||||
export default cptable;
|
|
||||||
1502
modules/shp_utils/node_modules/xlsx/dist/cpexcel.full.mjs
generated
vendored
1502
modules/shp_utils/node_modules/xlsx/dist/cpexcel.full.mjs
generated
vendored
File diff suppressed because it is too large
Load Diff
1506
modules/shp_utils/node_modules/xlsx/dist/cpexcel.js
generated
vendored
1506
modules/shp_utils/node_modules/xlsx/dist/cpexcel.js
generated
vendored
File diff suppressed because it is too large
Load Diff
2
modules/shp_utils/node_modules/xlsx/dist/shim.min.js
generated
vendored
2
modules/shp_utils/node_modules/xlsx/dist/shim.min.js
generated
vendored
File diff suppressed because one or more lines are too long
18
modules/shp_utils/node_modules/xlsx/dist/xlsx.core.min.js
generated
vendored
18
modules/shp_utils/node_modules/xlsx/dist/xlsx.core.min.js
generated
vendored
File diff suppressed because one or more lines are too long
1
modules/shp_utils/node_modules/xlsx/dist/xlsx.core.min.map
generated
vendored
1
modules/shp_utils/node_modules/xlsx/dist/xlsx.core.min.map
generated
vendored
File diff suppressed because one or more lines are too long
28259
modules/shp_utils/node_modules/xlsx/dist/xlsx.extendscript.js
generated
vendored
28259
modules/shp_utils/node_modules/xlsx/dist/xlsx.extendscript.js
generated
vendored
File diff suppressed because it is too large
Load Diff
24
modules/shp_utils/node_modules/xlsx/dist/xlsx.full.min.js
generated
vendored
24
modules/shp_utils/node_modules/xlsx/dist/xlsx.full.min.js
generated
vendored
File diff suppressed because one or more lines are too long
1
modules/shp_utils/node_modules/xlsx/dist/xlsx.full.min.map
generated
vendored
1
modules/shp_utils/node_modules/xlsx/dist/xlsx.full.min.map
generated
vendored
File diff suppressed because one or more lines are too long
10
modules/shp_utils/node_modules/xlsx/dist/xlsx.mini.min.js
generated
vendored
10
modules/shp_utils/node_modules/xlsx/dist/xlsx.mini.min.js
generated
vendored
File diff suppressed because one or more lines are too long
1
modules/shp_utils/node_modules/xlsx/dist/xlsx.mini.min.map
generated
vendored
1
modules/shp_utils/node_modules/xlsx/dist/xlsx.mini.min.map
generated
vendored
File diff suppressed because one or more lines are too long
4
modules/shp_utils/node_modules/xlsx/dist/xlsx.zahl.js
generated
vendored
4
modules/shp_utils/node_modules/xlsx/dist/xlsx.zahl.js
generated
vendored
File diff suppressed because one or more lines are too long
2
modules/shp_utils/node_modules/xlsx/dist/xlsx.zahl.mjs
generated
vendored
2
modules/shp_utils/node_modules/xlsx/dist/xlsx.zahl.mjs
generated
vendored
File diff suppressed because one or more lines are too long
4
modules/shp_utils/node_modules/xlsx/dist/zahl.d.ts
generated
vendored
4
modules/shp_utils/node_modules/xlsx/dist/zahl.d.ts
generated
vendored
@ -1,4 +0,0 @@
|
|||||||
/* zahl.d.ts (C) 2022-present SheetJS */
|
|
||||||
// TypeScript Version: 2.2
|
|
||||||
declare const XLSX_ZAHL_PAYLOAD: string;
|
|
||||||
export default XLSX_ZAHL_PAYLOAD;
|
|
||||||
183
modules/shp_utils/node_modules/xlsx/package.json
generated
vendored
183
modules/shp_utils/node_modules/xlsx/package.json
generated
vendored
@ -1,183 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "xlsx",
|
|
||||||
"version": "0.20.3",
|
|
||||||
"author": "sheetjs",
|
|
||||||
"description": "SheetJS Spreadsheet data parser and writer",
|
|
||||||
"keywords": [
|
|
||||||
"excel",
|
|
||||||
"xls",
|
|
||||||
"xlsx",
|
|
||||||
"xlsb",
|
|
||||||
"xlsm",
|
|
||||||
"ods",
|
|
||||||
"csv",
|
|
||||||
"dbf",
|
|
||||||
"dif",
|
|
||||||
"sylk",
|
|
||||||
"office",
|
|
||||||
"spreadsheet"
|
|
||||||
],
|
|
||||||
"bin": {
|
|
||||||
"xlsx": "./bin/xlsx.njs"
|
|
||||||
},
|
|
||||||
"main": "xlsx.js",
|
|
||||||
"module": "xlsx.mjs",
|
|
||||||
"unpkg": "dist/xlsx.full.min.js",
|
|
||||||
"jsdelivr": "dist/xlsx.full.min.js",
|
|
||||||
"types": "types/index.d.ts",
|
|
||||||
"exports": {
|
|
||||||
".": {
|
|
||||||
"import": "./xlsx.mjs",
|
|
||||||
"require": "./xlsx.js",
|
|
||||||
"types": "./types/index.d.ts"
|
|
||||||
},
|
|
||||||
"./xlsx.mjs": {
|
|
||||||
"import": "./xlsx.mjs",
|
|
||||||
"types": "./types/index.d.ts"
|
|
||||||
},
|
|
||||||
"./xlsx.js": {
|
|
||||||
"require": "./xlsx.js",
|
|
||||||
"types": "./types/index.d.ts"
|
|
||||||
},
|
|
||||||
"./dist/xlsx.core.min": {
|
|
||||||
"import": "./dist/xlsx.core.min.js",
|
|
||||||
"require": "./dist/xlsx.core.min.js",
|
|
||||||
"types": "./types/index.d.ts"
|
|
||||||
},
|
|
||||||
"./dist/xlsx.core.min.js": {
|
|
||||||
"import": "./dist/xlsx.core.min.js",
|
|
||||||
"require": "./dist/xlsx.core.min.js",
|
|
||||||
"types": "./types/index.d.ts"
|
|
||||||
},
|
|
||||||
"./dist/xlsx.full.min": {
|
|
||||||
"import": "./dist/xlsx.full.min.js",
|
|
||||||
"require": "./dist/xlsx.full.min.js",
|
|
||||||
"types": "./types/index.d.ts"
|
|
||||||
},
|
|
||||||
"./dist/xlsx.full.min.js": {
|
|
||||||
"import": "./dist/xlsx.full.min.js",
|
|
||||||
"require": "./dist/xlsx.full.min.js",
|
|
||||||
"types": "./types/index.d.ts"
|
|
||||||
},
|
|
||||||
"./dist/xlsx.mini.min": {
|
|
||||||
"import": "./dist/xlsx.mini.min.js",
|
|
||||||
"require": "./dist/xlsx.mini.min.js",
|
|
||||||
"types": "./types/index.d.ts"
|
|
||||||
},
|
|
||||||
"./dist/xlsx.mini.min.js": {
|
|
||||||
"import": "./dist/xlsx.mini.min.js",
|
|
||||||
"require": "./dist/xlsx.mini.min.js",
|
|
||||||
"types": "./types/index.d.ts"
|
|
||||||
},
|
|
||||||
"./dist/xlsx.zahl": {
|
|
||||||
"import": "./dist/xlsx.zahl.mjs",
|
|
||||||
"require": "./dist/xlsx.zahl.js",
|
|
||||||
"types": "./dist/zahl.d.ts"
|
|
||||||
},
|
|
||||||
"./dist/xlsx.zahl.mjs": {
|
|
||||||
"import": "./dist/xlsx.zahl.mjs",
|
|
||||||
"types": "./dist/zahl.d.ts"
|
|
||||||
},
|
|
||||||
"./dist/xlsx.zahl.js": {
|
|
||||||
"require": "./dist/xlsx.zahl.js",
|
|
||||||
"types": "./dist/zahl.d.ts"
|
|
||||||
},
|
|
||||||
"./dist/cpexcel": {
|
|
||||||
"import": "./dist/cpexcel.full.mjs",
|
|
||||||
"require": "./dist/cpexcel.js",
|
|
||||||
"types": "./dist/cpexcel.d.ts"
|
|
||||||
},
|
|
||||||
"./dist/cpexcel.js": {
|
|
||||||
"require": "./dist/cpexcel.js",
|
|
||||||
"types": "./dist/cpexcel.d.ts"
|
|
||||||
},
|
|
||||||
"./dist/cpexcel.full": {
|
|
||||||
"import": "./dist/cpexcel.full.mjs",
|
|
||||||
"require": "./dist/cpexcel.js",
|
|
||||||
"types": "./dist/cpexcel.d.ts"
|
|
||||||
},
|
|
||||||
"./dist/cpexcel.full.mjs": {
|
|
||||||
"import": "./dist/cpexcel.full.mjs",
|
|
||||||
"types": "./dist/cpexcel.d.ts"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"browser": {
|
|
||||||
"buffer": false,
|
|
||||||
"crypto": false,
|
|
||||||
"stream": false,
|
|
||||||
"process": false,
|
|
||||||
"fs": false
|
|
||||||
},
|
|
||||||
"sideEffects": false,
|
|
||||||
"dependencies": {
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@sheetjs/uglify-js": "~2.7.3",
|
|
||||||
"@types/node": "^8.5.9",
|
|
||||||
"acorn": "7.4.1",
|
|
||||||
"adler-32": "~1.3.1",
|
|
||||||
"alex": "8.1.1",
|
|
||||||
"blanket": "~1.2.3",
|
|
||||||
"cfb": "~1.2.2",
|
|
||||||
"codepage": "~1.15.0",
|
|
||||||
"commander": "~2.17.1",
|
|
||||||
"crc-32": "~1.2.2",
|
|
||||||
"dtslint": "^0.1.2",
|
|
||||||
"eslint": "7.23.0",
|
|
||||||
"eslint-plugin-html": "^6.1.2",
|
|
||||||
"eslint-plugin-json": "^2.1.2",
|
|
||||||
"exit-on-epipe": "~1.0.1",
|
|
||||||
"fflate": "^0.7.1",
|
|
||||||
"jsdom": "~11.1.0",
|
|
||||||
"markdown-spellcheck": "^1.3.1",
|
|
||||||
"mocha": "~2.5.3",
|
|
||||||
"sinon": "^1.17.7",
|
|
||||||
"ssf": "~0.11.2",
|
|
||||||
"typescript": "2.2.0",
|
|
||||||
"wmf": "~1.0.1",
|
|
||||||
"word": "~0.3.0"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://git.sheetjs.com/SheetJS/sheetjs"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"pretest": "npm run lint",
|
|
||||||
"test": "npm run tests-only",
|
|
||||||
"pretest-only": "git submodule init && git submodule update",
|
|
||||||
"tests-only": "make travis",
|
|
||||||
"build": "make",
|
|
||||||
"lint": "make fullint",
|
|
||||||
"dtslint": "dtslint types"
|
|
||||||
},
|
|
||||||
"config": {
|
|
||||||
"blanket": {
|
|
||||||
"pattern": "xlsx.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"alex": {
|
|
||||||
"allow": [
|
|
||||||
"chinese",
|
|
||||||
"special",
|
|
||||||
"simple",
|
|
||||||
"just",
|
|
||||||
"crash",
|
|
||||||
"wtf",
|
|
||||||
"holes"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"homepage": "https://sheetjs.com/",
|
|
||||||
"files": [
|
|
||||||
"CHANGELOG.md", "LICENSE", "README.md", "bower.json", "package.json", "xlsx.js", "xlsx.mjs", "xlsxworker.js",
|
|
||||||
"bin/xlsx.njs",
|
|
||||||
"dist/LICENSE", "dist/*.mjs", "dist/*.js", "dist/*.map", "dist/*.d.ts",
|
|
||||||
"types/index.d.ts", "types/tsconfig.json"
|
|
||||||
],
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://git.sheetjs.com/SheetJS/sheetjs/issues"
|
|
||||||
},
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.8"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1065
modules/shp_utils/node_modules/xlsx/types/index.d.ts
generated
vendored
1065
modules/shp_utils/node_modules/xlsx/types/index.d.ts
generated
vendored
File diff suppressed because it is too large
Load Diff
15
modules/shp_utils/node_modules/xlsx/types/tsconfig.json
generated
vendored
15
modules/shp_utils/node_modules/xlsx/types/tsconfig.json
generated
vendored
@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "commonjs",
|
|
||||||
"lib": [ "es5" ],
|
|
||||||
"noImplicitAny": true,
|
|
||||||
"noImplicitThis": true,
|
|
||||||
"strictNullChecks": false,
|
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": { "xlsx": ["."] },
|
|
||||||
"types": [],
|
|
||||||
"noEmit": true,
|
|
||||||
"strictFunctionTypes": true,
|
|
||||||
"forceConsistentCasingInFileNames": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
28103
modules/shp_utils/node_modules/xlsx/xlsx.js
generated
vendored
28103
modules/shp_utils/node_modules/xlsx/xlsx.js
generated
vendored
File diff suppressed because it is too large
Load Diff
28228
modules/shp_utils/node_modules/xlsx/xlsx.mjs
generated
vendored
28228
modules/shp_utils/node_modules/xlsx/xlsx.mjs
generated
vendored
File diff suppressed because it is too large
Load Diff
14
modules/shp_utils/node_modules/xlsx/xlsxworker.js
generated
vendored
14
modules/shp_utils/node_modules/xlsx/xlsxworker.js
generated
vendored
@ -1,14 +0,0 @@
|
|||||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
|
||||||
importScripts('dist/shim.min.js');
|
|
||||||
/* uncomment the next line for encoding support */
|
|
||||||
importScripts('dist/cpexcel.js');
|
|
||||||
importScripts('xlsx.js');
|
|
||||||
postMessage({t:"ready"});
|
|
||||||
|
|
||||||
onmessage = function (evt) {
|
|
||||||
var v;
|
|
||||||
try {
|
|
||||||
v = XLSX.read(evt.data.d, {type: evt.data.b, codepage: evt.data.c});
|
|
||||||
postMessage({t:"xlsx", d:JSON.stringify(v)});
|
|
||||||
} catch(e) { postMessage({t:"e",d:e.stack||e}); }
|
|
||||||
};
|
|
||||||
24
modules/shp_utils/package-lock.json
generated
24
modules/shp_utils/package-lock.json
generated
@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "shp_utils",
|
|
||||||
"lockfileVersion": 3,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {
|
|
||||||
"": {
|
|
||||||
"dependencies": {
|
|
||||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/xlsx": {
|
|
||||||
"version": "0.20.3",
|
|
||||||
"resolved": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
|
|
||||||
"integrity": "sha512-oLDq3jw7AcLqKWH2AhCpVTZl8mf6X2YReP+Neh0SJUzV/BdZYjth94tG5toiMB1PPrYtxOCfaoUCkvtuH+3AJA==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"bin": {
|
|
||||||
"xlsx": "bin/xlsx.njs"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.8"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"dependencies": {
|
|
||||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user