@shopgate/pwa-core 7.30.0-alpha.6 → 7.30.0-alpha.8
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/classes/AppCommand/index.js +115 -11
- package/classes/AppCommand/spec.js +260 -6
- package/classes/AppCommandRequest/index.js +129 -20
- package/classes/AppPermissionsRequest/AppPermissionsRequest.js +45 -7
- package/classes/AppPermissionsRequest/GetAppPermissionsRequest.js +48 -9
- package/classes/AppPermissionsRequest/RequestAppPermissionsRequest.js +54 -9
- package/classes/Bridge/index.js +34 -4
- package/classes/Bridge/spec.js +24 -1
- package/classes/BrightnessRequest/index.js +59 -10
- package/classes/BrightnessRequest/spec.js +111 -6
- package/classes/BrowserConnector/index.js +180 -26
- package/classes/Conditioner/index.js +74 -8
- package/classes/Conditioner/spec.js +75 -1
- package/classes/DataRequest/index.js +116 -13
- package/classes/DevServerBridge/index.js +86 -9
- package/classes/DevServerBridge/spec.js +231 -14
- package/classes/ErrorManager/index.js +144 -20
- package/classes/ErrorManager/spec.js +244 -2
- package/classes/Event/index.js +101 -15
- package/classes/HttpRequest/index.js +182 -21
- package/classes/PipelineDependencies/index.js +42 -6
- package/classes/PipelineDependencies/spec.js +46 -3
- package/classes/PipelineManager/index.js +517 -71
- package/classes/PipelineManager/spec.js +733 -15
- package/classes/PipelineRequest/index.js +167 -19
- package/classes/PipelineRequest/mock.js +118 -21
- package/classes/PipelineRequest/spec.js +333 -2
- package/classes/PipelineSequence/index.js +34 -6
- package/classes/Request/index.js +61 -13
- package/classes/RequestBuffer/index.js +43 -6
- package/classes/RequestManager/index.js +216 -33
- package/classes/RequestManager/spec.js +188 -1
- package/classes/Scanner/index.js +246 -67
- package/classes/ScannerEvent/index.js +23 -9
- package/classes/ScannerEventHandler/index.js +39 -16
- package/classes/ScannerEventListener/index.js +84 -24
- package/classes/ScannerManager/ScanProcessingError.js +11 -3
- package/classes/ScannerManager/index.js +133 -21
- package/classes/WebStorageRequest/index.js +76 -9
- package/commands/analyticsSetCustomValues.js +8 -2
- package/commands/appPermissions.js +10 -3
- package/commands/brightness.js +33 -5
- package/commands/broadcastEvent.js +8 -2
- package/commands/cleanTab.js +11 -3
- package/commands/closeInAppBrowser.js +22 -2
- package/commands/flushTab.js +8 -2
- package/commands/getWebStorageEntry.js +11 -2
- package/commands/hideMenuBar.js +8 -2
- package/commands/hideNavigationBar.js +8 -2
- package/commands/hideSplashScreen.js +8 -2
- package/commands/onload.js +13 -3
- package/commands/openAppSettings.js +8 -2
- package/commands/openPage.js +8 -2
- package/commands/openPageExtern.js +8 -2
- package/commands/performCommandsAfterDelay.js +11 -3
- package/commands/plotProjects.js +65 -7
- package/commands/popTabToRoot.js +11 -3
- package/commands/registerEvents.js +10 -2
- package/commands/scanner.js +76 -7
- package/commands/setCookie.js +8 -2
- package/commands/setDebugLoggingEnabled.js +8 -2
- package/commands/setScrollingEnabled.js +7 -2
- package/commands/setWebStorageEntry.js +8 -2
- package/commands/shareItem.js +18 -2
- package/commands/showNavigationBar.js +8 -2
- package/commands/showTab.js +13 -2
- package/commands/unifiedTracking.js +128 -30
- package/constants/AppCommands.js +6 -1
- package/constants/AppEvents.js +9 -1
- package/constants/AppPermissions.js +57 -13
- package/constants/Command.js +1 -1
- package/constants/ErrorHandleTypes.js +2 -1
- package/constants/ErrorManager.js +15 -1
- package/constants/Pipeline.js +52 -17
- package/constants/ProcessTypes.js +3 -1
- package/constants/RequestManagerModes.js +19 -7
- package/constants/RequestTypes.js +2 -1
- package/constants/Scanner.js +39 -10
- package/constants/Trilean.js +6 -1
- package/emitters/ui.js +2 -1
- package/helpers/index.js +66 -8
- package/helpers/logGroup.js +56 -8
- package/helpers/version.js +216 -22
- package/index.js +60 -5
- package/package.json +1 -1
|
@@ -1,29 +1,106 @@
|
|
|
1
|
-
|
|
1
|
+
import fetch from 'isomorphic-fetch';
|
|
2
|
+
import { logger } from "../../helpers";
|
|
3
|
+
import event from "../Event";
|
|
4
|
+
|
|
5
|
+
/**
|
|
2
6
|
* The DevServerBridge emulates the SGJavaScriptBridge within browser environments.
|
|
3
7
|
* It routes supported app commands to the Frontend SDK which can mimic the behavior of the app.
|
|
4
|
-
*/
|
|
8
|
+
*/
|
|
9
|
+
class DevServerBridge {
|
|
10
|
+
/**
|
|
5
11
|
* The constructor.
|
|
6
12
|
* @param {string} ip The IP of the dev server.
|
|
7
13
|
* @param {number} port The port of the dev server.
|
|
8
|
-
*/
|
|
14
|
+
*/
|
|
15
|
+
constructor(ip = process.env.IP, port = process.env.PORT) {
|
|
16
|
+
this.ip = ip;
|
|
17
|
+
this.port = port;
|
|
18
|
+
this.supportedCommands = ['sendPipelineRequest', 'sendHttpRequest', 'sendDataRequest', 'getWebStorageEntry'];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
9
22
|
* Dispatches multiple commands to the dev server.
|
|
10
23
|
* @param {Array} commands The commands to dispatch.
|
|
11
24
|
* @param {string} libVersion The lib version for the command.
|
|
12
25
|
* @return {DevServerBridge}
|
|
13
|
-
*/
|
|
26
|
+
*/
|
|
27
|
+
dispatchCommandsForVersion(commands, libVersion) {
|
|
28
|
+
if (Array.isArray(commands)) {
|
|
29
|
+
commands.forEach(command => {
|
|
30
|
+
this.dispatchCommandForVersion(command, libVersion);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
14
37
|
* Dispatches a single command to the dev server.
|
|
15
38
|
* @param {Object} command The command to dispatch.
|
|
16
39
|
* @param {string} libVersion The lib version for the command.
|
|
17
40
|
* @return {DevServerBridge}
|
|
18
|
-
*/
|
|
19
|
-
|
|
41
|
+
*/
|
|
42
|
+
dispatchCommandForVersion(command, libVersion) {
|
|
43
|
+
const {
|
|
44
|
+
c: name
|
|
45
|
+
} = command || {};
|
|
46
|
+
if (this.supportedCommands.includes(name)) {
|
|
47
|
+
// Append an optional suffix for special command related endpoints
|
|
48
|
+
let suffix = '';
|
|
49
|
+
if (name === 'getWebStorageEntry') {
|
|
50
|
+
suffix = 'web_storage';
|
|
51
|
+
} else if (name === 'sendHttpRequest') {
|
|
52
|
+
suffix = 'http_request';
|
|
53
|
+
}
|
|
54
|
+
const url = `http://${this.ip}:${this.port}/${suffix}`;
|
|
55
|
+
const options = {
|
|
56
|
+
method: 'post',
|
|
57
|
+
headers: new Headers({
|
|
58
|
+
'Content-Type': 'application/json'
|
|
59
|
+
}),
|
|
60
|
+
body: JSON.stringify({
|
|
61
|
+
cmds: [command],
|
|
62
|
+
ver: libVersion
|
|
63
|
+
})
|
|
64
|
+
};
|
|
65
|
+
fetch(url, options).then(response => response.json()).then(this.processDevServerResponse).catch(err => err && logger.error(err));
|
|
66
|
+
}
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
20
71
|
* Handles a response of the dev server.
|
|
21
72
|
* @param {Object} response The server response.
|
|
22
73
|
* @return {DevServerBridge}
|
|
23
|
-
*/
|
|
24
|
-
|
|
74
|
+
*/
|
|
75
|
+
processDevServerResponse(response) {
|
|
76
|
+
const {
|
|
77
|
+
cmds = []
|
|
78
|
+
} = response || {};
|
|
79
|
+
|
|
80
|
+
// Process the response commands.
|
|
81
|
+
cmds.forEach(command => {
|
|
82
|
+
const name = command.c;
|
|
83
|
+
const params = command.p;
|
|
84
|
+
let args = [];
|
|
85
|
+
|
|
86
|
+
/**
|
|
25
87
|
* The server returns a response command for a request command.
|
|
26
88
|
* If the native app receives such a command, it calls a related event within the
|
|
27
89
|
* webviews. Here the response parameters are sorted in the specified order for
|
|
28
90
|
* the different response events.
|
|
29
|
-
*/
|
|
91
|
+
*/
|
|
92
|
+
if (name === 'pipelineResponse') {
|
|
93
|
+
args = [params.error, params.serial, params.output];
|
|
94
|
+
} else if (name === 'httpResponse') {
|
|
95
|
+
args = [params.error, params.serial, params.response];
|
|
96
|
+
} else if (name === 'dataResponse') {
|
|
97
|
+
args = [params.serial, params.status, params.body, params.bodyContentType];
|
|
98
|
+
} else if (name === 'webStorageResponse') {
|
|
99
|
+
args = [params.serial, params.age, params.value];
|
|
100
|
+
}
|
|
101
|
+
event.call(name, args);
|
|
102
|
+
});
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export default DevServerBridge;
|
|
@@ -1,15 +1,232 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import DevServerBridge from "./index";
|
|
2
|
+
|
|
3
|
+
// A libVersion for the bridge method calls
|
|
4
|
+
const libVersion = '16.1';
|
|
5
|
+
const devServerIp = '192.168.0.1';
|
|
6
|
+
const devServerPort = '1337';
|
|
7
|
+
|
|
8
|
+
// Mocks of the env variables.
|
|
9
|
+
global.process.env = {
|
|
10
|
+
IP: devServerIp,
|
|
11
|
+
PORT: devServerPort
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// Mocks of the global Headers class.
|
|
15
|
+
global.Headers = class Headers {};
|
|
16
|
+
|
|
17
|
+
// Create a mock for the fetch method.
|
|
18
|
+
const mockedFetchResponse = {};
|
|
19
|
+
let mockedFetch;
|
|
20
|
+
jest.mock('isomorphic-fetch', () => (...args) => mockedFetch(...args));
|
|
21
|
+
|
|
22
|
+
// Create a mock for the Event class.
|
|
23
|
+
const mockedEventCall = jest.fn();
|
|
24
|
+
jest.mock("../Event", () => ({
|
|
25
|
+
call: (...args) => mockedEventCall(...args)
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
// Create a mock for the error logger.
|
|
29
|
+
const mockedLoggerError = jest.fn();
|
|
30
|
+
jest.mock("../../helpers", () => ({
|
|
31
|
+
logger: {
|
|
32
|
+
error: (...args) => {
|
|
33
|
+
mockedLoggerError(...args);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}));
|
|
37
|
+
let dispatchCommandSpy;
|
|
38
|
+
let processResponseSpy;
|
|
39
|
+
|
|
40
|
+
/**
|
|
8
41
|
* Updates the mock for the fetch module.
|
|
9
|
-
* @param {boolean} throwError
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
42
|
+
* @param {boolean} throwError Whether the mocked fetch shall throw an error.
|
|
43
|
+
*/
|
|
44
|
+
const updateMockedFetch = (throwError = false) => {
|
|
45
|
+
if (!throwError) {
|
|
46
|
+
mockedFetch = jest.fn().mockResolvedValue({
|
|
47
|
+
json: () => mockedFetchResponse
|
|
48
|
+
});
|
|
49
|
+
} else {
|
|
50
|
+
mockedFetch = jest.fn().mockRejectedValue(new Error());
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
describe('DevServerBridge', () => {
|
|
54
|
+
let instance;
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
mockedEventCall.mockClear();
|
|
57
|
+
updateMockedFetch();
|
|
58
|
+
instance = new DevServerBridge();
|
|
59
|
+
dispatchCommandSpy = jest.spyOn(instance, 'dispatchCommandForVersion');
|
|
60
|
+
processResponseSpy = jest.spyOn(instance, 'processDevServerResponse');
|
|
61
|
+
});
|
|
62
|
+
describe('.constructor()', () => {
|
|
63
|
+
it('should work as expected without parameters', () => {
|
|
64
|
+
expect(instance.ip).toBe(devServerIp);
|
|
65
|
+
expect(instance.port).toBe(devServerPort);
|
|
66
|
+
});
|
|
67
|
+
it('should apply custom parameters', () => {
|
|
68
|
+
const customIp = '127.0.0.1';
|
|
69
|
+
const customPort = '4711';
|
|
70
|
+
instance = new DevServerBridge(customIp, customPort);
|
|
71
|
+
expect(instance.ip).toBe(customIp);
|
|
72
|
+
expect(instance.port).toBe(customPort);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
describe('.dispatchCommandsForVersion()', () => {
|
|
76
|
+
it('should call dispatchCommand for every single command', () => {
|
|
77
|
+
const commands = [{
|
|
78
|
+
c: 'sendPipelineRequest'
|
|
79
|
+
}, {
|
|
80
|
+
c: 'openPage'
|
|
81
|
+
}];
|
|
82
|
+
const result = instance.dispatchCommandsForVersion(commands, libVersion);
|
|
83
|
+
expect(result).toEqual(instance);
|
|
84
|
+
expect(dispatchCommandSpy).toHaveBeenCalledTimes(2);
|
|
85
|
+
expect(dispatchCommandSpy.mock.calls[0][0].c).toBe('sendPipelineRequest');
|
|
86
|
+
expect(dispatchCommandSpy.mock.calls[0][1]).toBe(libVersion);
|
|
87
|
+
expect(dispatchCommandSpy.mock.calls[1][0].c).toBe('openPage');
|
|
88
|
+
expect(dispatchCommandSpy.mock.calls[1][1]).toBe(libVersion);
|
|
89
|
+
});
|
|
90
|
+
it('should call dispatchCommand when no commands where passed', () => {
|
|
91
|
+
const result = instance.dispatchCommandsForVersion(null, libVersion);
|
|
92
|
+
expect(result).toEqual(instance);
|
|
93
|
+
expect(dispatchCommandSpy).toHaveBeenCalledTimes(0);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
describe('.dispatchCommandForVersion()', () => {
|
|
97
|
+
it('should dispatch a webStorage entry command', done => {
|
|
98
|
+
const name = 'getWebStorageEntry';
|
|
99
|
+
const command = {
|
|
100
|
+
c: name
|
|
101
|
+
};
|
|
102
|
+
const result = instance.dispatchCommandForVersion(command, libVersion);
|
|
103
|
+
expect(result).toEqual(instance);
|
|
104
|
+
// The dispatch method has async behavior. So we wait for the next tick before we check.
|
|
105
|
+
setTimeout(() => {
|
|
106
|
+
expect(mockedFetch).toHaveBeenCalledTimes(1);
|
|
107
|
+
expect(mockedFetch.mock.calls[0][0].endsWith('web_storage')).toBe(true);
|
|
108
|
+
expect(mockedFetch.mock.calls[0][1].body.includes(name)).toBe(true);
|
|
109
|
+
expect(processResponseSpy).toHaveBeenCalledTimes(1);
|
|
110
|
+
done();
|
|
111
|
+
}, 0);
|
|
112
|
+
});
|
|
113
|
+
it('should dispatch a httpRequest command', done => {
|
|
114
|
+
const name = 'sendHttpRequest';
|
|
115
|
+
const command = {
|
|
116
|
+
c: name
|
|
117
|
+
};
|
|
118
|
+
const result = instance.dispatchCommandForVersion(command, libVersion);
|
|
119
|
+
expect(result).toEqual(instance);
|
|
120
|
+
// The dispatch method has async behavior. So we wait for the next tick before we check.
|
|
121
|
+
setTimeout(() => {
|
|
122
|
+
expect(mockedFetch).toHaveBeenCalledTimes(1);
|
|
123
|
+
expect(mockedFetch.mock.calls[0][0].endsWith('http_request')).toBe(true);
|
|
124
|
+
expect(mockedFetch.mock.calls[0][1].body.includes(name)).toBe(true);
|
|
125
|
+
expect(processResponseSpy).toHaveBeenCalledTimes(1);
|
|
126
|
+
done();
|
|
127
|
+
}, 0);
|
|
128
|
+
});
|
|
129
|
+
it('should not do anything if the command is not whitelisted', done => {
|
|
130
|
+
const command = {
|
|
131
|
+
c: 'openPage'
|
|
132
|
+
};
|
|
133
|
+
const result = instance.dispatchCommandForVersion(command, libVersion);
|
|
134
|
+
expect(result).toEqual(instance);
|
|
135
|
+
// The dispatch method has async behavior. So we wait for the next tick before we check.
|
|
136
|
+
setTimeout(() => {
|
|
137
|
+
expect(mockedFetch).toHaveBeenCalledTimes(0);
|
|
138
|
+
expect(processResponseSpy).toHaveBeenCalledTimes(0);
|
|
139
|
+
done();
|
|
140
|
+
}, 0);
|
|
141
|
+
});
|
|
142
|
+
it('should not do anything if the command is empty', done => {
|
|
143
|
+
const result = instance.dispatchCommandForVersion(null, libVersion);
|
|
144
|
+
expect(result).toEqual(instance);
|
|
145
|
+
// The dispatch method has async behavior. So we wait for the next tick before we check.
|
|
146
|
+
setTimeout(() => {
|
|
147
|
+
expect(mockedFetch).toHaveBeenCalledTimes(0);
|
|
148
|
+
expect(processResponseSpy).toHaveBeenCalledTimes(0);
|
|
149
|
+
done();
|
|
150
|
+
}, 0);
|
|
151
|
+
});
|
|
152
|
+
it('should handle fetch errors', done => {
|
|
153
|
+
updateMockedFetch(true);
|
|
154
|
+
const command = {
|
|
155
|
+
c: 'sendPipelineRequest'
|
|
156
|
+
};
|
|
157
|
+
const result = instance.dispatchCommandForVersion(command, libVersion);
|
|
158
|
+
expect(result).toEqual(instance);
|
|
159
|
+
// The dispatch method has async behavior. So we wait for the next tick before we check.
|
|
160
|
+
setTimeout(() => {
|
|
161
|
+
expect(mockedFetch).toHaveBeenCalledTimes(1);
|
|
162
|
+
expect(processResponseSpy).toHaveBeenCalledTimes(0);
|
|
163
|
+
expect(mockedLoggerError).toHaveBeenCalledTimes(1);
|
|
164
|
+
expect(mockedLoggerError.mock.calls[0][0]).toBeInstanceOf(Error);
|
|
165
|
+
done();
|
|
166
|
+
}, 0);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
describe('.processDevServerResponse()', () => {
|
|
170
|
+
it('should handle a response commands as expected', () => {
|
|
171
|
+
const serial = 'abc123';
|
|
172
|
+
const commands = [{
|
|
173
|
+
c: 'pipelineResponse',
|
|
174
|
+
p: {
|
|
175
|
+
serial,
|
|
176
|
+
error: null,
|
|
177
|
+
output: {}
|
|
178
|
+
}
|
|
179
|
+
}, {
|
|
180
|
+
c: 'httpResponse',
|
|
181
|
+
p: {
|
|
182
|
+
serial,
|
|
183
|
+
error: null,
|
|
184
|
+
response: {}
|
|
185
|
+
}
|
|
186
|
+
}, {
|
|
187
|
+
c: 'dataResponse',
|
|
188
|
+
p: {
|
|
189
|
+
serial,
|
|
190
|
+
status: 200,
|
|
191
|
+
body: '',
|
|
192
|
+
bodyContentType: ''
|
|
193
|
+
}
|
|
194
|
+
}, {
|
|
195
|
+
c: 'webStorageResponse',
|
|
196
|
+
p: {
|
|
197
|
+
serial,
|
|
198
|
+
age: 40,
|
|
199
|
+
value: {}
|
|
200
|
+
}
|
|
201
|
+
}, {
|
|
202
|
+
c: 'unknownResponse',
|
|
203
|
+
p: {}
|
|
204
|
+
}];
|
|
205
|
+
const result = instance.processDevServerResponse({
|
|
206
|
+
cmds: commands
|
|
207
|
+
});
|
|
208
|
+
expect(result).toEqual(instance);
|
|
209
|
+
expect(mockedEventCall).toHaveBeenCalledTimes(5);
|
|
210
|
+
const [pipelineResponse, httpResponse, dataResponse, webStorageResponse, unknownResponse] = mockedEventCall.mock.calls;
|
|
211
|
+
expect(pipelineResponse[0]).toBe('pipelineResponse');
|
|
212
|
+
expect(pipelineResponse[1]).toHaveLength(3);
|
|
213
|
+
expect(pipelineResponse[1][1]).toBe(serial);
|
|
214
|
+
expect(httpResponse[0]).toBe('httpResponse');
|
|
215
|
+
expect(httpResponse[1]).toHaveLength(3);
|
|
216
|
+
expect(httpResponse[1][1]).toBe(serial);
|
|
217
|
+
expect(dataResponse[0]).toBe('dataResponse');
|
|
218
|
+
expect(dataResponse[1]).toHaveLength(4);
|
|
219
|
+
expect(dataResponse[1][0]).toBe(serial);
|
|
220
|
+
expect(webStorageResponse[0]).toBe('webStorageResponse');
|
|
221
|
+
expect(webStorageResponse[1]).toHaveLength(3);
|
|
222
|
+
expect(webStorageResponse[1][0]).toBe(serial);
|
|
223
|
+
expect(unknownResponse[0]).toBe('unknownResponse');
|
|
224
|
+
expect(unknownResponse[1]).toHaveLength(0);
|
|
225
|
+
});
|
|
226
|
+
it('should work as expected when nothing was passed', () => {
|
|
227
|
+
const result = instance.processDevServerResponse(null);
|
|
228
|
+
expect(result).toEqual(instance);
|
|
229
|
+
expect(mockedEventCall).toHaveBeenCalledTimes(0);
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
});
|
|
@@ -1,26 +1,100 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "core-js/modules/es.string.replace.js";
|
|
2
|
+
import EventEmitter from 'events';
|
|
3
|
+
import { DEFAULT_CONTEXT, SOURCE_PIPELINE, DEFAULT_SEVERITY } from "../../constants/ErrorManager";
|
|
4
|
+
export const emitter = new EventEmitter();
|
|
5
|
+
const pipelineVersionSuffix = /\.v\d+$/;
|
|
6
|
+
|
|
7
|
+
/**
|
|
2
8
|
* The ErrorManager class.
|
|
3
|
-
*/
|
|
9
|
+
*/
|
|
10
|
+
class ErrorManager {
|
|
11
|
+
/**
|
|
4
12
|
* Constructor.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
this.
|
|
18
|
-
this.
|
|
19
|
-
this.timer=null;
|
|
13
|
+
*/
|
|
14
|
+
constructor() {
|
|
15
|
+
/**
|
|
16
|
+
* Calls dispatch() as an interval.
|
|
17
|
+
*/
|
|
18
|
+
this.startTimer = async () => {
|
|
19
|
+
await this.stopTimer();
|
|
20
|
+
this.timer = setInterval(this.dispatch, 500);
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Clears the dispatch interval.
|
|
24
|
+
*/
|
|
25
|
+
this.stopTimer = async () => {
|
|
26
|
+
await clearInterval(this.timer);
|
|
27
|
+
this.timer = null;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Dispatched the stored error objects through the event emitter.
|
|
31
|
+
* @returns {boolean}
|
|
32
|
+
*/
|
|
33
|
+
this.dispatch = () => {
|
|
34
|
+
if (this.errorQueue.size === 0) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
this.errorQueue.forEach(error => {
|
|
38
|
+
emitter.emit(error.source, error);
|
|
39
|
+
});
|
|
40
|
+
this.stopTimer();
|
|
41
|
+
this.errorQueue.clear();
|
|
42
|
+
return true;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Validates an error object.
|
|
46
|
+
* @param {*} error The error object.
|
|
47
|
+
* @returns {boolean}
|
|
48
|
+
*/
|
|
49
|
+
this.validate = (error = {}) => {
|
|
50
|
+
const {
|
|
51
|
+
code = null,
|
|
52
|
+
message = null,
|
|
53
|
+
source = null
|
|
54
|
+
} = error;
|
|
55
|
+
if (!code || !message || !source) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
if (typeof code !== 'string' || typeof source !== 'string') {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return typeof message === 'string' || typeof message === 'function';
|
|
62
|
+
};
|
|
63
|
+
// Queue of errors that will be dispatched.
|
|
64
|
+
this.errorQueue = new Map();
|
|
65
|
+
|
|
66
|
+
// List of override message for specific errors.
|
|
67
|
+
this.messages = {};
|
|
68
|
+
|
|
69
|
+
// A variable to handle the intervals.
|
|
70
|
+
this.timer = null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
20
74
|
* Gets a message by the given error.
|
|
21
75
|
* @param {{ code: string, context: string, source: string }} error The error object.
|
|
22
76
|
* @returns {string|null}
|
|
23
|
-
*/
|
|
77
|
+
*/
|
|
78
|
+
getMessage(error) {
|
|
79
|
+
if (!this.validate(error)) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
const {
|
|
83
|
+
code,
|
|
84
|
+
context = DEFAULT_CONTEXT,
|
|
85
|
+
source
|
|
86
|
+
} = error;
|
|
87
|
+
const id = `${source}-${context}-${code}`;
|
|
88
|
+
const unvId = `${source}-${context.replace(pipelineVersionSuffix, '')}-${code}`;
|
|
89
|
+
const defaultId = `${source}-${DEFAULT_CONTEXT}-${code}`;
|
|
90
|
+
let message = this.messages[id] || this.messages[unvId] || this.messages[defaultId] || null;
|
|
91
|
+
if (typeof message === 'function') {
|
|
92
|
+
message = message(error);
|
|
93
|
+
}
|
|
94
|
+
return message;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
24
98
|
* Sets an override for a specific error message.
|
|
25
99
|
* @param {Object} errorTemplate The error object.
|
|
26
100
|
* @param {string} errorTemplate.code The error code.
|
|
@@ -28,7 +102,24 @@ this.timer=null;}/**
|
|
|
28
102
|
* @param {string} errorTemplate.message The default error message.
|
|
29
103
|
* @param {string} [errorTemplate.source=SOURCE_PIPELINE] The source of the error.
|
|
30
104
|
* @returns {ErrorManager}
|
|
31
|
-
*/
|
|
105
|
+
*/
|
|
106
|
+
setMessage(errorTemplate = {}) {
|
|
107
|
+
const error = {
|
|
108
|
+
source: SOURCE_PIPELINE,
|
|
109
|
+
...errorTemplate
|
|
110
|
+
};
|
|
111
|
+
if (!this.validate(error)) {
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
const {
|
|
115
|
+
context = DEFAULT_CONTEXT
|
|
116
|
+
} = error;
|
|
117
|
+
const id = `${error.source}-${context}-${error.code}`;
|
|
118
|
+
this.messages[id] = error.message;
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
32
123
|
* Adds a new error object to the queue.
|
|
33
124
|
* @param {Object} error The error object.
|
|
34
125
|
* @param {string} error.code The error code.
|
|
@@ -36,4 +127,37 @@ this.timer=null;}/**
|
|
|
36
127
|
* @param {string} error.message The default error message.
|
|
37
128
|
* @param {string} error.source The source of the error.
|
|
38
129
|
* @param {Object} error.meta Some meta data.
|
|
39
|
-
*/
|
|
130
|
+
*/
|
|
131
|
+
queue(error = {}) {
|
|
132
|
+
if (!this.validate(error)) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const {
|
|
136
|
+
code,
|
|
137
|
+
context = DEFAULT_CONTEXT,
|
|
138
|
+
message,
|
|
139
|
+
source,
|
|
140
|
+
meta,
|
|
141
|
+
severity = DEFAULT_SEVERITY
|
|
142
|
+
} = error;
|
|
143
|
+
const id = `${source}-${context}-${code}`;
|
|
144
|
+
const overrideMessage = this.getMessage(error) || message;
|
|
145
|
+
this.errorQueue.set(id, {
|
|
146
|
+
id,
|
|
147
|
+
code,
|
|
148
|
+
context,
|
|
149
|
+
message: overrideMessage,
|
|
150
|
+
meta: {
|
|
151
|
+
...meta,
|
|
152
|
+
message
|
|
153
|
+
},
|
|
154
|
+
source,
|
|
155
|
+
severity
|
|
156
|
+
});
|
|
157
|
+
if (!this.timer) {
|
|
158
|
+
this.startTimer();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/** @type {ErrorManager} */
|
|
163
|
+
export default new ErrorManager();
|