@tramvai/module-common 5.16.2 → 5.17.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/lib/CommonModule.browser.js +3 -11
- package/lib/CommonModule.es.js +3 -11
- package/lib/CommonModule.js +2 -10
- package/lib/command/CommandModule.browser.js +9 -7
- package/lib/command/CommandModule.es.js +9 -7
- package/lib/command/CommandModule.js +8 -6
- package/lib/command/commandLineRunner.new.browser.js +159 -0
- package/lib/command/commandLineRunner.new.d.ts +57 -0
- package/lib/command/commandLineRunner.new.es.js +159 -0
- package/lib/command/commandLineRunner.new.js +163 -0
- package/lib/hook/HookModule.browser.js +22 -0
- package/lib/hook/HookModule.d.ts +4 -0
- package/lib/hook/HookModule.es.js +22 -0
- package/lib/hook/HookModule.js +26 -0
- package/package.json +20 -20
- package/lib/command/commandLineRunner.browser.js +0 -145
- package/lib/command/commandLineRunner.es.js +0 -145
- package/lib/command/commandLineRunner.js +0 -149
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var dippy = require('@tinkoff/dippy');
|
|
6
|
+
var errors = require('@tinkoff/errors');
|
|
7
|
+
var tokensCommon = require('@tramvai/tokens-common');
|
|
8
|
+
var tokensCorePrivate = require('@tramvai/tokens-core-private');
|
|
9
|
+
|
|
10
|
+
class CommandLineRunner {
|
|
11
|
+
constructor({ rootDi, lines, logger, plugins, hookFactory, executionContextManager, executionEndHandlers, }) {
|
|
12
|
+
this.executionContextByDi = new WeakMap();
|
|
13
|
+
this.abortControllerByDi = new WeakMap();
|
|
14
|
+
this.rootDi = rootDi;
|
|
15
|
+
this.lines = lines;
|
|
16
|
+
this.hookFactory = hookFactory;
|
|
17
|
+
this.plugins = plugins;
|
|
18
|
+
this.executionContextManager = executionContextManager;
|
|
19
|
+
this.executionEndHandlers = executionEndHandlers;
|
|
20
|
+
this.log = logger('command:command-line-runner');
|
|
21
|
+
this.runLineHook = this.hookFactory.createAsync('runLine');
|
|
22
|
+
this.runCommandHook = this.hookFactory.createAsync('runCommand');
|
|
23
|
+
this.runCommandFnHook = this.hookFactory.createAsync('runCommandFn');
|
|
24
|
+
this.runLineHook.tapPromise('commandLineRunner', async (_, { env, line, di, key }) => {
|
|
25
|
+
const commands = this.lines[env][line];
|
|
26
|
+
const timingInfo = {};
|
|
27
|
+
di.register({ provide: tokensCorePrivate.COMMAND_LINE_TIMING_INFO_TOKEN, useValue: timingInfo });
|
|
28
|
+
this.log.debug({
|
|
29
|
+
event: 'command-run',
|
|
30
|
+
type: env,
|
|
31
|
+
status: line,
|
|
32
|
+
});
|
|
33
|
+
try {
|
|
34
|
+
for (const command of commands) {
|
|
35
|
+
// emulate old `CommandLineRunner` behavior, important for race conditions at client-side,
|
|
36
|
+
// when new line executes in the middle of current line, and we need cleanup current line before
|
|
37
|
+
await Promise.resolve();
|
|
38
|
+
await this.runCommandHook.callPromise({
|
|
39
|
+
env,
|
|
40
|
+
line,
|
|
41
|
+
di,
|
|
42
|
+
command,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
this.executionContextByDi.delete(di);
|
|
48
|
+
this.abortControllerByDi.delete(di);
|
|
49
|
+
for (const executionEndHandler of this.executionEndHandlers) {
|
|
50
|
+
executionEndHandler(di, env, line, timingInfo, key);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
this.runCommandHook.tapPromise('commandLineRunner', async (_, { env, line, di, command }) => {
|
|
55
|
+
const commands = di.get({ token: command, optional: true });
|
|
56
|
+
if (!commands) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const rootExecutionContext = di.get({ token: tokensCommon.ROOT_EXECUTION_CONTEXT_TOKEN, optional: true });
|
|
60
|
+
const timingInfo = di.get(tokensCorePrivate.COMMAND_LINE_TIMING_INFO_TOKEN);
|
|
61
|
+
const commandName = command.toString();
|
|
62
|
+
timingInfo[commandName] = { start: performance.now() };
|
|
63
|
+
return this.executionContextManager
|
|
64
|
+
.withContext(rootExecutionContext, `command-line:${commandName}`, async (executionContext, abortController) => {
|
|
65
|
+
this.executionContextByDi.set(di, executionContext);
|
|
66
|
+
this.abortControllerByDi.set(di, abortController);
|
|
67
|
+
if (!Array.isArray(commands)) {
|
|
68
|
+
await this.runCommandFnHook.callPromise({ fn: commands, line, command, di });
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
await Promise.all(commands.map((fn) => {
|
|
72
|
+
return this.runCommandFnHook.callPromise({ fn, line, command, di });
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
.finally(() => {
|
|
77
|
+
timingInfo[commandName].end = performance.now();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
this.runCommandFnHook.tapPromise('commandLineRunner', async (_, { fn, command, di }) => {
|
|
81
|
+
try {
|
|
82
|
+
await this.executeCommand(fn, command, di);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
// in case if any error happens during line execution results from other line handlers will not be used anyway
|
|
86
|
+
this.abortControllerByDi
|
|
87
|
+
.get(di)
|
|
88
|
+
?.abort('Execution context were aborted because of one of the commands failed');
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
this.plugins?.forEach((plugin) => {
|
|
93
|
+
plugin.apply(this);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
async run(env, line, providers, customDi, key) {
|
|
97
|
+
const di = customDi ?? this.resolveDi(env, line, this.rootDi, providers);
|
|
98
|
+
await this.runLineHook.callPromise({ env, line, di, key });
|
|
99
|
+
return di;
|
|
100
|
+
}
|
|
101
|
+
resolveDi(env, line, rootDi, providers) {
|
|
102
|
+
let di = rootDi;
|
|
103
|
+
if (env === 'server' && line === 'customer') {
|
|
104
|
+
di = dippy.createChildContainer(di);
|
|
105
|
+
}
|
|
106
|
+
if (providers) {
|
|
107
|
+
providers.forEach((item) => {
|
|
108
|
+
return di.register(item);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return di;
|
|
112
|
+
}
|
|
113
|
+
resolveExecutionContextFromDi(di) {
|
|
114
|
+
return this.executionContextByDi.get(di) ?? null;
|
|
115
|
+
}
|
|
116
|
+
async executeCommand(command, commandToken, di) {
|
|
117
|
+
const commandName = commandToken.toString();
|
|
118
|
+
if (!(command instanceof Function)) {
|
|
119
|
+
const error = new TypeError(`Expected function in line processing "commandLineListTokens.${commandName}", received "${command}".
|
|
120
|
+
Check that all commandLineListTokens providers return functions`);
|
|
121
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
122
|
+
const commands = di.get(commandToken);
|
|
123
|
+
const record = di.getRecord(commandToken.name);
|
|
124
|
+
// need to find stack trace from this specific token provider
|
|
125
|
+
for (let i = 0; i < commands.length; i++) {
|
|
126
|
+
if (commands[i] === command) {
|
|
127
|
+
// @ts-expect-error
|
|
128
|
+
error.stack = `${error.stack}\n---- caused by: ----\n${record.multi[i].stack || ''}`;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
this.log.error({
|
|
133
|
+
event: 'line-error',
|
|
134
|
+
error,
|
|
135
|
+
line: commandName,
|
|
136
|
+
});
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const { name = '' } = command;
|
|
140
|
+
this.log.debug({
|
|
141
|
+
event: 'line-run',
|
|
142
|
+
line: commandName,
|
|
143
|
+
command: name,
|
|
144
|
+
});
|
|
145
|
+
try {
|
|
146
|
+
await command();
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
this.log[errors.isSilentError(error) ? 'debug' : 'error']({
|
|
150
|
+
event: 'line-error',
|
|
151
|
+
error,
|
|
152
|
+
line: commandName,
|
|
153
|
+
command: name,
|
|
154
|
+
});
|
|
155
|
+
if (typeof error === 'object') {
|
|
156
|
+
error.di = di;
|
|
157
|
+
}
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
exports.CommandLineRunner = CommandLineRunner;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { declareModule, provide, Scope } from '@tinkoff/dippy';
|
|
2
|
+
import { TAPABLE_HOOK_FACTORY_TOKEN } from '@tramvai/core';
|
|
3
|
+
import { TapableHooks, Hooks } from '@tinkoff/hook-runner';
|
|
4
|
+
import { HOOK_TOKEN } from '@tramvai/tokens-common';
|
|
5
|
+
|
|
6
|
+
const TramvaiHookModule = declareModule({
|
|
7
|
+
name: 'TramvaiHookModule',
|
|
8
|
+
providers: [
|
|
9
|
+
provide({
|
|
10
|
+
provide: TAPABLE_HOOK_FACTORY_TOKEN,
|
|
11
|
+
scope: Scope.SINGLETON,
|
|
12
|
+
useClass: TapableHooks,
|
|
13
|
+
}),
|
|
14
|
+
provide({
|
|
15
|
+
provide: HOOK_TOKEN,
|
|
16
|
+
scope: Scope.SINGLETON,
|
|
17
|
+
useClass: Hooks,
|
|
18
|
+
}),
|
|
19
|
+
],
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export { TramvaiHookModule };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const TramvaiHookModule: import("@tinkoff/dippy/lib/modules/module.h").ModuleClass & Partial<import("@tinkoff/dippy/lib/modules/module.h").ModuleSecretParameters> & {
|
|
2
|
+
[x: string]: (...args: any[]) => import("@tinkoff/dippy").ModuleType;
|
|
3
|
+
};
|
|
4
|
+
//# sourceMappingURL=HookModule.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { declareModule, provide, Scope } from '@tinkoff/dippy';
|
|
2
|
+
import { TAPABLE_HOOK_FACTORY_TOKEN } from '@tramvai/core';
|
|
3
|
+
import { TapableHooks, Hooks } from '@tinkoff/hook-runner';
|
|
4
|
+
import { HOOK_TOKEN } from '@tramvai/tokens-common';
|
|
5
|
+
|
|
6
|
+
const TramvaiHookModule = declareModule({
|
|
7
|
+
name: 'TramvaiHookModule',
|
|
8
|
+
providers: [
|
|
9
|
+
provide({
|
|
10
|
+
provide: TAPABLE_HOOK_FACTORY_TOKEN,
|
|
11
|
+
scope: Scope.SINGLETON,
|
|
12
|
+
useClass: TapableHooks,
|
|
13
|
+
}),
|
|
14
|
+
provide({
|
|
15
|
+
provide: HOOK_TOKEN,
|
|
16
|
+
scope: Scope.SINGLETON,
|
|
17
|
+
useClass: Hooks,
|
|
18
|
+
}),
|
|
19
|
+
],
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export { TramvaiHookModule };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var dippy = require('@tinkoff/dippy');
|
|
6
|
+
var core = require('@tramvai/core');
|
|
7
|
+
var hookRunner = require('@tinkoff/hook-runner');
|
|
8
|
+
var tokensCommon = require('@tramvai/tokens-common');
|
|
9
|
+
|
|
10
|
+
const TramvaiHookModule = dippy.declareModule({
|
|
11
|
+
name: 'TramvaiHookModule',
|
|
12
|
+
providers: [
|
|
13
|
+
dippy.provide({
|
|
14
|
+
provide: core.TAPABLE_HOOK_FACTORY_TOKEN,
|
|
15
|
+
scope: dippy.Scope.SINGLETON,
|
|
16
|
+
useClass: hookRunner.TapableHooks,
|
|
17
|
+
}),
|
|
18
|
+
dippy.provide({
|
|
19
|
+
provide: tokensCommon.HOOK_TOKEN,
|
|
20
|
+
scope: dippy.Scope.SINGLETON,
|
|
21
|
+
useClass: hookRunner.Hooks,
|
|
22
|
+
}),
|
|
23
|
+
],
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
exports.TramvaiHookModule = TramvaiHookModule;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tramvai/module-common",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.17.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
@@ -32,34 +32,34 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@akashbabu/lfu-cache": "1.0.2",
|
|
34
34
|
"@tinkoff/errors": "0.6.2",
|
|
35
|
-
"@tinkoff/hook-runner": "0.7.
|
|
35
|
+
"@tinkoff/hook-runner": "0.7.3",
|
|
36
36
|
"@tinkoff/lru-cache-nano": "^7.9.0",
|
|
37
37
|
"@tinkoff/pubsub": "0.8.2",
|
|
38
38
|
"@tinkoff/url": "0.11.2",
|
|
39
|
-
"@tramvai/experiments": "5.
|
|
40
|
-
"@tramvai/module-cookie": "5.
|
|
41
|
-
"@tramvai/module-environment": "5.
|
|
42
|
-
"@tramvai/module-log": "5.
|
|
39
|
+
"@tramvai/experiments": "5.17.0",
|
|
40
|
+
"@tramvai/module-cookie": "5.17.0",
|
|
41
|
+
"@tramvai/module-environment": "5.17.0",
|
|
42
|
+
"@tramvai/module-log": "5.17.0",
|
|
43
43
|
"@tramvai/safe-strings": "0.8.4",
|
|
44
|
-
"@tramvai/tokens-child-app": "5.
|
|
45
|
-
"@tramvai/tokens-common": "5.
|
|
46
|
-
"@tramvai/tokens-core-private": "5.
|
|
47
|
-
"@tramvai/tokens-metrics": "5.
|
|
48
|
-
"@tramvai/tokens-render": "5.
|
|
49
|
-
"@tramvai/tokens-router": "5.
|
|
50
|
-
"@tramvai/tokens-server-private": "5.
|
|
51
|
-
"@tramvai/types-actions-state-context": "5.
|
|
44
|
+
"@tramvai/tokens-child-app": "5.17.0",
|
|
45
|
+
"@tramvai/tokens-common": "5.17.0",
|
|
46
|
+
"@tramvai/tokens-core-private": "5.17.0",
|
|
47
|
+
"@tramvai/tokens-metrics": "5.17.0",
|
|
48
|
+
"@tramvai/tokens-render": "5.17.0",
|
|
49
|
+
"@tramvai/tokens-router": "5.17.0",
|
|
50
|
+
"@tramvai/tokens-server-private": "5.17.0",
|
|
51
|
+
"@tramvai/types-actions-state-context": "5.17.0",
|
|
52
52
|
"hoist-non-react-statics": "^3.3.1"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"@tinkoff/dippy": "0.11.3",
|
|
56
56
|
"@tinkoff/utils": "^2.1.2",
|
|
57
|
-
"@tramvai/cli": "5.
|
|
58
|
-
"@tramvai/core": "5.
|
|
59
|
-
"@tramvai/papi": "5.
|
|
60
|
-
"@tramvai/react": "5.
|
|
61
|
-
"@tramvai/state": "5.
|
|
62
|
-
"@tramvai/tokens-server": "5.
|
|
57
|
+
"@tramvai/cli": "5.17.0",
|
|
58
|
+
"@tramvai/core": "5.17.0",
|
|
59
|
+
"@tramvai/papi": "5.17.0",
|
|
60
|
+
"@tramvai/react": "5.17.0",
|
|
61
|
+
"@tramvai/state": "5.17.0",
|
|
62
|
+
"@tramvai/tokens-server": "5.17.0",
|
|
63
63
|
"react": ">=16.14.0",
|
|
64
64
|
"tslib": "^2.4.0"
|
|
65
65
|
},
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import { isSilentError } from '@tinkoff/errors';
|
|
2
|
-
import { COMMAND_LINE_TIMING_INFO_TOKEN } from '@tramvai/tokens-core-private';
|
|
3
|
-
import { createChildContainer } from '@tinkoff/dippy';
|
|
4
|
-
import { ROOT_EXECUTION_CONTEXT_TOKEN } from '@tramvai/tokens-common';
|
|
5
|
-
|
|
6
|
-
class CommandLineRunner {
|
|
7
|
-
constructor({ lines, rootDi, logger, executionContextManager, executionEndHandlers }) {
|
|
8
|
-
this.executionContextByDi = new WeakMap();
|
|
9
|
-
this.abortControllerByDi = new WeakMap();
|
|
10
|
-
this.lines = lines;
|
|
11
|
-
this.rootDi = rootDi;
|
|
12
|
-
this.log = logger('command:command-line-runner');
|
|
13
|
-
this.executionContextManager = executionContextManager;
|
|
14
|
-
this.executionEndHandlers = executionEndHandlers;
|
|
15
|
-
}
|
|
16
|
-
run(type, status, providers, customDi, key) {
|
|
17
|
-
const di = customDi ?? this.resolveDi(type, status, this.rootDi, providers);
|
|
18
|
-
const rootExecutionContext = di.get({ token: ROOT_EXECUTION_CONTEXT_TOKEN, optional: true });
|
|
19
|
-
this.log.debug({
|
|
20
|
-
event: 'command-run',
|
|
21
|
-
type,
|
|
22
|
-
status,
|
|
23
|
-
});
|
|
24
|
-
const timingInfo = {};
|
|
25
|
-
di.register({ provide: COMMAND_LINE_TIMING_INFO_TOKEN, useValue: timingInfo });
|
|
26
|
-
return (this.lines[type][status]
|
|
27
|
-
.reduce((chain, line) => {
|
|
28
|
-
return chain.then(() => {
|
|
29
|
-
const lineName = line.toString();
|
|
30
|
-
timingInfo[lineName] = { start: performance.now() };
|
|
31
|
-
// eslint-disable-next-line promise/no-nesting
|
|
32
|
-
return Promise.resolve()
|
|
33
|
-
.then(() => {
|
|
34
|
-
return this.executionContextManager.withContext(rootExecutionContext, `command-line:${lineName}`, async (executionContext, abortController) => {
|
|
35
|
-
this.executionContextByDi.set(di, executionContext);
|
|
36
|
-
this.abortControllerByDi.set(di, abortController);
|
|
37
|
-
await this.createLineChain(di, line);
|
|
38
|
-
});
|
|
39
|
-
})
|
|
40
|
-
.finally(() => {
|
|
41
|
-
timingInfo[lineName].end = performance.now();
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
}, Promise.resolve())
|
|
45
|
-
// После завершения цепочки отдаем context выполнения
|
|
46
|
-
.finally(() => {
|
|
47
|
-
this.executionContextByDi.delete(di);
|
|
48
|
-
this.abortControllerByDi.delete(di);
|
|
49
|
-
if (this.executionEndHandlers) {
|
|
50
|
-
for (const executionEndHandler of this.executionEndHandlers) {
|
|
51
|
-
executionEndHandler(di, type, status, timingInfo, key);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
})
|
|
55
|
-
.then(() => di));
|
|
56
|
-
}
|
|
57
|
-
resolveDi(type, status, rootDi, providers) {
|
|
58
|
-
let di = rootDi;
|
|
59
|
-
if (status === 'customer' && type !== 'client') {
|
|
60
|
-
di = createChildContainer(di);
|
|
61
|
-
}
|
|
62
|
-
if (providers) {
|
|
63
|
-
providers.forEach((item) => {
|
|
64
|
-
return di.register(item);
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
return di;
|
|
68
|
-
}
|
|
69
|
-
resolveExecutionContextFromDi(di) {
|
|
70
|
-
return this.executionContextByDi.get(di) ?? null;
|
|
71
|
-
}
|
|
72
|
-
createLineChain(di, line) {
|
|
73
|
-
let lineInstance;
|
|
74
|
-
try {
|
|
75
|
-
lineInstance = di.get({ token: line, optional: true });
|
|
76
|
-
// Пропускаем step. Так как нет действий
|
|
77
|
-
if (lineInstance === null) {
|
|
78
|
-
return Promise.resolve();
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
catch (e) {
|
|
82
|
-
// Логируем ошибку и дальше падаем
|
|
83
|
-
this.log.error(e);
|
|
84
|
-
return this.throwError(e, di);
|
|
85
|
-
}
|
|
86
|
-
if (!Array.isArray(lineInstance)) {
|
|
87
|
-
return this.instanceExecute(lineInstance, line, di);
|
|
88
|
-
}
|
|
89
|
-
return Promise.all(lineInstance.map((instance) => {
|
|
90
|
-
return this.instanceExecute(instance, line, di);
|
|
91
|
-
}));
|
|
92
|
-
}
|
|
93
|
-
instanceExecute(instance, line, di) {
|
|
94
|
-
if (!(instance instanceof Function)) {
|
|
95
|
-
const error = new TypeError(`Expected function in line processing "commandLineListTokens.${line.toString()}", received "${instance}".
|
|
96
|
-
Check that all commandLineListTokens subscribers return functions`);
|
|
97
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
98
|
-
const instances = di.get(line);
|
|
99
|
-
const record = di.getRecord(line.toString());
|
|
100
|
-
// пробегаемся по всем инстансам и для текущего получаем его запись, из которой можно получить стек
|
|
101
|
-
for (let i = 0; i < instances.length; i++) {
|
|
102
|
-
if (instances[i] === instance) {
|
|
103
|
-
// @ts-expect-error
|
|
104
|
-
error.stack = `${error.stack}\n---- caused by: ----\n${record.multi[i].stack || ''}`;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
this.log.error({
|
|
109
|
-
event: 'line-error',
|
|
110
|
-
error,
|
|
111
|
-
line: line.toString(),
|
|
112
|
-
});
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
const { name = '' } = instance;
|
|
116
|
-
this.log.debug({
|
|
117
|
-
event: 'line-run',
|
|
118
|
-
line: line.toString(),
|
|
119
|
-
command: name,
|
|
120
|
-
});
|
|
121
|
-
return Promise.resolve()
|
|
122
|
-
.then(() => instance())
|
|
123
|
-
.catch((err) => {
|
|
124
|
-
this.log[isSilentError(err) ? 'debug' : 'error']({
|
|
125
|
-
event: 'line-error',
|
|
126
|
-
error: err,
|
|
127
|
-
line: line.toString(),
|
|
128
|
-
command: name,
|
|
129
|
-
});
|
|
130
|
-
// in case if any error happens during line execution results from other line handlers will not be used anyway
|
|
131
|
-
this.abortControllerByDi.get(di)?.abort(err);
|
|
132
|
-
this.throwError(err, di);
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
// eslint-disable-next-line class-methods-use-this
|
|
136
|
-
throwError(err, di) {
|
|
137
|
-
if (typeof err === 'object') {
|
|
138
|
-
// eslint-disable-next-line no-param-reassign
|
|
139
|
-
err.di = di;
|
|
140
|
-
}
|
|
141
|
-
throw err;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export { CommandLineRunner };
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import { isSilentError } from '@tinkoff/errors';
|
|
2
|
-
import { COMMAND_LINE_TIMING_INFO_TOKEN } from '@tramvai/tokens-core-private';
|
|
3
|
-
import { createChildContainer } from '@tinkoff/dippy';
|
|
4
|
-
import { ROOT_EXECUTION_CONTEXT_TOKEN } from '@tramvai/tokens-common';
|
|
5
|
-
|
|
6
|
-
class CommandLineRunner {
|
|
7
|
-
constructor({ lines, rootDi, logger, executionContextManager, executionEndHandlers }) {
|
|
8
|
-
this.executionContextByDi = new WeakMap();
|
|
9
|
-
this.abortControllerByDi = new WeakMap();
|
|
10
|
-
this.lines = lines;
|
|
11
|
-
this.rootDi = rootDi;
|
|
12
|
-
this.log = logger('command:command-line-runner');
|
|
13
|
-
this.executionContextManager = executionContextManager;
|
|
14
|
-
this.executionEndHandlers = executionEndHandlers;
|
|
15
|
-
}
|
|
16
|
-
run(type, status, providers, customDi, key) {
|
|
17
|
-
const di = customDi ?? this.resolveDi(type, status, this.rootDi, providers);
|
|
18
|
-
const rootExecutionContext = di.get({ token: ROOT_EXECUTION_CONTEXT_TOKEN, optional: true });
|
|
19
|
-
this.log.debug({
|
|
20
|
-
event: 'command-run',
|
|
21
|
-
type,
|
|
22
|
-
status,
|
|
23
|
-
});
|
|
24
|
-
const timingInfo = {};
|
|
25
|
-
di.register({ provide: COMMAND_LINE_TIMING_INFO_TOKEN, useValue: timingInfo });
|
|
26
|
-
return (this.lines[type][status]
|
|
27
|
-
.reduce((chain, line) => {
|
|
28
|
-
return chain.then(() => {
|
|
29
|
-
const lineName = line.toString();
|
|
30
|
-
timingInfo[lineName] = { start: performance.now() };
|
|
31
|
-
// eslint-disable-next-line promise/no-nesting
|
|
32
|
-
return Promise.resolve()
|
|
33
|
-
.then(() => {
|
|
34
|
-
return this.executionContextManager.withContext(rootExecutionContext, `command-line:${lineName}`, async (executionContext, abortController) => {
|
|
35
|
-
this.executionContextByDi.set(di, executionContext);
|
|
36
|
-
this.abortControllerByDi.set(di, abortController);
|
|
37
|
-
await this.createLineChain(di, line);
|
|
38
|
-
});
|
|
39
|
-
})
|
|
40
|
-
.finally(() => {
|
|
41
|
-
timingInfo[lineName].end = performance.now();
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
}, Promise.resolve())
|
|
45
|
-
// После завершения цепочки отдаем context выполнения
|
|
46
|
-
.finally(() => {
|
|
47
|
-
this.executionContextByDi.delete(di);
|
|
48
|
-
this.abortControllerByDi.delete(di);
|
|
49
|
-
if (this.executionEndHandlers) {
|
|
50
|
-
for (const executionEndHandler of this.executionEndHandlers) {
|
|
51
|
-
executionEndHandler(di, type, status, timingInfo, key);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
})
|
|
55
|
-
.then(() => di));
|
|
56
|
-
}
|
|
57
|
-
resolveDi(type, status, rootDi, providers) {
|
|
58
|
-
let di = rootDi;
|
|
59
|
-
if (status === 'customer' && type !== 'client') {
|
|
60
|
-
di = createChildContainer(di);
|
|
61
|
-
}
|
|
62
|
-
if (providers) {
|
|
63
|
-
providers.forEach((item) => {
|
|
64
|
-
return di.register(item);
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
return di;
|
|
68
|
-
}
|
|
69
|
-
resolveExecutionContextFromDi(di) {
|
|
70
|
-
return this.executionContextByDi.get(di) ?? null;
|
|
71
|
-
}
|
|
72
|
-
createLineChain(di, line) {
|
|
73
|
-
let lineInstance;
|
|
74
|
-
try {
|
|
75
|
-
lineInstance = di.get({ token: line, optional: true });
|
|
76
|
-
// Пропускаем step. Так как нет действий
|
|
77
|
-
if (lineInstance === null) {
|
|
78
|
-
return Promise.resolve();
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
catch (e) {
|
|
82
|
-
// Логируем ошибку и дальше падаем
|
|
83
|
-
this.log.error(e);
|
|
84
|
-
return this.throwError(e, di);
|
|
85
|
-
}
|
|
86
|
-
if (!Array.isArray(lineInstance)) {
|
|
87
|
-
return this.instanceExecute(lineInstance, line, di);
|
|
88
|
-
}
|
|
89
|
-
return Promise.all(lineInstance.map((instance) => {
|
|
90
|
-
return this.instanceExecute(instance, line, di);
|
|
91
|
-
}));
|
|
92
|
-
}
|
|
93
|
-
instanceExecute(instance, line, di) {
|
|
94
|
-
if (!(instance instanceof Function)) {
|
|
95
|
-
const error = new TypeError(`Expected function in line processing "commandLineListTokens.${line.toString()}", received "${instance}".
|
|
96
|
-
Check that all commandLineListTokens subscribers return functions`);
|
|
97
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
98
|
-
const instances = di.get(line);
|
|
99
|
-
const record = di.getRecord(line.toString());
|
|
100
|
-
// пробегаемся по всем инстансам и для текущего получаем его запись, из которой можно получить стек
|
|
101
|
-
for (let i = 0; i < instances.length; i++) {
|
|
102
|
-
if (instances[i] === instance) {
|
|
103
|
-
// @ts-expect-error
|
|
104
|
-
error.stack = `${error.stack}\n---- caused by: ----\n${record.multi[i].stack || ''}`;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
this.log.error({
|
|
109
|
-
event: 'line-error',
|
|
110
|
-
error,
|
|
111
|
-
line: line.toString(),
|
|
112
|
-
});
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
const { name = '' } = instance;
|
|
116
|
-
this.log.debug({
|
|
117
|
-
event: 'line-run',
|
|
118
|
-
line: line.toString(),
|
|
119
|
-
command: name,
|
|
120
|
-
});
|
|
121
|
-
return Promise.resolve()
|
|
122
|
-
.then(() => instance())
|
|
123
|
-
.catch((err) => {
|
|
124
|
-
this.log[isSilentError(err) ? 'debug' : 'error']({
|
|
125
|
-
event: 'line-error',
|
|
126
|
-
error: err,
|
|
127
|
-
line: line.toString(),
|
|
128
|
-
command: name,
|
|
129
|
-
});
|
|
130
|
-
// in case if any error happens during line execution results from other line handlers will not be used anyway
|
|
131
|
-
this.abortControllerByDi.get(di)?.abort(err);
|
|
132
|
-
this.throwError(err, di);
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
// eslint-disable-next-line class-methods-use-this
|
|
136
|
-
throwError(err, di) {
|
|
137
|
-
if (typeof err === 'object') {
|
|
138
|
-
// eslint-disable-next-line no-param-reassign
|
|
139
|
-
err.di = di;
|
|
140
|
-
}
|
|
141
|
-
throw err;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export { CommandLineRunner };
|