vladx 1.0.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/README.md +256 -0
- package/bin/cli.js +486 -0
- package/bin/vlad.js +539 -0
- package/bin/vladpm.js +710 -0
- package/bin/vladx.js +491 -0
- package/package.json +57 -0
- package/src/engine/jit-compiler.js +285 -0
- package/src/engine/vladx-engine.js +941 -0
- package/src/index.js +44 -0
- package/src/interpreter/interpreter.js +2114 -0
- package/src/lexer/lexer.js +658 -0
- package/src/lexer/optimized-lexer.js +106 -0
- package/src/lexer/regex-cache.js +83 -0
- package/src/parser/ast-nodes.js +472 -0
- package/src/parser/parser.js +1408 -0
- package/src/runtime/advanced-type-system.js +209 -0
- package/src/runtime/async-manager.js +252 -0
- package/src/runtime/builtins.js +143 -0
- package/src/runtime/bundler.js +422 -0
- package/src/runtime/cache-manager.js +126 -0
- package/src/runtime/data-structures.js +612 -0
- package/src/runtime/debugger.js +260 -0
- package/src/runtime/enhanced-module-system.js +196 -0
- package/src/runtime/environment-enhanced.js +272 -0
- package/src/runtime/environment.js +140 -0
- package/src/runtime/event-emitter.js +232 -0
- package/src/runtime/formatter.js +280 -0
- package/src/runtime/functional.js +359 -0
- package/src/runtime/io-operations.js +390 -0
- package/src/runtime/linter.js +374 -0
- package/src/runtime/logging.js +314 -0
- package/src/runtime/minifier.js +242 -0
- package/src/runtime/module-system.js +377 -0
- package/src/runtime/network-operations.js +373 -0
- package/src/runtime/profiler.js +295 -0
- package/src/runtime/repl.js +336 -0
- package/src/runtime/security-manager.js +244 -0
- package/src/runtime/source-map-generator.js +208 -0
- package/src/runtime/test-runner.js +394 -0
- package/src/runtime/transformer.js +277 -0
- package/src/runtime/type-system.js +244 -0
- package/src/runtime/vladx-object.js +250 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debugger — Отладчик для пошагового выполнения
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export class Debugger {
|
|
6
|
+
constructor(interpreter) {
|
|
7
|
+
this.interpreter = interpreter;
|
|
8
|
+
this.breakpoints = new Set();
|
|
9
|
+
this.stepMode = false;
|
|
10
|
+
this.stepDepth = 0;
|
|
11
|
+
this.currentFrame = null;
|
|
12
|
+
this.callStack = [];
|
|
13
|
+
this.watchExpressions = [];
|
|
14
|
+
this.paused = false;
|
|
15
|
+
this.onNextBreakpoint = null;
|
|
16
|
+
this.sourceMaps = new Map();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Установить breakpoint
|
|
21
|
+
*/
|
|
22
|
+
setBreakpoint(filename, line) {
|
|
23
|
+
const key = `${filename}:${line}`;
|
|
24
|
+
this.breakpoints.add(key);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Удалить breakpoint
|
|
29
|
+
*/
|
|
30
|
+
removeBreakpoint(filename, line) {
|
|
31
|
+
const key = `${filename}:${line}`;
|
|
32
|
+
this.breakpoints.delete(key);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Проверить breakpoint
|
|
37
|
+
*/
|
|
38
|
+
shouldBreak(filename, line) {
|
|
39
|
+
const key = `${filename}:${line}`;
|
|
40
|
+
return this.breakpoints.has(key);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Включить пошаговый режим
|
|
45
|
+
*/
|
|
46
|
+
stepInto() {
|
|
47
|
+
this.stepMode = 'into';
|
|
48
|
+
this.stepDepth = this.callStack.length;
|
|
49
|
+
this.paused = false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Шагнуть (перепрыгнуть через функцию)
|
|
54
|
+
*/
|
|
55
|
+
stepOver() {
|
|
56
|
+
this.stepMode = 'over';
|
|
57
|
+
this.stepDepth = this.callStack.length;
|
|
58
|
+
this.paused = false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Шагнуть из функции
|
|
63
|
+
*/
|
|
64
|
+
stepOut() {
|
|
65
|
+
this.stepMode = 'out';
|
|
66
|
+
this.stepDepth = this.callStack.length;
|
|
67
|
+
this.paused = false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Продолжить выполнение
|
|
72
|
+
*/
|
|
73
|
+
continue() {
|
|
74
|
+
this.stepMode = false;
|
|
75
|
+
this.paused = false;
|
|
76
|
+
if (this.onNextBreakpoint) {
|
|
77
|
+
this.onNextBreakpoint();
|
|
78
|
+
this.onNextBreakpoint = null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Проверить, нужно ли паузу
|
|
84
|
+
*/
|
|
85
|
+
checkBreak(filename, line) {
|
|
86
|
+
if (this.stepMode) {
|
|
87
|
+
switch (this.stepMode) {
|
|
88
|
+
case 'into':
|
|
89
|
+
return true;
|
|
90
|
+
case 'over':
|
|
91
|
+
return this.callStack.length <= this.stepDepth;
|
|
92
|
+
case 'out':
|
|
93
|
+
return this.callStack.length < this.stepDepth;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return this.shouldBreak(filename, line);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Добавить watch expression
|
|
102
|
+
*/
|
|
103
|
+
addWatch(expression) {
|
|
104
|
+
this.watchExpressions.push(expression);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Удалить watch expression
|
|
109
|
+
*/
|
|
110
|
+
removeWatch(expression) {
|
|
111
|
+
const index = this.watchExpressions.indexOf(expression);
|
|
112
|
+
if (index !== -1) {
|
|
113
|
+
this.watchExpressions.splice(index, 1);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Оценить watch expressions
|
|
119
|
+
*/
|
|
120
|
+
async evaluateWatches() {
|
|
121
|
+
const results = {};
|
|
122
|
+
|
|
123
|
+
for (const expr of this.watchExpressions) {
|
|
124
|
+
try {
|
|
125
|
+
results[expr] = await this.interpreter.evaluateExpression(expr);
|
|
126
|
+
} catch (e) {
|
|
127
|
+
results[expr] = { error: e.message };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return results;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Получить стек вызовов
|
|
136
|
+
*/
|
|
137
|
+
getCallStack() {
|
|
138
|
+
return this.callStack.map(frame => ({
|
|
139
|
+
filename: frame.filename,
|
|
140
|
+
line: frame.line,
|
|
141
|
+
function: frame.functionName,
|
|
142
|
+
locals: this.getLocals(frame)
|
|
143
|
+
}));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Получить локальные переменные
|
|
148
|
+
*/
|
|
149
|
+
getLocals(frame) {
|
|
150
|
+
if (!frame || !frame.environment) {
|
|
151
|
+
return {};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const locals = {};
|
|
155
|
+
for (const [key, value] of frame.environment.variables) {
|
|
156
|
+
locals[key] = value;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return locals;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Получить значение переменной
|
|
164
|
+
*/
|
|
165
|
+
getVariable(name) {
|
|
166
|
+
if (!this.currentFrame || !this.currentFrame.environment) {
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
return this.currentFrame.environment.get(name);
|
|
172
|
+
} catch (e) {
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Установить значение переменной
|
|
179
|
+
*/
|
|
180
|
+
setVariable(name, value) {
|
|
181
|
+
if (!this.currentFrame || !this.currentFrame.environment) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
this.currentFrame.environment.assign(name, value);
|
|
187
|
+
return true;
|
|
188
|
+
} catch (e) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Добавить фрейм в стек вызовов
|
|
195
|
+
*/
|
|
196
|
+
pushFrame(frame) {
|
|
197
|
+
this.callStack.push(frame);
|
|
198
|
+
this.currentFrame = frame;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Удалить фрейм из стека вызовов
|
|
203
|
+
*/
|
|
204
|
+
popFrame() {
|
|
205
|
+
this.callStack.pop();
|
|
206
|
+
this.currentFrame = this.callStack[this.callStack.length - 1];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Получить текущее состояние
|
|
211
|
+
*/
|
|
212
|
+
getState() {
|
|
213
|
+
return {
|
|
214
|
+
paused: this.paused,
|
|
215
|
+
breakpoints: Array.from(this.breakpoints),
|
|
216
|
+
watchExpressions: [...this.watchExpressions],
|
|
217
|
+
callStack: this.getCallStack(),
|
|
218
|
+
currentFrame: this.currentFrame ? {
|
|
219
|
+
filename: this.currentFrame.filename,
|
|
220
|
+
line: this.currentFrame.line,
|
|
221
|
+
function: this.currentFrame.functionName
|
|
222
|
+
} : null
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Добавить source map
|
|
228
|
+
*/
|
|
229
|
+
addSourceMap(filename, map) {
|
|
230
|
+
this.sourceMaps.set(filename, map);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Конвертировать позицию в исходный код
|
|
235
|
+
*/
|
|
236
|
+
mapPosition(filename, line, column) {
|
|
237
|
+
const map = this.sourceMaps.get(filename);
|
|
238
|
+
if (!map) {
|
|
239
|
+
return { line, column };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Simplified source map lookup
|
|
243
|
+
// В реальной реализации нужно парсить source map JSON
|
|
244
|
+
return { line, column };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Очистить состояние
|
|
249
|
+
*/
|
|
250
|
+
clear() {
|
|
251
|
+
this.breakpoints.clear();
|
|
252
|
+
this.stepMode = false;
|
|
253
|
+
this.callStack = [];
|
|
254
|
+
this.watchExpressions = [];
|
|
255
|
+
this.currentFrame = null;
|
|
256
|
+
this.paused = false;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export default Debugger;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EnhancedModuleSystem — Улучшенная система модулей
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ModuleSystem } from './module-system.js';
|
|
6
|
+
|
|
7
|
+
export class EnhancedModuleSystem extends ModuleSystem {
|
|
8
|
+
constructor(interpreter) {
|
|
9
|
+
super(interpreter);
|
|
10
|
+
this.circularDependencies = new Map();
|
|
11
|
+
this.dependencyGraph = new Map();
|
|
12
|
+
this.importStack = [];
|
|
13
|
+
this.dynamicImports = new Map();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Проверка на циклические зависимости
|
|
18
|
+
*/
|
|
19
|
+
checkCircularDependencies(modulePath) {
|
|
20
|
+
if (this.importStack.includes(modulePath)) {
|
|
21
|
+
const cycle = [...this.importStack, modulePath];
|
|
22
|
+
throw new Error(`Циклическая зависимость: ${cycle.join(' -> ')}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
this.importStack.push(modulePath);
|
|
26
|
+
|
|
27
|
+
const dependencies = this.dependencyGraph.get(modulePath) || [];
|
|
28
|
+
|
|
29
|
+
for (const dep of dependencies) {
|
|
30
|
+
this.checkCircularDependencies(dep);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this.importStack.pop();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Добавить зависимость в граф
|
|
38
|
+
*/
|
|
39
|
+
addDependency(from, to) {
|
|
40
|
+
if (!this.dependencyGraph.has(from)) {
|
|
41
|
+
this.dependencyGraph.set(from, []);
|
|
42
|
+
}
|
|
43
|
+
this.dependencyGraph.get(from).push(to);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Динамический импорт
|
|
48
|
+
*/
|
|
49
|
+
async dynamicImport(modulePath, currentPath) {
|
|
50
|
+
const cacheKey = `${currentPath}:${modulePath}`;
|
|
51
|
+
|
|
52
|
+
if (this.dynamicImports.has(cacheKey)) {
|
|
53
|
+
return this.dynamicImports.get(cacheKey);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const promise = this.loadModule(modulePath, currentPath);
|
|
57
|
+
this.dynamicImports.set(cacheKey, promise);
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
return await promise;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
this.dynamicImports.delete(cacheKey);
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Переэкспорт
|
|
69
|
+
*/
|
|
70
|
+
async reExport(fromModule, exports, currentPath) {
|
|
71
|
+
const module = await this.loadModule(fromModule, currentPath);
|
|
72
|
+
|
|
73
|
+
if (Array.isArray(exports)) {
|
|
74
|
+
// Именованный реэкспорт
|
|
75
|
+
const result = {};
|
|
76
|
+
for (const name of exports) {
|
|
77
|
+
if (name in module) {
|
|
78
|
+
result[name] = module[name];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
} else if (typeof exports === 'string') {
|
|
83
|
+
// Реэкспорт по умолчанию
|
|
84
|
+
return module[exports] || module;
|
|
85
|
+
} else {
|
|
86
|
+
// Реэкспорт всего
|
|
87
|
+
return module;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Conditional экспорт
|
|
93
|
+
*/
|
|
94
|
+
async conditionalExport(modulePath, conditions, currentPath) {
|
|
95
|
+
const module = await this.loadModule(modulePath, currentPath);
|
|
96
|
+
|
|
97
|
+
for (const [condition, value] of Object.entries(conditions)) {
|
|
98
|
+
if (this.checkCondition(condition)) {
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return module;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Проверка условия экспорта
|
|
108
|
+
*/
|
|
109
|
+
checkCondition(condition) {
|
|
110
|
+
switch (condition) {
|
|
111
|
+
case 'production':
|
|
112
|
+
return process.env.NODE_ENV === 'production';
|
|
113
|
+
case 'development':
|
|
114
|
+
return process.env.NODE_ENV === 'development';
|
|
115
|
+
case 'test':
|
|
116
|
+
return process.env.NODE_ENV === 'test';
|
|
117
|
+
case 'node':
|
|
118
|
+
return typeof process !== 'undefined';
|
|
119
|
+
case 'browser':
|
|
120
|
+
return typeof window !== 'undefined';
|
|
121
|
+
default:
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Получить граф зависимостей
|
|
128
|
+
*/
|
|
129
|
+
getDependencyGraph() {
|
|
130
|
+
return {
|
|
131
|
+
graph: Object.fromEntries(this.dependencyGraph),
|
|
132
|
+
circular: Array.from(this.circularDependencies.entries())
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Очистить граф зависимостей
|
|
138
|
+
*/
|
|
139
|
+
clearDependencyGraph() {
|
|
140
|
+
this.dependencyGraph.clear();
|
|
141
|
+
this.circularDependencies.clear();
|
|
142
|
+
this.importStack = [];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Топологическая сортировка зависимостей
|
|
147
|
+
*/
|
|
148
|
+
topologicalSort() {
|
|
149
|
+
const visited = new Set();
|
|
150
|
+
const result = [];
|
|
151
|
+
const graph = Object.fromEntries(this.dependencyGraph);
|
|
152
|
+
|
|
153
|
+
const visit = (node) => {
|
|
154
|
+
if (visited.has(node)) return;
|
|
155
|
+
visited.add(node);
|
|
156
|
+
|
|
157
|
+
const dependencies = graph[node] || [];
|
|
158
|
+
for (const dep of dependencies) {
|
|
159
|
+
visit(dep);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
result.push(node);
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
for (const node of Object.keys(graph)) {
|
|
166
|
+
visit(node);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Проверить модуль на наличие зависимостей
|
|
174
|
+
*/
|
|
175
|
+
hasDependencies(modulePath) {
|
|
176
|
+
const deps = this.dependencyGraph.get(modulePath);
|
|
177
|
+
return deps && deps.length > 0;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Получить все модули, которые зависят от данного
|
|
182
|
+
*/
|
|
183
|
+
getDependents(modulePath) {
|
|
184
|
+
const dependents = [];
|
|
185
|
+
|
|
186
|
+
for (const [from, tos] of this.dependencyGraph.entries()) {
|
|
187
|
+
if (tos.includes(modulePath)) {
|
|
188
|
+
dependents.push(from);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return dependents;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export default EnhancedModuleSystem;
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment — Улучшенное управление окружением
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { CacheManager } from './cache-manager.js';
|
|
6
|
+
import { SecurityManager } from './security-manager.js';
|
|
7
|
+
|
|
8
|
+
export class EnvironmentEnhanced {
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
this.name = options.name || process.env.NODE_ENV || 'development';
|
|
11
|
+
this.isDevelopment = this.name === 'development';
|
|
12
|
+
this.isProduction = this.name === 'production';
|
|
13
|
+
this.isTest = this.name === 'test';
|
|
14
|
+
|
|
15
|
+
this.cache = new CacheManager({
|
|
16
|
+
maxSize: options.cacheSize || 1000,
|
|
17
|
+
ttl: options.cacheTTL || 300000
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
this.security = new SecurityManager({
|
|
21
|
+
enabled: options.securityEnabled !== false,
|
|
22
|
+
allowedPaths: options.allowedPaths || [],
|
|
23
|
+
maxFileSize: options.maxFileSize || 10 * 1024 * 1024
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
this.config = options.config || {};
|
|
27
|
+
this.variables = options.variables || {};
|
|
28
|
+
this.plugins = new Map();
|
|
29
|
+
this.middleware = [];
|
|
30
|
+
this.hooks = new Map();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Получить переменную окружения
|
|
35
|
+
*/
|
|
36
|
+
get(key, defaultValue) {
|
|
37
|
+
if (key in this.variables) {
|
|
38
|
+
return this.variables[key];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (key in process.env) {
|
|
42
|
+
return process.env[key];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return defaultValue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Установить переменную окружения
|
|
50
|
+
*/
|
|
51
|
+
set(key, value) {
|
|
52
|
+
this.variables[key] = value;
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Получить конфигурацию
|
|
58
|
+
*/
|
|
59
|
+
getConfig(key, defaultValue) {
|
|
60
|
+
return this.getNestedValue(this.config, key, defaultValue);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Получить вложенное значение
|
|
65
|
+
*/
|
|
66
|
+
getNestedValue(obj, path, defaultValue) {
|
|
67
|
+
const keys = path.split('.');
|
|
68
|
+
let result = obj;
|
|
69
|
+
|
|
70
|
+
for (const key of keys) {
|
|
71
|
+
if (result && typeof result === 'object' && key in result) {
|
|
72
|
+
result = result[key];
|
|
73
|
+
} else {
|
|
74
|
+
return defaultValue;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Добавить плагин
|
|
83
|
+
*/
|
|
84
|
+
use(plugin) {
|
|
85
|
+
const name = plugin.name || `plugin_${this.plugins.size}`;
|
|
86
|
+
this.plugins.set(name, plugin);
|
|
87
|
+
|
|
88
|
+
if (plugin.install) {
|
|
89
|
+
plugin.install(this);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Добавить middleware
|
|
97
|
+
*/
|
|
98
|
+
add(middleware) {
|
|
99
|
+
this.middleware.push(middleware);
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Выполнить middleware
|
|
105
|
+
*/
|
|
106
|
+
async executeMiddleware(context) {
|
|
107
|
+
for (const middleware of this.middleware) {
|
|
108
|
+
const result = await middleware(context, this);
|
|
109
|
+
|
|
110
|
+
if (result === false) {
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return context;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Добавить hook
|
|
120
|
+
*/
|
|
121
|
+
on(event, callback) {
|
|
122
|
+
if (!this.hooks.has(event)) {
|
|
123
|
+
this.hooks.set(event, []);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
this.hooks.get(event).push(callback);
|
|
127
|
+
return this;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Удалить hook
|
|
132
|
+
*/
|
|
133
|
+
off(event, callback) {
|
|
134
|
+
const hooks = this.hooks.get(event);
|
|
135
|
+
if (hooks) {
|
|
136
|
+
const index = hooks.indexOf(callback);
|
|
137
|
+
if (index !== -1) {
|
|
138
|
+
hooks.splice(index, 1);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return this;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Запустить hook
|
|
146
|
+
*/
|
|
147
|
+
async emit(event, ...args) {
|
|
148
|
+
const hooks = this.hooks.get(event);
|
|
149
|
+
if (hooks) {
|
|
150
|
+
for (const callback of hooks) {
|
|
151
|
+
await callback(...args);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return this;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Проверить функцию
|
|
159
|
+
*/
|
|
160
|
+
hasFeature(feature) {
|
|
161
|
+
return this.getConfig(`features.${feature}`, false);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Получить режим работы
|
|
166
|
+
*/
|
|
167
|
+
getMode() {
|
|
168
|
+
return this.name;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Получить информацию о системе
|
|
173
|
+
*/
|
|
174
|
+
getSystemInfo() {
|
|
175
|
+
return {
|
|
176
|
+
platform: process.platform,
|
|
177
|
+
arch: process.arch,
|
|
178
|
+
nodeVersion: process.version,
|
|
179
|
+
cpus: process.cpuUsage(),
|
|
180
|
+
memory: process.memoryUsage(),
|
|
181
|
+
uptime: process.uptime(),
|
|
182
|
+
env: process.env.NODE_ENV
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Логирование
|
|
188
|
+
*/
|
|
189
|
+
log(level, ...args) {
|
|
190
|
+
const timestamp = new Date().toISOString();
|
|
191
|
+
const message = args.map(arg =>
|
|
192
|
+
typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
|
|
193
|
+
).join(' ');
|
|
194
|
+
|
|
195
|
+
console.log(`[${timestamp}] [${level.toUpperCase()}] ${message}`);
|
|
196
|
+
|
|
197
|
+
this.emit('log', { level, message, timestamp });
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
info(...args) {
|
|
201
|
+
this.log('info', ...args);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
warn(...args) {
|
|
205
|
+
this.log('warn', ...args);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
error(...args) {
|
|
209
|
+
this.log('error', ...args);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
debug(...args) {
|
|
213
|
+
if (this.isDevelopment) {
|
|
214
|
+
this.log('debug', ...args);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Измерение времени
|
|
220
|
+
*/
|
|
221
|
+
time(label) {
|
|
222
|
+
this.timers = this.timers || {};
|
|
223
|
+
this.timers[label] = Date.now();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
timeEnd(label) {
|
|
227
|
+
if (!this.timers || !(label in this.timers)) {
|
|
228
|
+
return 0;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const duration = Date.now() - this.timers[label];
|
|
232
|
+
delete this.timers[label];
|
|
233
|
+
|
|
234
|
+
this.info(`${label}: ${duration}ms`);
|
|
235
|
+
return duration;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Очистить ресурсы
|
|
240
|
+
*/
|
|
241
|
+
async cleanup() {
|
|
242
|
+
this.cache.clear();
|
|
243
|
+
|
|
244
|
+
for (const [name, plugin] of this.plugins) {
|
|
245
|
+
if (plugin.uninstall) {
|
|
246
|
+
await plugin.uninstall(this);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
this.plugins.clear();
|
|
251
|
+
this.middleware = [];
|
|
252
|
+
this.hooks.clear();
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Получить статистику окружения
|
|
257
|
+
*/
|
|
258
|
+
getStats() {
|
|
259
|
+
return {
|
|
260
|
+
name: this.name,
|
|
261
|
+
cache: this.cache.getStats(),
|
|
262
|
+
plugins: Array.from(this.plugins.keys()),
|
|
263
|
+
middleware: this.middleware.length,
|
|
264
|
+
hooks: Object.fromEntries(
|
|
265
|
+
Array.from(this.hooks.entries()).map(([k, v]) => [k, v.length])
|
|
266
|
+
),
|
|
267
|
+
system: this.getSystemInfo()
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export default EnvironmentEnhanced;
|