@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,467 @@
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.default = propSemanticTransformer;
37
+ const ts = __importStar(require("typescript"));
38
+ const utils_1 = require("./utils");
39
+ function findSymbolByName(typeChecker, sourceFile, name) {
40
+ return typeChecker.getSymbolsInScope(sourceFile, ts.SymbolFlags.Class | ts.SymbolFlags.Interface | ts.SymbolFlags.TypeAlias | ts.SymbolFlags.Value).find(symbol => symbol.getName() === name);
41
+ }
42
+ // Проверяет, относится ли тип узла к XML-типам (XmlDocument, XmlElem и т.д.)
43
+ // с учетом union и intersection типов. Проверка немного тупая, так как TypeScript
44
+ // считает что любой TopElem документа не может быть isTypeAssignableTo к XmlElem.
45
+ // Но с этим разберемся позже, а пока такое решение работает.
46
+ function isXmlRelatedType(typeChecker, node, xmlDocumentSymbol, xmlElemSymbol) {
47
+ if (!xmlDocumentSymbol && !xmlElemSymbol) {
48
+ return false;
49
+ }
50
+ let type;
51
+ try {
52
+ type = typeChecker.getTypeAtLocation(node);
53
+ }
54
+ catch (err) {
55
+ return false;
56
+ }
57
+ // Проверяем является ли тип any (в этом случае пропускаем проверку)
58
+ if (type.flags & ts.TypeFlags.Any) {
59
+ return false;
60
+ }
61
+ // Проверяем XmlDocument
62
+ if (xmlDocumentSymbol) {
63
+ try {
64
+ const xmlDocType = typeChecker.getDeclaredTypeOfSymbol(xmlDocumentSymbol);
65
+ if (typeChecker.isTypeAssignableTo(type, xmlDocType)) {
66
+ return true;
67
+ }
68
+ }
69
+ catch {
70
+ // Игнорируем ошибки
71
+ }
72
+ }
73
+ // Проверяем XmlElem (включая XmElem)
74
+ if (xmlElemSymbol) {
75
+ try {
76
+ const xmlElemType = typeChecker.getDeclaredTypeOfSymbol(xmlElemSymbol);
77
+ if (typeChecker.isTypeAssignableTo(type, xmlElemType)) {
78
+ return true;
79
+ }
80
+ }
81
+ catch {
82
+ // Игнорируем ошибки
83
+ }
84
+ }
85
+ const typeString = typeChecker.typeToString(type);
86
+ if (typeString.startsWith("typeof tools")) {
87
+ return true;
88
+ }
89
+ if (typeString.startsWith("typeof botest")) {
90
+ return true;
91
+ }
92
+ // Проверяем по имени типа (для generic типов вроде XmlElem<T>)
93
+ if (typeString.startsWith('XmlElem<') ||
94
+ typeString.startsWith('XmElem<') ||
95
+ typeString.startsWith('XmlMultiElem<') ||
96
+ typeString.startsWith('XmlTopElem') ||
97
+ typeString === 'XmlDocument' ||
98
+ typeString === 'XmlElem' ||
99
+ typeString === 'XmElem') {
100
+ return true;
101
+ }
102
+ // Проверяем intersection types (например, XmlTopElem & PersonBase & ...)
103
+ if (type.isIntersection && type.isIntersection()) {
104
+ const hasXmlType = type.types.some(t => {
105
+ const tString = typeChecker.typeToString(t);
106
+ return tString.startsWith('XmlElem<') ||
107
+ tString.startsWith('XmElem<') ||
108
+ tString.startsWith('XmlMultiElem<') ||
109
+ tString.startsWith('XmlTopElem') ||
110
+ tString === 'XmlDocument' ||
111
+ tString === 'XmlElem' ||
112
+ tString === 'XmElem';
113
+ });
114
+ if (hasXmlType) {
115
+ return true;
116
+ }
117
+ }
118
+ // Проверяем union types (например, XmlElem<string> | string)
119
+ if (type.isUnion()) {
120
+ return type.types.some(t => {
121
+ const tString = typeChecker.typeToString(t);
122
+ const match = tString.startsWith('XmlElem<') ||
123
+ tString.startsWith('XmElem<') ||
124
+ tString.startsWith('XmlMultiElem<') ||
125
+ tString.startsWith('XmlTopElem') ||
126
+ tString === 'XmlDocument' ||
127
+ tString === 'XmlElem' ||
128
+ tString === 'XmElem';
129
+ return match;
130
+ });
131
+ }
132
+ return false;
133
+ }
134
+ // Собирает все объявления переменных в файле (включая var, let, const)
135
+ function collectVariableDeclarations(sourceFile) {
136
+ const declarations = new Set();
137
+ function visit(node) {
138
+ // Собираем объявления переменных
139
+ if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
140
+ declarations.add(node.name.text);
141
+ }
142
+ // Собираем параметры функций
143
+ else if (ts.isParameter(node) && ts.isIdentifier(node.name)) {
144
+ declarations.add(node.name.text);
145
+ }
146
+ // Собираем объявления функций
147
+ else if (ts.isFunctionDeclaration(node) && node.name) {
148
+ declarations.add(node.name.text);
149
+ }
150
+ ts.forEachChild(node, visit);
151
+ }
152
+ visit(sourceFile);
153
+ return declarations;
154
+ }
155
+ function propSemanticTransformer(program) {
156
+ return (context) => (file) => {
157
+ let tempCounter = 0;
158
+ const typeChecker = program.getTypeChecker();
159
+ const xmlDocumentSymbol = findSymbolByName(typeChecker, file, "XmlDocument");
160
+ const xmlElemSymbol = findSymbolByName(typeChecker, file, "XmlElem");
161
+ // Собираем все объявленные переменные в файле, без учета области их видимости,
162
+ // надеемся на то, что мы не можем переопределить глобальные функции в файле,
163
+ // и при этом компилятор TypeScript в случае неправильно использования выдаст ошибку.
164
+ const declaredVariables = collectVariableDeclarations(file);
165
+ const scopeStack = [];
166
+ let currentScope = { tempDeclarations: [] };
167
+ // Функция для создания временной переменной в текущем scope
168
+ function createTempVariable() {
169
+ const temp = ts.factory.createIdentifier(`_tmp${tempCounter++}`);
170
+ currentScope.tempDeclarations.push(ts.factory.createVariableDeclaration(temp, undefined, undefined, undefined));
171
+ return temp;
172
+ }
173
+ const visitor = (node) => {
174
+ if ((0, utils_1.isUntouchable)(node)) {
175
+ return node;
176
+ // return ts.visitEachChild(node, visitor, context);
177
+ }
178
+ // Обрабатываем функции как scope boundaries
179
+ if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node) || ts.isConstructorDeclaration(node) || ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node)) {
180
+ // Сохраняем текущий scope и создаём новый
181
+ scopeStack.push(currentScope);
182
+ currentScope = { tempDeclarations: [] };
183
+ // Обрабатываем тело функции
184
+ let transformedNode;
185
+ if (ts.isFunctionDeclaration(node)) {
186
+ transformedNode = ts.factory.updateFunctionDeclaration(node, node.modifiers, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, node.body ? ts.visitNode(node.body, visitor) : undefined);
187
+ }
188
+ else if (ts.isFunctionExpression(node)) {
189
+ transformedNode = ts.factory.updateFunctionExpression(node, node.modifiers, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, ts.visitNode(node.body, visitor));
190
+ }
191
+ else if (ts.isArrowFunction(node)) {
192
+ transformedNode = ts.factory.updateArrowFunction(node, node.modifiers, node.typeParameters, node.parameters, node.type, node.equalsGreaterThanToken, ts.visitNode(node.body, visitor));
193
+ }
194
+ else if (ts.isMethodDeclaration(node)) {
195
+ transformedNode = ts.factory.updateMethodDeclaration(node, node.modifiers, node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters, node.type, node.body ? ts.visitNode(node.body, visitor) : undefined);
196
+ }
197
+ else if (ts.isConstructorDeclaration(node)) {
198
+ transformedNode = ts.factory.updateConstructorDeclaration(node, node.modifiers, node.parameters, node.body ? ts.visitNode(node.body, visitor) : undefined);
199
+ }
200
+ else if (ts.isGetAccessorDeclaration(node)) {
201
+ transformedNode = ts.factory.updateGetAccessorDeclaration(node, node.modifiers, node.name, node.parameters, node.type, node.body ? ts.visitNode(node.body, visitor) : undefined);
202
+ }
203
+ else if (ts.isSetAccessorDeclaration(node)) {
204
+ transformedNode = ts.factory.updateSetAccessorDeclaration(node, node.modifiers, node.name, node.parameters, node.body ? ts.visitNode(node.body, visitor) : undefined);
205
+ }
206
+ else {
207
+ transformedNode = node;
208
+ }
209
+ // Если есть временные переменные для этого scope, добавляем их в начало блока
210
+ const scopeTempDeclarations = currentScope.tempDeclarations;
211
+ // Восстанавливаем предыдущий scope
212
+ currentScope = scopeStack.pop();
213
+ // Добавляем временные переменные в начало тела функции, если они есть
214
+ if (scopeTempDeclarations.length > 0) {
215
+ const varStatement = ts.factory.createVariableStatement(undefined, ts.factory.createVariableDeclarationList(scopeTempDeclarations, ts.NodeFlags.Let));
216
+ // Проверяем, имеет ли функция блочное тело
217
+ if (ts.isFunctionDeclaration(transformedNode) && transformedNode.body) {
218
+ return ts.factory.updateFunctionDeclaration(transformedNode, transformedNode.modifiers, transformedNode.asteriskToken, transformedNode.name, transformedNode.typeParameters, transformedNode.parameters, transformedNode.type, ts.factory.updateBlock(transformedNode.body, [varStatement, ...transformedNode.body.statements]));
219
+ }
220
+ else if (ts.isFunctionExpression(transformedNode)) {
221
+ return ts.factory.updateFunctionExpression(transformedNode, transformedNode.modifiers, transformedNode.asteriskToken, transformedNode.name, transformedNode.typeParameters, transformedNode.parameters, transformedNode.type, ts.factory.updateBlock(transformedNode.body, [varStatement, ...transformedNode.body.statements]));
222
+ }
223
+ else if (ts.isArrowFunction(transformedNode) && ts.isBlock(transformedNode.body)) {
224
+ return ts.factory.updateArrowFunction(transformedNode, transformedNode.modifiers, transformedNode.typeParameters, transformedNode.parameters, transformedNode.type, transformedNode.equalsGreaterThanToken, ts.factory.updateBlock(transformedNode.body, [varStatement, ...transformedNode.body.statements]));
225
+ }
226
+ else if (ts.isMethodDeclaration(transformedNode) && transformedNode.body) {
227
+ return ts.factory.updateMethodDeclaration(transformedNode, transformedNode.modifiers, transformedNode.asteriskToken, transformedNode.name, transformedNode.questionToken, transformedNode.typeParameters, transformedNode.parameters, transformedNode.type, ts.factory.updateBlock(transformedNode.body, [varStatement, ...transformedNode.body.statements]));
228
+ }
229
+ else if (ts.isConstructorDeclaration(transformedNode) && transformedNode.body) {
230
+ return ts.factory.updateConstructorDeclaration(transformedNode, transformedNode.modifiers, transformedNode.parameters, ts.factory.updateBlock(transformedNode.body, [varStatement, ...transformedNode.body.statements]));
231
+ }
232
+ else if (ts.isGetAccessorDeclaration(transformedNode) && transformedNode.body) {
233
+ return ts.factory.updateGetAccessorDeclaration(transformedNode, transformedNode.modifiers, transformedNode.name, transformedNode.parameters, transformedNode.type, ts.factory.updateBlock(transformedNode.body, [varStatement, ...transformedNode.body.statements]));
234
+ }
235
+ else if (ts.isSetAccessorDeclaration(transformedNode) && transformedNode.body) {
236
+ return ts.factory.updateSetAccessorDeclaration(transformedNode, transformedNode.modifiers, transformedNode.name, transformedNode.parameters, ts.factory.updateBlock(transformedNode.body, [varStatement, ...transformedNode.body.statements]));
237
+ }
238
+ }
239
+ return transformedNode;
240
+ }
241
+ // Handle CallExpression for simple function calls (someFunc(...))
242
+ if (ts.isCallExpression(node) && !ts.isPropertyAccessExpression(node.expression)) {
243
+ // Простой вызов функции (не метод объекта)
244
+ const funcExpression = ts.visitNode(node.expression, visitor);
245
+ const args = node.arguments.map(arg => ts.visitNode(arg, visitor));
246
+ // Если выражение функции помечено как untouchable, не трансформируем
247
+ if ((0, utils_1.isUntouchable)(funcExpression)) {
248
+ return ts.factory.updateCallExpression(node, funcExpression, node.typeArguments, args);
249
+ }
250
+ // Проверяем, является ли вызываемая функция локальной переменной
251
+ // Если это идентификатор и он объявлен в файле - преобразуем
252
+ if (ts.isIdentifier(node.expression) && declaredVariables.has(node.expression.text)) {
253
+ // Оборачиваем в bt.callFunction
254
+ return ts.factory.createCallExpression((0, utils_1.markUntouchable)(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("bt"), "callFunction")), undefined, [funcExpression, ts.factory.createArrayLiteralExpression(args)]);
255
+ }
256
+ // Если это не локальная переменная - возвращаем как есть (глобальная функция)
257
+ return ts.factory.updateCallExpression(node, funcExpression, node.typeArguments, args);
258
+ }
259
+ // Handle CallExpression for method calls (obj.method(...) or obj["method"](...))
260
+ if (ts.isCallExpression(node) && (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression))) {
261
+ const propOrElemAccess = node.expression;
262
+ const expression = propOrElemAccess.expression;
263
+ const propertyName = ts.isPropertyAccessExpression(propOrElemAccess)
264
+ ? ts.factory.createStringLiteral(propOrElemAccess.name.text)
265
+ : ts.visitNode(propOrElemAccess.argumentExpression, visitor);
266
+ // Проверяем, есть ли XML тип в цепочке доступа
267
+ const isXmlType = isXmlRelatedType(typeChecker, expression, xmlDocumentSymbol, xmlElemSymbol);
268
+ // Если это XML тип, не трансформируем вообще - обрабатываем только аргументы
269
+ if (isXmlType) {
270
+ const base = ts.visitNode(node.expression, visitor);
271
+ const args = node.arguments.map(arg => ts.visitNode(arg, visitor));
272
+ return ts.factory.updateCallExpression(node, base, node.typeArguments, args);
273
+ }
274
+ // Обходим base-часть и аргументы
275
+ const base = ts.visitNode(expression, visitor);
276
+ const args = node.arguments.map(arg => ts.visitNode(arg, visitor));
277
+ if ((0, utils_1.isUntouchable)(propOrElemAccess)) {
278
+ // original method call, but args transformed
279
+ return ts.factory.updateCallExpression(node, propOrElemAccess, node.typeArguments, args);
280
+ }
281
+ // Вызываем функцию сразу без шага получения свойства, если base — untouchable (например, для выражений вида __env.__parent.someFunc())
282
+ if ((0, utils_1.isUntouchable)(base)) {
283
+ return ts.factory.createCallExpression((0, utils_1.markUntouchable)(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("bt"), "callFunction")), undefined, [propOrElemAccess, ts.factory.createArrayLiteralExpression(args)]);
284
+ }
285
+ if (propOrElemAccess.questionDotToken) {
286
+ // Handle optional chaining for method calls: obj?.method(...) or obj?.["method"](...)
287
+ const temp = createTempVariable();
288
+ const assigned = ts.factory.createAssignment(temp, base);
289
+ const nullCheck = ts.factory.createBinaryExpression(assigned, ts.factory.createToken(ts.SyntaxKind.EqualsEqualsToken), ts.factory.createNull());
290
+ const undefinedCheck = ts.factory.createBinaryExpression(temp, ts.factory.createToken(ts.SyntaxKind.EqualsEqualsToken), ts.factory.createIdentifier("undefined"));
291
+ const combinedCheck = ts.factory.createBinaryExpression(nullCheck, ts.factory.createToken(ts.SyntaxKind.BarBarToken), undefinedCheck);
292
+ const whenTrue = ts.factory.createIdentifier("undefined");
293
+ // Сначала получаем метод: bt.getProperty(temp, "method")
294
+ const getMethod = ts.factory.createCallExpression((0, utils_1.markUntouchable)(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("bt"), "getProperty")), undefined, [temp, propertyName]);
295
+ // Затем вызываем: bt.callFunction(method, [args])
296
+ const whenFalse = ts.factory.createCallExpression((0, utils_1.markUntouchable)(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("bt"), "callFunction")), undefined, [getMethod, ts.factory.createArrayLiteralExpression(args)]);
297
+ return ts.factory.createConditionalExpression(combinedCheck, undefined, whenTrue, undefined, whenFalse);
298
+ }
299
+ // Проверяем, является ли base результатом optional chaining (ConditionalExpression с undefined)
300
+ // Если да, то внедряем вызов в whenFalse ветку существующего conditional expression
301
+ if (ts.isConditionalExpression(base)) {
302
+ const isOptionalChainResult = ts.isIdentifier(base.whenTrue) && base.whenTrue.text === "undefined";
303
+ if (isOptionalChainResult) {
304
+ // Заменяем whenFalse ветку на вызов функции
305
+ const getMethod = ts.factory.createCallExpression((0, utils_1.markUntouchable)(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("bt"), "getProperty")), undefined, [base.whenFalse, propertyName]);
306
+ const callFunc = ts.factory.createCallExpression((0, utils_1.markUntouchable)(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("bt"), "callFunction")), undefined, [getMethod, ts.factory.createArrayLiteralExpression(args)]);
307
+ return ts.factory.updateConditionalExpression(base, base.condition, base.questionToken, base.whenTrue, base.colonToken, callFunc);
308
+ }
309
+ }
310
+ // Non-optional method call:
311
+ // 1. Получаем метод: bt.getProperty(obj, "method")
312
+ const getMethod = ts.factory.createCallExpression((0, utils_1.markUntouchable)(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("bt"), "getProperty")), undefined, [base, propertyName]);
313
+ // 2. Вызываем метод: bt.callFunction(method, [args])
314
+ return ts.factory.createCallExpression((0, utils_1.markUntouchable)(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("bt"), "callFunction")), undefined, [getMethod, ts.factory.createArrayLiteralExpression(args)]);
315
+ }
316
+ // Handle PropertyAccessExpression for property access
317
+ if (ts.isPropertyAccessExpression(node)) {
318
+ // Если это вызов метода (obj.method(...)) → уже обработано выше
319
+ if (node.parent && ts.isCallExpression(node.parent) && node.parent.expression === node) {
320
+ // return node;
321
+ // мы правильно это делаем? ну например для последовательности obj.method.prop.other()
322
+ // где мы преобразуем [obj.method.prop].other()
323
+ return ts.factory.updatePropertyAccessExpression(node, ts.visitNode(node.expression, visitor), node.name);
324
+ }
325
+ // Проверяем, является ли это присваиванием (obj.prop = value)
326
+ const isAssignment = node.parent &&
327
+ ts.isBinaryExpression(node.parent) &&
328
+ node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
329
+ node.parent.left === node;
330
+ if (isAssignment) {
331
+ // Это присваивание: obj.prop = value
332
+ // Не трансформируем здесь, обработаем в BinaryExpression
333
+ return node;
334
+ }
335
+ // Проверяем, есть ли XML тип в цепочке доступа (проверяем ДО трансформации)
336
+ const isXmlType = isXmlRelatedType(typeChecker, node.expression, xmlDocumentSymbol, xmlElemSymbol);
337
+ // Если это XML тип, не трансформируем вообще - возвращаем оригинальный узел
338
+ // и не посещаем его дочерние узлы для трансформации
339
+ if (isXmlType) {
340
+ // return node;
341
+ const base = ts.visitNode(node.expression, visitor);
342
+ return ts.factory.updatePropertyAccessExpression(node, base, node.name);
343
+ }
344
+ // Обходим base-часть
345
+ const base = ts.visitNode(node.expression, visitor);
346
+ const property = ts.factory.createStringLiteral(node.name.text);
347
+ // Оставляем без изменений, если base — untouchable (например, для выражений вида __env.__parent.SOME_CONSTANT)
348
+ if ((0, utils_1.isUntouchable)(base)) {
349
+ return node;
350
+ }
351
+ if (node.questionDotToken) {
352
+ // Handle optional chaining for property access
353
+ const temp = createTempVariable();
354
+ const assigned = ts.factory.createAssignment(temp, base);
355
+ const nullCheck = ts.factory.createBinaryExpression(assigned, ts.factory.createToken(ts.SyntaxKind.EqualsEqualsToken), ts.factory.createNull());
356
+ const undefinedCheck = ts.factory.createBinaryExpression(temp, ts.factory.createToken(ts.SyntaxKind.EqualsEqualsToken), ts.factory.createIdentifier("undefined"));
357
+ const combinedCheck = ts.factory.createBinaryExpression(nullCheck, ts.factory.createToken(ts.SyntaxKind.BarBarToken), undefinedCheck);
358
+ const whenTrue = ts.factory.createIdentifier("undefined");
359
+ const whenFalse = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("bt"), "getProperty"), undefined, [temp, property]);
360
+ return ts.factory.createConditionalExpression(combinedCheck, undefined, whenTrue, undefined, whenFalse);
361
+ }
362
+ // Проверяем, не является ли base результатом optional chaining (ConditionalExpression с undefined)
363
+ // Если да, то встраиваем getProperty в whenFalse ветку существующего conditional expression
364
+ // ТОЛЬКО если текущий узел не имеет ?.
365
+ if (ts.isConditionalExpression(base)) {
366
+ const isOptionalChainResult = ts.isIdentifier(base.whenTrue) && base.whenTrue.text === "undefined";
367
+ if (isOptionalChainResult) {
368
+ // Заменяем whenFalse ветку на getProperty от результата whenFalse
369
+ const getProp = ts.factory.createCallExpression((0, utils_1.markUntouchable)(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("bt"), "getProperty")), undefined, [base.whenFalse, property]);
370
+ return ts.factory.updateConditionalExpression(base, base.condition, base.questionToken, base.whenTrue, base.colonToken, getProp);
371
+ }
372
+ }
373
+ // Non-optional property access: bt.getProperty(obj, "prop")
374
+ return ts.factory.createCallExpression((0, utils_1.markUntouchable)(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("bt"), "getProperty")), undefined, [base, property]);
375
+ }
376
+ // Handle ElementAccessExpression for property access obj["prop"]
377
+ if (ts.isElementAccessExpression(node)) {
378
+ // Если это вызов метода (obj["method"](...)) → уже обработано выше
379
+ if (node.parent && ts.isCallExpression(node.parent) && node.parent.expression === node) {
380
+ return ts.factory.updateElementAccessExpression(node, ts.visitNode(node.expression, visitor), ts.visitNode(node.argumentExpression, visitor));
381
+ }
382
+ // Проверяем, является ли это присваиванием (obj["prop"] = value)
383
+ const isAssignment = node.parent &&
384
+ ts.isBinaryExpression(node.parent) &&
385
+ node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
386
+ node.parent.left === node;
387
+ if (isAssignment) {
388
+ // Это присваивание: obj["prop"] = value
389
+ // Не трансформируем здесь, обработаем в BinaryExpression
390
+ return node;
391
+ }
392
+ // Проверяем, есть ли XML тип в цепочке доступа
393
+ const isXmlType = isXmlRelatedType(typeChecker, node.expression, xmlDocumentSymbol, xmlElemSymbol);
394
+ if (isXmlType) {
395
+ const base = ts.visitNode(node.expression, visitor);
396
+ const argument = ts.visitNode(node.argumentExpression, visitor);
397
+ return ts.factory.updateElementAccessExpression(node, base, argument);
398
+ }
399
+ // Обходим base-часть и expression для property
400
+ const base = ts.visitNode(node.expression, visitor);
401
+ const property = ts.visitNode(node.argumentExpression, visitor);
402
+ if ((0, utils_1.isUntouchable)(base)) {
403
+ return node;
404
+ }
405
+ if (node.questionDotToken) {
406
+ // Handle optional chaining: obj?.["prop"]
407
+ const temp = createTempVariable();
408
+ const assigned = ts.factory.createAssignment(temp, base);
409
+ const nullCheck = ts.factory.createBinaryExpression(assigned, ts.factory.createToken(ts.SyntaxKind.EqualsEqualsToken), ts.factory.createNull());
410
+ const undefinedCheck = ts.factory.createBinaryExpression(temp, ts.factory.createToken(ts.SyntaxKind.EqualsEqualsToken), ts.factory.createIdentifier("undefined"));
411
+ const combinedCheck = ts.factory.createBinaryExpression(nullCheck, ts.factory.createToken(ts.SyntaxKind.BarBarToken), undefinedCheck);
412
+ const whenTrue = ts.factory.createIdentifier("undefined");
413
+ const whenFalse = ts.factory.createCallExpression((0, utils_1.markUntouchable)(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("bt"), "getProperty")), undefined, [temp, property]);
414
+ return ts.factory.createConditionalExpression(combinedCheck, undefined, whenTrue, undefined, whenFalse);
415
+ }
416
+ if (ts.isConditionalExpression(base)) {
417
+ const isOptionalChainResult = ts.isIdentifier(base.whenTrue) && base.whenTrue.text === "undefined";
418
+ if (isOptionalChainResult) {
419
+ const getProp = ts.factory.createCallExpression((0, utils_1.markUntouchable)(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("bt"), "getProperty")), undefined, [base.whenFalse, property]);
420
+ return ts.factory.updateConditionalExpression(base, base.condition, base.questionToken, base.whenTrue, base.colonToken, getProp);
421
+ }
422
+ }
423
+ // Non-optional property access: bt.getProperty(obj, "prop")
424
+ return ts.factory.createCallExpression((0, utils_1.markUntouchable)(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("bt"), "getProperty")), undefined, [base, property]);
425
+ }
426
+ // Handle BinaryExpression for assignments (obj.prop = value or obj["prop"] = value)
427
+ if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && (ts.isPropertyAccessExpression(node.left) || ts.isElementAccessExpression(node.left))) {
428
+ const propOrElemAccess = node.left;
429
+ const expression = propOrElemAccess.expression;
430
+ // Проверяем, есть ли XML тип в цепочке доступа (проверяем ДО трансформации)
431
+ const isXmlType = isXmlRelatedType(typeChecker, expression, xmlDocumentSymbol, xmlElemSymbol);
432
+ // Если это XML тип, не трансформируем вообще - обрабатываем только правую часть
433
+ if (isXmlType) {
434
+ const left = ts.visitNode(propOrElemAccess, visitor);
435
+ const value = ts.visitNode(node.right, visitor);
436
+ return ts.factory.updateBinaryExpression(node, left, node.operatorToken, value);
437
+ }
438
+ // Обходим base-часть и правую часть присваивания
439
+ const base = ts.visitNode(expression, visitor);
440
+ const property = ts.isPropertyAccessExpression(propOrElemAccess)
441
+ ? ts.factory.createStringLiteral(propOrElemAccess.name.text)
442
+ : ts.visitNode(propOrElemAccess.argumentExpression, visitor);
443
+ const value = ts.visitNode(node.right, visitor);
444
+ if ((0, utils_1.isUntouchable)(base)) {
445
+ return ts.factory.updateBinaryExpression(node, propOrElemAccess, node.operatorToken, value);
446
+ }
447
+ // bt.setProperty(obj, "prop", value)
448
+ return ts.factory.createCallExpression((0, utils_1.markUntouchable)(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("bt"), "setProperty")), undefined, [base, property, value]);
449
+ }
450
+ // Continue visiting other nodes
451
+ return ts.visitEachChild(node, visitor, context);
452
+ };
453
+ // Visit the entire file to transform nodes
454
+ const transformedFile = ts.visitNode(file, visitor);
455
+ // Добавляем временные переменные top-level scope в начало файла (если они есть)
456
+ const varStatement = currentScope.tempDeclarations.length > 0
457
+ ? [
458
+ ts.factory.createVariableStatement(undefined, ts.factory.createVariableDeclarationList(currentScope.tempDeclarations, ts.NodeFlags.Let)),
459
+ ]
460
+ : [];
461
+ // Update source file with variable declarations only (no helper function)
462
+ return ts.factory.updateSourceFile(transformedFile, [
463
+ ...varStatement,
464
+ ...transformedFile.statements,
465
+ ]);
466
+ };
467
+ }