@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.
Files changed (116) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +66 -0
  3. package/build/builder/config.js +88 -0
  4. package/build/cli/commands/artifact.js +14 -0
  5. package/build/cli/commands/build.js +25 -0
  6. package/build/cli/commands/dev.js +190 -0
  7. package/build/cli/commands/index.js +18 -0
  8. package/build/cli/commands/init.js +15 -0
  9. package/build/cli/commands/link.js +18 -0
  10. package/build/cli/commands/push.js +28 -0
  11. package/build/cli/index.js +14 -0
  12. package/build/cli/types.js +2 -0
  13. package/build/core/artifacting/context.js +54 -0
  14. package/build/core/artifacting/index.js +37 -0
  15. package/build/core/artifacting/stages/index.js +10 -0
  16. package/build/core/artifacting/stages/main-archive.js +72 -0
  17. package/build/core/artifacting/stages/validate.js +70 -0
  18. package/build/core/artifacting/types.js +6 -0
  19. package/build/core/artifacting/utils/index.js +10 -0
  20. package/build/core/artifacting/utils/zip.js +94 -0
  21. package/build/core/babel.js +96 -0
  22. package/build/core/btconfig.types.js +6 -0
  23. package/build/core/build.js +280 -0
  24. package/build/core/building/compile-mode.js +146 -0
  25. package/build/core/building/compiler.js +281 -0
  26. package/build/core/building/coordinator.js +71 -0
  27. package/build/core/building/files.js +290 -0
  28. package/build/core/building/index.js +102 -0
  29. package/build/core/building/output.js +92 -0
  30. package/build/core/building/transformers.js +110 -0
  31. package/build/core/building/types.js +19 -0
  32. package/build/core/config.js +157 -0
  33. package/build/core/dependencies.js +223 -0
  34. package/build/core/linking/cache.js +260 -0
  35. package/build/core/linking/context.js +149 -0
  36. package/build/core/linking/dependencies.js +240 -0
  37. package/build/core/linking/executables.js +61 -0
  38. package/build/core/linking/generators/api-ext.js +57 -0
  39. package/build/core/linking/generators/component.js +83 -0
  40. package/build/core/linking/generators/filemap.js +53 -0
  41. package/build/core/linking/generators/index.js +21 -0
  42. package/build/core/linking/generators/init-xml.js +37 -0
  43. package/build/core/linking/generators/package-json.js +50 -0
  44. package/build/core/linking/index.js +213 -0
  45. package/build/core/linking/linkers/component.js +175 -0
  46. package/build/core/linking/linkers/index.js +69 -0
  47. package/build/core/linking/linkers/standalone.js +144 -0
  48. package/build/core/linking/linkers/system.js +86 -0
  49. package/build/core/linking/parsers.js +278 -0
  50. package/build/core/linking/types.js +6 -0
  51. package/build/core/linking/utils/copy.js +101 -0
  52. package/build/core/linking/utils/index.js +26 -0
  53. package/build/core/linking/utils/node-modules.js +226 -0
  54. package/build/core/linking/utils/package-type.js +101 -0
  55. package/build/core/linking/utils/url.js +73 -0
  56. package/build/core/linking/utils/write.js +91 -0
  57. package/build/core/logger.js +10 -0
  58. package/build/core/pushing/config.js +90 -0
  59. package/build/core/pushing/index.js +96 -0
  60. package/build/core/pushing/init-scripts.js +173 -0
  61. package/build/core/pushing/queue.js +95 -0
  62. package/build/core/pushing/reinit.js +61 -0
  63. package/build/core/pushing/session.js +167 -0
  64. package/build/core/pushing/types.js +6 -0
  65. package/build/core/pushing/upload.js +35 -0
  66. package/build/core/tsconfig.js +78 -0
  67. package/build/core/utils/index.js +17 -0
  68. package/build/core/utils/logger.js +46 -0
  69. package/build/core/utils/properties.js +81 -0
  70. package/build/core/utils/xml.js +44 -0
  71. package/build/core/utils.js +59 -0
  72. package/build/index.js +76 -0
  73. package/build/plugins/destructuring.js +83 -0
  74. package/build/plugins/forOfToForIn.js +14 -0
  75. package/build/plugins/loopHoistVariables.js +160 -0
  76. package/build/plugins/precedence.js +172 -0
  77. package/build/plugins/removeImportExport.js +42 -0
  78. package/build/plugins/replaceDollar.js +16 -0
  79. package/build/plugins/spreadArray.js +42 -0
  80. package/build/plugins/spreadObject.js +91 -0
  81. package/build/transformers/arrayFunctional.js +467 -0
  82. package/build/transformers/arrayGeneral.js +222 -0
  83. package/build/transformers/blockScoping.js +212 -0
  84. package/build/transformers/destructuring.js +133 -0
  85. package/build/transformers/dirname.js +79 -0
  86. package/build/transformers/enumsToObjects.js +25 -0
  87. package/build/transformers/execObj.js +220 -0
  88. package/build/transformers/forOfToForIn.js +45 -0
  89. package/build/transformers/funcSemantic.js +113 -0
  90. package/build/transformers/functions.js +270 -0
  91. package/build/transformers/globalCache.js +34 -0
  92. package/build/transformers/loopHoistVariables.js +352 -0
  93. package/build/transformers/math.js +39 -0
  94. package/build/transformers/namespaces.js +22 -0
  95. package/build/transformers/numericSeparator.js +46 -0
  96. package/build/transformers/objectProperties.js +54 -0
  97. package/build/transformers/precedence.js +192 -0
  98. package/build/transformers/propSemantic.js +467 -0
  99. package/build/transformers/remodule.js +620 -0
  100. package/build/transformers/removeImportExport.js +135 -0
  101. package/build/transformers/replaceDollar.js +46 -0
  102. package/build/transformers/shorthandProperties.js +34 -0
  103. package/build/transformers/spreadArray.js +68 -0
  104. package/build/transformers/spreadObject.js +134 -0
  105. package/build/transformers/string.js +138 -0
  106. package/build/transformers/templateLiterals.js +104 -0
  107. package/build/transformers/tocodelibrary.js +178 -0
  108. package/build/transformers/utils.js +202 -0
  109. package/build/wshcm/client.js +193 -0
  110. package/build/wshcm/evaluator.js +111 -0
  111. package/build/wshcm/exceptions.js +25 -0
  112. package/build/wshcm/index.js +20 -0
  113. package/build/wshcm/soap-utils.js +228 -0
  114. package/build/wshcm/types.js +2 -0
  115. package/build/wshcm/uploader.js +320 -0
  116. package/package.json +51 -0
