@autofleet/rabbit 3.2.19-beta.5 → 3.2.19-beta.7
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/dist/index.d.ts +19 -11
- package/dist/index.js +61 -43
- package/dist/lib/types.d.ts +4 -0
- package/dist/lib/types.js +6 -1
- package/package.json +1 -1
- package/src/index.ts +77 -48
- package/src/lib/types.ts +5 -0
- package/coverage/clover.xml +0 -7
- package/coverage/coverage-final.json +0 -1
- package/coverage/lcov-report/base.css +0 -212
- package/coverage/lcov-report/index.html +0 -60
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -1
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -158
- package/coverage/lcov.info +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { EventEmitter } from 'events';
|
|
|
3
3
|
import { AmqpConnectionManager, ChannelWrapper, CreateChannelOpts } from 'amqp-connection-manager';
|
|
4
4
|
import { ConfirmChannel, ConsumeMessage, Options, Replies } from 'amqplib';
|
|
5
5
|
import { RedisConfig } from './lib/redis';
|
|
6
|
-
import { CallbackFunction, ConsumeMessageOrNull, ConsumeOptions, CustomMessageHeaders, QueuesCache, RedisLockType, ExchangesCache, QueueSetupPromisesDictionary } from './lib/types';
|
|
6
|
+
import { CallbackFunction, ConsumeMessageOrNull, ConsumeOptions, CustomMessageHeaders, QueuesCache, RedisLockType, ExchangesCache, QueueSetupPromisesDictionary, ConnectionRole } from './lib/types';
|
|
7
7
|
export interface IAfRabbitMq {
|
|
8
8
|
ack: any;
|
|
9
9
|
nack: any;
|
|
@@ -37,10 +37,12 @@ type newChannelOpts = {
|
|
|
37
37
|
name?: string;
|
|
38
38
|
onClose?: null | ((args: any | null) => void);
|
|
39
39
|
options?: CreateChannelOpts | undefined;
|
|
40
|
+
connectionRole: ConnectionRole;
|
|
40
41
|
};
|
|
41
42
|
type assertChannelOpts = {
|
|
42
43
|
channelName?: string;
|
|
43
44
|
force?: boolean;
|
|
45
|
+
connectionRole: ConnectionRole;
|
|
44
46
|
};
|
|
45
47
|
declare class RabbitMq implements IAfRabbitMq {
|
|
46
48
|
static parseMsg(msg: any): any;
|
|
@@ -60,9 +62,11 @@ declare class RabbitMq implements IAfRabbitMq {
|
|
|
60
62
|
channel: ChannelWrapper | null;
|
|
61
63
|
publishChannelSetupPromise: Promise<ChannelWrapper> | null;
|
|
62
64
|
blockReconnect: boolean | null | undefined;
|
|
63
|
-
|
|
65
|
+
consumeConnection: AmqpConnectionManager | null | undefined;
|
|
66
|
+
publishConnection: AmqpConnectionManager | null | undefined;
|
|
64
67
|
em: EventEmitter;
|
|
65
|
-
|
|
68
|
+
creatingConsumeConnection: boolean;
|
|
69
|
+
creatingPublishConnection: boolean;
|
|
66
70
|
exchanges: ExchangesCache;
|
|
67
71
|
queues: QueuesCache;
|
|
68
72
|
queueSetupPromises: QueueSetupPromisesDictionary;
|
|
@@ -76,15 +80,19 @@ declare class RabbitMq implements IAfRabbitMq {
|
|
|
76
80
|
private shouldConsumeMessageByTimestamp;
|
|
77
81
|
ack: (channel: ConfirmChannel, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp?: boolean, releaseLock?: null) => (userMsg: ConsumeMessage) => Promise<any>;
|
|
78
82
|
nack: (channel: ConfirmChannel, queue: string, options: any, deadQueueOptions: Options.AssertQueue, msg: ConsumeMessageOrNull, releaseLock: any) => (userMsg: ConsumeMessageOrNull, { skipRetry, }?: NackOptions) => Promise<any>;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
geConnectionByRole: (connectionRole: ConnectionRole) => {
|
|
84
|
+
connectionByRole: AmqpConnectionManager | null | undefined;
|
|
85
|
+
creatingConnectionByRole: boolean;
|
|
86
|
+
};
|
|
87
|
+
getConnection(connectionRole: ConnectionRole): Promise<AmqpConnectionManager | null | undefined>;
|
|
88
|
+
getNewChannel({ name, onClose, options, connectionRole, }?: newChannelOpts): Promise<ChannelWrapper>;
|
|
89
|
+
assertChannel({ force, connectionRole }?: assertChannelOpts): Promise<ChannelWrapper>;
|
|
82
90
|
assertExchange(exchangeName: string, options?: any): Promise<any>;
|
|
83
|
-
getQueueLength(queue: string): Promise<Replies.AssertQueue>;
|
|
91
|
+
getQueueLength(queue: string, connectionRole?: ConnectionRole): Promise<Replies.AssertQueue>;
|
|
84
92
|
private deleteQueue;
|
|
85
|
-
bindQueue(queue: string, exchange: string): Promise<void>;
|
|
86
|
-
setupQueue(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue>;
|
|
87
|
-
assertQueue(queueName: string, options?: Options.AssertQueue): Promise<any>;
|
|
93
|
+
bindQueue(queue: string, exchange: string, connectionRole: ConnectionRole): Promise<void>;
|
|
94
|
+
setupQueue(queueName: string, connectionRole: ConnectionRole, options?: Options.AssertQueue): Promise<Replies.AssertQueue>;
|
|
95
|
+
assertQueue(queueName: string, connectionRole: ConnectionRole, options?: Options.AssertQueue): Promise<any>;
|
|
88
96
|
private saveConsumer;
|
|
89
97
|
consume(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any>;
|
|
90
98
|
private lockRedisIfNeeded;
|
|
@@ -93,7 +101,7 @@ declare class RabbitMq implements IAfRabbitMq {
|
|
|
93
101
|
consumeFromExchange(queue: string, exchange: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any>;
|
|
94
102
|
publish(exchange: string, content: any, customHeaders?: any): Promise<boolean>;
|
|
95
103
|
sendToQueue(queue: string, content: any, options?: any, customHeaders?: any): Promise<boolean | undefined>;
|
|
96
|
-
isConnected(): Promise<boolean>;
|
|
104
|
+
isConnected(connectionRole: ConnectionRole): Promise<boolean>;
|
|
97
105
|
gracefulShutdown(signal: string): Promise<void>;
|
|
98
106
|
}
|
|
99
107
|
export default RabbitMq;
|
package/dist/index.js
CHANGED
|
@@ -115,11 +115,16 @@ class RabbitMq {
|
|
|
115
115
|
});
|
|
116
116
|
}
|
|
117
117
|
};
|
|
118
|
+
this.geConnectionByRole = (connectionRole) => (connectionRole === types_1.ConnectionRole.Consumer
|
|
119
|
+
? { connectionByRole: this.consumeConnection, creatingConnectionByRole: this.creatingConsumeConnection }
|
|
120
|
+
: { connectionByRole: this.publishConnection, creatingConnectionByRole: this.creatingPublishConnection });
|
|
118
121
|
this.em = new events_1.EventEmitter();
|
|
119
122
|
this.channel = null;
|
|
120
123
|
this.publishChannelSetupPromise = null;
|
|
121
|
-
this.
|
|
122
|
-
this.
|
|
124
|
+
this.consumeConnection = null;
|
|
125
|
+
this.publishConnection = null;
|
|
126
|
+
this.creatingPublishConnection = false;
|
|
127
|
+
this.creatingConsumeConnection = false;
|
|
123
128
|
this.exchanges = {};
|
|
124
129
|
this.queues = {};
|
|
125
130
|
this.queueSetupPromises = {};
|
|
@@ -140,30 +145,31 @@ class RabbitMq {
|
|
|
140
145
|
});
|
|
141
146
|
}
|
|
142
147
|
}
|
|
143
|
-
async getConnection() {
|
|
148
|
+
async getConnection(connectionRole) {
|
|
144
149
|
return new Promise(async (resolve, reject) => {
|
|
150
|
+
let { connectionByRole, creatingConnectionByRole } = this.geConnectionByRole(connectionRole);
|
|
145
151
|
if (this.blockReconnect) {
|
|
146
152
|
debug('rabbit: block reconnect');
|
|
147
153
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
148
154
|
// @ts-ignore
|
|
149
155
|
return resolve();
|
|
150
156
|
}
|
|
151
|
-
if (
|
|
152
|
-
if (this.options?.disableReconnect ||
|
|
157
|
+
if (connectionByRole !== null) {
|
|
158
|
+
if (this.options?.disableReconnect || connectionByRole?.isConnected()) {
|
|
153
159
|
debug('rabbit: connection - is connected');
|
|
154
160
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
155
161
|
// @ts-ignore
|
|
156
|
-
return resolve(
|
|
162
|
+
return resolve(connectionByRole);
|
|
157
163
|
}
|
|
158
164
|
debug('rabbit: connection - reconnecting');
|
|
159
165
|
}
|
|
160
|
-
if (
|
|
166
|
+
if (creatingConnectionByRole) {
|
|
161
167
|
debug('rabbit: creating connection emi');
|
|
162
168
|
this.em.once(consts_1.CONNECTION_CREATED_CONST, resolve);
|
|
163
169
|
this.em.once(consts_1.CONNECTION_FAILED_CONST, reject);
|
|
164
170
|
return;
|
|
165
171
|
}
|
|
166
|
-
|
|
172
|
+
creatingConnectionByRole = true;
|
|
167
173
|
let isResolved = false;
|
|
168
174
|
// It is import to use it as a function and not as a variable
|
|
169
175
|
// because of k8s changes the env variables
|
|
@@ -176,11 +182,15 @@ class RabbitMq {
|
|
|
176
182
|
return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
|
|
177
183
|
};
|
|
178
184
|
const defaultUrls = findServers();
|
|
179
|
-
const
|
|
185
|
+
const newConnection = await (0, amqp_connection_manager_1.connect)(defaultUrls, {
|
|
180
186
|
findServers,
|
|
181
187
|
});
|
|
182
|
-
|
|
183
|
-
|
|
188
|
+
if (!newConnection) {
|
|
189
|
+
logger_1.default.error('rabbit: couldnt create a connection');
|
|
190
|
+
return resolve(connectionByRole);
|
|
191
|
+
}
|
|
192
|
+
connectionByRole = newConnection;
|
|
193
|
+
connectionByRole.on('error', (err) => {
|
|
184
194
|
logger_1.default.error('rabbit: connection error', { err });
|
|
185
195
|
if (!isResolved) {
|
|
186
196
|
isResolved = true;
|
|
@@ -188,7 +198,7 @@ class RabbitMq {
|
|
|
188
198
|
this.em.emit(consts_1.CONNECTION_FAILED_CONST, err);
|
|
189
199
|
}
|
|
190
200
|
});
|
|
191
|
-
|
|
201
|
+
connectionByRole.on('connectFailed', (err) => {
|
|
192
202
|
this.consumersTags = [];
|
|
193
203
|
logger_1.default.error('rabbit: connection connectFailed', { err });
|
|
194
204
|
if (!isResolved) {
|
|
@@ -197,7 +207,7 @@ class RabbitMq {
|
|
|
197
207
|
this.em.emit(consts_1.CONNECTION_FAILED_CONST, err);
|
|
198
208
|
}
|
|
199
209
|
});
|
|
200
|
-
|
|
210
|
+
connectionByRole.on('disconnect', ({ err }) => {
|
|
201
211
|
this.consumersTags = [];
|
|
202
212
|
debug('rabbit: connection closed');
|
|
203
213
|
if (this.options?.disableReconnect) {
|
|
@@ -208,24 +218,27 @@ class RabbitMq {
|
|
|
208
218
|
logger_1.default.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
|
|
209
219
|
}
|
|
210
220
|
});
|
|
211
|
-
|
|
221
|
+
connectionByRole.once('connect', async () => {
|
|
212
222
|
debug('rabbit: connection established');
|
|
213
|
-
|
|
214
|
-
this.em.emit(consts_1.CONNECTION_CREATED_CONST,
|
|
223
|
+
creatingConnectionByRole = false;
|
|
224
|
+
this.em.emit(consts_1.CONNECTION_CREATED_CONST, connectionByRole);
|
|
215
225
|
isResolved = true;
|
|
216
|
-
resolve(
|
|
226
|
+
resolve(connectionByRole);
|
|
217
227
|
});
|
|
218
228
|
});
|
|
219
229
|
}
|
|
220
|
-
async getNewChannel({ name = (0, utils_1.rand)().toString(), onClose = null, options = {} } = {}) {
|
|
230
|
+
async getNewChannel({ name = (0, utils_1.rand)().toString(), onClose = null, options = {}, connectionRole, } = { connectionRole: types_1.ConnectionRole.Consumer }) {
|
|
221
231
|
let connection;
|
|
222
232
|
try {
|
|
223
|
-
connection = await this.getConnection();
|
|
233
|
+
connection = await this.getConnection(connectionRole);
|
|
224
234
|
}
|
|
225
235
|
catch (e) {
|
|
226
236
|
logger_1.default.error(`rabbit: error on get connection for new channel ${name} `, { e });
|
|
227
237
|
throw e;
|
|
228
238
|
}
|
|
239
|
+
if (!connection) {
|
|
240
|
+
throw new Error(`rabbit: couldnt get connection for new channel ${name}`);
|
|
241
|
+
}
|
|
229
242
|
const channel = connection.createChannel({ ...options });
|
|
230
243
|
(0, events_1.once)(channel, 'close').then((args) => {
|
|
231
244
|
logger_1.default.error(`rabbit: channel ${name} closed`);
|
|
@@ -241,14 +254,14 @@ class RabbitMq {
|
|
|
241
254
|
throw err;
|
|
242
255
|
}
|
|
243
256
|
}
|
|
244
|
-
async assertChannel({ force = false } = {}) {
|
|
257
|
+
async assertChannel({ force = false, connectionRole } = { connectionRole: types_1.ConnectionRole.Consumer }) {
|
|
245
258
|
if (!this.publishChannelSetupPromise) {
|
|
246
259
|
this.publishChannelSetupPromise = new Promise(async (resolve, reject) => {
|
|
247
260
|
if (this.channel && !force) {
|
|
248
261
|
return resolve(this.channel);
|
|
249
262
|
}
|
|
250
263
|
try {
|
|
251
|
-
const channel = await this.getNewChannel({});
|
|
264
|
+
const channel = await this.getNewChannel({ connectionRole });
|
|
252
265
|
channel.on('error', (err) => {
|
|
253
266
|
logger_1.default.error('rabbit: channel error', { err });
|
|
254
267
|
});
|
|
@@ -263,7 +276,7 @@ class RabbitMq {
|
|
|
263
276
|
return this.publishChannelSetupPromise;
|
|
264
277
|
}
|
|
265
278
|
async assertExchange(exchangeName, options) {
|
|
266
|
-
const channel = await this.assertChannel();
|
|
279
|
+
const channel = await this.assertChannel({ connectionRole: options.connectionRole });
|
|
267
280
|
if (this.exchanges[exchangeName]) {
|
|
268
281
|
return this.exchanges[exchangeName];
|
|
269
282
|
}
|
|
@@ -271,32 +284,33 @@ class RabbitMq {
|
|
|
271
284
|
this.exchanges[exchangeName] = exchange;
|
|
272
285
|
return exchange;
|
|
273
286
|
}
|
|
274
|
-
async getQueueLength(queue) {
|
|
287
|
+
async getQueueLength(queue, connectionRole = types_1.ConnectionRole.Consumer) {
|
|
275
288
|
RabbitMq.validateName('queue', queue);
|
|
289
|
+
const { connectionByRole } = this.geConnectionByRole(connectionRole);
|
|
276
290
|
const { channel } = this;
|
|
277
291
|
if (!channel) {
|
|
278
292
|
throw new Error('channel is not defined');
|
|
279
293
|
}
|
|
280
|
-
debug('rabbit: getting queue length', { queue, connected:
|
|
294
|
+
debug('rabbit: getting queue length', { queue, connected: connectionByRole?.isConnected() });
|
|
281
295
|
return channel?.checkQueue(queue);
|
|
282
296
|
}
|
|
283
|
-
async deleteQueue(queue) {
|
|
297
|
+
async deleteQueue(queue, connectionRole) {
|
|
284
298
|
RabbitMq.validateName('queue', queue);
|
|
285
|
-
const channel = await this.assertChannel();
|
|
299
|
+
const channel = await this.assertChannel({ connectionRole });
|
|
286
300
|
logger_1.default.info('rabbit: deleting queue', { queue });
|
|
287
301
|
const deleteQueueRes = await channel.deleteQueue(queue);
|
|
288
302
|
debug('queue deleted', deleteQueueRes);
|
|
289
303
|
return deleteQueueRes;
|
|
290
304
|
}
|
|
291
|
-
async bindQueue(queue, exchange) {
|
|
292
|
-
const channel = await this.assertChannel();
|
|
305
|
+
async bindQueue(queue, exchange, connectionRole) {
|
|
306
|
+
const channel = await this.assertChannel({ connectionRole });
|
|
293
307
|
await channel.addSetup((setupChannel) => setupChannel.bindQueue(queue, exchange, ''));
|
|
294
308
|
return channel.bindQueue(queue, exchange, '');
|
|
295
309
|
}
|
|
296
|
-
async setupQueue(queueName, options) {
|
|
310
|
+
async setupQueue(queueName, connectionRole, options) {
|
|
297
311
|
let queue;
|
|
298
312
|
try {
|
|
299
|
-
const channel = await this.assertChannel();
|
|
313
|
+
const channel = await this.assertChannel({ connectionRole });
|
|
300
314
|
debug('assertQueue->channel.addSetup', { queueName });
|
|
301
315
|
await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, options));
|
|
302
316
|
debug('assertQueue->channel.assertQueue', { queueName });
|
|
@@ -306,8 +320,8 @@ class RabbitMq {
|
|
|
306
320
|
logger_1.default.error('rabbit: assertQueue error', { queueName, options, error: e });
|
|
307
321
|
if (!this.options?.dontRetryAssert) {
|
|
308
322
|
debug('retrying assertQueue', { queueName });
|
|
309
|
-
const channel = await this.assertChannel({ force: true });
|
|
310
|
-
await this.deleteQueue(queueName);
|
|
323
|
+
const channel = await this.assertChannel({ force: true, connectionRole });
|
|
324
|
+
await this.deleteQueue(queueName, connectionRole);
|
|
311
325
|
debug('retrying assertQueue->channel.addSetup', { queueName });
|
|
312
326
|
await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, options));
|
|
313
327
|
debug('retrying assertQueue->channel.assertQueue', { queueName });
|
|
@@ -320,7 +334,7 @@ class RabbitMq {
|
|
|
320
334
|
this.queues[queueName] = queueName;
|
|
321
335
|
return queue;
|
|
322
336
|
}
|
|
323
|
-
async assertQueue(queueName, options) {
|
|
337
|
+
async assertQueue(queueName, connectionRole, options) {
|
|
324
338
|
RabbitMq.validateName('queue', queueName);
|
|
325
339
|
if (this.queues[queueName]) {
|
|
326
340
|
delete this.queueSetupPromises[queueName];
|
|
@@ -329,7 +343,7 @@ class RabbitMq {
|
|
|
329
343
|
if (this.queueSetupPromises[queueName]) {
|
|
330
344
|
return this.queueSetupPromises[queueName];
|
|
331
345
|
}
|
|
332
|
-
this.queueSetupPromises[queueName] = this.setupQueue(queueName, options);
|
|
346
|
+
this.queueSetupPromises[queueName] = this.setupQueue(queueName, connectionRole, options);
|
|
333
347
|
return this.queueSetupPromises[queueName];
|
|
334
348
|
}
|
|
335
349
|
saveConsumer(queue, callback, options) {
|
|
@@ -372,7 +386,7 @@ class RabbitMq {
|
|
|
372
386
|
}
|
|
373
387
|
logger_1.default.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
374
388
|
}
|
|
375
|
-
const channel = await this.getNewChannel({});
|
|
389
|
+
const channel = await this.getNewChannel({ connectionRole: types_1.ConnectionRole.Consumer });
|
|
376
390
|
return channel.addSetup(async (confirmChannel) => {
|
|
377
391
|
await confirmChannel.assertQueue(queue, options ? { messageTtl: options.messageTtl } : undefined);
|
|
378
392
|
await confirmChannel.prefetch(limit, true);
|
|
@@ -452,7 +466,7 @@ class RabbitMq {
|
|
|
452
466
|
RabbitMq.validateName('queue', queue);
|
|
453
467
|
const { limit, deadMessageTtl } = optionsWithDefaults;
|
|
454
468
|
await this.saveConsumer(queue, callback, options);
|
|
455
|
-
const channel = await this.getNewChannel({ name: `consume-exchange
|
|
469
|
+
const channel = await this.getNewChannel({ name: `consume - exchange - ${exchange} -queue - ${queue}`, connectionRole: types_1.ConnectionRole.Consumer });
|
|
456
470
|
return channel.addSetup(async (c) => {
|
|
457
471
|
const assertExchange = await (0, utils_1.assertExchangeFanout)(c, exchange);
|
|
458
472
|
await c.assertQueue(queue);
|
|
@@ -467,14 +481,14 @@ class RabbitMq {
|
|
|
467
481
|
async publish(exchange, content, customHeaders) {
|
|
468
482
|
return (0, utils_1.wrapSetImmediate)(async () => {
|
|
469
483
|
RabbitMq.validateName('exchange', exchange);
|
|
470
|
-
const channel = await this.assertChannel();
|
|
471
|
-
await this.assertExchange(exchange);
|
|
484
|
+
const channel = await this.assertChannel({ connectionRole: types_1.ConnectionRole.Publisher });
|
|
485
|
+
await this.assertExchange(exchange, { connectionRole: types_1.ConnectionRole.Publisher });
|
|
472
486
|
await channel.publish(exchange, '', Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
473
487
|
});
|
|
474
488
|
}
|
|
475
489
|
async sendToQueue(queue, content, options, customHeaders) {
|
|
476
490
|
try {
|
|
477
|
-
await this.assertChannel();
|
|
491
|
+
await this.assertChannel({ connectionRole: types_1.ConnectionRole.Publisher });
|
|
478
492
|
}
|
|
479
493
|
catch (e) {
|
|
480
494
|
logger_1.default.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
|
|
@@ -482,7 +496,7 @@ class RabbitMq {
|
|
|
482
496
|
}
|
|
483
497
|
try {
|
|
484
498
|
RabbitMq.validateName('queue', queue);
|
|
485
|
-
await this.assertQueue(queue, options);
|
|
499
|
+
await this.assertQueue(queue, types_1.ConnectionRole.Publisher, options);
|
|
486
500
|
}
|
|
487
501
|
catch (e) {
|
|
488
502
|
logger_1.default.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
|
|
@@ -494,13 +508,17 @@ class RabbitMq {
|
|
|
494
508
|
return res;
|
|
495
509
|
}
|
|
496
510
|
catch (e) {
|
|
497
|
-
const isConnected = await this.isConnected();
|
|
511
|
+
const isConnected = await this.isConnected(types_1.ConnectionRole.Publisher);
|
|
498
512
|
logger_1.default.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
|
|
499
513
|
throw e;
|
|
500
514
|
}
|
|
501
515
|
}
|
|
502
|
-
async isConnected() {
|
|
503
|
-
const connection = await this.getConnection();
|
|
516
|
+
async isConnected(connectionRole) {
|
|
517
|
+
const connection = await this.getConnection(connectionRole);
|
|
518
|
+
if (!connection) {
|
|
519
|
+
logger_1.default.error('rabbit: isConnected - false');
|
|
520
|
+
return false;
|
|
521
|
+
}
|
|
504
522
|
const isConnected = connection.isConnected();
|
|
505
523
|
if (!isConnected) {
|
|
506
524
|
logger_1.default.error('rabbit: isConnected - false');
|
package/dist/lib/types.d.ts
CHANGED
package/dist/lib/types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CONSUMER_DEFAULT_OPTIONS = void 0;
|
|
3
|
+
exports.ConnectionRole = exports.CONSUMER_DEFAULT_OPTIONS = void 0;
|
|
4
4
|
const HA_PROMOTE_ON_FAILURE = 'ha-promote-on-failure';
|
|
5
5
|
const HA_PROMOTE_ON_SHUTDOWN = 'ha-promote-on-shutdown';
|
|
6
6
|
exports.CONSUMER_DEFAULT_OPTIONS = {
|
|
@@ -9,3 +9,8 @@ exports.CONSUMER_DEFAULT_OPTIONS = {
|
|
|
9
9
|
[HA_PROMOTE_ON_SHUTDOWN]: 'always',
|
|
10
10
|
},
|
|
11
11
|
};
|
|
12
|
+
var ConnectionRole;
|
|
13
|
+
(function (ConnectionRole) {
|
|
14
|
+
ConnectionRole["Consumer"] = "consumer";
|
|
15
|
+
ConnectionRole["Publisher"] = "publisher";
|
|
16
|
+
})(ConnectionRole = exports.ConnectionRole || (exports.ConnectionRole = {}));
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -36,13 +36,13 @@ import {
|
|
|
36
36
|
QueuesCache,
|
|
37
37
|
RedisLockType,
|
|
38
38
|
ExchangesCache, CONSUMER_DEFAULT_OPTIONS, QueueSetupPromisesDictionary,
|
|
39
|
+
ConnectionRole,
|
|
39
40
|
} from './lib/types';
|
|
40
41
|
|
|
41
42
|
// const debug = nodeDebug('af-rabbitmq')
|
|
42
43
|
const debug = logger.debug.bind(logger);
|
|
43
44
|
|
|
44
45
|
const PUBLISH_TIMEOUT = 1000 * 10;
|
|
45
|
-
|
|
46
46
|
export interface IAfRabbitMq {
|
|
47
47
|
ack: any;
|
|
48
48
|
nack: any;
|
|
@@ -82,11 +82,13 @@ type newChannelOpts = {
|
|
|
82
82
|
name?: string;
|
|
83
83
|
onClose?: null | ((args: any | null) => void);
|
|
84
84
|
options?: CreateChannelOpts | undefined;
|
|
85
|
+
connectionRole: ConnectionRole,
|
|
85
86
|
};
|
|
86
87
|
|
|
87
88
|
type assertChannelOpts = {
|
|
88
89
|
channelName?: string;
|
|
89
90
|
force?: boolean;
|
|
91
|
+
connectionRole: ConnectionRole;
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
type AfConsumer = {
|
|
@@ -145,11 +147,15 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
145
147
|
|
|
146
148
|
blockReconnect: boolean | null | undefined
|
|
147
149
|
|
|
148
|
-
|
|
150
|
+
consumeConnection: AmqpConnectionManager | null | undefined;
|
|
151
|
+
|
|
152
|
+
publishConnection: AmqpConnectionManager | null | undefined;
|
|
149
153
|
|
|
150
154
|
em: EventEmitter;
|
|
151
155
|
|
|
152
|
-
|
|
156
|
+
creatingConsumeConnection: boolean;
|
|
157
|
+
|
|
158
|
+
creatingPublishConnection: boolean;
|
|
153
159
|
|
|
154
160
|
exchanges: ExchangesCache;
|
|
155
161
|
|
|
@@ -172,8 +178,10 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
172
178
|
this.em = new EventEmitter();
|
|
173
179
|
this.channel = null;
|
|
174
180
|
this.publishChannelSetupPromise = null;
|
|
175
|
-
this.
|
|
176
|
-
this.
|
|
181
|
+
this.consumeConnection = null;
|
|
182
|
+
this.publishConnection = null;
|
|
183
|
+
this.creatingPublishConnection = false;
|
|
184
|
+
this.creatingConsumeConnection = false;
|
|
177
185
|
this.exchanges = {};
|
|
178
186
|
this.queues = {};
|
|
179
187
|
this.queueSetupPromises = {};
|
|
@@ -270,30 +278,35 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
270
278
|
}
|
|
271
279
|
}
|
|
272
280
|
|
|
273
|
-
|
|
274
|
-
|
|
281
|
+
geConnectionByRole = (connectionRole: ConnectionRole) => (connectionRole === ConnectionRole.Consumer
|
|
282
|
+
? { connectionByRole: this.consumeConnection, creatingConnectionByRole: this.creatingConsumeConnection }
|
|
283
|
+
: { connectionByRole: this.publishConnection, creatingConnectionByRole: this.creatingPublishConnection });
|
|
284
|
+
|
|
285
|
+
async getConnection(connectionRole: ConnectionRole) {
|
|
286
|
+
return new Promise<AmqpConnectionManager | undefined | null>(async (resolve, reject) => {
|
|
287
|
+
let { connectionByRole, creatingConnectionByRole } = this.geConnectionByRole(connectionRole);
|
|
275
288
|
if (this.blockReconnect) {
|
|
276
289
|
debug('rabbit: block reconnect');
|
|
277
290
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
278
291
|
// @ts-ignore
|
|
279
292
|
return resolve();
|
|
280
293
|
}
|
|
281
|
-
if (
|
|
282
|
-
if (this.options?.disableReconnect ||
|
|
294
|
+
if (connectionByRole !== null) {
|
|
295
|
+
if (this.options?.disableReconnect || connectionByRole?.isConnected()) {
|
|
283
296
|
debug('rabbit: connection - is connected');
|
|
284
297
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
285
298
|
// @ts-ignore
|
|
286
|
-
return resolve(
|
|
299
|
+
return resolve(connectionByRole);
|
|
287
300
|
}
|
|
288
301
|
debug('rabbit: connection - reconnecting');
|
|
289
302
|
}
|
|
290
|
-
if (
|
|
303
|
+
if (creatingConnectionByRole) {
|
|
291
304
|
debug('rabbit: creating connection emi');
|
|
292
305
|
this.em.once(CONNECTION_CREATED_CONST, resolve);
|
|
293
306
|
this.em.once(CONNECTION_FAILED_CONST, reject);
|
|
294
307
|
return;
|
|
295
308
|
}
|
|
296
|
-
|
|
309
|
+
creatingConnectionByRole = true;
|
|
297
310
|
let isResolved = false;
|
|
298
311
|
|
|
299
312
|
// It is import to use it as a function and not as a variable
|
|
@@ -310,12 +323,18 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
310
323
|
};
|
|
311
324
|
|
|
312
325
|
const defaultUrls = findServers();
|
|
313
|
-
const
|
|
326
|
+
const newConnection: AmqpConnectionManager = await connect(defaultUrls, {
|
|
314
327
|
findServers,
|
|
315
328
|
});
|
|
316
329
|
|
|
317
|
-
|
|
318
|
-
|
|
330
|
+
if (!newConnection) {
|
|
331
|
+
logger.error('rabbit: couldnt create a connection');
|
|
332
|
+
return resolve(connectionByRole);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
connectionByRole = newConnection;
|
|
336
|
+
|
|
337
|
+
connectionByRole.on('error', (err) => {
|
|
319
338
|
logger.error('rabbit: connection error', { err });
|
|
320
339
|
if (!isResolved) {
|
|
321
340
|
isResolved = true;
|
|
@@ -324,7 +343,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
324
343
|
}
|
|
325
344
|
});
|
|
326
345
|
|
|
327
|
-
|
|
346
|
+
connectionByRole.on('connectFailed', (err) => {
|
|
328
347
|
this.consumersTags = [];
|
|
329
348
|
logger.error('rabbit: connection connectFailed', { err });
|
|
330
349
|
if (!isResolved) {
|
|
@@ -334,7 +353,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
334
353
|
}
|
|
335
354
|
});
|
|
336
355
|
|
|
337
|
-
|
|
356
|
+
connectionByRole.on('disconnect', ({ err }) => {
|
|
338
357
|
this.consumersTags = [];
|
|
339
358
|
debug('rabbit: connection closed');
|
|
340
359
|
if (this.options?.disableReconnect) {
|
|
@@ -344,24 +363,29 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
344
363
|
logger.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
|
|
345
364
|
}
|
|
346
365
|
});
|
|
347
|
-
|
|
366
|
+
connectionByRole.once('connect', async () => {
|
|
348
367
|
debug('rabbit: connection established');
|
|
349
|
-
|
|
350
|
-
this.em.emit(CONNECTION_CREATED_CONST,
|
|
368
|
+
creatingConnectionByRole = false;
|
|
369
|
+
this.em.emit(CONNECTION_CREATED_CONST, connectionByRole);
|
|
351
370
|
isResolved = true;
|
|
352
|
-
resolve(
|
|
371
|
+
resolve(connectionByRole);
|
|
353
372
|
});
|
|
354
373
|
});
|
|
355
374
|
}
|
|
356
375
|
|
|
357
|
-
async getNewChannel({
|
|
358
|
-
|
|
376
|
+
async getNewChannel({
|
|
377
|
+
name = rand().toString(), onClose = null, options = {}, connectionRole,
|
|
378
|
+
}: newChannelOpts = { connectionRole: ConnectionRole.Consumer }): Promise<ChannelWrapper> {
|
|
379
|
+
let connection!: AmqpConnectionManager | undefined | null;
|
|
359
380
|
try {
|
|
360
|
-
connection = await this.getConnection();
|
|
381
|
+
connection = await this.getConnection(connectionRole);
|
|
361
382
|
} catch (e) {
|
|
362
383
|
logger.error(`rabbit: error on get connection for new channel ${name} `, { e });
|
|
363
384
|
throw e;
|
|
364
385
|
}
|
|
386
|
+
if (!connection) {
|
|
387
|
+
throw new Error(`rabbit: couldnt get connection for new channel ${name}`);
|
|
388
|
+
}
|
|
365
389
|
const channel = connection.createChannel({ ...options });
|
|
366
390
|
once(channel, 'close').then((args) => {
|
|
367
391
|
logger.error(`rabbit: channel ${name} closed`);
|
|
@@ -377,7 +401,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
377
401
|
}
|
|
378
402
|
}
|
|
379
403
|
|
|
380
|
-
async assertChannel({ force = false }
|
|
404
|
+
async assertChannel({ force = false, connectionRole }: assertChannelOpts = { connectionRole: ConnectionRole.Consumer }): Promise<ChannelWrapper> {
|
|
381
405
|
if (!this.publishChannelSetupPromise) {
|
|
382
406
|
this.publishChannelSetupPromise = new Promise<ChannelWrapper>(async (resolve, reject) => {
|
|
383
407
|
if (this.channel && !force) {
|
|
@@ -385,7 +409,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
385
409
|
}
|
|
386
410
|
|
|
387
411
|
try {
|
|
388
|
-
const channel = await this.getNewChannel({});
|
|
412
|
+
const channel = await this.getNewChannel({ connectionRole });
|
|
389
413
|
channel.on('error', (err) => {
|
|
390
414
|
logger.error('rabbit: channel error', { err });
|
|
391
415
|
});
|
|
@@ -400,7 +424,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
400
424
|
}
|
|
401
425
|
|
|
402
426
|
async assertExchange(exchangeName: string, options?: any) {
|
|
403
|
-
const channel: ChannelWrapper = await this.assertChannel();
|
|
427
|
+
const channel: ChannelWrapper = await this.assertChannel({ connectionRole: options.connectionRole });
|
|
404
428
|
if (this.exchanges[exchangeName]) {
|
|
405
429
|
return this.exchanges[exchangeName];
|
|
406
430
|
}
|
|
@@ -409,35 +433,36 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
409
433
|
return exchange;
|
|
410
434
|
}
|
|
411
435
|
|
|
412
|
-
async getQueueLength(queue: string) {
|
|
436
|
+
async getQueueLength(queue: string, connectionRole: ConnectionRole = ConnectionRole.Consumer): Promise<Replies.AssertQueue> {
|
|
413
437
|
RabbitMq.validateName('queue', queue);
|
|
438
|
+
const { connectionByRole } = this.geConnectionByRole(connectionRole);
|
|
414
439
|
const { channel } = this;
|
|
415
440
|
if (!channel) {
|
|
416
441
|
throw new Error('channel is not defined');
|
|
417
442
|
}
|
|
418
|
-
debug('rabbit: getting queue length', { queue, connected:
|
|
443
|
+
debug('rabbit: getting queue length', { queue, connected: connectionByRole?.isConnected() });
|
|
419
444
|
return channel?.checkQueue(queue);
|
|
420
445
|
}
|
|
421
446
|
|
|
422
|
-
private async deleteQueue(queue: string) {
|
|
447
|
+
private async deleteQueue(queue: string, connectionRole: ConnectionRole) {
|
|
423
448
|
RabbitMq.validateName('queue', queue);
|
|
424
|
-
const channel: ChannelWrapper = await this.assertChannel();
|
|
449
|
+
const channel: ChannelWrapper = await this.assertChannel({ connectionRole });
|
|
425
450
|
logger.info('rabbit: deleting queue', { queue });
|
|
426
451
|
const deleteQueueRes = await channel.deleteQueue(queue);
|
|
427
452
|
debug('queue deleted', deleteQueueRes);
|
|
428
453
|
return deleteQueueRes;
|
|
429
454
|
}
|
|
430
455
|
|
|
431
|
-
async bindQueue(queue: string, exchange: string) {
|
|
432
|
-
const channel: ChannelWrapper = await this.assertChannel();
|
|
456
|
+
async bindQueue(queue: string, exchange: string, connectionRole: ConnectionRole) {
|
|
457
|
+
const channel: ChannelWrapper = await this.assertChannel({ connectionRole });
|
|
433
458
|
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.bindQueue(queue, exchange, ''));
|
|
434
459
|
return channel.bindQueue(queue, exchange, '');
|
|
435
460
|
}
|
|
436
461
|
|
|
437
|
-
async setupQueue(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
|
|
462
|
+
async setupQueue(queueName: string, connectionRole: ConnectionRole, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
|
|
438
463
|
let queue: Replies.AssertQueue;
|
|
439
464
|
try {
|
|
440
|
-
const channel: ChannelWrapper = await this.assertChannel();
|
|
465
|
+
const channel: ChannelWrapper = await this.assertChannel({ connectionRole });
|
|
441
466
|
debug('assertQueue->channel.addSetup', { queueName });
|
|
442
467
|
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, options));
|
|
443
468
|
debug('assertQueue->channel.assertQueue', { queueName });
|
|
@@ -446,8 +471,8 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
446
471
|
logger.error('rabbit: assertQueue error', { queueName, options, error: e });
|
|
447
472
|
if (!this.options?.dontRetryAssert) {
|
|
448
473
|
debug('retrying assertQueue', { queueName });
|
|
449
|
-
const channel = await this.assertChannel({ force: true });
|
|
450
|
-
await this.deleteQueue(queueName);
|
|
474
|
+
const channel = await this.assertChannel({ force: true, connectionRole });
|
|
475
|
+
await this.deleteQueue(queueName, connectionRole);
|
|
451
476
|
|
|
452
477
|
debug('retrying assertQueue->channel.addSetup', { queueName });
|
|
453
478
|
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, options));
|
|
@@ -462,7 +487,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
462
487
|
return queue;
|
|
463
488
|
}
|
|
464
489
|
|
|
465
|
-
async assertQueue(queueName: string, options?: Options.AssertQueue) {
|
|
490
|
+
async assertQueue(queueName: string, connectionRole: ConnectionRole, options?: Options.AssertQueue) {
|
|
466
491
|
RabbitMq.validateName('queue', queueName);
|
|
467
492
|
if (this.queues[queueName]) {
|
|
468
493
|
delete this.queueSetupPromises[queueName];
|
|
@@ -473,7 +498,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
473
498
|
return this.queueSetupPromises[queueName];
|
|
474
499
|
}
|
|
475
500
|
|
|
476
|
-
this.queueSetupPromises[queueName] = this.setupQueue(queueName, options);
|
|
501
|
+
this.queueSetupPromises[queueName] = this.setupQueue(queueName, connectionRole, options);
|
|
477
502
|
return this.queueSetupPromises[queueName];
|
|
478
503
|
}
|
|
479
504
|
|
|
@@ -527,7 +552,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
527
552
|
}
|
|
528
553
|
logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
529
554
|
}
|
|
530
|
-
const channel = await this.getNewChannel({});
|
|
555
|
+
const channel = await this.getNewChannel({ connectionRole: ConnectionRole.Consumer });
|
|
531
556
|
return channel.addSetup(async (confirmChannel: ConfirmChannel) => {
|
|
532
557
|
await confirmChannel.assertQueue(queue, options ? { messageTtl: options.messageTtl } : undefined);
|
|
533
558
|
await confirmChannel.prefetch(limit, true);
|
|
@@ -619,7 +644,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
619
644
|
RabbitMq.validateName('queue', queue);
|
|
620
645
|
const { limit, deadMessageTtl } = optionsWithDefaults;
|
|
621
646
|
await this.saveConsumer(queue, callback, options);
|
|
622
|
-
const channel: ChannelWrapper = await this.getNewChannel({ name: `consume-exchange
|
|
647
|
+
const channel: ChannelWrapper = await this.getNewChannel({ name: `consume - exchange - ${exchange} -queue - ${queue}`, connectionRole: ConnectionRole.Consumer });
|
|
623
648
|
|
|
624
649
|
return channel.addSetup(async (c: ConfirmChannel) => {
|
|
625
650
|
const assertExchange = await assertExchangeFanout(c, exchange);
|
|
@@ -640,8 +665,8 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
640
665
|
async publish(exchange: string, content: any, customHeaders?: any) : Promise<boolean> {
|
|
641
666
|
return wrapSetImmediate(async () => {
|
|
642
667
|
RabbitMq.validateName('exchange', exchange);
|
|
643
|
-
const channel: ChannelWrapper = await this.assertChannel();
|
|
644
|
-
await this.assertExchange(exchange);
|
|
668
|
+
const channel: ChannelWrapper = await this.assertChannel({ connectionRole: ConnectionRole.Publisher });
|
|
669
|
+
await this.assertExchange(exchange, { connectionRole: ConnectionRole.Publisher });
|
|
645
670
|
await channel.publish(exchange, '',
|
|
646
671
|
Buffer.from(JSON.stringify(content)),
|
|
647
672
|
RabbitMq.getPublishOptions(customHeaders));
|
|
@@ -655,7 +680,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
655
680
|
customHeaders?: any,
|
|
656
681
|
): Promise<boolean | undefined> {
|
|
657
682
|
try {
|
|
658
|
-
await this.assertChannel();
|
|
683
|
+
await this.assertChannel({ connectionRole: ConnectionRole.Publisher });
|
|
659
684
|
} catch (e) {
|
|
660
685
|
logger.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
|
|
661
686
|
throw e;
|
|
@@ -663,7 +688,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
663
688
|
|
|
664
689
|
try {
|
|
665
690
|
RabbitMq.validateName('queue', queue);
|
|
666
|
-
await this.assertQueue(queue, options);
|
|
691
|
+
await this.assertQueue(queue, ConnectionRole.Publisher, options);
|
|
667
692
|
} catch (e) {
|
|
668
693
|
logger.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
|
|
669
694
|
throw e;
|
|
@@ -676,14 +701,18 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
676
701
|
debug(`rabbit: sending to queue ${queue}`, { res });
|
|
677
702
|
return res;
|
|
678
703
|
} catch (e) {
|
|
679
|
-
const isConnected = await this.isConnected();
|
|
704
|
+
const isConnected = await this.isConnected(ConnectionRole.Publisher);
|
|
680
705
|
logger.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
|
|
681
706
|
throw e;
|
|
682
707
|
}
|
|
683
708
|
}
|
|
684
709
|
|
|
685
|
-
async isConnected()
|
|
686
|
-
const connection = await this.getConnection();
|
|
710
|
+
async isConnected(connectionRole: ConnectionRole): Promise<boolean> {
|
|
711
|
+
const connection = await this.getConnection(connectionRole);
|
|
712
|
+
if (!connection) {
|
|
713
|
+
logger.error('rabbit: isConnected - false');
|
|
714
|
+
return false;
|
|
715
|
+
}
|
|
687
716
|
const isConnected = connection.isConnected();
|
|
688
717
|
if (!isConnected) {
|
|
689
718
|
logger.error('rabbit: isConnected - false');
|
package/src/lib/types.ts
CHANGED
package/coverage/clover.xml
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<coverage generated="1675584950929" clover="3.2.0">
|
|
3
|
-
<project timestamp="1675584950929" name="All files">
|
|
4
|
-
<metrics statements="0" coveredstatements="0" conditionals="0" coveredconditionals="0" methods="0" coveredmethods="0" elements="0" coveredelements="0" complexity="0" loc="0" ncloc="0" packages="0" files="0" classes="0">
|
|
5
|
-
</metrics>
|
|
6
|
-
</project>
|
|
7
|
-
</coverage>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{}
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
body, html {
|
|
2
|
-
margin:0; padding: 0;
|
|
3
|
-
height: 100%;
|
|
4
|
-
}
|
|
5
|
-
body {
|
|
6
|
-
font-family: Helvetica Neue, Helvetica, Arial;
|
|
7
|
-
font-size: 14px;
|
|
8
|
-
color:#333;
|
|
9
|
-
}
|
|
10
|
-
.small { font-size: 12px; }
|
|
11
|
-
*, *:after, *:before {
|
|
12
|
-
-webkit-box-sizing:border-box;
|
|
13
|
-
-moz-box-sizing:border-box;
|
|
14
|
-
box-sizing:border-box;
|
|
15
|
-
}
|
|
16
|
-
h1 { font-size: 20px; margin: 0;}
|
|
17
|
-
h2 { font-size: 14px; }
|
|
18
|
-
pre {
|
|
19
|
-
font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
|
20
|
-
margin: 0;
|
|
21
|
-
padding: 0;
|
|
22
|
-
-moz-tab-size: 2;
|
|
23
|
-
-o-tab-size: 2;
|
|
24
|
-
tab-size: 2;
|
|
25
|
-
}
|
|
26
|
-
a { color:#0074D9; text-decoration:none; }
|
|
27
|
-
a:hover { text-decoration:underline; }
|
|
28
|
-
.strong { font-weight: bold; }
|
|
29
|
-
.space-top1 { padding: 10px 0 0 0; }
|
|
30
|
-
.pad2y { padding: 20px 0; }
|
|
31
|
-
.pad1y { padding: 10px 0; }
|
|
32
|
-
.pad2x { padding: 0 20px; }
|
|
33
|
-
.pad2 { padding: 20px; }
|
|
34
|
-
.pad1 { padding: 10px; }
|
|
35
|
-
.space-left2 { padding-left:55px; }
|
|
36
|
-
.space-right2 { padding-right:20px; }
|
|
37
|
-
.center { text-align:center; }
|
|
38
|
-
.clearfix { display:block; }
|
|
39
|
-
.clearfix:after {
|
|
40
|
-
content:'';
|
|
41
|
-
display:block;
|
|
42
|
-
height:0;
|
|
43
|
-
clear:both;
|
|
44
|
-
visibility:hidden;
|
|
45
|
-
}
|
|
46
|
-
.fl { float: left; }
|
|
47
|
-
@media only screen and (max-width:640px) {
|
|
48
|
-
.col3 { width:100%; max-width:100%; }
|
|
49
|
-
.hide-mobile { display:none!important; }
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
.quiet {
|
|
53
|
-
color: #7f7f7f;
|
|
54
|
-
color: rgba(0,0,0,0.5);
|
|
55
|
-
}
|
|
56
|
-
.quiet a { opacity: 0.7; }
|
|
57
|
-
|
|
58
|
-
.fraction {
|
|
59
|
-
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
|
|
60
|
-
font-size: 10px;
|
|
61
|
-
color: #555;
|
|
62
|
-
background: #E8E8E8;
|
|
63
|
-
padding: 4px 5px;
|
|
64
|
-
border-radius: 3px;
|
|
65
|
-
vertical-align: middle;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
div.path a:link, div.path a:visited { color: #333; }
|
|
69
|
-
table.coverage {
|
|
70
|
-
border-collapse: collapse;
|
|
71
|
-
margin: 10px 0 0 0;
|
|
72
|
-
padding: 0;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
table.coverage td {
|
|
76
|
-
margin: 0;
|
|
77
|
-
padding: 0;
|
|
78
|
-
vertical-align: top;
|
|
79
|
-
}
|
|
80
|
-
table.coverage td.line-count {
|
|
81
|
-
text-align: right;
|
|
82
|
-
padding: 0 5px 0 20px;
|
|
83
|
-
}
|
|
84
|
-
table.coverage td.line-coverage {
|
|
85
|
-
text-align: right;
|
|
86
|
-
padding-right: 10px;
|
|
87
|
-
min-width:20px;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
table.coverage td span.cline-any {
|
|
91
|
-
display: inline-block;
|
|
92
|
-
padding: 0 5px;
|
|
93
|
-
width: 100%;
|
|
94
|
-
}
|
|
95
|
-
.missing-if-branch {
|
|
96
|
-
display: inline-block;
|
|
97
|
-
margin-right: 5px;
|
|
98
|
-
border-radius: 3px;
|
|
99
|
-
position: relative;
|
|
100
|
-
padding: 0 4px;
|
|
101
|
-
background: #333;
|
|
102
|
-
color: yellow;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
.skip-if-branch {
|
|
106
|
-
display: none;
|
|
107
|
-
margin-right: 10px;
|
|
108
|
-
position: relative;
|
|
109
|
-
padding: 0 4px;
|
|
110
|
-
background: #ccc;
|
|
111
|
-
color: white;
|
|
112
|
-
}
|
|
113
|
-
.missing-if-branch .typ, .skip-if-branch .typ {
|
|
114
|
-
color: inherit !important;
|
|
115
|
-
}
|
|
116
|
-
.coverage-summary {
|
|
117
|
-
border-collapse: collapse;
|
|
118
|
-
width: 100%;
|
|
119
|
-
}
|
|
120
|
-
.coverage-summary tr { border-bottom: 1px solid #bbb; }
|
|
121
|
-
.keyline-all { border: 1px solid #ddd; }
|
|
122
|
-
.coverage-summary td, .coverage-summary th { padding: 10px; }
|
|
123
|
-
.coverage-summary tbody { border: 1px solid #bbb; }
|
|
124
|
-
.coverage-summary td { border-right: 1px solid #bbb; }
|
|
125
|
-
.coverage-summary td:last-child { border-right: none; }
|
|
126
|
-
.coverage-summary th {
|
|
127
|
-
text-align: left;
|
|
128
|
-
font-weight: normal;
|
|
129
|
-
white-space: nowrap;
|
|
130
|
-
}
|
|
131
|
-
.coverage-summary th.file { border-right: none !important; }
|
|
132
|
-
.coverage-summary th.pct { }
|
|
133
|
-
.coverage-summary th.pic,
|
|
134
|
-
.coverage-summary th.abs,
|
|
135
|
-
.coverage-summary td.pct,
|
|
136
|
-
.coverage-summary td.abs { text-align: right; }
|
|
137
|
-
.coverage-summary td.file { white-space: nowrap; }
|
|
138
|
-
.coverage-summary td.pic { min-width: 120px !important; }
|
|
139
|
-
.coverage-summary tfoot td { }
|
|
140
|
-
|
|
141
|
-
.coverage-summary .sorter {
|
|
142
|
-
height: 10px;
|
|
143
|
-
width: 7px;
|
|
144
|
-
display: inline-block;
|
|
145
|
-
margin-left: 0.5em;
|
|
146
|
-
background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
|
|
147
|
-
}
|
|
148
|
-
.coverage-summary .sorted .sorter {
|
|
149
|
-
background-position: 0 -20px;
|
|
150
|
-
}
|
|
151
|
-
.coverage-summary .sorted-desc .sorter {
|
|
152
|
-
background-position: 0 -10px;
|
|
153
|
-
}
|
|
154
|
-
.status-line { height: 10px; }
|
|
155
|
-
/* dark red */
|
|
156
|
-
.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
|
|
157
|
-
.low .chart { border:1px solid #C21F39 }
|
|
158
|
-
/* medium red */
|
|
159
|
-
.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
|
|
160
|
-
/* light red */
|
|
161
|
-
.low, .cline-no { background:#FCE1E5 }
|
|
162
|
-
/* light green */
|
|
163
|
-
.high, .cline-yes { background:rgb(230,245,208) }
|
|
164
|
-
/* medium green */
|
|
165
|
-
.cstat-yes { background:rgb(161,215,106) }
|
|
166
|
-
/* dark green */
|
|
167
|
-
.status-line.high, .high .cover-fill { background:rgb(77,146,33) }
|
|
168
|
-
.high .chart { border:1px solid rgb(77,146,33) }
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
.medium .chart { border:1px solid #666; }
|
|
172
|
-
.medium .cover-fill { background: #666; }
|
|
173
|
-
|
|
174
|
-
.cbranch-no { background: yellow !important; color: #111; }
|
|
175
|
-
|
|
176
|
-
.cstat-skip { background: #ddd; color: #111; }
|
|
177
|
-
.fstat-skip { background: #ddd; color: #111 !important; }
|
|
178
|
-
.cbranch-skip { background: #ddd !important; color: #111; }
|
|
179
|
-
|
|
180
|
-
span.cline-neutral { background: #eaeaea; }
|
|
181
|
-
.medium { background: #eaeaea; }
|
|
182
|
-
|
|
183
|
-
.cover-fill, .cover-empty {
|
|
184
|
-
display:inline-block;
|
|
185
|
-
height: 12px;
|
|
186
|
-
}
|
|
187
|
-
.chart {
|
|
188
|
-
line-height: 0;
|
|
189
|
-
}
|
|
190
|
-
.cover-empty {
|
|
191
|
-
background: white;
|
|
192
|
-
}
|
|
193
|
-
.cover-full {
|
|
194
|
-
border-right: none !important;
|
|
195
|
-
}
|
|
196
|
-
pre.prettyprint {
|
|
197
|
-
border: none !important;
|
|
198
|
-
padding: 0 !important;
|
|
199
|
-
margin: 0 !important;
|
|
200
|
-
}
|
|
201
|
-
.com { color: #999 !important; }
|
|
202
|
-
.ignore-none { color: #999; font-weight: normal; }
|
|
203
|
-
|
|
204
|
-
.wrapper {
|
|
205
|
-
min-height: 100%;
|
|
206
|
-
height: auto !important;
|
|
207
|
-
height: 100%;
|
|
208
|
-
margin: 0 auto -48px;
|
|
209
|
-
}
|
|
210
|
-
.footer, .push {
|
|
211
|
-
height: 48px;
|
|
212
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<title>Code coverage report for All files</title>
|
|
5
|
-
<meta charset="utf-8" />
|
|
6
|
-
<link rel="stylesheet" href="prettify.css" />
|
|
7
|
-
<link rel="stylesheet" href="base.css" />
|
|
8
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
9
|
-
<style type='text/css'>
|
|
10
|
-
.coverage-summary .sorter {
|
|
11
|
-
background-image: url(sort-arrow-sprite.png);
|
|
12
|
-
}
|
|
13
|
-
</style>
|
|
14
|
-
</head>
|
|
15
|
-
<body>
|
|
16
|
-
<div class='wrapper'>
|
|
17
|
-
<div class='pad1'>
|
|
18
|
-
<h1>
|
|
19
|
-
All files
|
|
20
|
-
</h1>
|
|
21
|
-
<div class='clearfix'>
|
|
22
|
-
</div>
|
|
23
|
-
</div>
|
|
24
|
-
<div class='status-line medium'></div>
|
|
25
|
-
<div class="pad1">
|
|
26
|
-
<table class="coverage-summary">
|
|
27
|
-
<thead>
|
|
28
|
-
<tr>
|
|
29
|
-
<th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
|
|
30
|
-
<th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
|
|
31
|
-
<th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
|
|
32
|
-
<th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
|
|
33
|
-
<th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
|
|
34
|
-
<th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
|
|
35
|
-
<th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
|
|
36
|
-
<th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
|
|
37
|
-
<th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
|
|
38
|
-
<th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
|
|
39
|
-
</tr>
|
|
40
|
-
</thead>
|
|
41
|
-
<tbody></tbody>
|
|
42
|
-
</table>
|
|
43
|
-
</div><div class='push'></div><!-- for sticky footer -->
|
|
44
|
-
</div><!-- /wrapper -->
|
|
45
|
-
<div class='footer quiet pad2 space-top1 center small'>
|
|
46
|
-
Code coverage
|
|
47
|
-
generated by <a href="https://istanbul.js.org/" target="_blank">istanbul</a> at Sun Feb 05 2023 10:15:50 GMT+0200 (Israel Standard Time)
|
|
48
|
-
</div>
|
|
49
|
-
</div>
|
|
50
|
-
<script src="prettify.js"></script>
|
|
51
|
-
<script>
|
|
52
|
-
window.onload = function () {
|
|
53
|
-
if (typeof prettyPrint === 'function') {
|
|
54
|
-
prettyPrint();
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
</script>
|
|
58
|
-
<script src="sorter.js"></script>
|
|
59
|
-
</body>
|
|
60
|
-
</html>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V<U;++V){var ae=Z[V];if(ae.ignoreCase){ac=true}else{if(/[a-z]/i.test(ae.source.replace(/\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi,""))){S=true;ac=false;break}}}var Y={b:8,t:9,n:10,v:11,f:12,r:13};function ab(ah){var ag=ah.charCodeAt(0);if(ag!==92){return ag}var af=ah.charAt(1);ag=Y[af];if(ag){return ag}else{if("0"<=af&&af<="7"){return parseInt(ah.substring(1),8)}else{if(af==="u"||af==="x"){return parseInt(ah.substring(2),16)}else{return ah.charCodeAt(1)}}}}function T(af){if(af<32){return(af<16?"\\x0":"\\x")+af.toString(16)}var ag=String.fromCharCode(af);if(ag==="\\"||ag==="-"||ag==="["||ag==="]"){ag="\\"+ag}return ag}function X(am){var aq=am.substring(1,am.length-1).match(new RegExp("\\\\u[0-9A-Fa-f]{4}|\\\\x[0-9A-Fa-f]{2}|\\\\[0-3][0-7]{0,2}|\\\\[0-7]{1,2}|\\\\[\\s\\S]|-|[^-\\\\]","g"));var ak=[];var af=[];var ao=aq[0]==="^";for(var ar=ao?1:0,aj=aq.length;ar<aj;++ar){var ah=aq[ar];if(/\\[bdsw]/i.test(ah)){ak.push(ah)}else{var ag=ab(ah);var al;if(ar+2<aj&&"-"===aq[ar+1]){al=ab(aq[ar+2]);ar+=2}else{al=ag}af.push([ag,al]);if(!(al<65||ag>122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;ar<af.length;++ar){var at=af[ar];if(at[0]<=ap[1]+1){ap[1]=Math.max(ap[1],at[1])}else{ai.push(ap=at)}}var an=["["];if(ao){an.push("^")}an.push.apply(an,ak);for(var ar=0;ar<ai.length;++ar){var at=ai[ar];an.push(T(at[0]));if(at[1]>at[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak<ah;++ak){var ag=aj[ak];if(ag==="("){++am}else{if("\\"===ag.charAt(0)){var af=+ag.substring(1);if(af&&af<=am){an[af]=-1}}}}for(var ak=1;ak<an.length;++ak){if(-1===an[ak]){an[ak]=++ad}}for(var ak=0,am=0;ak<ah;++ak){var ag=aj[ak];if(ag==="("){++am;if(an[am]===undefined){aj[ak]="(?:"}}else{if("\\"===ag.charAt(0)){var af=+ag.substring(1);if(af&&af<=am){aj[ak]="\\"+an[am]}}}}for(var ak=0,am=0;ak<ah;++ak){if("^"===aj[ak]&&"^"!==aj[ak+1]){aj[ak]=""}}if(al.ignoreCase&&S){for(var ak=0;ak<ah;++ak){var ag=aj[ak];var ai=ag.charAt(0);if(ag.length>=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V<U;++V){var ae=Z[V];if(ae.global||ae.multiline){throw new Error(""+ae)}aa.push("(?:"+W(ae)+")")}return new RegExp(aa.join("|"),ac?"gi":"g")}function a(V){var U=/(?:^|\s)nocode(?:\s|$)/;var X=[];var T=0;var Z=[];var W=0;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=document.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Y=S&&"pre"===S.substring(0,3);function aa(ab){switch(ab.nodeType){case 1:if(U.test(ab.className)){return}for(var ae=ab.firstChild;ae;ae=ae.nextSibling){aa(ae)}var ad=ab.nodeName;if("BR"===ad||"LI"===ad){X[W]="\n";Z[W<<1]=T++;Z[(W++<<1)|1]=ab}break;case 3:case 4:var ac=ab.nodeValue;if(ac.length){if(!Y){ac=ac.replace(/[ \t\r\n]+/g," ")}else{ac=ac.replace(/\r\n?/g,"\n")}X[W]=ac;Z[W<<1]=T;T+=ac.length;Z[(W++<<1)|1]=ab}break}}aa(V);return{sourceCode:X.join("").replace(/\n$/,""),spans:Z}}function B(S,U,W,T){if(!U){return}var V={sourceCode:U,basePos:S};W(V);T.push.apply(T,V.decorations)}var v=/\S/;function o(S){var V=undefined;for(var U=S.firstChild;U;U=U.nextSibling){var T=U.nodeType;V=(T===1)?(V?S:U):(T===3)?(v.test(U.nodeValue)?S:V):V}return V===S?undefined:V}function g(U,T){var S={};var V;(function(){var ad=U.concat(T);var ah=[];var ag={};for(var ab=0,Z=ad.length;ab<Z;++ab){var Y=ad[ab];var ac=Y[3];if(ac){for(var ae=ac.length;--ae>=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae<aq;++ae){var ag=an[ae];var ap=aj[ag];var ai=void 0;var am;if(typeof ap==="string"){am=false}else{var aa=S[ag.charAt(0)];if(aa){ai=ag.match(aa[1]);ap=aa[0]}else{for(var ao=0;ao<X;++ao){aa=T[ao];ai=ag.match(aa[1]);if(ai){ap=aa[0];break}}if(!ai){ap=F}}am=ap.length>=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y<W.length;++Y){ae(W[Y])}if(ag===(ag|0)){W[0].setAttribute("value",ag)}var aa=ac.createElement("OL");aa.className="linenums";var X=Math.max(0,((ag-1))|0)||0;for(var Y=0,T=W.length;Y<T;++Y){af=W[Y];af.className="L"+((Y+X)%10);if(!af.firstChild){af.appendChild(ac.createTextNode("\xA0"))}aa.appendChild(af)}V.appendChild(aa)}function D(ac){var aj=/\bMSIE\b/.test(navigator.userAgent);var am=/\n/g;var al=ac.sourceCode;var an=al.length;var V=0;var aa=ac.spans;var T=aa.length;var ah=0;var X=ac.decorations;var Y=X.length;var Z=0;X[Y]=an;var ar,aq;for(aq=ar=0;aq<Y;){if(X[aq]!==X[aq+2]){X[ar++]=X[aq++];X[ar++]=X[aq++]}else{aq+=2}}Y=ar;for(aq=ar=0;aq<Y;){var at=X[aq];var ab=X[aq+1];var W=aq+2;while(W+2<=Y&&X[W+1]===ab){W+=2}X[ar++]=at;X[ar++]=ab;aq=W}Y=X.length=ar;var ae=null;while(ah<T){var af=aa[ah];var S=aa[ah+2]||an;var ag=X[Z];var ap=X[Z+2]||an;var W=Math.min(S,ap);var ak=aa[ah+1];var U;if(ak.nodeType!==1&&(U=al.substring(V,W))){if(aj){U=U.replace(am,"\r")}ak.nodeValue=U;var ai=ak.ownerDocument;var ao=ai.createElement("SPAN");ao.className=X[Z+1];var ad=ak.parentNode;ad.replaceChild(ao,ak);ao.appendChild(ak);if(V<S){aa[ah+1]=ak=ai.createTextNode(al.substring(W,S));ad.insertBefore(ak,ao.nextSibling)}}V=W;if(V>=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*</.test(S)?"default-markup":"default-code"}return t[T]}c(K,["default-code"]);c(g([],[[F,/^[^<?]+/],[E,/^<!\w[^>]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa<ac.length;++aa){for(var Z=0,V=ac[aa].length;Z<V;++Z){T.push(ac[aa][Z])}}ac=null;var W=Date;if(!W.now){W={now:function(){return +(new Date)}}}var X=0;var S;var ab=/\blang(?:uage)?-([\w.]+)(?!\S)/;var ae=/\bprettyprint\b/;function U(){var ag=(window.PR_SHOULD_USE_CONTINUATION?W.now()+250:Infinity);for(;X<T.length&&W.now()<ag;X++){var aj=T[X];var ai=aj.className;if(ai.indexOf("prettyprint")>=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X<T.length){setTimeout(U,250)}else{if(ad){ad()}}}U()}window.prettyPrintOne=y;window.prettyPrint=b;window.PR={createSimpleLexer:g,registerLangHandler:c,sourceDecorator:i,PR_ATTRIB_NAME:P,PR_ATTRIB_VALUE:n,PR_COMMENT:j,PR_DECLARATION:E,PR_KEYWORD:z,PR_LITERAL:G,PR_NOCODE:N,PR_PLAIN:F,PR_PUNCTUATION:L,PR_SOURCE:J,PR_STRING:C,PR_TAG:m,PR_TYPE:O}})();PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_DECLARATION,/^<!\w[^>]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^<script\b[^>]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:<!--|-->)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]);
|
|
Binary file
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
var addSorting = (function () {
|
|
2
|
-
"use strict";
|
|
3
|
-
var cols,
|
|
4
|
-
currentSort = {
|
|
5
|
-
index: 0,
|
|
6
|
-
desc: false
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
// returns the summary table element
|
|
10
|
-
function getTable() { return document.querySelector('.coverage-summary'); }
|
|
11
|
-
// returns the thead element of the summary table
|
|
12
|
-
function getTableHeader() { return getTable().querySelector('thead tr'); }
|
|
13
|
-
// returns the tbody element of the summary table
|
|
14
|
-
function getTableBody() { return getTable().querySelector('tbody'); }
|
|
15
|
-
// returns the th element for nth column
|
|
16
|
-
function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; }
|
|
17
|
-
|
|
18
|
-
// loads all columns
|
|
19
|
-
function loadColumns() {
|
|
20
|
-
var colNodes = getTableHeader().querySelectorAll('th'),
|
|
21
|
-
colNode,
|
|
22
|
-
cols = [],
|
|
23
|
-
col,
|
|
24
|
-
i;
|
|
25
|
-
|
|
26
|
-
for (i = 0; i < colNodes.length; i += 1) {
|
|
27
|
-
colNode = colNodes[i];
|
|
28
|
-
col = {
|
|
29
|
-
key: colNode.getAttribute('data-col'),
|
|
30
|
-
sortable: !colNode.getAttribute('data-nosort'),
|
|
31
|
-
type: colNode.getAttribute('data-type') || 'string'
|
|
32
|
-
};
|
|
33
|
-
cols.push(col);
|
|
34
|
-
if (col.sortable) {
|
|
35
|
-
col.defaultDescSort = col.type === 'number';
|
|
36
|
-
colNode.innerHTML = colNode.innerHTML + '<span class="sorter"></span>';
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return cols;
|
|
40
|
-
}
|
|
41
|
-
// attaches a data attribute to every tr element with an object
|
|
42
|
-
// of data values keyed by column name
|
|
43
|
-
function loadRowData(tableRow) {
|
|
44
|
-
var tableCols = tableRow.querySelectorAll('td'),
|
|
45
|
-
colNode,
|
|
46
|
-
col,
|
|
47
|
-
data = {},
|
|
48
|
-
i,
|
|
49
|
-
val;
|
|
50
|
-
for (i = 0; i < tableCols.length; i += 1) {
|
|
51
|
-
colNode = tableCols[i];
|
|
52
|
-
col = cols[i];
|
|
53
|
-
val = colNode.getAttribute('data-value');
|
|
54
|
-
if (col.type === 'number') {
|
|
55
|
-
val = Number(val);
|
|
56
|
-
}
|
|
57
|
-
data[col.key] = val;
|
|
58
|
-
}
|
|
59
|
-
return data;
|
|
60
|
-
}
|
|
61
|
-
// loads all row data
|
|
62
|
-
function loadData() {
|
|
63
|
-
var rows = getTableBody().querySelectorAll('tr'),
|
|
64
|
-
i;
|
|
65
|
-
|
|
66
|
-
for (i = 0; i < rows.length; i += 1) {
|
|
67
|
-
rows[i].data = loadRowData(rows[i]);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
// sorts the table using the data for the ith column
|
|
71
|
-
function sortByIndex(index, desc) {
|
|
72
|
-
var key = cols[index].key,
|
|
73
|
-
sorter = function (a, b) {
|
|
74
|
-
a = a.data[key];
|
|
75
|
-
b = b.data[key];
|
|
76
|
-
return a < b ? -1 : a > b ? 1 : 0;
|
|
77
|
-
},
|
|
78
|
-
finalSorter = sorter,
|
|
79
|
-
tableBody = document.querySelector('.coverage-summary tbody'),
|
|
80
|
-
rowNodes = tableBody.querySelectorAll('tr'),
|
|
81
|
-
rows = [],
|
|
82
|
-
i;
|
|
83
|
-
|
|
84
|
-
if (desc) {
|
|
85
|
-
finalSorter = function (a, b) {
|
|
86
|
-
return -1 * sorter(a, b);
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
for (i = 0; i < rowNodes.length; i += 1) {
|
|
91
|
-
rows.push(rowNodes[i]);
|
|
92
|
-
tableBody.removeChild(rowNodes[i]);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
rows.sort(finalSorter);
|
|
96
|
-
|
|
97
|
-
for (i = 0; i < rows.length; i += 1) {
|
|
98
|
-
tableBody.appendChild(rows[i]);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
// removes sort indicators for current column being sorted
|
|
102
|
-
function removeSortIndicators() {
|
|
103
|
-
var col = getNthColumn(currentSort.index),
|
|
104
|
-
cls = col.className;
|
|
105
|
-
|
|
106
|
-
cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
|
|
107
|
-
col.className = cls;
|
|
108
|
-
}
|
|
109
|
-
// adds sort indicators for current column being sorted
|
|
110
|
-
function addSortIndicators() {
|
|
111
|
-
getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted';
|
|
112
|
-
}
|
|
113
|
-
// adds event listeners for all sorter widgets
|
|
114
|
-
function enableUI() {
|
|
115
|
-
var i,
|
|
116
|
-
el,
|
|
117
|
-
ithSorter = function ithSorter(i) {
|
|
118
|
-
var col = cols[i];
|
|
119
|
-
|
|
120
|
-
return function () {
|
|
121
|
-
var desc = col.defaultDescSort;
|
|
122
|
-
|
|
123
|
-
if (currentSort.index === i) {
|
|
124
|
-
desc = !currentSort.desc;
|
|
125
|
-
}
|
|
126
|
-
sortByIndex(i, desc);
|
|
127
|
-
removeSortIndicators();
|
|
128
|
-
currentSort.index = i;
|
|
129
|
-
currentSort.desc = desc;
|
|
130
|
-
addSortIndicators();
|
|
131
|
-
};
|
|
132
|
-
};
|
|
133
|
-
for (i =0 ; i < cols.length; i += 1) {
|
|
134
|
-
if (cols[i].sortable) {
|
|
135
|
-
// add the click event handler on the th so users
|
|
136
|
-
// dont have to click on those tiny arrows
|
|
137
|
-
el = getNthColumn(i).querySelector('.sorter').parentElement;
|
|
138
|
-
if (el.addEventListener) {
|
|
139
|
-
el.addEventListener('click', ithSorter(i));
|
|
140
|
-
} else {
|
|
141
|
-
el.attachEvent('onclick', ithSorter(i));
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
// adds sorting functionality to the UI
|
|
147
|
-
return function () {
|
|
148
|
-
if (!getTable()) {
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
cols = loadColumns();
|
|
152
|
-
loadData(cols);
|
|
153
|
-
addSortIndicators();
|
|
154
|
-
enableUI();
|
|
155
|
-
};
|
|
156
|
-
})();
|
|
157
|
-
|
|
158
|
-
window.addEventListener('load', addSorting);
|
package/coverage/lcov.info
DELETED
|
File without changes
|