@boristype/bt-cli 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +66 -0
- package/build/builder/config.js +88 -0
- package/build/cli/commands/artifact.js +14 -0
- package/build/cli/commands/build.js +25 -0
- package/build/cli/commands/dev.js +190 -0
- package/build/cli/commands/index.js +18 -0
- package/build/cli/commands/init.js +15 -0
- package/build/cli/commands/link.js +18 -0
- package/build/cli/commands/push.js +28 -0
- package/build/cli/index.js +14 -0
- package/build/cli/types.js +2 -0
- package/build/core/artifacting/context.js +54 -0
- package/build/core/artifacting/index.js +37 -0
- package/build/core/artifacting/stages/index.js +10 -0
- package/build/core/artifacting/stages/main-archive.js +72 -0
- package/build/core/artifacting/stages/validate.js +70 -0
- package/build/core/artifacting/types.js +6 -0
- package/build/core/artifacting/utils/index.js +10 -0
- package/build/core/artifacting/utils/zip.js +94 -0
- package/build/core/babel.js +96 -0
- package/build/core/btconfig.types.js +6 -0
- package/build/core/build.js +280 -0
- package/build/core/building/compile-mode.js +146 -0
- package/build/core/building/compiler.js +281 -0
- package/build/core/building/coordinator.js +71 -0
- package/build/core/building/files.js +290 -0
- package/build/core/building/index.js +102 -0
- package/build/core/building/output.js +92 -0
- package/build/core/building/transformers.js +110 -0
- package/build/core/building/types.js +19 -0
- package/build/core/config.js +157 -0
- package/build/core/dependencies.js +223 -0
- package/build/core/linking/cache.js +260 -0
- package/build/core/linking/context.js +149 -0
- package/build/core/linking/dependencies.js +240 -0
- package/build/core/linking/executables.js +61 -0
- package/build/core/linking/generators/api-ext.js +57 -0
- package/build/core/linking/generators/component.js +83 -0
- package/build/core/linking/generators/filemap.js +53 -0
- package/build/core/linking/generators/index.js +21 -0
- package/build/core/linking/generators/init-xml.js +37 -0
- package/build/core/linking/generators/package-json.js +50 -0
- package/build/core/linking/index.js +213 -0
- package/build/core/linking/linkers/component.js +175 -0
- package/build/core/linking/linkers/index.js +69 -0
- package/build/core/linking/linkers/standalone.js +144 -0
- package/build/core/linking/linkers/system.js +86 -0
- package/build/core/linking/parsers.js +278 -0
- package/build/core/linking/types.js +6 -0
- package/build/core/linking/utils/copy.js +101 -0
- package/build/core/linking/utils/index.js +26 -0
- package/build/core/linking/utils/node-modules.js +226 -0
- package/build/core/linking/utils/package-type.js +101 -0
- package/build/core/linking/utils/url.js +73 -0
- package/build/core/linking/utils/write.js +91 -0
- package/build/core/logger.js +10 -0
- package/build/core/pushing/config.js +90 -0
- package/build/core/pushing/index.js +96 -0
- package/build/core/pushing/init-scripts.js +173 -0
- package/build/core/pushing/queue.js +95 -0
- package/build/core/pushing/reinit.js +61 -0
- package/build/core/pushing/session.js +167 -0
- package/build/core/pushing/types.js +6 -0
- package/build/core/pushing/upload.js +35 -0
- package/build/core/tsconfig.js +78 -0
- package/build/core/utils/index.js +17 -0
- package/build/core/utils/logger.js +46 -0
- package/build/core/utils/properties.js +81 -0
- package/build/core/utils/xml.js +44 -0
- package/build/core/utils.js +59 -0
- package/build/index.js +76 -0
- package/build/plugins/destructuring.js +83 -0
- package/build/plugins/forOfToForIn.js +14 -0
- package/build/plugins/loopHoistVariables.js +160 -0
- package/build/plugins/precedence.js +172 -0
- package/build/plugins/removeImportExport.js +42 -0
- package/build/plugins/replaceDollar.js +16 -0
- package/build/plugins/spreadArray.js +42 -0
- package/build/plugins/spreadObject.js +91 -0
- package/build/transformers/arrayFunctional.js +467 -0
- package/build/transformers/arrayGeneral.js +222 -0
- package/build/transformers/blockScoping.js +212 -0
- package/build/transformers/destructuring.js +133 -0
- package/build/transformers/dirname.js +79 -0
- package/build/transformers/enumsToObjects.js +25 -0
- package/build/transformers/execObj.js +220 -0
- package/build/transformers/forOfToForIn.js +45 -0
- package/build/transformers/funcSemantic.js +113 -0
- package/build/transformers/functions.js +270 -0
- package/build/transformers/globalCache.js +34 -0
- package/build/transformers/loopHoistVariables.js +352 -0
- package/build/transformers/math.js +39 -0
- package/build/transformers/namespaces.js +22 -0
- package/build/transformers/numericSeparator.js +46 -0
- package/build/transformers/objectProperties.js +54 -0
- package/build/transformers/precedence.js +192 -0
- package/build/transformers/propSemantic.js +467 -0
- package/build/transformers/remodule.js +620 -0
- package/build/transformers/removeImportExport.js +135 -0
- package/build/transformers/replaceDollar.js +46 -0
- package/build/transformers/shorthandProperties.js +34 -0
- package/build/transformers/spreadArray.js +68 -0
- package/build/transformers/spreadObject.js +134 -0
- package/build/transformers/string.js +138 -0
- package/build/transformers/templateLiterals.js +104 -0
- package/build/transformers/tocodelibrary.js +178 -0
- package/build/transformers/utils.js +202 -0
- package/build/wshcm/client.js +193 -0
- package/build/wshcm/evaluator.js +111 -0
- package/build/wshcm/exceptions.js +25 -0
- package/build/wshcm/index.js +20 -0
- package/build/wshcm/soap-utils.js +228 -0
- package/build/wshcm/types.js +2 -0
- package/build/wshcm/uploader.js +320 -0
- package/package.json +51 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.WshcmClient = void 0;
|
|
37
|
+
const https = __importStar(require("https"));
|
|
38
|
+
const http = __importStar(require("http"));
|
|
39
|
+
const exceptions_1 = require("./exceptions");
|
|
40
|
+
const soap_utils_1 = require("./soap-utils");
|
|
41
|
+
const evaluator_1 = require("./evaluator");
|
|
42
|
+
// ============================================================================
|
|
43
|
+
// Main WSHCM Client
|
|
44
|
+
// ============================================================================
|
|
45
|
+
/** Таймаут HTTP-запросов по умолчанию (30 секунд) */
|
|
46
|
+
const DEFAULT_REQUEST_TIMEOUT = 30_000;
|
|
47
|
+
/**
|
|
48
|
+
* Клиент для работы с WebSoft HCM через SP-XML API
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* const client = new WshcmClient({
|
|
53
|
+
* overHttps: false,
|
|
54
|
+
* host: 'localhost',
|
|
55
|
+
* port: 8080,
|
|
56
|
+
* username: 'admin',
|
|
57
|
+
* password: 'password'
|
|
58
|
+
* });
|
|
59
|
+
*
|
|
60
|
+
* await client.initialize();
|
|
61
|
+
* const result = await client.callMethod<string>('tools', 'some_method', ['arg1', 'arg2']);
|
|
62
|
+
*
|
|
63
|
+
* const evaluator = client.createEvaluator();
|
|
64
|
+
* await evaluator.initialize();
|
|
65
|
+
* // ... use evaluator ...
|
|
66
|
+
* await evaluator.close();
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
class WshcmClient {
|
|
70
|
+
baseUrl;
|
|
71
|
+
username;
|
|
72
|
+
password;
|
|
73
|
+
cookies = [];
|
|
74
|
+
isHttps;
|
|
75
|
+
requestTimeout;
|
|
76
|
+
/**
|
|
77
|
+
* Создает новый экземпляр WSHCM-клиента
|
|
78
|
+
* @param options - опции подключения
|
|
79
|
+
*/
|
|
80
|
+
constructor(options) {
|
|
81
|
+
this.isHttps = options.overHttps;
|
|
82
|
+
this.baseUrl = `${options.overHttps ? 'https' : 'http'}://${options.host}:${options.port}`;
|
|
83
|
+
this.username = options.username;
|
|
84
|
+
this.password = options.password;
|
|
85
|
+
this.requestTimeout = options.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Инициализирует клиент и проверяет авторизацию
|
|
89
|
+
* Должен быть вызван после создания экземпляра
|
|
90
|
+
*/
|
|
91
|
+
async initialize() {
|
|
92
|
+
const statusCode = await this.makeRequest('/spxml_web/main.htm', 'GET');
|
|
93
|
+
if (statusCode !== 200) {
|
|
94
|
+
throw new exceptions_1.UnauthorizedError();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Вызывает метод через SP-XML API
|
|
99
|
+
* @template T - тип возвращаемого значения
|
|
100
|
+
* @param lib - библиотека/модуль (например, "tools", или URL модуля)
|
|
101
|
+
* @param method - имя метода
|
|
102
|
+
* @param methodArgs - массив аргументов метода
|
|
103
|
+
* @returns результат выполнения метода
|
|
104
|
+
*/
|
|
105
|
+
async callMethod(lib, method, methodArgs = []) {
|
|
106
|
+
const headers = {
|
|
107
|
+
'accept': '*/*',
|
|
108
|
+
'accept-language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7',
|
|
109
|
+
'cache-control': 'no-cache',
|
|
110
|
+
'content-type': 'application/soap+xml; charset=UTF-8',
|
|
111
|
+
'pragma': 'no-cache',
|
|
112
|
+
'x-spxml-client': 'SP-XML Web client 1.0',
|
|
113
|
+
};
|
|
114
|
+
const body = (0, soap_utils_1.renderRequest)(lib, method, methodArgs);
|
|
115
|
+
const responseText = await this.makeRequest('/api/spxml/CallMethod', 'POST', headers, body);
|
|
116
|
+
return (0, soap_utils_1.parseResponse)(responseText);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Создаёт новый Evaluator для выполнения произвольного кода на сервере.
|
|
120
|
+
*
|
|
121
|
+
* Вызывающий код отвечает за lifecycle evaluator-а:
|
|
122
|
+
* вызов `initialize()` перед использованием и `close()` после завершения.
|
|
123
|
+
*
|
|
124
|
+
* @returns новый экземпляр Evaluator
|
|
125
|
+
*/
|
|
126
|
+
createEvaluator() {
|
|
127
|
+
return new evaluator_1.Evaluator(this);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Выполняет HTTP-запрос
|
|
131
|
+
* @param path - путь запроса
|
|
132
|
+
* @param method - HTTP-метод
|
|
133
|
+
* @param headers - заголовки
|
|
134
|
+
* @param body - тело запроса
|
|
135
|
+
* @returns статус-код или тело ответа
|
|
136
|
+
*/
|
|
137
|
+
makeRequest(path, method, headers = {}, body) {
|
|
138
|
+
return new Promise((resolve, reject) => {
|
|
139
|
+
const url = new URL(this.baseUrl + path);
|
|
140
|
+
const auth = Buffer.from(`${this.username}:${this.password}`).toString('base64');
|
|
141
|
+
const allHeaders = {
|
|
142
|
+
...headers,
|
|
143
|
+
'Authorization': `Basic ${auth}`,
|
|
144
|
+
};
|
|
145
|
+
if (this.cookies.length > 0) {
|
|
146
|
+
allHeaders['Cookie'] = this.cookies.join('; ');
|
|
147
|
+
}
|
|
148
|
+
if (body) {
|
|
149
|
+
allHeaders['Content-Length'] = Buffer.byteLength(body).toString();
|
|
150
|
+
}
|
|
151
|
+
const options = {
|
|
152
|
+
hostname: url.hostname,
|
|
153
|
+
port: url.port,
|
|
154
|
+
path: url.pathname + url.search,
|
|
155
|
+
method: method,
|
|
156
|
+
headers: allHeaders,
|
|
157
|
+
timeout: this.requestTimeout,
|
|
158
|
+
};
|
|
159
|
+
const lib = this.isHttps ? https : http;
|
|
160
|
+
const req = lib.request(options, (res) => {
|
|
161
|
+
// Сохраняем cookies
|
|
162
|
+
const setCookie = res.headers['set-cookie'];
|
|
163
|
+
if (setCookie) {
|
|
164
|
+
this.cookies.push(...setCookie.map(cookie => cookie.split(';')[0]));
|
|
165
|
+
}
|
|
166
|
+
let data = '';
|
|
167
|
+
res.on('data', (chunk) => {
|
|
168
|
+
data += chunk;
|
|
169
|
+
});
|
|
170
|
+
res.on('end', () => {
|
|
171
|
+
if (method === 'GET') {
|
|
172
|
+
resolve(res.statusCode || 500);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
resolve(data);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
req.on('timeout', () => {
|
|
180
|
+
req.destroy();
|
|
181
|
+
reject(new exceptions_1.WshcmException(`Request timed out after ${this.requestTimeout}ms: ${method} ${path}`));
|
|
182
|
+
});
|
|
183
|
+
req.on('error', (error) => {
|
|
184
|
+
reject(new exceptions_1.WshcmException(`Request failed: ${error.message}`));
|
|
185
|
+
});
|
|
186
|
+
if (body) {
|
|
187
|
+
req.write(body);
|
|
188
|
+
}
|
|
189
|
+
req.end();
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
exports.WshcmClient = WshcmClient;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Evaluator = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Evaluator для выполнения произвольного BorisScript-кода на сервере
|
|
6
|
+
*
|
|
7
|
+
* Создает временный модуль на сервере с функциями execute и drop_self,
|
|
8
|
+
* позволяя выполнять динамический код через eval.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const evaluator = client.evaluator;
|
|
13
|
+
* await evaluator.initialize();
|
|
14
|
+
* const result = await evaluator.eval('return 2 + 2;');
|
|
15
|
+
* await evaluator.close();
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
class Evaluator {
|
|
19
|
+
client;
|
|
20
|
+
evalKey;
|
|
21
|
+
libUrl;
|
|
22
|
+
initialized = false;
|
|
23
|
+
/**
|
|
24
|
+
* Создает новый evaluator
|
|
25
|
+
* @param client - экземпляр WshcmClient
|
|
26
|
+
*/
|
|
27
|
+
constructor(client) {
|
|
28
|
+
this.client = client;
|
|
29
|
+
this.evalKey = 'unsafe_eval_' + this.generateRandomString(32);
|
|
30
|
+
this.libUrl = `x-local://wt/${this.evalKey}.bs`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Инициализирует evaluator, создавая временный модуль на сервере
|
|
34
|
+
*/
|
|
35
|
+
async initialize() {
|
|
36
|
+
if (this.initialized) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const content = this.getUnsafeEvalScript();
|
|
40
|
+
await this.client.callMethod('tools', 'put_url_text_server', [this.libUrl, content]);
|
|
41
|
+
this.initialized = true;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Выполняет произвольный BorisScript-код на сервере
|
|
45
|
+
* @param code - код для выполнения
|
|
46
|
+
* @returns результат выполнения
|
|
47
|
+
*/
|
|
48
|
+
async eval(code) {
|
|
49
|
+
if (!this.initialized) {
|
|
50
|
+
await this.initialize();
|
|
51
|
+
}
|
|
52
|
+
return this.client.callMethod(this.libUrl, 'execute', [code]);
|
|
53
|
+
}
|
|
54
|
+
async evalCode(code) {
|
|
55
|
+
// Оборачиваем код в функцию, чтобы явно не возвращать никакого результата всего сегмента кода, даже если в коде есть return
|
|
56
|
+
const randomFuncName = '__evaluator_wrapper_' + this.generateRandomString(32);
|
|
57
|
+
const wrappedCode = `function ${randomFuncName}() {\n${code}\n}\n${randomFuncName}();return;`;
|
|
58
|
+
return this.eval(wrappedCode);
|
|
59
|
+
}
|
|
60
|
+
async evalExpr(expr) {
|
|
61
|
+
return this.eval(expr);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Закрывает evaluator и удаляет временный модуль с сервера
|
|
65
|
+
* @returns true если удаление успешно, false в противном случае
|
|
66
|
+
*/
|
|
67
|
+
async close() {
|
|
68
|
+
if (!this.initialized) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const result = await this.client.callMethod(this.libUrl, 'drop_self', []);
|
|
73
|
+
this.initialized = false;
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Генерирует случайную строку заданной длины
|
|
82
|
+
*/
|
|
83
|
+
generateRandomString(length) {
|
|
84
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
85
|
+
let result = '';
|
|
86
|
+
for (let i = 0; i < length; i++) {
|
|
87
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Возвращает содержимое временного модуля unsafe_eval.bs
|
|
93
|
+
*/
|
|
94
|
+
getUnsafeEvalScript() {
|
|
95
|
+
return `"META:ALLOW-CALL-FROM-CLIENT:1"
|
|
96
|
+
function execute(code) {
|
|
97
|
+
return eval(code);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
"META:ALLOW-CALL-FROM-CLIENT:1"
|
|
101
|
+
function drop_self() {
|
|
102
|
+
try {
|
|
103
|
+
DeleteFile("${this.libUrl}");
|
|
104
|
+
return true;
|
|
105
|
+
} catch (err) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}`;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
exports.Evaluator = Evaluator;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UnauthorizedError = exports.WshcmException = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Базовое исключение для WSHCM-клиента
|
|
6
|
+
*/
|
|
7
|
+
class WshcmException extends Error {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = 'WshcmException';
|
|
11
|
+
Object.setPrototypeOf(this, WshcmException.prototype);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.WshcmException = WshcmException;
|
|
15
|
+
/**
|
|
16
|
+
* Исключение при ошибке авторизации
|
|
17
|
+
*/
|
|
18
|
+
class UnauthorizedError extends WshcmException {
|
|
19
|
+
constructor(message = 'Unauthorized') {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = 'UnauthorizedError';
|
|
22
|
+
Object.setPrototypeOf(this, UnauthorizedError.prototype);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.UnauthorizedError = UnauthorizedError;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* WSHCM Client - клиент для работы с WebSoft HCM через SP-XML API
|
|
4
|
+
*
|
|
5
|
+
* @module wshcm
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.WshcmUploader = exports.parseResponse = exports.renderRequest = exports.UnauthorizedError = exports.WshcmException = exports.Evaluator = exports.WshcmClient = void 0;
|
|
9
|
+
var client_1 = require("./client");
|
|
10
|
+
Object.defineProperty(exports, "WshcmClient", { enumerable: true, get: function () { return client_1.WshcmClient; } });
|
|
11
|
+
var evaluator_1 = require("./evaluator");
|
|
12
|
+
Object.defineProperty(exports, "Evaluator", { enumerable: true, get: function () { return evaluator_1.Evaluator; } });
|
|
13
|
+
var exceptions_1 = require("./exceptions");
|
|
14
|
+
Object.defineProperty(exports, "WshcmException", { enumerable: true, get: function () { return exceptions_1.WshcmException; } });
|
|
15
|
+
Object.defineProperty(exports, "UnauthorizedError", { enumerable: true, get: function () { return exceptions_1.UnauthorizedError; } });
|
|
16
|
+
var soap_utils_1 = require("./soap-utils");
|
|
17
|
+
Object.defineProperty(exports, "renderRequest", { enumerable: true, get: function () { return soap_utils_1.renderRequest; } });
|
|
18
|
+
Object.defineProperty(exports, "parseResponse", { enumerable: true, get: function () { return soap_utils_1.parseResponse; } });
|
|
19
|
+
var uploader_1 = require("./uploader");
|
|
20
|
+
Object.defineProperty(exports, "WshcmUploader", { enumerable: true, get: function () { return uploader_1.WshcmUploader; } });
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderRequest = renderRequest;
|
|
4
|
+
exports.parseResponse = parseResponse;
|
|
5
|
+
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
6
|
+
const exceptions_1 = require("./exceptions");
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// XML Parser / Builder instances
|
|
9
|
+
// ============================================================================
|
|
10
|
+
/**
|
|
11
|
+
* XMLParser для SOAP-ответов.
|
|
12
|
+
* `removeNSPrefix: true` убирает namespace-префиксы (soap:Envelope → Envelope),
|
|
13
|
+
* что позволяет обращаться к элементам напрямую без привязки к префиксам сервера.
|
|
14
|
+
*/
|
|
15
|
+
const soapParser = new fast_xml_parser_1.XMLParser({
|
|
16
|
+
ignoreAttributes: false,
|
|
17
|
+
attributeNamePrefix: '@_',
|
|
18
|
+
removeNSPrefix: true,
|
|
19
|
+
trimValues: true,
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* XMLBuilder для формирования SOAP-запросов.
|
|
23
|
+
* Автоматически экранирует XML-сущности в значениях и атрибутах.
|
|
24
|
+
*/
|
|
25
|
+
const soapBuilder = new fast_xml_parser_1.XMLBuilder({
|
|
26
|
+
ignoreAttributes: false,
|
|
27
|
+
attributeNamePrefix: '@_',
|
|
28
|
+
format: true,
|
|
29
|
+
indentBy: ' ',
|
|
30
|
+
suppressEmptyNode: false,
|
|
31
|
+
processEntities: true,
|
|
32
|
+
});
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// Request Building
|
|
35
|
+
// ============================================================================
|
|
36
|
+
/**
|
|
37
|
+
* Преобразует аргумент метода в объект для XMLBuilder
|
|
38
|
+
* @param arg - значение аргумента
|
|
39
|
+
* @returns объект с VALUE-TYPE атрибутом и текстовым содержимым
|
|
40
|
+
*/
|
|
41
|
+
function buildArgumentValue(arg) {
|
|
42
|
+
if (typeof arg === 'string') {
|
|
43
|
+
return {
|
|
44
|
+
'@_VALUE-TYPE': 'string',
|
|
45
|
+
'#text': arg
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (typeof arg === 'number') {
|
|
49
|
+
return {
|
|
50
|
+
'@_VALUE-TYPE': Number.isInteger(arg) ? 'integer' : 'real',
|
|
51
|
+
'#text': arg,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (typeof arg === 'boolean') {
|
|
55
|
+
return {
|
|
56
|
+
'@_VALUE-TYPE': 'bool',
|
|
57
|
+
'#text': arg ? 1 : 0
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (arg === null || arg === undefined) {
|
|
61
|
+
return { '@_VALUE-TYPE': 'string', '#text': '' };
|
|
62
|
+
}
|
|
63
|
+
// Для объектов и массивов — неподдерживаемый тип, используем JSON как строку
|
|
64
|
+
try {
|
|
65
|
+
return { '@_VALUE-TYPE': 'string', '#text': JSON.stringify(arg) };
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
throw new exceptions_1.WshcmException('Unsupported argument type');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Рендерит SOAP-запрос для вызова метода
|
|
73
|
+
* @param lib - библиотека/модуль
|
|
74
|
+
* @param method - имя метода
|
|
75
|
+
* @param methodArgs - аргументы метода
|
|
76
|
+
* @returns XML-строка SOAP-запроса
|
|
77
|
+
*/
|
|
78
|
+
function renderRequest(lib, method, methodArgs) {
|
|
79
|
+
const argData = {};
|
|
80
|
+
for (let i = 0; i < methodArgs.length; i++) {
|
|
81
|
+
argData[`arg-${i}`] = buildArgumentValue(methodArgs[i]);
|
|
82
|
+
}
|
|
83
|
+
const requestObj = {
|
|
84
|
+
'?xml': { '@_version': '1.0', '@_encoding': 'utf-8' },
|
|
85
|
+
'soap:Envelope': {
|
|
86
|
+
'@_xmlns:soap': 'http://schemas.xmlsoap.org/soap/envelope/',
|
|
87
|
+
'@_xmlns': 'http://www.datex-soft.com/soap/',
|
|
88
|
+
'soap:Body': {
|
|
89
|
+
'CallMethod': {
|
|
90
|
+
'LibName': lib,
|
|
91
|
+
'MethodName': method,
|
|
92
|
+
'ArgData': argData,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
return soapBuilder.build(requestObj);
|
|
98
|
+
}
|
|
99
|
+
// ============================================================================
|
|
100
|
+
// Response Parsing
|
|
101
|
+
// ============================================================================
|
|
102
|
+
/**
|
|
103
|
+
* Рекурсивно ищет элемент по имени в распарсенном XML-объекте.
|
|
104
|
+
* Аналог SimpleXmlParser.findElement — ищет ключ на любом уровне вложенности.
|
|
105
|
+
*
|
|
106
|
+
* @param obj - распарсенный XML-объект
|
|
107
|
+
* @param key - имя искомого элемента
|
|
108
|
+
* @returns найденный элемент или undefined
|
|
109
|
+
*/
|
|
110
|
+
function findElement(obj, key) {
|
|
111
|
+
if (!obj || typeof obj !== 'object')
|
|
112
|
+
return undefined;
|
|
113
|
+
const record = obj;
|
|
114
|
+
if (key in record)
|
|
115
|
+
return record[key];
|
|
116
|
+
for (const val of Object.values(record)) {
|
|
117
|
+
const found = findElement(val, key);
|
|
118
|
+
if (found !== undefined)
|
|
119
|
+
return found;
|
|
120
|
+
}
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Парсит значение элемента на основе VALUE-TYPE атрибута.
|
|
125
|
+
*
|
|
126
|
+
* fast-xml-parser представляет элемент с атрибутами как объект:
|
|
127
|
+
* - `@_VALUE-TYPE` — тип значения
|
|
128
|
+
* - `#text` — текстовое содержимое (может отсутствовать для пустых элементов)
|
|
129
|
+
* - остальные ключи — дочерние элементы (для Object/Array типов)
|
|
130
|
+
*
|
|
131
|
+
* @param element - распарсенный XML-элемент
|
|
132
|
+
* @returns JS-значение соответствующего типа
|
|
133
|
+
*/
|
|
134
|
+
function parseResultValue(element) {
|
|
135
|
+
if (element === undefined || element === null)
|
|
136
|
+
return undefined;
|
|
137
|
+
// Если элемент — примитив (нет атрибутов), вернуть как есть
|
|
138
|
+
if (typeof element !== 'object')
|
|
139
|
+
return element;
|
|
140
|
+
const valueType = element['@_VALUE-TYPE'];
|
|
141
|
+
if (!valueType || valueType === 'undefined' || valueType === 'null') {
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
if (valueType === 'string') {
|
|
145
|
+
const text = element['#text'];
|
|
146
|
+
return text != null ? String(text) : '';
|
|
147
|
+
}
|
|
148
|
+
if (valueType === 'integer') {
|
|
149
|
+
return parseInt(String(element['#text'] ?? '0'), 10);
|
|
150
|
+
}
|
|
151
|
+
if (valueType === 'real') {
|
|
152
|
+
return parseFloat(String(element['#text'] ?? '0'));
|
|
153
|
+
}
|
|
154
|
+
if (valueType === 'bool') {
|
|
155
|
+
return (element['#text'] ?? 0) == 1;
|
|
156
|
+
}
|
|
157
|
+
if (valueType === 'Object') {
|
|
158
|
+
return parseResultObject(element);
|
|
159
|
+
}
|
|
160
|
+
if (valueType === 'Array') {
|
|
161
|
+
return parseResultArray(element);
|
|
162
|
+
}
|
|
163
|
+
throw new exceptions_1.WshcmException(`Unexpected VALUE-TYPE: ${valueType}`);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Парсит объект из распарсенного XML-элемента.
|
|
167
|
+
* Итерирует дочерние ключи (исключая `@_*` атрибуты и `#text`),
|
|
168
|
+
* рекурсивно разбирая каждый через {@link parseResultValue}.
|
|
169
|
+
*
|
|
170
|
+
* @param element - элемент с `@_VALUE-TYPE="Object"`
|
|
171
|
+
* @returns JS-объект
|
|
172
|
+
*/
|
|
173
|
+
function parseResultObject(element) {
|
|
174
|
+
const result = {};
|
|
175
|
+
for (const [key, value] of Object.entries(element)) {
|
|
176
|
+
if (key.startsWith('@_') || key === '#text')
|
|
177
|
+
continue;
|
|
178
|
+
result[key] = parseResultValue(value);
|
|
179
|
+
}
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Парсит массив из распарсенного XML-элемента.
|
|
184
|
+
* Итерирует дочерние ключи (исключая `@_*` атрибуты и `#text`),
|
|
185
|
+
* рекурсивно разбирая каждый через {@link parseResultValue}.
|
|
186
|
+
*
|
|
187
|
+
* @param element - элемент с `@_VALUE-TYPE="Array"`
|
|
188
|
+
* @returns JS-массив
|
|
189
|
+
*/
|
|
190
|
+
function parseResultArray(element) {
|
|
191
|
+
const result = [];
|
|
192
|
+
for (const [key, value] of Object.entries(element)) {
|
|
193
|
+
if (key.startsWith('@_') || key === '#text')
|
|
194
|
+
continue;
|
|
195
|
+
result.push(parseResultValue(value));
|
|
196
|
+
}
|
|
197
|
+
return result;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Парсит SOAP-ответ и извлекает результат.
|
|
201
|
+
*
|
|
202
|
+
* Использует `fast-xml-parser` с `removeNSPrefix: true` для прозрачной
|
|
203
|
+
* работы с namespace-префиксами (soap:Envelope → Envelope и т.д.).
|
|
204
|
+
*
|
|
205
|
+
* @param responseText - XML-строка ответа
|
|
206
|
+
* @returns результат выполнения метода
|
|
207
|
+
*/
|
|
208
|
+
function parseResponse(responseText) {
|
|
209
|
+
const parsed = soapParser.parse(responseText);
|
|
210
|
+
// Проверяем на ошибку SOAP Fault
|
|
211
|
+
const fault = findElement(parsed, 'Fault');
|
|
212
|
+
if (fault && typeof fault === 'object') {
|
|
213
|
+
const errorCode = fault.faultcode ?? 'UNKNOWN';
|
|
214
|
+
const errorMessage = fault.faultstring ?? 'Unknown error';
|
|
215
|
+
throw new exceptions_1.WshcmException(`ERR: (${errorCode}) ${errorMessage}`);
|
|
216
|
+
}
|
|
217
|
+
// Ищем ResultData
|
|
218
|
+
const resultData = findElement(parsed, 'ResultData');
|
|
219
|
+
if (!resultData) {
|
|
220
|
+
return undefined;
|
|
221
|
+
}
|
|
222
|
+
// Ищем Result внутри ResultData
|
|
223
|
+
const result = typeof resultData === 'object' ? resultData.Result : undefined;
|
|
224
|
+
if (result === undefined) {
|
|
225
|
+
throw new exceptions_1.WshcmException('Unexpected response: Result element not found');
|
|
226
|
+
}
|
|
227
|
+
return parseResultValue(result);
|
|
228
|
+
}
|