@@ -0,0 +1,320 @@
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.WshcmUploader = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const crypto = __importStar(require("crypto"));
40
+ /**
41
+ * Описание файла для загрузки
42
+ */
43
+ class FileDescription {
44
+ /** Абсолютный путь к файлу */
45
+ path;
46
+ /** Относительный путь от базовой директории */
47
+ relative;
48
+ /** MD5 хеш относительного пути (в верхнем регистре) */
49
+ hash;
50
+ /** Размер файла в байтах */
51
+ size;
52
+ constructor(filePath, basePath) {
53
+ this.path = filePath;
54
+ this.relative = path.relative(basePath, filePath).replace(/\\/g, '/');
55
+ this.hash = crypto.createHash('md5').update(this.relative).digest('hex').toUpperCase();
56
+ this.size = fs.statSync(filePath).size;
57
+ }
58
+ }
59
+ /**
60
+ * Информация о чанке файла
61
+ */
62
+ class ChunkInfo {
63
+ /** Путь к файлу */
64
+ path;
65
+ /** Начало чанка в файле (байты) */
66
+ chunkStart;
67
+ /** Конец чанка в файле (байты) */
68
+ chunkEnd;
69
+ /** Хеш файла */
70
+ hash;
71
+ /** Индекс чанка */
72
+ index;
73
+ constructor(filePath, chunkStart, chunkEnd, hash, index) {
74
+ this.path = filePath;
75
+ this.chunkStart = chunkStart;
76
+ this.chunkEnd = chunkEnd;
77
+ this.hash = hash;
78
+ this.index = index;
79
+ }
80
+ toString() {
81
+ return `[ ${this.hash} : '${this.path}' : (${this.index}) ${this.chunkStart}-${this.chunkEnd} ]`;
82
+ }
83
+ }
84
+ /**
85
+ * Загрузчик файлов для WSHCM
86
+ *
87
+ * Позволяет загружать файлы и директории на сервер WebSoft HCM
88
+ * с разбиением на чанки и последующей сборкой на сервере.
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * const evaluator = client.createEvaluator();
93
+ * await evaluator.initialize();
94
+ *
95
+ * const uploader = new WshcmUploader({
96
+ * evaluator,
97
+ * path: './myfile.txt',
98
+ * destination: 'x-local://wt/uploaded/',
99
+ * chunkSize: 4 * 1024 * 1024 // 4MB
100
+ * });
101
+ *
102
+ * await uploader.prepare();
103
+ * await uploader.upload((uploaded, total) => {
104
+ * console.log(`Progress: ${(uploaded / total * 100).toFixed(2)}%`);
105
+ * });
106
+ * const urls = await uploader.finish();
107
+ *
108
+ * await evaluator.close();
109
+ * ```
110
+ */
111
+ class WshcmUploader {
112
+ evaluator;
113
+ chunkSize;
114
+ uploadPath;
115
+ destination;
116
+ isDir = false;
117
+ isFile = false;
118
+ isGlob = false;
119
+ totalSize = 0;
120
+ /** Базовый путь для вычисления relative paths */
121
+ basePath = '';
122
+ /** Имя для finish скрипта (пустое для glob режима) */
123
+ uploadName = '';
124
+ files = [];
125
+ // Пути на сервере
126
+ destPath = '';
127
+ tempPath = '';
128
+ chunkPath1 = '';
129
+ chunkPath2 = '';
130
+ /**
131
+ * Создает новый загрузчик файлов
132
+ *
133
+ * Lifecycle evaluator-а управляется вызывающим кодом —
134
+ * uploader не вызывает evaluator.close().
135
+ */
136
+ constructor(options) {
137
+ this.evaluator = options.evaluator;
138
+ this.uploadPath = options.path;
139
+ this.destination = options.destination;
140
+ this.chunkSize = options.chunkSize || 4 * 1024 * 1024; // 4MB по умолчанию
141
+ }
142
+ /**
143
+ * Подготавливает загрузку: сканирует файлы, создает структуру на сервере
144
+ *
145
+ * Поддерживаемые форматы path:
146
+ * - `file.txt` — загрузка одного файла
147
+ * - `dir/` — загрузка директории (как вложенная папка)
148
+ * - `dir/*` — загрузка содержимого директории (без вложенной папки)
149
+ */
150
+ async prepare() {
151
+ // Проверяем glob-паттерн (dir/* или dir\*)
152
+ if (this.uploadPath.endsWith('/*') || this.uploadPath.endsWith('\\*')) {
153
+ this.isGlob = true;
154
+ const dirPath = this.uploadPath.slice(0, -2);
155
+ if (!fs.existsSync(dirPath) || !fs.statSync(dirPath).isDirectory()) {
156
+ throw new Error(`Glob pattern requires existing directory: ${dirPath}`);
157
+ }
158
+ this.basePath = dirPath;
159
+ this.uploadName = ''; // пустое имя сигнализирует glob-режим на сервере
160
+ this.scanDirectory(dirPath, dirPath);
161
+ }
162
+ else {
163
+ // Обычный режим: файл или директория
164
+ const stats = fs.statSync(this.uploadPath);
165
+ if (stats.isDirectory()) {
166
+ this.isDir = true;
167
+ this.basePath = path.dirname(this.uploadPath);
168
+ this.uploadName = path.basename(this.uploadPath);
169
+ this.scanDirectory(this.uploadPath, this.basePath);
170
+ }
171
+ else if (stats.isFile()) {
172
+ this.isFile = true;
173
+ this.basePath = path.dirname(this.uploadPath);
174
+ this.uploadName = path.basename(this.uploadPath);
175
+ const fileDesc = new FileDescription(this.uploadPath, this.basePath);
176
+ this.files.push(fileDesc);
177
+ }
178
+ else {
179
+ throw new Error('Path is not a file or directory');
180
+ }
181
+ }
182
+ // Сортируем файлы по размеру (от меньших к большим) для эффективного батчинга
183
+ this.files.sort((a, b) => a.size - b.size);
184
+ // Вычисляем общий размер
185
+ this.totalSize = this.files.reduce((sum, file) => sum + file.size, 0);
186
+ // Читаем скрипт подготовки
187
+ const prepareScript = fs.readFileSync(path.join(__dirname, '..', '..', 'resources', 'upload_prepare.bs'), 'utf-8');
188
+ // Заменяем переменную
189
+ const script = prepareScript.replace('{{destination}}', this.destination);
190
+ // Выполняем на сервере
191
+ const response = await this.evaluator.eval(script);
192
+ // Сохраняем пути
193
+ this.destPath = response.dest_path.replace(/\\/g, '\\\\');
194
+ this.tempPath = response.temp_path.replace(/\\/g, '\\\\');
195
+ const [part1, part2] = response.chunk_path.split('RELATIVE_PATH_HASH');
196
+ this.chunkPath1 = part1.replace(/\\/g, '\\\\');
197
+ this.chunkPath2 = part2.replace(/\\/g, '\\\\');
198
+ // Создаем директории для чанков на сервере
199
+ const obtainDirCode = this.files
200
+ .map(file => `ObtainDirectory('${this.chunkPath1}${file.hash}', true);`)
201
+ .join('\n');
202
+ await this.evaluator.eval(obtainDirCode);
203
+ }
204
+ /**
205
+ * Загружает файлы на сервер по частям (чанкам)
206
+ * Мелкие чанки группируются в батчи для оптимизации
207
+ * @param callback - функция для отслеживания прогресса
208
+ */
209
+ async upload(callback) {
210
+ const chunks = [];
211
+ // Создаем список всех чанков (файлы уже отсортированы по размеру)
212
+ for (const file of this.files) {
213
+ this.chunksFromFile(file, chunks);
214
+ }
215
+ // Группируем чанки в батчи
216
+ const batches = this.batchChunks(chunks);
217
+ let uploadedBytes = 0;
218
+ // Загружаем батчи
219
+ for (const batch of batches) {
220
+ uploadedBytes += await this.uploadBatch(batch);
221
+ if (callback) {
222
+ callback(uploadedBytes, this.totalSize);
223
+ }
224
+ }
225
+ }
226
+ /**
227
+ * Финализирует загрузку: собирает чанки и перемещает файлы в целевую директорию
228
+ * @returns массив URL загруженных файлов
229
+ */
230
+ async finish() {
231
+ // Читаем скрипт финализации
232
+ const finishScript = fs.readFileSync(path.join(__dirname, '..', '..', 'resources', 'upload_finish.bs'), 'utf-8');
233
+ // Заменяем переменные
234
+ const filePaths = JSON.stringify(this.files.map(f => f.relative));
235
+ let script = finishScript;
236
+ script = script.replace('{{file_name}}', this.uploadName);
237
+ script = script.replace('{{dest_path}}', this.destPath);
238
+ script = script.replace('{{temp_path}}', this.tempPath);
239
+ script = script.replace('{{file_paths}}', filePaths);
240
+ // Выполняем на сервере
241
+ const response = await this.evaluator.eval(script);
242
+ if (response.error) {
243
+ throw new Error(response.message || 'Upload finish failed');
244
+ }
245
+ return response.value || [];
246
+ }
247
+ /**
248
+ * Сканирует директорию рекурсивно и добавляет файлы в список
249
+ */
250
+ scanDirectory(dirPath, basePath) {
251
+ const entries = fs.readdirSync(dirPath, { withFileTypes: true });
252
+ for (const entry of entries) {
253
+ const fullPath = path.join(dirPath, entry.name);
254
+ if (entry.isDirectory()) {
255
+ this.scanDirectory(fullPath, basePath);
256
+ }
257
+ else if (entry.isFile()) {
258
+ const fileDesc = new FileDescription(fullPath, basePath);
259
+ this.files.push(fileDesc);
260
+ }
261
+ }
262
+ }
263
+ /**
264
+ * Разбивает файл на чанки
265
+ */
266
+ chunksFromFile(file, chunks) {
267
+ let index = 0;
268
+ for (let start = 0; start < file.size; start += this.chunkSize) {
269
+ const end = Math.min(start + this.chunkSize, file.size);
270
+ chunks.push(new ChunkInfo(file.path, start, end, file.hash, index));
271
+ index++;
272
+ }
273
+ }
274
+ /**
275
+ * Группирует чанки в батчи для оптимизации загрузки
276
+ * Суммарный размер данных в батче не превышает chunkSize
277
+ */
278
+ batchChunks(chunks) {
279
+ const batches = [];
280
+ let currentBatch = [];
281
+ let currentSize = 0;
282
+ for (const chunk of chunks) {
283
+ const chunkSize = chunk.chunkEnd - chunk.chunkStart;
284
+ // Если батч переполнится — закрываем его
285
+ if (currentSize + chunkSize > this.chunkSize && currentBatch.length > 0) {
286
+ batches.push(currentBatch);
287
+ currentBatch = [];
288
+ currentSize = 0;
289
+ }
290
+ currentBatch.push(chunk);
291
+ currentSize += chunkSize;
292
+ }
293
+ if (currentBatch.length > 0) {
294
+ batches.push(currentBatch);
295
+ }
296
+ return batches;
297
+ }
298
+ /**
299
+ * Загружает батч чанков одним запросом
300
+ * @returns размер загруженных данных в байтах
301
+ */
302
+ async uploadBatch(batch) {
303
+ const statements = [];
304
+ let totalSize = 0;
305
+ for (const chunk of batch) {
306
+ const size = chunk.chunkEnd - chunk.chunkStart;
307
+ const buffer = Buffer.alloc(size);
308
+ const fd = await fs.promises.open(chunk.path, 'r');
309
+ await fd.read(buffer, 0, size, chunk.chunkStart);
310
+ await fd.close();
311
+ const encoded = buffer.toString('base64');
312
+ const serverPath = `${this.chunkPath1}${chunk.hash}${this.chunkPath2}_${chunk.index}`;
313
+ statements.push(`PutFileData('${serverPath}', Base64Decode('${encoded}'))`);
314
+ totalSize += size;
315
+ }
316
+ await this.evaluator.eval(statements.join('\n'));
317
+ return totalSize;
318
+ }
319
+ }
320
+ exports.WshcmUploader = WshcmUploader;
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@boristype/bt-cli",
3
+ "version": "0.1.0-alpha.0",
4
+ "description": "This tool compiles TypeScript into valid SP-XML JavaScript (also known as BorisScript), ensuring full compliance with the specific constraints and APIs of the WebSoft HCM platform.",
5
+ "main": "./build/index.js",
6
+ "bin": {
7
+ "btc": "./build/index.js"
8
+ },
9
+ "files": [
10
+ "build",
11
+ "README.md"
12
+ ],
13
+ "author": "punkhomov",
14
+ "license": "MIT",
15
+ "engines": {
16
+ "node": ">=22.0.0"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/BorisType/BorisType.git"
21
+ },
22
+ "bugs": {
23
+ "url": "https://github.com/BorisType/BorisType/issues"
24
+ },
25
+ "homepage": "https://github.com/BorisType/BorisType#readme",
26
+ "devDependencies": {
27
+ "@types/node": "^24.7.2",
28
+ "typescript": "^5.9.2"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "dependencies": {
34
+ "@types/archiver": "^7.0.0",
35
+ "archiver": "^7.0.1",
36
+ "chalk": "^5.6.0",
37
+ "chokidar": "^5.0.0",
38
+ "commander": "^14.0.1",
39
+ "fast-xml-parser": "^5.3.3",
40
+ "typescript": "^5.9.2",
41
+ "@boristype/ws-client": "^0.1.0-alpha.0",
42
+ "@boristype/bt-ir": "^0.1.0-alpha.0",
43
+ "@boristype/ws-version": "^0.1.0-alpha.0"
44
+ },
45
+ "peerDependencies": {
46
+ "@boristype/runtime": "^0.1.0-alpha.0"
47
+ },
48
+ "scripts": {
49
+ "build": "tsc"
50
+ }
51
+ }