├── .editorconfig
├── .eslintrc.json
├── .gitignore
├── .prettierignore
├── .travis.yml
├── README.md
├── angular.json
├── integration
├── app
│ ├── browserslist
│ ├── environments
│ │ ├── environment.prod.ts
│ │ └── environment.ts
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ ├── polyfills.ts
│ ├── src
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.ts
│ │ └── app.module.ts
│ ├── styles.css
│ ├── tsconfig.app.json
│ └── tsconfig.spec.json
└── tests
│ ├── autobind.spec.ts
│ ├── clipboard.spec.ts
│ ├── console-format-api.spec.ts
│ ├── console-group-api.spec.ts
│ ├── console.spec.ts
│ ├── css-parcer.spec.ts
│ ├── decorators.spec.ts
│ ├── helpers
│ ├── console-fake.ts
│ ├── custom-colors.enum.ts
│ └── test.component.ts
│ ├── injector.spec.ts
│ ├── json.spec.ts
│ ├── logger.module.spec.ts
│ ├── setupJest.ts
│ └── tsconfig.spec.json
├── jest.config.js
├── lib
├── ng-package.json
├── package.json
├── src
│ ├── decorators
│ │ ├── autobind.decorator.ts
│ │ ├── debug.decorator.ts
│ │ ├── error.decorator.ts
│ │ ├── groups
│ │ │ ├── group-collapsed.decorator.ts
│ │ │ ├── group.common.ts
│ │ │ └── group.decorator.ts
│ │ ├── info.decorator.ts
│ │ ├── log.decorator.ts
│ │ ├── logger.decorator.ts
│ │ ├── timer.decorator.ts
│ │ ├── trace.decorator.ts
│ │ └── warn.decorator.ts
│ ├── interfaces
│ │ ├── logger.external.ts
│ │ └── logger.internal.ts
│ ├── logger.config.ts
│ ├── logger.injector.ts
│ ├── logger.module.ts
│ ├── logger.options.ts
│ ├── logger.service.ts
│ ├── public-api.ts
│ └── services
│ │ ├── clipboard-factory.service.ts
│ │ ├── console.service.ts
│ │ ├── css-factory.service.ts
│ │ ├── factory.service.ts
│ │ ├── group-factory.service.ts
│ │ ├── json-factory.service.ts
│ │ └── timer-factory.service.ts
└── tsconfig.lib.json
├── ngx-logger.iml
├── package.json
├── renovate.json
├── tsconfig.json
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_size = 4
7 | end_of_line = lf
8 | indent_style = space
9 | max_line_length = 120
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
12 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@angular-ru/eslint-config"
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 | *.iml
3 |
4 | # compiled output
5 | /dist
6 | /tmp
7 | /out-tsc
8 | # Only exists if Bazel was run
9 | /bazel-out
10 | /.cache
11 |
12 | # dependencies
13 | node_modules/
14 |
15 | # profiling files
16 | chrome-profiler-events.json
17 | speed-measure-plugin.json
18 |
19 | # IDEs and editors
20 | /.idea
21 | .project
22 | .classpath
23 | .c9/
24 | *.launch
25 | .settings/
26 | *.sublime-workspace
27 |
28 | # IDE - VSCode
29 | .vscode/*
30 | !.vscode/settings.json
31 | !.vscode/tasks.json
32 | !.vscode/launch.json
33 | !.vscode/extensions.json
34 | .history/*
35 |
36 | # misc
37 | /.sass-cache
38 | /connect.lock
39 | /coverage
40 | /libpeerconnection.log
41 | npm-debug.log
42 | yarn-error.log
43 | testem.log
44 | /typings
45 |
46 | # System Files
47 | .DS_Store
48 | Thumbs.db
49 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | .idea/**
2 | .cache/**
3 | coverage/**
4 | **/node_modules/**
5 | dist/**
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 |
2 | language: node_js
3 | sudo: false
4 | node_js:
5 | - "12.3.1"
6 | install:
7 | - npm install
8 | script:
9 | - npm run lint
10 | - npm test
11 | - npm run build:lib
12 | - npm run build:app
13 | after_success:
14 | - npm run coverage
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Angular Logger
2 |
3 | > Lightweight and configurable Angular logger
4 |
5 | [](https://travis-ci.org/Angular-RU/angular-logger)
6 | [](https://badge.fury.io/js/%40angular-ru%2Flogger)
7 | [](https://coveralls.io/github/Angular-RU/angular-logger?branch=develop)
8 | [](https://npm-stat.com/charts.html?package=@angular-ru/logger&from=2017-01-12)
9 |
10 | ```typescript
11 | import { LoggerModule } from '@angular-ru/logger';
12 | ...
13 |
14 | @NgModule({
15 | imports: [
16 | LoggerModule.forRoot()
17 | ],
18 | ...
19 | })
20 | export class AppModule {}
21 | ```
22 |
23 | ## Motivation
24 |
25 | This logger is a handy tool that can be useful in the design and development of the enterprise application level. Easy
26 | setting of logging levels and convenient work with groups. Among other things, you can use meta programming
27 | (decorators).
28 |
29 | ## Table of contents
30 |
31 | - [Logging](#)
32 | - [Basic usage API `trace`, `debug`, `info`, `warn`, `error`](#example-basic-methods)
33 | - [Groups, `groupCollapsed`, `collapsible`](#example-groups)
34 | - [Nested groups (usage pipe method)](#example-nested-groups)
35 | - [Set logging level (worked in single or groups)](#example-set-minimal-logging-level)
36 | - [Customization style line](#example-set-style-line)
37 | - [Customization global style line](#example-set-global-style-line)
38 | - [Add css classes](#example-css-classes)
39 | - [Output pretty json `stringify`](#example-pretty-json)
40 | - [Copy `json, object, text` to clipboard](#example-clipboard)
41 | - [Basic decorators](#example-decorators)
42 | - [Decorator groups](#example-decorator-groups)
43 | - [Decorator groups with function title](#example-decorator-group-with-function-title)
44 | - [Configuration `Angular Logger`](#example-full-configurations)
45 |
46 | * [Todo](#todo)
47 |
48 | ## Logging
49 |
50 | ```
51 | $ npm install @angular-ru/logger --save
52 | ```
53 |
54 | ```typescript
55 | import { LoggerModule } from '@angular-ru/logger';
56 | ...
57 |
58 | @NgModule({
59 | imports: [
60 | LoggerModule.forRoot()
61 | ],
62 | ...
63 | })
64 | export class AppModule {}
65 | ```
66 |
67 | **Online examples**: https://stackblitz.com/github/Angular-RU/ng-logger
68 |
69 | 
70 |
71 | ### Example: basic methods
72 |
73 | ```typescript
74 | import { LoggerService } from '@angular-ru/logger';
75 |
76 | export class AppComponent implements OnInit {
77 | constructor(private readonly logger: LoggerService) {}
78 |
79 | public ngOnInit(): void {
80 | this.logger.trace('trace is worked', 1, { a: 1 });
81 | this.logger.debug('debug is worked', 2, {});
82 | this.logger.info('info is worked', 3, Object);
83 | this.logger.warn('warn is worked', 4, String);
84 | this.logger.error('error is worked', 5, (2.55).toFixed());
85 | }
86 | }
87 | ```
88 |
89 | - **Default level: All**
90 |
91 | 
92 |
93 | - **Disable trace on console (filter):**
94 |
95 | ```typescript
96 | import { LoggerService } from '@angular-ru/logger';
97 |
98 | export class AppComponent implements OnInit {
99 | private readonly traceIsWork: string = 'trace is worked';
100 | constructor(private readonly logger: LoggerService) {}
101 |
102 | public ngOnInit(): void {
103 | this.logger.group('Show trace in opened group', ({ trace }: LoggerService): void => {
104 | for (let i: number = 0; i < 20; i++) {
105 | trace(this.traceIsWork, i);
106 | }
107 | });
108 | }
109 | }
110 | ```
111 |
112 | ### Example: groups
113 |
114 | - **Logger groups with auto closed (usage callback):**
115 |
116 | ```typescript
117 | import { LoggerService } from '@angular-ru/logger';
118 |
119 | export class AppComponent implements OnInit {
120 | private readonly traceIsWork: string = 'trace is worked';
121 | private readonly debugIsWork: string = 'debug is worked';
122 | private readonly infoIsWork: string = 'info is worked';
123 | private readonly warnIsWork: string = 'warn is worked';
124 | private readonly errorIsWork: string = 'error is worked';
125 |
126 | constructor(private readonly logger: LoggerService) {}
127 |
128 | public ngOnInit(): void {
129 | this.logger.groupCollapsed('EXAMPLE 2: show stack', () => {
130 | this.logger.trace(this.traceIsWork, 1, { a: 1 });
131 | this.logger.debug(this.debugIsWork, 2, console);
132 | this.logger.info(this.infoIsWork, 3, Object);
133 | this.logger.warn(this.warnIsWork, 4, String);
134 | this.logger.error(this.errorIsWork, 5, (2.55).toFixed());
135 | });
136 |
137 | this.logger.group('Show trace in opened group', ({ trace }: LoggerService): void => {
138 | for (let i: number = 0; i < 20; i++) {
139 | trace(this.traceIsWork, i);
140 | }
141 | });
142 |
143 | this.logger.groupCollapsed('Show trace in collapsed group', ({ debug }: LoggerService): void => {
144 | for (let i: number = 0; i < 15; i++) {
145 | debug(this.traceIsWork, i);
146 | }
147 | });
148 | }
149 | }
150 | ```
151 |
152 | 
153 |
154 | ### Example: nested groups
155 |
156 | - **Logger nested groups (with pipe):**
157 |
158 | ```typescript
159 | import { LoggerService } from '@angular-ru/logger';
160 |
161 | export class AppComponent implements OnInit {
162 | private readonly traceIsWork: string = 'trace is worked';
163 | private readonly debugIsWork: string = 'debug is worked';
164 | private readonly infoIsWork: string = 'info is worked';
165 | private readonly warnIsWork: string = 'warn is worked';
166 | private readonly errorIsWork: string = 'error is worked';
167 |
168 | constructor(private readonly logger: LoggerService) {}
169 |
170 | public ngOnInit(): void {
171 | this.logger
172 | .groupCollapsed('GROUP TEST')
173 | .pipe(({ trace, debug, info, warn, error }: LoggerService) => {
174 | trace(this.traceIsWork);
175 | debug(this.debugIsWork);
176 | info(this.infoIsWork);
177 | warn(this.warnIsWork);
178 | error(this.errorIsWork);
179 | })
180 | .close();
181 |
182 | this.logger
183 | .group('A')
184 | .pipe(
185 | ({ trace }: LoggerService) => trace(this.traceIsWork),
186 | ({ debug }: LoggerService) => debug(this.debugIsWork),
187 | ({ info }: LoggerService) => info(this.infoIsWork),
188 | ({ warn }: LoggerService) => warn(this.warnIsWork),
189 | ({ error }: LoggerService) => error(this.errorIsWork)
190 | )
191 | .groupCollapsed('B')
192 | .pipe(
193 | ({ trace }: LoggerService) => trace(this.traceIsWork),
194 | ({ debug }: LoggerService) => debug(this.debugIsWork),
195 | ({ info }: LoggerService) => info(this.infoIsWork),
196 | ({ warn }: LoggerService) => warn(this.warnIsWork),
197 | ({ error }: LoggerService) => error(this.errorIsWork)
198 | )
199 | .group('C')
200 | .pipe(
201 | ({ trace }: LoggerService) => trace(this.traceIsWork),
202 | ({ debug }: LoggerService) => debug(this.debugIsWork),
203 | ({ info }: LoggerService) => info(this.infoIsWork),
204 | ({ warn }: LoggerService) => warn(this.warnIsWork),
205 | ({ error }: LoggerService) => error(this.errorIsWork)
206 | )
207 | .closeAll();
208 | }
209 | }
210 | ```
211 |
212 | 
213 |
214 | ### Example: set minimal logging level
215 |
216 | Basic parameterization
217 |
218 | ```typescript
219 | import { LoggerService } from '@angular-ru/logger';
220 |
221 | export class AppComponent implements OnInit {
222 | private readonly traceIsWork: string = 'trace is worked';
223 | private readonly debugIsWork: string = 'debug is worked';
224 | private readonly infoIsWork: string = 'info is worked';
225 | private readonly warnIsWork: string = 'warn is worked';
226 | private readonly errorIsWork: string = 'error is worked';
227 |
228 | constructor(private readonly logger: LoggerService) {}
229 |
230 | public ngOnInit(): void {
231 | this.logger.trace(this.traceIsWork, 1, { a: 1 });
232 | this.logger.debug(this.debugIsWork, 2, console);
233 | this.logger.info(this.infoIsWork, 3, Object);
234 | this.logger.warn(this.warnIsWork, 4, String);
235 | this.logger.error(this.errorIsWork, 5, (2.55).toFixed());
236 |
237 | this.logger.level = LoggerLevel.INFO;
238 | this.logger.log('Set new logger level');
239 |
240 | this.logger.trace(this.traceIsWork, 1, { a: 1 });
241 | this.logger.debug(this.debugIsWork, 2, console);
242 | this.logger.info(this.infoIsWork, 3, Object);
243 | this.logger.warn(this.warnIsWork, 4, String);
244 | this.logger.error(this.errorIsWork, 5, (2.55).toFixed());
245 | }
246 | }
247 | ```
248 |
249 | 
250 |
251 | - **Logger level groups (pretty usage API):**
252 |
253 | ```typescript
254 | import { LoggerService, LoggerLevel } from '@angular-ru/logger';
255 |
256 | export class AppComponent implements OnInit {
257 | private readonly traceIsWork: string = 'trace is worked';
258 | private readonly debugIsWork: string = 'debug is worked';
259 | private readonly infoIsWork: string = 'info is worked';
260 | private readonly warnIsWork: string = 'warn is worked';
261 | private readonly errorIsWork: string = 'error is worked';
262 |
263 | constructor(private readonly logger: LoggerService) {}
264 |
265 | public ngOnInit(): void {
266 | this.logger.level = LoggerLevel.INFO;
267 |
268 | this.logger.trace
269 | .group('A')
270 | .pipe(
271 | ({ trace }: LoggerService) => trace(this.traceIsWork),
272 | ({ debug }: LoggerService) => debug(this.debugIsWork),
273 | ({ info }: LoggerService) => info(this.infoIsWork),
274 | ({ warn }: LoggerService) => warn(this.warnIsWork),
275 | ({ error }: LoggerService) => error(this.errorIsWork)
276 | )
277 | .close()
278 |
279 | .debug.group('B')
280 | .pipe(
281 | ({ trace }: LoggerService) => trace(this.traceIsWork),
282 | ({ debug }: LoggerService) => debug(this.debugIsWork),
283 | ({ info }: LoggerService) => info(this.infoIsWork),
284 | ({ warn }: LoggerService) => warn(this.warnIsWork),
285 | ({ error }: LoggerService) => error(this.errorIsWork)
286 | )
287 | .close()
288 |
289 | .info.group('C')
290 | .pipe(
291 | ({ trace }: LoggerService) => trace(this.traceIsWork),
292 | ({ debug }: LoggerService) => debug(this.debugIsWork),
293 | ({ info }: LoggerService) => info(this.infoIsWork),
294 | ({ warn }: LoggerService) => warn(this.warnIsWork),
295 | ({ error }: LoggerService) => error(this.errorIsWork)
296 | )
297 | .close()
298 |
299 | .warn.group('D')
300 | .pipe(
301 | ({ trace }: LoggerService) => trace(this.traceIsWork),
302 | ({ debug }: LoggerService) => debug(this.debugIsWork),
303 | ({ info }: LoggerService) => info(this.infoIsWork),
304 | ({ warn }: LoggerService) => warn(this.warnIsWork),
305 | ({ error }: LoggerService) => error(this.errorIsWork)
306 | )
307 | .close()
308 |
309 | .error.group('E')
310 | .pipe(
311 | ({ trace }: LoggerService) => trace(this.traceIsWork),
312 | ({ debug }: LoggerService) => debug(this.debugIsWork),
313 | ({ info }: LoggerService) => info(this.infoIsWork),
314 | ({ warn }: LoggerService) => warn(this.warnIsWork),
315 | ({ error }: LoggerService) => error(this.errorIsWork)
316 | )
317 | .close();
318 |
319 | this.logger.level = LoggerLevel.ALL;
320 | }
321 | }
322 | ```
323 |
324 | 
325 |
326 | ### Example: set style line
327 |
328 | ```typescript
329 | import { LoggerService } from '@angular-ru/logger';
330 |
331 | export class AppComponent implements OnInit {
332 | constructor(private readonly logger: LoggerService) {}
333 |
334 | public ngOnInit(): void {
335 | this.logger.clear();
336 |
337 | this.logger.css('text-transform: uppercase; font-weight: bold').debug('window current ', window);
338 | this.logger.css('color: red; text-decoration: underline; font-weight: bold').info('It is awesome logger');
339 | this.logger.debug({ a: 1 });
340 |
341 | this.logger.warn(setStyle);
342 | this.logger.info('For global configuration, use the constructor parameters');
343 | }
344 | }
345 | ```
346 |
347 | 
348 |
349 | ### Example: set global style line
350 |
351 | ```typescript
352 | import { LoggerService } from '@angular-ru/logger';
353 |
354 | export class AppComponent implements OnInit {
355 | constructor(private readonly logger: LoggerService) {}
356 |
357 | public ngOnInit(): void {
358 | this.logger.clear();
359 |
360 | this.logger.css('font-weight: normal; text-decoration: none; font-style: italic').info(3.14);
361 | this.logger.css('font-weight: normal;').info(3.14);
362 | this.logger.warn('global format with style!');
363 | }
364 | }
365 | ```
366 |
367 | 
368 |
369 | ### Example: CSS classes
370 |
371 | ```typescript
372 | import { LoggerModule } from '@angular-ru/logger';
373 |
374 | @NgModule({
375 | // ..
376 | imports: [
377 | LoggerModule.forRoot({
378 | cssClassMap: {
379 | bold: 'font-weight: bold',
380 | 'line-through': 'text-decoration: line-through',
381 | 'code-sandbox': `
382 | color: #666;
383 | background: #f4f4f4;
384 | border-left: 3px solid #f36d33;
385 | font-family: monospace;
386 | font-size: 15px;`
387 | }
388 | })
389 | ]
390 | // ..
391 | })
392 | ```
393 |
394 | ```typescript
395 | import { LoggerService } from '@angular-ru/logger';
396 |
397 | export class AppComponent implements OnInit {
398 | constructor(private readonly logger: LoggerService) {}
399 |
400 | public ngOnInit(): void {
401 | this.logger.cssClass('bold line-through').log('JavaScript sucks', 'JavaScript is the best');
402 |
403 | this.logger
404 | .cssClass('code-sandbox')
405 | .log('\n @Component({ .. })' + '\n export class AppComponent { .. } \n\n');
406 |
407 | this.logger.cssClass('bold line-through').debug('JavaScript sucks', 'JavaScript is the best');
408 | }
409 | }
410 | export class AppModule {}
411 | ```
412 |
413 | 
414 |
415 | ### Example: pretty json
416 |
417 | ```typescript
418 | import { LoggerService } from '@angular-ru/logger';
419 |
420 | export class AppComponent implements OnInit {
421 | constructor(private readonly logger: LoggerService) {}
422 |
423 | public ngOnInit(): void {
424 | // default browser print json
425 | this.logger.debug('Classic output json', jsonExample);
426 |
427 | // for pretty json usage logger.log method
428 | this.logger.log(...this.logger.prettyJSON(jsonExample));
429 | }
430 | }
431 | ```
432 |
433 | 
434 |
435 | ### Example: clipboard
436 |
437 | ```typescript
438 | import { LoggerService } from '@angular-ru/logger';
439 |
440 | export class AppComponent implements OnInit {
441 | constructor(private readonly logger: LoggerService) {}
442 |
443 | public ngOnInit(): void {
444 | const example: string = 'test string';
445 | this.logger.log(example);
446 | this.logger.copy(example);
447 | }
448 | }
449 | ```
450 |
451 | 
452 |
453 | ### Example: decorators
454 |
455 | ```typescript
456 | import { LoggerService, Logger, DebugLog, TraceLog, InfoLog, WarnLog, ErrorLog, Log, LogFn } from '@angular-ru/logger';
457 |
458 | export class AppComponent {
459 | @Logger() public logger: LoggerService;
460 | @TraceLog() public trace: LogFn;
461 | @DebugLog() public debug: LogFn;
462 | @InfoLog() public info: LogFn;
463 | @ErrorLog() public error: LogFn;
464 | @WarnLog() public warn: LogFn;
465 | @Log() public log: LogFn;
466 |
467 | private readonly traceIsWork: string = 'trace is worked';
468 | private readonly debugIsWork: string = 'debug is worked';
469 | private readonly infoIsWork: string = 'info is worked';
470 | private readonly warnIsWork: string = 'warn is worked';
471 | private readonly errorIsWork: string = 'error is worked';
472 |
473 | public showExample(): void {
474 | this.logger.clear();
475 | this.logger.log('log is worked');
476 | this.trace(this.traceIsWork, 1, { a: 1 });
477 | this.debug(this.debugIsWork, 2, console);
478 | this.info(this.infoIsWork, 3, Object);
479 | this.warn(this.warnIsWork, 4, String);
480 | this.error(this.errorIsWork, 5, (2.55).toFixed());
481 | }
482 | }
483 | ```
484 |
485 | 
486 |
487 | ### Example: decorator groups
488 |
489 | ```typescript
490 | import { LoggerService, Logger, LoggerLevel, Group } from '@angular-ru/logger';
491 |
492 | export class AppComponent {
493 | @Logger() public logger: LoggerService;
494 |
495 | @Group('test title', LoggerLevel.WARN)
496 | private helloWorld(name: string): string {
497 | this.logger.log('log only in group', name);
498 | return 'hello world';
499 | }
500 |
501 | public showExample11(): void {
502 | this.logger.log(this.helloWorld('Hello'));
503 | }
504 | }
505 | ```
506 |
507 | 
508 |
509 | ### Example: decorator group with function title
510 |
511 | ```typescript
512 | import { Log, LogFn, Group } from '@angular-ru/logger';
513 |
514 | export class AppComponent {
515 | @Log() public log: LogFn;
516 |
517 | @Group((name: string) => `Test group with ${name}`)
518 | public method(name: string): string {
519 | this.log('group is worked');
520 | return name;
521 | }
522 |
523 | public showExample(): void {
524 | this.method('hello world');
525 | }
526 | }
527 | ```
528 |
529 | 
530 |
531 | ### Example: timer decorator
532 |
533 | ```typescript
534 | import { Log, LogFn, TimerLog, LoggerLevel, LoggerService, Logger } from '@angular-ru/logger';
535 | export class AppComponent {
536 | @Log() public log: LogFn;
537 | @Logger() public logger: LoggerService;
538 |
539 | @TimerLog('Test timer')
540 | public showExample(): void {
541 | this.logger.clear();
542 | this.log('test log');
543 | }
544 |
545 | @TimerLog('Advanced timer', LoggerLevel.WARN, false)
546 | public showExample(): void {
547 | this.logger.clear();
548 | this.log('Advanced test log');
549 | }
550 | }
551 | ```
552 |
553 | 
554 |
555 | ### Example: format output
556 |
557 | ```typescript
558 | import { LoggerModule, NgModule, FormatOutput } from '@angular-ru/logger';
559 |
560 | @NgModule({
561 | //..
562 | imports: [
563 | LoggerModule.forRoot({
564 | format(label: string, labelStyle: string): FormatOutput {
565 | const date = new Date().toLocaleString('ru-RU').replace(',', '');
566 | const customLabel: string = `${date} ${label}`;
567 | return { label: customLabel, style: labelStyle };
568 | }
569 | })
570 | ]
571 | })
572 | export class AppModule {}
573 | ```
574 |
575 | ```typescript
576 | import { LoggerService, OnInit } from '@angular-ru/logger';
577 |
578 | export class AppComponent implements OnInit {
579 | constructor(private readonly logger: LoggerService) {}
580 |
581 | public ngOnInit(): void {
582 | this.logger.trace('trace is worked', 1, { a: 1 });
583 | this.logger.debug('debug is worked', 2, {});
584 | this.logger.info('info is worked', 3, Object);
585 | this.logger.warn('warn is worked', 4, String);
586 | this.logger.error('error is worked', 5, (2.55).toFixed());
587 | }
588 | }
589 | ```
590 |
591 | 
592 |
593 | ### Example: full configurations
594 |
595 | ```typescript
596 | import { LoggerModule, NgModule, LoggerLevel } from '@angular-ru/logger';
597 |
598 | @NgModule({
599 | // ..
600 | imports: [
601 | LoggerModule.forRoot({
602 | useLevelGroup: true,
603 | globalLineStyle: 'color: red; text-decoration: underline; font-weight: bold; font-size: 15px',
604 | cssClassMap: {
605 | bold: 'font-weight: bold',
606 | 'line-through': 'text-decoration: line-through',
607 | 'code-sandbox': `
608 | color: #666;
609 | background: #f4f4f4;
610 | border-left: 3px solid #f36d33;
611 | font-family: monospace;
612 | font-size: 15px;`
613 | },
614 | labelNames: {
615 | [LoggerLevel.TRACE]: '[trace]',
616 | [LoggerLevel.DEBUG]: '[debug]',
617 | [LoggerLevel.INFO]: '[info]',
618 | [LoggerLevel.WARN]: '[warn]',
619 | [LoggerLevel.ERROR]: '[error]'
620 | },
621 | labelColors: {
622 | [LoggerLevel.TRACE]: 'violet',
623 | [LoggerLevel.DEBUG]: 'black',
624 | [LoggerLevel.INFO]: 'tomato',
625 | [LoggerLevel.WARN]: 'green',
626 | [LoggerLevel.ERROR]: 'cyan'
627 | }
628 | })
629 | ]
630 | // ..
631 | })
632 | export class AppModule {}
633 | ```
634 |
635 | ```typescript
636 | import { LoggerService } from '@angular-ru/logger';
637 |
638 | export class AppComponent implements OnInit {
639 |
640 | public ngOnInit(): void {
641 | private readonly traceIsWork: string = 'trace is worked';
642 | private readonly debugIsWork: string = 'debug is worked';
643 | private readonly infoIsWork: string = 'info is worked';
644 | private readonly warnIsWork: string = 'warn is worked';
645 | private readonly errorIsWork: string = 'error is worked';
646 |
647 | constructor(private readonly logger: LoggerService) {}
648 |
649 | public showExample(): void {
650 | this.logger.log('Example');
651 | this.logger.trace(this.traceIsWork, 1, { a: 1 });
652 | this.logger.debug(this.debugIsWork, 2, console);
653 | this.logger.info(this.infoIsWork, 3, Object);
654 | this.logger.warn(this.warnIsWork, 4, String);
655 | this.logger.error(this.errorIsWork, 5, (2.55).toFixed());
656 | }
657 | }
658 | ```
659 |
660 | 
661 |
662 | ## Todo
663 |
664 | - [x] Override console
665 | - [x] Logger method (trace, debug, info, warning, error)
666 | - [x] Logger group + groupCollapsible (pipes)
667 | - [x] Logger pretty write object
668 | - [x] Set style by css
669 | - [x] Logger level groups (trace, debug, info, warn, error)
670 | - [x] Clipboard data
671 | - [x] Set global style
672 | - [x] Added css classes
673 | - [x] Dependency Injection for Angular
674 | - [x] Switch enable/disable default console output
675 | - [x] Decorators
676 | - [x] Timers (decorator)
677 | - [x] Format output console
678 |
679 | ## Authors
680 |
681 | [Eleonora Zbarskaya](https://github.com/kingofferelden), [Ivanov Maxim](https://github.com/splincode)
682 |
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "integration": {
7 | "root": "",
8 | "prefix": "",
9 | "sourceRoot": "integration",
10 | "projectType": "application",
11 | "schematics": {},
12 | "architect": {
13 | "build": {
14 | "builder": "@angular-devkit/build-angular:browser",
15 | "options": {
16 | "outputPath": "dist/integration",
17 | "index": "integration/app/index.html",
18 | "main": "integration/app/main.ts",
19 | "polyfills": "integration/app/polyfills.ts",
20 | "tsConfig": "integration/app/tsconfig.app.json",
21 | "assets": ["integration/app/favicon.ico", "integration/app/assets"],
22 | "styles": ["integration/app/styles.css"],
23 | "scripts": [],
24 | "es5BrowserSupport": true
25 | },
26 | "configurations": {
27 | "production": {
28 | "fileReplacements": [
29 | {
30 | "replace": "integration/app/src/environments/environment.ts",
31 | "with": "integration/app/src/environments/environment.prod.ts"
32 | }
33 | ],
34 | "optimization": true,
35 | "outputHashing": "all",
36 | "sourceMap": false,
37 | "extractCss": true,
38 | "namedChunks": false,
39 | "aot": true,
40 | "extractLicenses": true,
41 | "vendorChunk": true,
42 | "buildOptimizer": true,
43 | "budgets": [
44 | {
45 | "type": "initial",
46 | "maximumWarning": "2mb",
47 | "maximumError": "5mb"
48 | }
49 | ]
50 | }
51 | }
52 | },
53 | "serve": {
54 | "builder": "@angular-devkit/build-angular:dev-server",
55 | "options": {
56 | "browserTarget": "integration:build"
57 | },
58 | "configurations": {
59 | "production": {
60 | "browserTarget": "integration:build:production"
61 | }
62 | }
63 | }
64 | }
65 | },
66 | "logger": {
67 | "root": "",
68 | "prefix": "",
69 | "sourceRoot": "",
70 | "projectType": "library",
71 | "architect": {
72 | "build": {
73 | "builder": "@angular-devkit/build-ng-packagr:build",
74 | "options": {
75 | "tsConfig": "lib/tsconfig.lib.json",
76 | "project": "lib/ng-package.json"
77 | }
78 | }
79 | }
80 | }
81 | },
82 | "defaultProject": "logger"
83 | }
84 |
--------------------------------------------------------------------------------
/integration/app/browserslist:
--------------------------------------------------------------------------------
1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
2 | # For additional information regarding the format and rule options, please see:
3 | # https://github.com/browserslist/browserslist#queries
4 | #
5 | # For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
6 |
7 | > 0.5%
8 | last 2 versions
9 | Firefox ESR
10 | not dead
11 | not IE 9-11
--------------------------------------------------------------------------------
/integration/app/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | import { Any } from '../../../lib/src/interfaces/logger.internal';
2 |
3 | export const environment: Any = {
4 | production: true,
5 | useConfig: true
6 | };
7 |
--------------------------------------------------------------------------------
/integration/app/environments/environment.ts:
--------------------------------------------------------------------------------
1 | import { Any } from '../../../lib/src/interfaces/logger.internal';
2 |
3 | export const environment: Any = {
4 | production: false,
5 | useConfig: true
6 | };
7 |
--------------------------------------------------------------------------------
/integration/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Angular-RU/angular-logger/ce0cd7d55d0b9d077132f06d2c899dae544074a4/integration/app/favicon.ico
--------------------------------------------------------------------------------
/integration/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NgxLogger
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/integration/app/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { environment } from './environments/environment';
5 | import { AppModule } from './src/app.module';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic()
12 | .bootstrapModule(AppModule)
13 | .catch((err: Error): void => console.error(err));
14 |
--------------------------------------------------------------------------------
/integration/app/polyfills.ts:
--------------------------------------------------------------------------------
1 | import 'zone.js/dist/zone';
2 |
3 | import { Any } from '../../lib/src/interfaces/logger.internal';
4 |
5 | (window as Any)['__importDefault'] =
6 | (window as Any)['__importDefault'] ||
7 | function (mod: Any): Any {
8 | return mod && mod.__esModule ? mod : { default: mod };
9 | };
10 |
11 | (window as Any).global = window; // Included with Angular CLI.
12 |
--------------------------------------------------------------------------------
/integration/app/src/app.component.css:
--------------------------------------------------------------------------------
1 | .ext-box {
2 | display: none;
3 | }
4 |
5 | .ext-box.load {
6 | display: table;
7 | width: 100%;
8 | height: 100%;
9 | }
10 |
11 | .int-box {
12 | display: table-cell;
13 | vertical-align: middle;
14 | opacity: 0;
15 | transition: opacity 0.3s ease-out;
16 | }
17 |
18 | .load .int-box {
19 | opacity: 1;
20 | transition: opacity 0.3s ease-out;
21 | }
22 |
23 | .center-block {
24 | margin: 0 auto;
25 | display: block;
26 | padding: 10px;
27 | }
28 |
29 | .example.no-display {
30 | transition: opacity 0.3s ease-out;
31 | opacity: 0;
32 | height: 0;
33 | overflow: hidden;
34 | }
35 |
36 | .example {
37 | opacity: 1;
38 | height: auto;
39 | transition: opacity 0.3s ease-out;
40 | }
41 |
--------------------------------------------------------------------------------
/integration/app/src/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
Simple logger for javascript
7 |
8 | In order to see examples, you need to open the browser console or press F12.
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Basic method
18 | (trace, debug, info, ..)
19 |
20 |
21 |
22 |
23 |
24 |
25 | Example groups
26 | (closed, opened)
27 |
28 |
29 |
30 |
31 |
32 |
33 | Nested groups
34 | (deep)
35 |
36 |
37 |
38 |
39 |
40 |
Show only warnings and error
41 |
42 |
43 |
44 |
45 |
46 | Custom CSS styles
47 | for line
48 |
49 |
50 |
51 |
52 |
53 |
54 | Pretty JSON
55 | (output)
56 |
57 |
58 |
59 |
60 |
61 |
62 | Copy to clipboard
63 | ((string text))
64 |
65 |
66 |
67 |
68 |
69 |
70 | Level groups
71 | (trace, debug, info, ..)
72 |
73 |
74 |
75 |
76 |
77 |
78 | Global style line
79 | (css global style)
80 |
81 |
82 |
83 |
84 |
85 |
86 | CSS classes
87 | (set in console)
88 |
89 |
90 |
91 |
92 |
93 |
Decorator
94 |
95 |
96 |
97 |
98 |
99 | Decorator group
100 | with function title
101 |
102 |
103 |
104 |
105 |
106 |
Decorator timer
107 |
108 |
109 |
110 |
111 |
Advanced timer decorator
112 |
113 |
114 |
115 |
116 |
117 | Full configuration
118 | (change labels, colors)
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
You need open console
127 |
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/integration/app/src/app.component.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable:no-duplicate-string */
3 | import {
4 | DebugLog,
5 | ErrorLog,
6 | Group,
7 | InfoLog,
8 | Log,
9 | LogFn,
10 | Logger,
11 | LoggerLevel,
12 | LoggerService,
13 | TimerLog,
14 | TraceLog,
15 | WarnLog
16 | } from '@angular-ru/logger';
17 | import { Component, OnInit, ViewEncapsulation } from '@angular/core';
18 | import * as devtools from 'devtools-detect';
19 |
20 | @Component({
21 | selector: 'app-root',
22 | templateUrl: './app.component.html',
23 | styleUrls: ['./app.component.css'],
24 | encapsulation: ViewEncapsulation.None
25 | })
26 | export class AppComponent implements OnInit {
27 | @Logger() public loggerInjection!: LoggerService;
28 | @TraceLog() public trace!: LogFn;
29 | @DebugLog() public debug!: LogFn;
30 | @InfoLog() public info!: LogFn;
31 | @ErrorLog() public error!: LogFn;
32 | @WarnLog() public warn!: LogFn;
33 | @Log() public log!: LogFn;
34 |
35 | public isLoaded: boolean = false;
36 | public devToolsIsOpen: boolean = devtools.isOpen;
37 |
38 | private readonly traceIsWork: string = 'trace is worked';
39 | private readonly debugIsWork: string = 'debug is worked';
40 | private readonly infoIsWork: string = 'info is worked';
41 | private readonly warnIsWork: string = 'warn is worked';
42 | private readonly errorIsWork: string = 'error is worked';
43 |
44 | constructor(private readonly logger: LoggerService) {}
45 |
46 | public ngOnInit(): void {
47 | this.isLoaded = true;
48 | window.addEventListener('devtoolschange', (e: devtools.DevToolsEvent) => {
49 | this.devToolsIsOpen = e.detail.isOpen;
50 | });
51 | }
52 |
53 | public showExample1(): void {
54 | this.logger.clear();
55 | this.log('log is worked');
56 | this.trace(this.traceIsWork, 1, { a: 1 });
57 | this.debug(this.debugIsWork, 2, console);
58 | this.info(this.infoIsWork, 3, Object);
59 | this.warn(this.warnIsWork, 4, String);
60 | this.error(this.errorIsWork, 5, (2.55).toFixed());
61 | }
62 |
63 | public showExample2(): void {
64 | this.logger.clear();
65 |
66 | this.logger.groupCollapsed('EXAMPLE 2: show stack', () => {
67 | this.trace(this.traceIsWork, 1, { a: 1 });
68 | this.debug(this.debugIsWork, 2, console);
69 | this.info(this.infoIsWork, 3, Object);
70 | this.warn(this.warnIsWork, 4, String);
71 | this.error(this.errorIsWork, 5, (2.55).toFixed());
72 | });
73 |
74 | this.logger.group('Show trace in opened group', ({ trace }: LoggerService): void => {
75 | for (let i: number = 0; i < 20; i++) {
76 | trace(this.traceIsWork, i);
77 | }
78 | });
79 |
80 | this.logger
81 | .groupCollapsed('Show trace in collapsed group', ({ debug }: LoggerService): void => {
82 | for (let i: number = 0; i < 15; i++) {
83 | debug(this.traceIsWork, i);
84 | }
85 | })
86 | .closeAll();
87 | }
88 |
89 | public showExample3(): void {
90 | this.logger.clear();
91 |
92 | this.logger
93 | .groupCollapsed('GROUP TEST')
94 | .pipe(({ trace, debug, info, warn, error }: LoggerService) => {
95 | trace(this.traceIsWork);
96 | debug(this.debugIsWork);
97 | info(this.infoIsWork);
98 | warn(this.warnIsWork);
99 | error(this.errorIsWork);
100 | })
101 | .close();
102 |
103 | this.logger
104 | .group('A')
105 | .pipe(
106 | ({ trace }: LoggerService) => trace(this.traceIsWork),
107 | ({ debug }: LoggerService) => debug(this.debugIsWork),
108 | ({ info }: LoggerService) => info(this.infoIsWork),
109 | ({ warn }: LoggerService) => warn(this.warnIsWork),
110 | ({ error }: LoggerService) => error(this.errorIsWork)
111 | )
112 | .groupCollapsed('B')
113 | .pipe(
114 | ({ trace }: LoggerService) => trace(this.traceIsWork),
115 | ({ debug }: LoggerService) => debug(this.debugIsWork),
116 | ({ info }: LoggerService) => info(this.infoIsWork),
117 | ({ warn }: LoggerService) => warn(this.warnIsWork),
118 | ({ error }: LoggerService) => error(this.errorIsWork)
119 | )
120 | .group('C')
121 | .pipe(
122 | ({ trace }: LoggerService) => trace(this.traceIsWork),
123 | ({ debug }: LoggerService) => debug(this.debugIsWork),
124 | ({ info }: LoggerService) => info(this.infoIsWork),
125 | ({ warn }: LoggerService) => warn(this.warnIsWork),
126 | ({ error }: LoggerService) => error(this.errorIsWork)
127 | )
128 | .closeAll();
129 | }
130 |
131 | public showExample4(): void {
132 | this.logger.clear();
133 |
134 | this.logger.level = LoggerLevel.INFO;
135 |
136 | this.logger.log('log is working', 1, String);
137 | this.trace(this.traceIsWork, 4, String);
138 | this.debug(this.debugIsWork, 4, String);
139 | this.warn(this.warnIsWork, 4, String);
140 | this.error(this.errorIsWork, 5, (2.55).toFixed());
141 |
142 | this.logger.level = LoggerLevel.ALL;
143 | }
144 |
145 | public showExample5(): void {
146 | this.logger.clear();
147 |
148 | this.logger.css('text-transform: uppercase; font-weight: bold').debug('window current ', window);
149 |
150 | this.logger.css('color: red; text-decoration: underline; font-weight: bold').info('It is awesome logger');
151 | this.debug({ a: 1 });
152 |
153 | this.warn('logger.css(...) does not define a global format!');
154 | this.info('For global configuration, use the constructor parameters');
155 | }
156 |
157 | public showExample6(): void {
158 | this.logger.clear();
159 |
160 | const jsonExample: object = {
161 | id: 1,
162 | hello: 'world'
163 | };
164 |
165 | this.debug('Classic output json', jsonExample);
166 |
167 | this.logger.log(...this.logger.prettyJSON(jsonExample));
168 | }
169 |
170 | public showExample7(): void {
171 | this.logger.clear();
172 |
173 | const example: string = 'test string';
174 |
175 | this.logger.log(example);
176 | this.logger.copy(example);
177 | }
178 |
179 | public showExample8(): void {
180 | this.logger.clear();
181 | this.logger.level = LoggerLevel.INFO;
182 |
183 | this.trace
184 | .group('A')
185 | .pipe(
186 | ({ trace }: LoggerService) => trace(this.traceIsWork),
187 | ({ debug }: LoggerService) => debug(this.debugIsWork),
188 | ({ info }: LoggerService) => info(this.infoIsWork),
189 | ({ warn }: LoggerService) => warn(this.warnIsWork),
190 | ({ error }: LoggerService) => error(this.errorIsWork)
191 | )
192 | .close()
193 |
194 | .debug.group('B')
195 | .pipe(
196 | ({ trace }: LoggerService) => trace(this.traceIsWork),
197 | ({ debug }: LoggerService) => debug(this.debugIsWork),
198 | ({ info }: LoggerService) => info(this.infoIsWork),
199 | ({ warn }: LoggerService) => warn(this.warnIsWork),
200 | ({ error }: LoggerService) => error(this.errorIsWork)
201 | )
202 | .close()
203 |
204 | .info.group('C')
205 | .pipe(
206 | ({ trace }: LoggerService) => trace(this.traceIsWork),
207 | ({ debug }: LoggerService) => debug(this.debugIsWork),
208 | ({ info }: LoggerService) => info(this.infoIsWork),
209 | ({ warn }: LoggerService) => warn(this.warnIsWork),
210 | ({ error }: LoggerService) => error(this.errorIsWork)
211 | )
212 | .close()
213 |
214 | .warn.group('D')
215 | .pipe(
216 | ({ trace }: LoggerService) => trace(this.traceIsWork),
217 | ({ debug }: LoggerService) => debug(this.debugIsWork),
218 | ({ info }: LoggerService) => info(this.infoIsWork),
219 | ({ warn }: LoggerService) => warn(this.warnIsWork),
220 | ({ error }: LoggerService) => error(this.errorIsWork)
221 | )
222 | .close()
223 |
224 | .error.group('E')
225 | .pipe(
226 | ({ trace }: LoggerService) => trace(this.traceIsWork),
227 | ({ debug }: LoggerService) => debug(this.debugIsWork),
228 | ({ info }: LoggerService) => info(this.infoIsWork),
229 | ({ warn }: LoggerService) => warn(this.warnIsWork),
230 | ({ error }: LoggerService) => error(this.errorIsWork)
231 | )
232 | .close();
233 |
234 | this.logger.level = LoggerLevel.ALL;
235 | }
236 |
237 | public showExample9(): void {
238 | this.logger.clear();
239 |
240 | this.logger.css('font-weight: normal; text-decoration: none; font-style: italic;').info(3.14);
241 | this.logger.css('font-weight: normal;').info(3.14);
242 | this.warn('global format with style!');
243 | }
244 |
245 | public showExample10(): void {
246 | this.logger.clear();
247 |
248 | this.logger.cssClass('bold line-through').log('JavaScript sucks', 'JavaScript is the best');
249 |
250 | this.logger
251 | .cssClass('code-sandbox')
252 | .log('\n @Component({ .. })' + '\n export class AppComponent { .. } \n\n');
253 |
254 | this.logger.cssClass('bold line-through').debug('JavaScript sucks', 'JavaScript is the best');
255 |
256 | this.logger.level = LoggerLevel.INFO;
257 | }
258 |
259 | public showExample11(): void {
260 | this.loggerInjection.clear();
261 | this.logger.log(this.helloWorld('Max'));
262 | }
263 |
264 | @Group((name: string) => `Test group with ${name}`)
265 | public method(name: string): string {
266 | this.loggerInjection.log('group is worked');
267 | return name;
268 | }
269 |
270 | public showExample12(): void {
271 | this.loggerInjection.clear();
272 | this.method('hello world');
273 | }
274 |
275 | @TimerLog('Test timer')
276 | public showExample13(): void {
277 | this.logger.clear();
278 | this.log('test log');
279 | }
280 |
281 | @TimerLog('Advanced timer', LoggerLevel.WARN, false)
282 | public showExample14(): void {
283 | this.logger.clear();
284 | this.log('Advanced test log');
285 | }
286 |
287 | @Group('test title', LoggerLevel.WARN)
288 | private helloWorld(name: string): string {
289 | this.logger.log('log only in group', name);
290 | return 'hello world';
291 | }
292 | }
293 |
--------------------------------------------------------------------------------
/integration/app/src/app.module.ts:
--------------------------------------------------------------------------------
1 | import { LoggerModule } from '@angular-ru/logger';
2 | import { HttpClientModule } from '@angular/common/http';
3 | import { NgModule } from '@angular/core';
4 | import { BrowserModule } from '@angular/platform-browser';
5 |
6 | import { environment } from '../environments/environment';
7 | import { AppComponent } from './app.component';
8 |
9 | @NgModule({
10 | declarations: [AppComponent],
11 | imports: [
12 | LoggerModule.forRoot(
13 | environment.useConfig
14 | ? {
15 | useLevelGroup: true,
16 | cssClassMap: {
17 | bold: 'font-weight: bold',
18 | 'line-through': 'text-decoration: line-through',
19 | 'code-sandbox': `
20 | color: #666;
21 | background: #f4f4f4;
22 | border-left: 3px solid #f36d33;
23 | font-family: monospace;
24 | font-size: 15px;`
25 | }
26 | }
27 | : {}
28 | ),
29 | BrowserModule,
30 | HttpClientModule
31 | ],
32 | providers: [],
33 | bootstrap: [AppComponent]
34 | })
35 | export class AppModule {}
36 |
--------------------------------------------------------------------------------
/integration/app/styles.css:
--------------------------------------------------------------------------------
1 | @import url(https://fonts.googleapis.com/css?family=Lato:400, 300, 300italic, 400italic, 700, 700italic);
2 |
3 | body,
4 | html {
5 | height: 100%;
6 | width: 100%;
7 | margin: 0;
8 | padding: 0;
9 | left: 0;
10 | top: 0;
11 | font-size: 100%;
12 | }
13 |
14 | .center,
15 | .container {
16 | margin-left: auto;
17 | margin-right: auto;
18 | }
19 |
20 | * {
21 | font-family: Lato, Helvetica, sans-serif;
22 | color: #333447;
23 | line-height: 1.5;
24 | }
25 |
26 | h1 {
27 | font-size: 2.5rem;
28 | }
29 |
30 | h2 {
31 | font-size: 2rem;
32 | }
33 |
34 | h3 {
35 | font-size: 1.375rem;
36 | }
37 |
38 | h4 {
39 | font-size: 1.125rem;
40 | }
41 |
42 | h5 {
43 | font-size: 1rem;
44 | }
45 |
46 | h6 {
47 | font-size: 0.875rem;
48 | }
49 |
50 | p {
51 | font-size: 1.125rem;
52 | font-weight: 200;
53 | line-height: 1.8;
54 | }
55 |
56 | .font-light {
57 | font-weight: 300;
58 | }
59 |
60 | .font-regular {
61 | font-weight: 400;
62 | }
63 |
64 | .font-heavy {
65 | font-weight: 700;
66 | }
67 |
68 | .left {
69 | text-align: left;
70 | }
71 |
72 | .right {
73 | text-align: right;
74 | }
75 |
76 | .center {
77 | text-align: center;
78 | }
79 |
80 | .justify {
81 | text-align: justify;
82 | }
83 |
84 | .container {
85 | width: 90%;
86 | }
87 |
88 | .row {
89 | position: relative;
90 | width: 100%;
91 | }
92 |
93 | .row [class^='col'] {
94 | float: left;
95 | margin: 0.5rem 2%;
96 | min-height: 0.125rem;
97 | }
98 |
99 | .col-1,
100 | .col-10,
101 | .col-11,
102 | .col-12,
103 | .col-2,
104 | .col-3,
105 | .col-4,
106 | .col-5,
107 | .col-6,
108 | .col-7,
109 | .col-8,
110 | .col-9 {
111 | width: 96%;
112 | }
113 |
114 | .col-1-sm {
115 | width: 4.33%;
116 | }
117 |
118 | .col-2-sm {
119 | width: 12.66%;
120 | }
121 |
122 | .col-3-sm {
123 | width: 21%;
124 | }
125 |
126 | .col-4-sm {
127 | width: 29.33%;
128 | }
129 |
130 | .col-5-sm {
131 | width: 37.66%;
132 | }
133 |
134 | .col-6-sm {
135 | width: 46%;
136 | }
137 |
138 | .col-7-sm {
139 | width: 54.33%;
140 | }
141 |
142 | .col-8-sm {
143 | width: 62.66%;
144 | }
145 |
146 | .col-9-sm {
147 | width: 71%;
148 | }
149 |
150 | .col-10-sm {
151 | width: 79.33%;
152 | }
153 |
154 | .col-11-sm {
155 | width: 87.66%;
156 | }
157 |
158 | .col-12-sm {
159 | width: 96%;
160 | }
161 |
162 | .row::after {
163 | content: '';
164 | display: table;
165 | clear: both;
166 | }
167 |
168 | .hidden-sm {
169 | display: none;
170 | }
171 |
172 | @media only screen and (min-width: 33.75em) {
173 | .container {
174 | width: 80%;
175 | }
176 | }
177 |
178 | @media only screen and (min-width: 45em) {
179 | .col-1 {
180 | width: 4.33%;
181 | }
182 |
183 | .col-2 {
184 | width: 12.66%;
185 | }
186 |
187 | .col-3 {
188 | width: 21%;
189 | }
190 |
191 | .col-4 {
192 | width: 29.33%;
193 | }
194 |
195 | .col-5 {
196 | width: 37.66%;
197 | }
198 |
199 | .col-6 {
200 | width: 46%;
201 | }
202 |
203 | .col-7 {
204 | width: 54.33%;
205 | }
206 |
207 | .col-8 {
208 | width: 62.66%;
209 | }
210 |
211 | .col-9 {
212 | width: 71%;
213 | }
214 |
215 | .col-10 {
216 | width: 79.33%;
217 | }
218 |
219 | .col-11 {
220 | width: 87.66%;
221 | }
222 |
223 | .col-12 {
224 | width: 96%;
225 | }
226 |
227 | .hidden-sm {
228 | display: block;
229 | }
230 | }
231 |
232 | @media only screen and (min-width: 60em) {
233 | .container {
234 | width: 75%;
235 | max-width: 60rem;
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/integration/app/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "types": []
6 | },
7 | "exclude": ["**/*.spec.ts"]
8 | }
9 |
--------------------------------------------------------------------------------
/integration/app/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/spec",
5 | "types": ["jasmine", "node"]
6 | },
7 | "files": ["test.ts",
8 | "polyfills.ts"
9 | ],
10 | "include": ["**/*.spec.ts", "**/*.d.ts"]
11 | }
12 |
--------------------------------------------------------------------------------
/integration/tests/autobind.spec.ts:
--------------------------------------------------------------------------------
1 | import { autoBind } from '../../lib/src/decorators/autobind.decorator';
2 |
3 | describe('@autoBind', () => {
4 | class Foo {
5 | @autoBind
6 | public getFoo(): this {
7 | return this;
8 | }
9 |
10 | public getFooAgain(): this {
11 | return this;
12 | }
13 |
14 | @autoBind
15 | public onlyOnFoo(): this {
16 | return this;
17 | }
18 | }
19 |
20 | class Bar extends Foo {
21 | @autoBind()
22 | public getFoo(): this {
23 | return super.getFoo();
24 | }
25 |
26 | public getSuperMethod_getFoo(): () => this {
27 | return super.getFoo;
28 | }
29 |
30 | @autoBind
31 | public onlyOnBar(): this {
32 | return this;
33 | }
34 | }
35 |
36 | it('returns a bound instance for a method', function(): void {
37 | const foo: Foo = new Foo();
38 | const { getFoo }: Foo = foo;
39 |
40 | expect(getFoo()).toEqual(foo);
41 | });
42 |
43 | it('sets the correct instance descriptor options when bound', function(): void {
44 | const foo: Foo = new Foo();
45 | const { getFoo }: Foo = foo;
46 | const desc: PropertyDescriptor = Object.getOwnPropertyDescriptor(foo, 'getFoo') as PropertyDescriptor;
47 |
48 | expect(desc.configurable).toEqual(true);
49 | expect(desc.enumerable).toEqual(false);
50 | expect(desc.writable).toEqual(true);
51 | expect(desc.value).toEqual(getFoo);
52 | });
53 |
54 | it('works with multiple instances of the same class', function(): void {
55 | const foo1: Foo = new Foo();
56 | const foo2: Foo = new Foo();
57 |
58 | const getFoo1: () => Foo = foo1.getFoo;
59 | const getFoo2: () => Foo = foo2.getFoo;
60 |
61 | expect(getFoo1()).toEqual(foo1);
62 | expect(getFoo2()).toEqual(foo2);
63 | });
64 |
65 | it('returns the same bound function every time', function(): void {
66 | const foo: Foo = new Foo();
67 | const bar: Bar = new Bar();
68 |
69 | expect(foo.getFoo).toEqual(foo.getFoo);
70 | expect(bar.getFoo).toEqual(bar.getFoo);
71 | expect(bar.getSuperMethod_getFoo()).toEqual(bar.getSuperMethod_getFoo());
72 | expect(bar.getFooAgain()).toEqual(bar.getFooAgain());
73 | });
74 | });
75 |
--------------------------------------------------------------------------------
/integration/tests/clipboard.spec.ts:
--------------------------------------------------------------------------------
1 | import { LoggerService } from '../../lib/src/logger.service';
2 | import { ConsoleFake } from './helpers/console-fake';
3 | import { TestBed } from '@angular/core/testing';
4 | import { LoggerModule } from '../../lib/src/logger.module';
5 | import { ObjectKeyMap } from '../../lib/src/interfaces/logger.internal';
6 |
7 | describe('[TEST]: Check clipboard', () => {
8 | let logger: LoggerService;
9 | let buffer: string | null = null;
10 | const fakeConsole: ConsoleFake = new ConsoleFake();
11 | const textarea: Partial = {
12 | textContent: null,
13 | style: {} as CSSStyleDeclaration,
14 | select: (): void => {}
15 | };
16 |
17 | beforeAll(() => {
18 | TestBed.configureTestingModule({
19 | imports: [
20 | LoggerModule.forRoot({
21 | instance: fakeConsole
22 | })
23 | ]
24 | });
25 |
26 | logger = TestBed.get(LoggerService);
27 | });
28 |
29 | beforeEach(() => {
30 | buffer = null;
31 | window.clipboardData = null!;
32 | document.queryCommandSupported = null!;
33 | textarea.textContent = null!;
34 | document.execCommand = null!;
35 | });
36 |
37 | it(`Copy is security and save data local memory`, () => {
38 | Object.defineProperty(window, 'clipboardData', {
39 | writable: true,
40 | value: {
41 | setData: (type: string, value: string): void | boolean => {
42 | if (type === 'Text') {
43 | buffer = value;
44 | return true;
45 | }
46 | }
47 | }
48 | });
49 |
50 | const stringValue: string = 'test string';
51 | const isExec: boolean = logger.copy(stringValue);
52 |
53 | expect(isExec).toEqual(true);
54 | expect(buffer).toEqual(stringValue);
55 | });
56 |
57 | it('should be correct copy/paste document copy', () => {
58 | createMockQueryCommands(textarea);
59 |
60 | Object.defineProperty(document, 'execCommand', {
61 | writable: true,
62 | value: (): void | boolean => {
63 | buffer = textarea.textContent!;
64 | return true;
65 | }
66 | });
67 |
68 | const JsonValue: ObjectKeyMap = { a: 1, b: [1, 2, 3] };
69 | const isExec: boolean = logger.copy(JsonValue);
70 |
71 | expect(isExec).toEqual(true);
72 | expect(buffer).toEqual(JSON.stringify(JsonValue, null, 4));
73 | });
74 |
75 | it('should be throw exception when incorrect execCommand', () => {
76 | createMockQueryCommands(textarea);
77 |
78 | const JsonValue: ObjectKeyMap = { a: 1, b: [1, 2, 3] };
79 | const isExec: boolean = logger.copy(JsonValue);
80 |
81 | expect(isExec).toEqual(false);
82 | expect(buffer).toEqual(null);
83 | });
84 |
85 | it(`should be correct fallback`, () => {
86 | const stringValue: string = 'test string';
87 | const isExec: boolean = logger.copy(stringValue);
88 |
89 | expect(isExec).toEqual(false);
90 | expect(buffer).toEqual(null);
91 | });
92 | });
93 |
94 | function createMockQueryCommands(textareaRef: Partial): void {
95 | Object.defineProperty(document, 'queryCommandSupported', {
96 | writable: true,
97 | value: (): void | boolean => true
98 | });
99 |
100 | Object.defineProperty(document, 'body', {
101 | writable: true,
102 | value: {
103 | appendChild: (): void => {},
104 | removeChild: (): void => {}
105 | }
106 | });
107 |
108 | Object.defineProperty(document, 'createElement', {
109 | writable: true,
110 | value: (elementName: string): Partial | any => {
111 | if (elementName === 'textarea') {
112 | return textareaRef;
113 | }
114 | }
115 | });
116 | }
117 |
--------------------------------------------------------------------------------
/integration/tests/console-format-api.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 | import { LoggerModule } from '../../lib/src/logger.module';
3 | import { LoggerService } from '../../lib/src/logger.service';
4 | import { ConsoleFake } from './helpers/console-fake';
5 | import { CUSTOM_COLORS, CUSTOM_LABELS } from './helpers/custom-colors.enum';
6 | import { FormatOutput, LoggerLevel } from '../../lib/src/interfaces/logger.external';
7 | import { ObjectKeyMap } from '../../lib/src/interfaces/logger.internal';
8 |
9 | describe('[TEST]: Check global style', () => {
10 | let logger: LoggerService;
11 | const fakeConsole: ConsoleFake = new ConsoleFake();
12 |
13 | const traceIsWork: string = 'trace is worked';
14 | const debugIsWork: string = 'debug is worked';
15 | const infoIsWork: string = 'info is worked';
16 | const warnIsWork: string = 'warn is worked';
17 | const errorIsWork: string = 'error is worked';
18 |
19 | beforeAll(() => {
20 | TestBed.configureTestingModule({
21 | imports: [
22 | LoggerModule.forRoot({
23 | instance: fakeConsole,
24 | labelNames: {
25 | [LoggerLevel.TRACE]: CUSTOM_LABELS.TRACE,
26 | [LoggerLevel.DEBUG]: CUSTOM_LABELS.DEBUG,
27 | [LoggerLevel.INFO]: CUSTOM_LABELS.INFO,
28 | [LoggerLevel.WARN]: CUSTOM_LABELS.WARN,
29 | [LoggerLevel.ERROR]: CUSTOM_LABELS.ERROR
30 | },
31 | labelColors: {
32 | [LoggerLevel.TRACE]: CUSTOM_COLORS.TRACE,
33 | [LoggerLevel.DEBUG]: CUSTOM_COLORS.DEBUG,
34 | [LoggerLevel.INFO]: CUSTOM_COLORS.INFO,
35 | [LoggerLevel.WARN]: CUSTOM_COLORS.WARN,
36 | [LoggerLevel.ERROR]: CUSTOM_COLORS.ERROR
37 | },
38 | format(label: string, labelStyle: string): FormatOutput {
39 | const customLabel: string = `${label}`;
40 | return { label: customLabel, style: labelStyle };
41 | }
42 | })
43 | ]
44 | });
45 |
46 | logger = TestBed.get(LoggerService);
47 | });
48 |
49 | beforeEach(() => {
50 | logger.clear();
51 | });
52 |
53 | it(`Set new text for labels: [trace, debug, info, warn, error]`, () => {
54 | logger.level = LoggerLevel.ALL;
55 |
56 | const traceLine: number = 0;
57 | logger.trace(traceIsWork, 1, { a: 1 });
58 |
59 | const debugLine: number = 1;
60 | logger.debug(debugIsWork, 2, {});
61 |
62 | const infoLine: number = 2;
63 | logger.info(infoIsWork, 3, Object);
64 |
65 | const warnLine: number = 3;
66 | logger.warn(warnIsWork, 4, String);
67 |
68 | const errorLine: number = 4;
69 | logger.error(errorIsWork, 5, (2.55).toFixed());
70 |
71 | const stackOptionsList: ObjectKeyMap = fakeConsole.stackOptionsList();
72 |
73 | const { label: traceLabel }: ObjectKeyMap = stackOptionsList[traceLine];
74 | const { label: debugLabel }: ObjectKeyMap = stackOptionsList[debugLine];
75 | const { label: infoLabel }: ObjectKeyMap = stackOptionsList[infoLine];
76 | const { label: warnLabel }: ObjectKeyMap = stackOptionsList[warnLine];
77 | const { label: errorLabel }: ObjectKeyMap = stackOptionsList[errorLine];
78 |
79 | expect(traceLabel).toEqual(CUSTOM_LABELS.TRACE);
80 | expect(debugLabel).toEqual(CUSTOM_LABELS.DEBUG);
81 | expect(infoLabel).toEqual(CUSTOM_LABELS.INFO);
82 | expect(warnLabel).toEqual(CUSTOM_LABELS.WARN);
83 | expect(errorLabel).toEqual(CUSTOM_LABELS.ERROR);
84 | });
85 |
86 | it(`Detect custom colors for labels`, () => {
87 | logger.level = LoggerLevel.ALL;
88 |
89 | const traceLine: number = 0;
90 | logger.trace(traceIsWork, 1, { a: 1 });
91 |
92 | const debugLine: number = 1;
93 | logger.debug(debugIsWork, 2, {});
94 |
95 | const infoLine: number = 2;
96 | logger.info(infoIsWork, 3, Object);
97 |
98 | const warnLine: number = 3;
99 | logger.warn(warnIsWork, 4, String);
100 |
101 | const errorLine: number = 4;
102 | logger.error(errorIsWork, 5, (2.55).toFixed());
103 |
104 | const stackOptionsList: ObjectKeyMap = fakeConsole.stackOptionsList();
105 |
106 | const { styles: traceStyle }: ObjectKeyMap = stackOptionsList[traceLine];
107 | const { styles: debugStyle }: ObjectKeyMap = stackOptionsList[debugLine];
108 | const { styles: infoStyle }: ObjectKeyMap = stackOptionsList[infoLine];
109 | const { styles: warnStyle }: ObjectKeyMap = stackOptionsList[warnLine];
110 | const { styles: errorStyle }: ObjectKeyMap = stackOptionsList[errorLine];
111 |
112 | expect(traceStyle.color).toEqual(CUSTOM_COLORS.TRACE);
113 | expect(debugStyle.color).toEqual(CUSTOM_COLORS.DEBUG);
114 | expect(infoStyle.color).toEqual(CUSTOM_COLORS.INFO);
115 | expect(warnStyle.color).toEqual(CUSTOM_COLORS.WARN);
116 | expect(errorStyle.color).toEqual(CUSTOM_COLORS.ERROR);
117 | });
118 |
119 | it(`Clear custom labels: `, () => {
120 | logger.setLabels({
121 | [LoggerLevel.TRACE]: CUSTOM_LABELS.TRACE,
122 | [LoggerLevel.DEBUG]: CUSTOM_LABELS.DEBUG,
123 | [LoggerLevel.INFO]: CUSTOM_LABELS.INFO,
124 | [LoggerLevel.WARN]: CUSTOM_LABELS.WARN,
125 | [LoggerLevel.ERROR]: CUSTOM_LABELS.ERROR
126 | });
127 |
128 | const traceLine: number = 0;
129 | logger.trace(traceIsWork, 1, { a: 1 });
130 |
131 | const debugLine: number = 1;
132 | logger.debug(debugIsWork, 2, {});
133 |
134 | const infoLine: number = 2;
135 | logger.info(infoIsWork, 3, Object);
136 |
137 | const warnLine: number = 3;
138 | logger.warn(warnIsWork, 4, String);
139 |
140 | const errorLine: number = 4;
141 | logger.error(errorIsWork, 5, (2.55).toFixed());
142 |
143 | const stackOptionsList: ObjectKeyMap = fakeConsole.stackOptionsList();
144 |
145 | const { label: traceLabel }: ObjectKeyMap = stackOptionsList[traceLine];
146 | const { label: debugLabel }: ObjectKeyMap = stackOptionsList[debugLine];
147 | const { label: infoLabel }: ObjectKeyMap = stackOptionsList[infoLine];
148 | const { label: warnLabel }: ObjectKeyMap = stackOptionsList[warnLine];
149 | const { label: errorLabel }: ObjectKeyMap = stackOptionsList[errorLine];
150 |
151 | expect(traceLabel).toEqual(CUSTOM_LABELS.TRACE);
152 | expect(debugLabel).toEqual(CUSTOM_LABELS.DEBUG);
153 | expect(infoLabel).toEqual(CUSTOM_LABELS.INFO);
154 | expect(warnLabel).toEqual(CUSTOM_LABELS.WARN);
155 | expect(errorLabel).toEqual(CUSTOM_LABELS.ERROR);
156 | });
157 |
158 | it(`Set new colors for labels`, () => {
159 | logger.level = LoggerLevel.ALL;
160 | logger.clear();
161 |
162 | logger.setColors({
163 | [LoggerLevel.TRACE]: CUSTOM_COLORS.TRACE,
164 | [LoggerLevel.DEBUG]: CUSTOM_COLORS.DEBUG,
165 | [LoggerLevel.INFO]: CUSTOM_COLORS.INFO,
166 | [LoggerLevel.WARN]: CUSTOM_COLORS.WARN,
167 | [LoggerLevel.ERROR]: CUSTOM_COLORS.ERROR
168 | });
169 |
170 | const traceLine: number = 0;
171 | logger.trace(traceIsWork, 1, { a: 1 });
172 |
173 | const debugLine: number = 1;
174 | logger.debug(debugIsWork, 2, {});
175 |
176 | const infoLine: number = 2;
177 | logger.info(infoIsWork, 3, Object);
178 |
179 | const warnLine: number = 3;
180 | logger.warn(warnIsWork, 4, String);
181 |
182 | const errorLine: number = 4;
183 | logger.error(errorIsWork, 5, (2.55).toFixed());
184 |
185 | const stackOptionsList: ObjectKeyMap = fakeConsole.stackOptionsList();
186 |
187 | const { styles: traceStyle }: ObjectKeyMap = stackOptionsList[traceLine];
188 | const { styles: debugStyle }: ObjectKeyMap = stackOptionsList[debugLine];
189 | const { styles: infoStyle }: ObjectKeyMap = stackOptionsList[infoLine];
190 | const { styles: warnStyle }: ObjectKeyMap = stackOptionsList[warnLine];
191 | const { styles: errorStyle }: ObjectKeyMap = stackOptionsList[errorLine];
192 |
193 | expect(traceStyle.color).toEqual(CUSTOM_COLORS.TRACE);
194 | expect(debugStyle.color).toEqual(CUSTOM_COLORS.DEBUG);
195 | expect(infoStyle.color).toEqual(CUSTOM_COLORS.INFO);
196 | expect(warnStyle.color).toEqual(CUSTOM_COLORS.WARN);
197 | expect(errorStyle.color).toEqual(CUSTOM_COLORS.ERROR);
198 | });
199 | });
200 |
--------------------------------------------------------------------------------
/integration/tests/console-group-api.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable:quotemark */
2 | import { LoggerService } from '../../lib/src/logger.service';
3 | import { ConsoleFake, TestLoggerGroupType, TestLoggerLineType } from './helpers/console-fake';
4 | import { TestBed } from '@angular/core/testing';
5 | import { LoggerModule } from '../../lib/src/logger.module';
6 | import { CUSTOM_COLORS, CUSTOM_LABELS } from './helpers/custom-colors.enum';
7 | import { LoggerLevel } from '../../lib/src/interfaces/logger.external';
8 |
9 | // tslint:disable-next-line:no-big-function
10 | describe('[TEST]: Check work in groups', () => {
11 | let logger: LoggerService;
12 | const fakeConsole: ConsoleFake = new ConsoleFake();
13 |
14 | const traceIsWork: string = 'trace is worked';
15 | const debugIsWork: string = 'debug is worked';
16 | const infoIsWork: string = 'info is worked';
17 | const warnIsWork: string = 'warn is worked';
18 | const errorIsWork: string = 'error is worked';
19 |
20 | const traceGroupIsWork: string = 'trace group is worked';
21 | const debugGroupIsWork: string = 'debug group is worked';
22 | const infoGroupIsWork: string = 'info group is worked';
23 | const warnGroupIsWork: string = 'warn group is worked';
24 | const errorGroupIsWork: string = 'error group is worked';
25 |
26 | beforeAll(() => {
27 | TestBed.configureTestingModule({
28 | imports: [
29 | LoggerModule.forRoot({
30 | instance: fakeConsole,
31 | labelNames: {
32 | [LoggerLevel.TRACE]: CUSTOM_LABELS.TRACE,
33 | [LoggerLevel.DEBUG]: CUSTOM_LABELS.DEBUG,
34 | [LoggerLevel.INFO]: CUSTOM_LABELS.INFO,
35 | [LoggerLevel.WARN]: CUSTOM_LABELS.WARN,
36 | [LoggerLevel.ERROR]: CUSTOM_LABELS.ERROR
37 | },
38 | labelColors: {
39 | [LoggerLevel.TRACE]: CUSTOM_COLORS.TRACE,
40 | [LoggerLevel.DEBUG]: CUSTOM_COLORS.DEBUG,
41 | [LoggerLevel.INFO]: CUSTOM_COLORS.INFO,
42 | [LoggerLevel.WARN]: CUSTOM_COLORS.WARN,
43 | [LoggerLevel.ERROR]: CUSTOM_COLORS.ERROR
44 | }
45 | })
46 | ]
47 | });
48 |
49 | logger = TestBed.get(LoggerService);
50 | });
51 |
52 | beforeEach(() => {
53 | logger.clear();
54 | });
55 |
56 | it(`Show classic group`, () => {
57 | logger.group('group label', ({ trace }: LoggerService): void => {
58 | trace(traceIsWork, 1, { a: 1 });
59 | });
60 |
61 | expect(fakeConsole.stack()).toEqual(
62 | fakeConsole.createStack(
63 | { [TestLoggerGroupType.GROUP_OPEN]: ['group label'] },
64 | { [TestLoggerLineType.TRACE_OR_DEBUG]: [traceIsWork, 1, { a: 1 }] },
65 | { [TestLoggerGroupType.GROUP_END]: [] }
66 | )
67 | );
68 | });
69 |
70 | it(`Pipe group`, () => {
71 | logger
72 | .group('group name')
73 | .pipe(({ trace }: LoggerService) => trace(traceIsWork))
74 | .pipe(({ debug }: LoggerService) => debug(debugIsWork))
75 | .pipe(({ info }: LoggerService) => info(infoIsWork))
76 | .pipe(({ warn }: LoggerService) => warn(warnIsWork))
77 | .pipe(({ error }: LoggerService) => error(errorIsWork))
78 | .close();
79 |
80 | expect(fakeConsole.stack()).toEqual(
81 | fakeConsole.createStack(
82 | { [TestLoggerGroupType.GROUP_OPEN]: [`group name`] },
83 | { [TestLoggerLineType.TRACE_OR_DEBUG]: [traceIsWork] },
84 | { [TestLoggerLineType.DEBUG]: [debugIsWork] },
85 | { [TestLoggerLineType.INFO]: [infoIsWork] },
86 | { [TestLoggerLineType.WARN]: [warnIsWork] },
87 | { [TestLoggerLineType.ERROR]: [errorIsWork] },
88 | { [TestLoggerGroupType.GROUP_END]: [] }
89 | )
90 | );
91 | });
92 |
93 | it(`Pipe group-collapsed`, () => {
94 | logger
95 | .groupCollapsed('group collapsed name')
96 | .pipe(({ trace }: LoggerService) => trace(traceIsWork))
97 | .pipe(({ debug }: LoggerService) => debug(debugIsWork))
98 | .pipe(({ info }: LoggerService) => info(infoIsWork))
99 | .pipe(({ warn }: LoggerService) => warn(warnIsWork))
100 | .pipe(({ error }: LoggerService) => error(errorIsWork))
101 | .close();
102 |
103 | expect(fakeConsole.stack()).toEqual(
104 | fakeConsole.createStack(
105 | { [TestLoggerGroupType.GROUP_COLLAPSED_OPEN]: [`group collapsed name`] },
106 | { [TestLoggerLineType.TRACE_OR_DEBUG]: [traceIsWork] },
107 | { [TestLoggerLineType.DEBUG]: [debugIsWork] },
108 | { [TestLoggerLineType.INFO]: [infoIsWork] },
109 | { [TestLoggerLineType.WARN]: [warnIsWork] },
110 | { [TestLoggerLineType.ERROR]: [errorIsWork] },
111 | { [TestLoggerGroupType.GROUP_END]: [] }
112 | )
113 | );
114 | });
115 |
116 | it(`Pipe groups (with collapsed)`, () => {
117 | logger
118 | .groupCollapsed('group A')
119 | .pipe(({ trace }: LoggerService) => trace(traceIsWork))
120 | .close()
121 | .group('group B')
122 | .pipe(({ trace }: LoggerService) => trace(traceIsWork))
123 | .close();
124 |
125 | expect(fakeConsole.stack()).toEqual(
126 | fakeConsole.createStack(
127 | { [TestLoggerGroupType.GROUP_COLLAPSED_OPEN]: [`group A`] },
128 | { [TestLoggerLineType.TRACE_OR_DEBUG]: [traceIsWork] },
129 | { [TestLoggerGroupType.GROUP_END]: [] },
130 | { [TestLoggerGroupType.GROUP_OPEN]: [`group B`] },
131 | { [TestLoggerLineType.TRACE_OR_DEBUG]: [traceIsWork] },
132 | { [TestLoggerGroupType.GROUP_END]: [] }
133 | )
134 | );
135 | });
136 |
137 | it(`Great groups with group`, () => {
138 | logger
139 | .group('A')
140 | .pipe(
141 | ({ trace }: LoggerService) => trace(traceIsWork),
142 | ({ debug }: LoggerService) => debug(debugIsWork),
143 | ({ info }: LoggerService) => info(infoIsWork),
144 | ({ warn }: LoggerService) => warn(warnIsWork),
145 | ({ error }: LoggerService) => error(errorIsWork)
146 | )
147 | .groupCollapsed('B')
148 | .pipe(
149 | ({ trace }: LoggerService) => trace(traceIsWork),
150 | ({ debug }: LoggerService) => debug(debugIsWork),
151 | ({ info }: LoggerService) => info(infoIsWork),
152 | ({ warn }: LoggerService) => warn(warnIsWork),
153 | ({ error }: LoggerService) => error(errorIsWork)
154 | )
155 | .group('C')
156 | .pipe(
157 | ({ trace }: LoggerService) => trace(traceIsWork),
158 | ({ debug }: LoggerService) => debug(debugIsWork),
159 | ({ info }: LoggerService) => info(infoIsWork),
160 | ({ warn }: LoggerService) => warn(warnIsWork),
161 | ({ error }: LoggerService) => error(errorIsWork)
162 | )
163 | .closeAll();
164 |
165 | expect(fakeConsole.stack()).toEqual(
166 | fakeConsole.createStack(
167 | { [TestLoggerGroupType.GROUP_OPEN]: [`A`] },
168 | { [TestLoggerLineType.TRACE_OR_DEBUG]: [traceIsWork] },
169 | { [TestLoggerLineType.DEBUG]: [debugIsWork] },
170 | { [TestLoggerLineType.INFO]: [infoIsWork] },
171 | { [TestLoggerLineType.WARN]: [warnIsWork] },
172 | { [TestLoggerLineType.ERROR]: [errorIsWork] },
173 | { [TestLoggerGroupType.GROUP_COLLAPSED_OPEN]: [`B`] },
174 | { [TestLoggerLineType.TRACE_OR_DEBUG]: [traceIsWork] },
175 | { [TestLoggerLineType.DEBUG]: [debugIsWork] },
176 | { [TestLoggerLineType.INFO]: [infoIsWork] },
177 | { [TestLoggerLineType.WARN]: [warnIsWork] },
178 | { [TestLoggerLineType.ERROR]: [errorIsWork] },
179 | { [TestLoggerGroupType.GROUP_OPEN]: [`C`] },
180 | { [TestLoggerLineType.TRACE_OR_DEBUG]: [traceIsWork] },
181 | { [TestLoggerLineType.DEBUG]: [debugIsWork] },
182 | { [TestLoggerLineType.INFO]: [infoIsWork] },
183 | { [TestLoggerLineType.WARN]: [warnIsWork] },
184 | { [TestLoggerLineType.ERROR]: [errorIsWork] },
185 | { [TestLoggerGroupType.GROUP_END]: [] },
186 | { [TestLoggerGroupType.GROUP_END]: [] },
187 | { [TestLoggerGroupType.GROUP_END]: [] }
188 | )
189 | );
190 | });
191 |
192 | it(`Level pretty groups`, () => {
193 | logger.level = LoggerLevel.ALL;
194 |
195 | logger.trace.group('A opened', ({ trace }: LoggerService) => trace(traceGroupIsWork));
196 | logger.debug.group('B opened', ({ debug }: LoggerService) => debug(debugGroupIsWork));
197 | logger.info.group('C opened', ({ info }: LoggerService) => info(infoGroupIsWork));
198 | logger.warn.group('D opened', ({ warn }: LoggerService) => warn(warnGroupIsWork));
199 | logger.error.group('E opened', ({ error }: LoggerService) => error(errorGroupIsWork));
200 |
201 | logger.level = LoggerLevel.INFO;
202 |
203 | logger.trace.groupCollapsed('A collapsed', ({ trace }: LoggerService) => trace(traceGroupIsWork));
204 | logger.debug.groupCollapsed('B collapsed', ({ debug }: LoggerService) => debug(debugGroupIsWork));
205 | logger.info.groupCollapsed('C collapsed', ({ info }: LoggerService) => info(infoGroupIsWork));
206 | logger.warn.groupCollapsed('D collapsed', ({ warn }: LoggerService) => warn(warnGroupIsWork));
207 | logger.error.groupCollapsed('E collapsed', ({ error }: LoggerService) => error(errorGroupIsWork));
208 |
209 | expect(fakeConsole.stack()).toEqual(
210 | fakeConsole.createStack(
211 | { [TestLoggerGroupType.GROUP_OPEN]: [`A opened`] },
212 | { [TestLoggerLineType.TRACE_OR_DEBUG]: [traceGroupIsWork] },
213 | { [TestLoggerGroupType.GROUP_END]: [] },
214 |
215 | { [TestLoggerGroupType.GROUP_OPEN]: [`B opened`] },
216 | { [TestLoggerLineType.DEBUG]: [debugGroupIsWork] },
217 | { [TestLoggerGroupType.GROUP_END]: [] },
218 |
219 | { [TestLoggerGroupType.GROUP_OPEN]: [`C opened`] },
220 | { [TestLoggerLineType.INFO]: [infoGroupIsWork] },
221 | { [TestLoggerGroupType.GROUP_END]: [] },
222 |
223 | { [TestLoggerGroupType.GROUP_OPEN]: [`D opened`] },
224 | { [TestLoggerLineType.WARN]: [warnGroupIsWork] },
225 | { [TestLoggerGroupType.GROUP_END]: [] },
226 |
227 | { [TestLoggerGroupType.GROUP_OPEN]: [`E opened`] },
228 | { [TestLoggerLineType.ERROR]: [errorGroupIsWork] },
229 | { [TestLoggerGroupType.GROUP_END]: [] },
230 |
231 | { [TestLoggerGroupType.GROUP_COLLAPSED_OPEN]: [`C collapsed`] },
232 | { [TestLoggerLineType.INFO]: [infoGroupIsWork] },
233 | { [TestLoggerGroupType.GROUP_END]: [] },
234 |
235 | { [TestLoggerGroupType.GROUP_COLLAPSED_OPEN]: [`D collapsed`] },
236 | { [TestLoggerLineType.WARN]: [warnGroupIsWork] },
237 | { [TestLoggerGroupType.GROUP_END]: [] },
238 |
239 | { [TestLoggerGroupType.GROUP_COLLAPSED_OPEN]: [`E collapsed`] },
240 | { [TestLoggerLineType.ERROR]: [errorGroupIsWork] },
241 | { [TestLoggerGroupType.GROUP_END]: [] }
242 | )
243 | );
244 | });
245 |
246 | it(`Level groups with pretty pipes`, () => {
247 | logger.level = LoggerLevel.INFO;
248 |
249 | logger.trace
250 | .group('A')
251 | .pipe(({ trace }: LoggerService) => trace('trace is worked from A'))
252 | .pipe(({ debug }: LoggerService) => debug('debug is worked from A'))
253 | .pipe(({ info }: LoggerService) => info('info is worked from A'))
254 | .pipe(({ warn }: LoggerService) => warn('warn is worked from A'))
255 | .pipe(({ error }: LoggerService) => error('error is worked from A'))
256 | .close()
257 |
258 | .debug.group('B')
259 | .pipe(({ trace }: LoggerService) => trace('trace is worked from B'))
260 | .pipe(({ debug }: LoggerService) => debug('debug is worked from B'))
261 | .pipe(({ info }: LoggerService) => info('info is worked from B'))
262 | .pipe(({ warn }: LoggerService) => warn('warn is worked from B'))
263 | .pipe(({ error }: LoggerService) => error('error is worked from B'))
264 | .close()
265 |
266 | .info.group('C')
267 | .pipe(({ trace }: LoggerService) => trace('trace is worked from C'))
268 | .pipe(({ debug }: LoggerService) => debug('debug is worked from C'))
269 | .pipe(({ info }: LoggerService) => info('info is worked from C'))
270 | .pipe(({ warn }: LoggerService) => warn('warn is worked from C'))
271 | .pipe(({ error }: LoggerService) => error('error is worked from C'))
272 | .close()
273 |
274 | .warn.group('D')
275 | .pipe(({ trace }: LoggerService) => trace('trace is worked from D'))
276 | .pipe(({ debug }: LoggerService) => debug('debug is worked from D'))
277 | .pipe(({ info }: LoggerService) => info('info is worked from D'))
278 | .pipe(({ warn }: LoggerService) => warn('warn is worked from D'))
279 | .pipe(({ error }: LoggerService) => error('error is worked from D'))
280 | .close()
281 |
282 | .error.group('E')
283 | .pipe(({ trace }: LoggerService) => trace('trace is worked from E'))
284 | .pipe(({ debug }: LoggerService) => debug('debug is worked from E'))
285 | .pipe(({ info }: LoggerService) => info('info is worked from E'))
286 | .pipe(({ warn }: LoggerService) => warn('warn is worked from E'))
287 | .pipe(({ error }: LoggerService) => error('error is worked from E'))
288 | .close();
289 |
290 | expect(fakeConsole.stack()).toEqual(
291 | fakeConsole.createStack(
292 | { [TestLoggerGroupType.GROUP_OPEN]: [`C`] },
293 | { [TestLoggerLineType.INFO]: ['info is worked from C'] },
294 | { [TestLoggerLineType.WARN]: ['warn is worked from C'] },
295 | { [TestLoggerLineType.ERROR]: ['error is worked from C'] },
296 | { [TestLoggerGroupType.GROUP_END]: [] },
297 |
298 | { [TestLoggerGroupType.GROUP_OPEN]: [`D`] },
299 | { [TestLoggerLineType.INFO]: ['info is worked from D'] },
300 | { [TestLoggerLineType.WARN]: ['warn is worked from D'] },
301 | { [TestLoggerLineType.ERROR]: ['error is worked from D'] },
302 | { [TestLoggerGroupType.GROUP_END]: [] },
303 |
304 | { [TestLoggerGroupType.GROUP_OPEN]: [`E`] },
305 | { [TestLoggerLineType.INFO]: ['info is worked from E'] },
306 | { [TestLoggerLineType.WARN]: ['warn is worked from E'] },
307 | { [TestLoggerLineType.ERROR]: ['error is worked from E'] },
308 | { [TestLoggerGroupType.GROUP_END]: [] }
309 | )
310 | );
311 | });
312 | });
313 |
314 | describe('[TEST]: ConsoleService based', () => {
315 | const fakeConsole: ConsoleFake = new ConsoleFake();
316 | let logger: LoggerService;
317 |
318 | beforeAll(() => {
319 | TestBed.configureTestingModule({
320 | imports: [
321 | LoggerModule.forRoot({
322 | instance: fakeConsole,
323 | useLevelGroup: false
324 | })
325 | ]
326 | });
327 |
328 | logger = TestBed.get(LoggerService);
329 | });
330 |
331 | it(`should be throw logger`, () => {
332 | try {
333 | logger.info.group('hello world');
334 | } catch (e) {
335 | expect(e.message).toEqual('logger.info.group is not a function');
336 | }
337 | });
338 | });
339 |
--------------------------------------------------------------------------------
/integration/tests/console.spec.ts:
--------------------------------------------------------------------------------
1 | import { ConsoleFake } from './helpers/console-fake';
2 | import { TestBed } from '@angular/core/testing';
3 | import { LoggerModule } from '../../lib/src/logger.module';
4 | import { ConsoleService } from '../../lib/src/services/console.service';
5 | import { LoggerService } from '../../lib/src/logger.service';
6 | import { LoggerLevel } from '../../lib/src/interfaces/logger.external';
7 |
8 | describe('[TEST]: ConsoleService', () => {
9 | let consoleInternal: ConsoleService;
10 | const fakeConsole: ConsoleFake = new ConsoleFake();
11 |
12 | beforeAll(() => {
13 | TestBed.configureTestingModule({
14 | imports: [
15 | LoggerModule.forRoot({
16 | instance: fakeConsole
17 | })
18 | ]
19 | });
20 |
21 | consoleInternal = TestBed.get(ConsoleService);
22 | });
23 |
24 | it(`check console instance`, () => {
25 | consoleInternal.console = console;
26 | expect(consoleInternal.console).toEqual(console);
27 | });
28 | });
29 |
30 | describe('[TEST]: ConsoleService without options', () => {
31 | let logger: LoggerService;
32 | let consoleService: ConsoleService;
33 |
34 | beforeAll(() => {
35 | TestBed.configureTestingModule({
36 | imports: [LoggerModule.forRoot()]
37 | });
38 |
39 | logger = TestBed.get(LoggerService);
40 | consoleService = TestBed.get(ConsoleService);
41 | });
42 |
43 | it(`should be truthy logger`, () => {
44 | expect(logger).toBeTruthy();
45 | });
46 |
47 | it(`should be correct minLevel and instance`, () => {
48 | expect(consoleService.minLevel).toEqual(LoggerLevel.ALL);
49 | expect(consoleService.instance).toEqual(console);
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/integration/tests/css-parcer.spec.ts:
--------------------------------------------------------------------------------
1 | import { LoggerService } from '../../lib/src/logger.service';
2 | import { ConsoleFake, TestLoggerLineType } from './helpers/console-fake';
3 | import { TestBed } from '@angular/core/testing';
4 | import { LoggerModule } from '../../lib/src/logger.module';
5 | import { LoggerLevel } from '../../lib/src/interfaces/logger.external';
6 |
7 | describe('[TEST]: Check style', () => {
8 | let logger: LoggerService;
9 | const fakeConsole: ConsoleFake = new ConsoleFake();
10 |
11 | const testString: string = 'test string';
12 |
13 | beforeAll(() => {
14 | TestBed.configureTestingModule({
15 | imports: [
16 | LoggerModule.forRoot({
17 | instance: fakeConsole,
18 | cssClassMap: {
19 | // tslint:disable-next-line:no-duplicate-string
20 | 'class-1': 'font-weight: bold',
21 | // tslint:disable-next-line:no-duplicate-string
22 | 'class-2': 'text-decoration: line-through',
23 | 'class-3': 'color: #666'
24 | }
25 | })
26 | ]
27 | });
28 |
29 | logger = TestBed.get(LoggerService);
30 | });
31 |
32 | beforeEach(() => logger.clear());
33 |
34 | it(`Set style another console line `, () => {
35 | logger.level = LoggerLevel.ALL;
36 |
37 | logger.css('color: red; text-decoration: underline; font-weight: bold').info(`It's awesome`);
38 |
39 | expect(fakeConsole.stack()).toEqual(
40 | fakeConsole.createStack({
41 | [TestLoggerLineType.INFO]: [
42 | 'color: red; text-decoration: underline; font-weight: bold;',
43 | `It's awesome`
44 | ]
45 | })
46 | );
47 | });
48 |
49 | it('Add css class', () => {
50 | logger.cssClass('class-1 class-3').log('Hello world');
51 |
52 | expect(fakeConsole.stack()).toEqual(
53 | fakeConsole.createStack({
54 | [TestLoggerLineType.LOG]: ['%c%s', 'font-weight: bold; color: #666;', 'Hello world']
55 | })
56 | );
57 |
58 | logger.clear();
59 |
60 | logger.cssClass('class-2').debug('Test 2');
61 | expect(fakeConsole.stack()).toEqual(
62 | fakeConsole.createStack({ [TestLoggerLineType.DEBUG]: ['text-decoration: line-through;', 'Test 2'] })
63 | );
64 | });
65 |
66 | it('Clear line style', () => {
67 | // with style
68 | logger.css('font-weight: bold');
69 | expect(logger.getCurrentLineStyle()).toEqual('font-weight: bold;');
70 |
71 | // without style
72 | logger.css('font-weight: bold');
73 | logger.clearCssCurrentLine();
74 | expect(logger.getCurrentLineStyle()).toEqual('');
75 | });
76 |
77 | it('Get current line style', () => {
78 | logger.css('text-transform: uppercase, font-weight: bold, font-size: 12px, margin: 10px, padding: 10px');
79 |
80 | expect(logger.getCurrentLineStyle()).toEqual(
81 | 'text-transform: uppercase, font-weight: bold, font-size: 12px, margin: 10px, padding: 10px;'
82 | );
83 | });
84 |
85 | it('should work with empty cssClass', () => {
86 | logger.cssClass('').debug(testString);
87 |
88 | expect(logger.getCurrentLineStyle()).toEqual('');
89 | });
90 | });
91 |
92 | describe('[TEST]: Check global styles', () => {
93 | let logger: LoggerService;
94 | const fakeConsole: ConsoleFake = new ConsoleFake();
95 | const testString: string = 'test string';
96 |
97 | beforeAll(() => {
98 | TestBed.configureTestingModule({
99 | imports: [
100 | LoggerModule.forRoot({
101 | instance: fakeConsole,
102 | globalLineStyle: 'color: violet; font-weight: bold; font-size: 12px'
103 | })
104 | ]
105 | });
106 |
107 | logger = TestBed.get(LoggerService);
108 | });
109 |
110 | beforeEach(() => logger.clear());
111 |
112 | it('should use global styles', () => {
113 | logger.log(testString);
114 | expect(fakeConsole.stack()).toEqual(
115 | '[{"log":["%c%s","color: violet; font-weight: bold; font-size: 12px;","test string"]}]'
116 | );
117 | });
118 |
119 | it('should use global styles and work with empty css', () => {
120 | logger.css('').log(testString);
121 | expect(fakeConsole.stack()).toEqual(
122 | '[{"log":["%c%s","color: violet; font-weight: bold; font-size: 12px;","test string"]}]'
123 | );
124 | });
125 | });
126 |
--------------------------------------------------------------------------------
/integration/tests/decorators.spec.ts:
--------------------------------------------------------------------------------
1 | import { ConsoleFake, TestLoggerLineType } from './helpers/console-fake';
2 | import { LoggerModule } from '../../lib/src/logger.module';
3 | import { LoggerService } from '../../lib/src/logger.service';
4 | import { MyTestComponent } from './helpers/test.component';
5 | import { ComponentFixture, TestBed } from '@angular/core/testing';
6 | import { LoggerLevel } from '../../lib/src/interfaces/logger.external';
7 | import { Fn } from '../../lib/src/interfaces/logger.internal';
8 |
9 | describe('[TEST]: Decorator API', () => {
10 | let logger: LoggerService;
11 | const fakeConsole: ConsoleFake = new ConsoleFake();
12 | const logIsWork: string = 'log is worked';
13 | const traceIsWork: string = 'trace is worked';
14 | const debugIsWork: string = 'debug is worked';
15 | const infoIsWork: string = 'info is worked';
16 | const warnIsWork: string = 'warn is worked';
17 | const errorIsWork: string = 'error is worked';
18 | const groupIsWork: string = 'group is worked';
19 | const groupCollapsedIsWork: string = 'groupCollapsed is worked';
20 |
21 | let fixture: ComponentFixture;
22 | let component: MyTestComponent;
23 |
24 | beforeEach(() => {
25 | TestBed.configureTestingModule({
26 | imports: [LoggerModule.forRoot({ instance: fakeConsole })],
27 | declarations: [MyTestComponent]
28 | }).compileComponents();
29 |
30 | fixture = TestBed.createComponent(MyTestComponent);
31 | component = fixture.componentInstance;
32 | logger = TestBed.get(LoggerService);
33 | logger.clear();
34 | });
35 |
36 | it('Logger decorator should correct work', () => {
37 | component.logger.log('Hello world');
38 | expect(fakeConsole.stack()).toEqual(fakeConsole.createStack({ [TestLoggerLineType.LOG]: ['Hello world'] }));
39 | });
40 |
41 | it('Group decorator should correct work', () => {
42 | const result: string = component.print(groupIsWork);
43 |
44 | expect(result).toEqual(groupIsWork);
45 | expect(fakeConsole.stack()).toEqual(
46 | fakeConsole.createStack({ group_open: ['Test group'] }, { log: ['group is worked'] }, { group_end: [] })
47 | );
48 | });
49 |
50 | it('Group decorator with level should correct work', () => {
51 | const result: string = component.printLevel(groupIsWork);
52 |
53 | expect(result).toEqual(groupIsWork);
54 | expect(fakeConsole.stack()).toEqual(
55 | fakeConsole.createStack({ group_open: ['Test group'] }, { log: [groupIsWork] }, { group_end: [] })
56 | );
57 | });
58 |
59 | it('GroupCollapced decorator should correct work', () => {
60 | const result: string = component.printCollapsed(groupCollapsedIsWork);
61 |
62 | expect(result).toEqual(groupCollapsedIsWork);
63 | expect(fakeConsole.stack()).toEqual(
64 | fakeConsole.createStack(
65 | { group_collapsed_open: ['Test group-collapsed'] },
66 | { log: [groupCollapsedIsWork] },
67 | { group_end: [] }
68 | )
69 | );
70 | });
71 |
72 | it('GroupCollapsed decorator with level should correct work', () => {
73 | const result: string = component.printCollapsedLevel(groupCollapsedIsWork);
74 |
75 | expect(result).toEqual(groupCollapsedIsWork);
76 | expect(fakeConsole.stack()).toEqual(
77 | fakeConsole.createStack(
78 | { group_collapsed_open: ['Test group-collapsed'] },
79 | { log: [groupCollapsedIsWork] },
80 | { group_end: [] }
81 | )
82 | );
83 | });
84 |
85 | it('Method decorators should correct work', () => {
86 | component.log(logIsWork);
87 | component.trace(traceIsWork);
88 | component.debug(debugIsWork);
89 | component.info(infoIsWork);
90 | component.error(errorIsWork);
91 | component.warn(warnIsWork);
92 | expect(fakeConsole.stack()).toEqual(
93 | fakeConsole.createStack(
94 | { [TestLoggerLineType.LOG]: [logIsWork] },
95 | { [TestLoggerLineType.TRACE_OR_DEBUG]: [traceIsWork] },
96 | { [TestLoggerLineType.DEBUG]: [debugIsWork] },
97 | { [TestLoggerLineType.INFO]: [infoIsWork] },
98 | { [TestLoggerLineType.ERROR]: [errorIsWork] },
99 | { [TestLoggerLineType.WARN]: [warnIsWork] }
100 | )
101 | );
102 | });
103 |
104 | it('should be correct invoke methods', () => {
105 | component.init();
106 | expect(component.count).toEqual(1);
107 | expect(fakeConsole.stack()).toEqual('[]');
108 | });
109 |
110 | it('should be correct title methods', () => {
111 | const result: string = component.method('hello world');
112 |
113 | expect(result).toEqual('hello world');
114 |
115 | expect(fakeConsole.stack()).toEqual(
116 | fakeConsole.createStack(
117 | { group_open: ['Test group with hello world'] },
118 | { log: [groupIsWork] },
119 | { group_end: [] }
120 | )
121 | );
122 | });
123 |
124 | it('timer invoke', () => {
125 | logger.level = LoggerLevel.ALL;
126 | component.ngOnInit();
127 | expect(fakeConsole.stack().includes('TimerLog: mock:ngOnInit')).toEqual(true);
128 | });
129 |
130 | it('can not execute', () => {
131 | logger.level = LoggerLevel.ERROR;
132 | component.ngOnInit();
133 | expect(fakeConsole.stack()).toEqual(fakeConsole.createStack());
134 | });
135 |
136 | it('query by second timer', (done: Fn) => {
137 | component.longQueryBySecond(3, done);
138 | expect(fakeConsole.stack()).toEqual(
139 | fakeConsole.createStack({ info: ['TimerLog: longQueryBySecond', 'took 3s to execute'] })
140 | );
141 | });
142 |
143 | it('query by ms timer', (done: Fn) => {
144 | component.longQueryBySecondMs(3, done);
145 | expect(fakeConsole.stack().includes('TimerLog: longQueryBySecondMs')).toEqual(true);
146 | });
147 |
148 | it('should correct work with errors', () => {
149 | try {
150 | component.badRequest();
151 | } catch (e) {
152 | expect(e.message).toEqual('error');
153 | }
154 | });
155 | });
156 |
--------------------------------------------------------------------------------
/integration/tests/helpers/console-fake.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | import { ObjectKeyMap } from '../../../lib/src/interfaces/logger.internal';
3 |
4 | export enum TestLoggerLineType {
5 | TABLE = 'table',
6 | ASSERT = 'assert',
7 | TRACE_OR_DEBUG = 'debug',
8 | LOG = 'log',
9 | DEBUG = 'info',
10 | INFO = 'info',
11 | WARN = 'warn',
12 | ERROR = 'error'
13 | }
14 |
15 | export enum TestLoggerGroupType {
16 | GROUP_OPEN = 'group_open',
17 | GROUP_COLLAPSED_OPEN = 'group_collapsed_open',
18 | GROUP_END = 'group_end'
19 | }
20 |
21 | export class ConsoleFake implements Console {
22 | // tslint:disable-next-line:no-any
23 | public Console: any;
24 | private _stack: ObjectKeyMap[] = [];
25 |
26 | public log(...args: string[]): void {
27 | args.unshift(null!, null!);
28 | this._stack.push({ [TestLoggerLineType.LOG]: args });
29 | }
30 |
31 | public debug(...args: string[]): void {
32 | this._stack.push({ [TestLoggerLineType.TRACE_OR_DEBUG]: args });
33 | }
34 |
35 | public info(...args: string[]): void {
36 | this._stack.push({ [TestLoggerLineType.INFO]: args });
37 | }
38 |
39 | public assert(condition: boolean, output: string): void {
40 | if (!condition) {
41 | this._stack.push({ [TestLoggerLineType.ASSERT]: [output] });
42 | }
43 | }
44 |
45 | public table(data: unknown): void {
46 | this._stack.push({ [TestLoggerLineType.TABLE]: [data] });
47 | }
48 |
49 | public warn(...args: string[]): void {
50 | this._stack.push({ [TestLoggerLineType.WARN]: args });
51 | }
52 |
53 | public error(...args: string[]): void {
54 | this._stack.push({ [TestLoggerLineType.ERROR]: args });
55 | }
56 |
57 | public group(...args: string[]): void {
58 | this._stack.push({ [TestLoggerGroupType.GROUP_OPEN]: args });
59 | }
60 |
61 | public groupCollapsed(...args: string[]): void {
62 | this._stack.push({ [TestLoggerGroupType.GROUP_COLLAPSED_OPEN]: args });
63 | }
64 |
65 | public groupEnd(): void {
66 | this._stack.push({ [TestLoggerGroupType.GROUP_END]: [] });
67 | }
68 |
69 | public createStack(...args: ObjectKeyMap[]): string {
70 | return JSON.stringify(args);
71 | }
72 |
73 | public stack(withoutLabel: number = 2): string {
74 | const history: ObjectKeyMap = [...this._stack];
75 | history.forEach((line: object, index: number) => {
76 | for (const arg in line) {
77 | if (line.hasOwnProperty(arg)) {
78 | const isArray: boolean = Array.isArray((line as any)[arg]);
79 | history[index] = { [arg]: isArray ? (line as any)[arg].slice(withoutLabel) : (line as any)[arg] };
80 | }
81 | }
82 | });
83 |
84 | return JSON.stringify(history);
85 | }
86 |
87 | public stackList(stack: string): string[] {
88 | const stackObject: ObjectKeyMap = JSON.parse(stack);
89 | const stackList: string[] = [];
90 |
91 | stackObject.forEach((line: string[]) => {
92 | for (const levelLog in line) {
93 | if (line.hasOwnProperty(levelLog)) {
94 | stackList.push(line[levelLog]);
95 | }
96 | }
97 | });
98 |
99 | return stackList;
100 | }
101 | public stackOptionsList(usageNext: boolean = false): ObjectKeyMap {
102 | const stackList: string[] = this.stackList(this.stack(0));
103 | const stackOptionsList: ObjectKeyMap = [];
104 |
105 | stackList.forEach((line: string) => {
106 | stackOptionsList.push({
107 | label: String(line[0]).replace('%c', ''),
108 | styles: this.parseCssString(line[usageNext ? 2 : 1])
109 | });
110 | });
111 |
112 | return stackOptionsList;
113 | }
114 |
115 | private parseCssString(css: string): ObjectKeyMap {
116 | const result: ObjectKeyMap = {};
117 | const attributes: string[] = css.split(';');
118 |
119 | attributes.forEach((attribute: string) => {
120 | const entry: string[] = attribute.split(':');
121 | const property: string = String(entry.splice(0, 1)[0]).trim();
122 | const options: string = entry.join(':').trim();
123 | if (property.length) {
124 | result[property] = options;
125 | }
126 | });
127 |
128 | return result;
129 | }
130 |
131 | public clear(): void {
132 | this._stack = [];
133 | }
134 |
135 | public count(): void {
136 | // noop;
137 | }
138 |
139 | public memory(): void {
140 | // noop;
141 | }
142 |
143 | public dir(): void {
144 | // noop;
145 | }
146 |
147 | public dirxml(): void {
148 | // noop;
149 | }
150 |
151 | public exception(): void {
152 | // noop;
153 | }
154 |
155 | public markTimeline(): void {
156 | // noop;
157 | }
158 |
159 | public profile(): void {
160 | // noop;
161 | }
162 |
163 | public profileEnd(): void {
164 | // noop;
165 | }
166 |
167 | public time(): void {
168 | // noop;
169 | }
170 |
171 | public timeEnd(): void {
172 | // noop;
173 | }
174 |
175 | public timeStamp(): void {
176 | // noop;
177 | }
178 |
179 | public timeline(): void {
180 | // noop;
181 | }
182 |
183 | public timelineEnd(): void {
184 | // noop;
185 | }
186 |
187 | public trace(): void {
188 | // noop;
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/integration/tests/helpers/custom-colors.enum.ts:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line @typescript-eslint/naming-convention,no-restricted-syntax
2 | export enum CUSTOM_COLORS {
3 | TRACE = 'BlueViolet',
4 | DEBUG = 'CornflowerBlue',
5 | INFO = 'DarkGreen',
6 | WARN = 'Coral',
7 | ERROR = 'Crimson'
8 | }
9 |
10 | // eslint-disable-next-line no-restricted-syntax,@typescript-eslint/naming-convention
11 | export enum CUSTOM_LABELS {
12 | TRACE = 'trace:',
13 | DEBUG = 'debug:',
14 | INFO = 'info:',
15 | WARN = 'warning:',
16 | ERROR = 'error:'
17 | }
18 |
--------------------------------------------------------------------------------
/integration/tests/helpers/test.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | import { DebugLog } from '../../../lib/src/decorators/debug.decorator';
4 | import { ErrorLog } from '../../../lib/src/decorators/error.decorator';
5 | import { GroupCollapsed } from '../../../lib/src/decorators/groups/group-collapsed.decorator';
6 | import { Group } from '../../../lib/src/decorators/groups/group.decorator';
7 | import { InfoLog } from '../../../lib/src/decorators/info.decorator';
8 | import { Log } from '../../../lib/src/decorators/log.decorator';
9 | import { Logger } from '../../../lib/src/decorators/logger.decorator';
10 | import { TimerLog } from '../../../lib/src/decorators/timer.decorator';
11 | import { TraceLog } from '../../../lib/src/decorators/trace.decorator';
12 | import { WarnLog } from '../../../lib/src/decorators/warn.decorator';
13 | import { LogFn, LoggerLevel, TimerInfo } from '../../../lib/src/interfaces/logger.external';
14 | import { Fn } from '../../../lib/src/interfaces/logger.internal';
15 | import { LoggerService } from '../../../lib/src/logger.service';
16 |
17 | interface HttpDebugInterface {
18 | method: string;
19 | url: string;
20 | queryParams: string;
21 | data: unknown;
22 | body: unknown;
23 | errorData: unknown;
24 | }
25 |
26 | // noinspection AngularMissingOrInvalidDeclarationInModule
27 | @Component({ selector: 'lib-hello-test', template: '' })
28 | export class MyTestComponent implements OnInit {
29 | @Logger() public logger!: LoggerService;
30 | @TraceLog() public trace!: LogFn;
31 | @DebugLog() public debug!: LogFn;
32 | @InfoLog() public info!: LogFn;
33 | @ErrorLog() public error!: LogFn;
34 | @WarnLog() public warn!: LogFn;
35 | @Log() public log!: LogFn;
36 |
37 | public count: number = 0;
38 | public hook: string | null = null;
39 | public doneHeavy: boolean = false;
40 | public name: string = 'MockLoggerComponent';
41 |
42 | public static getUrlInfo({ method, url, queryParams }: Partial): string {
43 | const params: string = queryParams ? `?${queryParams}` : '';
44 | return `[${method}] - ${url}${params}`;
45 | }
46 |
47 | @Group('Test group')
48 | public print(val: string): string {
49 | this.logger.log(val);
50 | return val;
51 | }
52 |
53 | @Group('Test group', LoggerLevel.WARN)
54 | public printLevel(val: string): string {
55 | this.logger.log(val);
56 | return val;
57 | }
58 |
59 | @GroupCollapsed('Test group-collapsed')
60 | public printCollapsed(val: string): string {
61 | this.logger.log(val);
62 | return val;
63 | }
64 |
65 | @GroupCollapsed('Test group-collapsed', LoggerLevel.WARN)
66 | public printCollapsedLevel(val: string): string {
67 | this.logger.log(val);
68 | return val;
69 | }
70 |
71 | public init(): void {
72 | this.logger.level = LoggerLevel.INFO;
73 | this.increment();
74 | }
75 |
76 | @Group('INCREMENT', LoggerLevel.DEBUG)
77 | public increment(): void {
78 | this.logger.debug('count', this.count);
79 | this.count++;
80 | }
81 |
82 | @Group((name: string): string => `Test group with ${name}`)
83 | public method(name: string): string {
84 | this.logger.log('group is worked');
85 | return name;
86 | }
87 |
88 | @Group((options: Partial): string => MyTestComponent.getUrlInfo(options))
89 | public hello(name: string): string {
90 | this.logger.log('group is worked');
91 | return name;
92 | }
93 |
94 | @TimerLog('mock:ngOnInit')
95 | public ngOnInit(): void {
96 | this.hook = 'ngOnInit';
97 | }
98 |
99 | @TimerLog('longQueryBySecond', LoggerLevel.INFO, false)
100 | public longQueryBySecond(seconds: number, done: Fn): void {
101 | this.extracted(seconds, done);
102 | }
103 |
104 | public longQueryBySecondMs(seconds: number, done: Fn): void {
105 | const info: TimerInfo | null = this.logger.startTime('longQueryBySecondMs');
106 | this.extracted(seconds, done);
107 | this.logger.endTime(info);
108 | }
109 |
110 | @TimerLog('badRequest', LoggerLevel.DEBUG, false)
111 | public badRequest(): void {
112 | throw new Error('error');
113 | }
114 |
115 | private extracted(seconds: number, done: Fn): void {
116 | // eslint-disable-next-line @typescript-eslint/no-magic-numbers
117 | const e: number = new Date().getTime() + seconds * 1000;
118 | while (new Date().getTime() <= e) {
119 | this.doneHeavy = true;
120 | }
121 | done();
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/integration/tests/injector.spec.ts:
--------------------------------------------------------------------------------
1 | import { LoggerInjector } from '../../lib/src/logger.injector';
2 | import { LoggerService } from '../../lib/src/logger.service';
3 |
4 | describe('[TEST]: Check injector error', () => {
5 | it('should return error', (): void => {
6 | let message: string | null = null;
7 |
8 | try {
9 | LoggerInjector.getInjector().get(LoggerService).log;
10 | } catch (e) {
11 | message = e.message;
12 | }
13 |
14 | expect(message).toEqual(`You've forgotten to import \`LoggerModule\``);
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/integration/tests/json.spec.ts:
--------------------------------------------------------------------------------
1 | import { LoggerService } from '../../lib/src/logger.service';
2 | import { ConsoleFake, TestLoggerLineType } from './helpers/console-fake';
3 | import { TestBed } from '@angular/core/testing';
4 | import { LoggerModule } from '../../lib/src/logger.module';
5 |
6 | describe('[TEST]: Check JSON', () => {
7 | let logger: LoggerService;
8 | const fakeConsole: ConsoleFake = new ConsoleFake();
9 |
10 | beforeAll(() => {
11 | TestBed.configureTestingModule({
12 | imports: [LoggerModule.forRoot({ instance: fakeConsole })]
13 | });
14 |
15 | logger = TestBed.get(LoggerService);
16 | });
17 |
18 | it('should be pretty json', () => {
19 | logger.clear();
20 | logger.log(logger.prettyJSON({ a: true, b: [1, 2], c: 'test string', d: null }));
21 |
22 | expect(fakeConsole.stack()).toEqual(
23 | fakeConsole.createStack({
24 | [TestLoggerLineType.LOG]: [
25 | [
26 | // tslint:disable-next-line:max-line-length
27 | '{\n %c"a":%c %ctrue%c,\n %c"b":%c [\n %c1%c,\n %c2%c\n ],\n %c"c":%c %c"test string"%c,\n %c"d":%c %cnull%c\n}',
28 | 'color:red',
29 | '',
30 | 'color:blue',
31 | '',
32 | 'color:red',
33 | '',
34 | 'color:darkorange',
35 | '',
36 | 'color:darkorange',
37 | '',
38 | 'color:red',
39 | '',
40 | 'color:green',
41 | '',
42 | 'color:red',
43 | '',
44 | 'color:magenta',
45 | ''
46 | ]
47 | ]
48 | })
49 | );
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/integration/tests/logger.module.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 | import { LoggerModule } from '../../lib/src/logger.module';
3 | import { LoggerService } from '../../lib/src/logger.service';
4 | import { ConsoleFake, TestLoggerLineType } from './helpers/console-fake';
5 | import { LoggerLevel } from '../../lib/src/interfaces/logger.external';
6 | import { ObjectKeyMap } from '../../lib/src/interfaces/logger.internal';
7 |
8 | describe('[TEST]: Execute method by Level', () => {
9 | let logger: LoggerService;
10 | const fakeConsole: ConsoleFake = new ConsoleFake();
11 |
12 | const traceIsWork: string = 'trace is worked';
13 | const debugIsWork: string = 'debug is worked';
14 | const infoIsWork: string = 'info is worked';
15 | const warnIsWork: string = 'warn is worked';
16 | const errorIsWork: string = 'error is worked';
17 | const customLogOutput: string = 'custom log output';
18 |
19 | beforeAll(() => {
20 | TestBed.configureTestingModule({
21 | imports: [LoggerModule.forRoot({ instance: fakeConsole })]
22 | });
23 |
24 | logger = TestBed.get(LoggerService);
25 | });
26 |
27 | beforeEach(() => logger.clear());
28 |
29 | it(`All data must go to the console, minimal level: TRACE`, () => {
30 | logger.level = LoggerLevel.TRACE;
31 |
32 | logger.log(customLogOutput);
33 | logger.trace(traceIsWork, 1, { a: 1 });
34 | logger.debug(debugIsWork, 2, {});
35 | logger.info(infoIsWork, 3, Object);
36 | logger.warn(warnIsWork, 4, String);
37 | logger.error(errorIsWork, 5, (2.55).toFixed());
38 |
39 | expect(fakeConsole.stack()).toEqual(
40 | fakeConsole.createStack(
41 | { [TestLoggerLineType.LOG]: [customLogOutput] },
42 | { [TestLoggerLineType.TRACE_OR_DEBUG]: [traceIsWork, 1, { a: 1 }] },
43 | { [TestLoggerLineType.DEBUG]: [debugIsWork, 2, {}] },
44 | { [TestLoggerLineType.INFO]: [infoIsWork, 3, Object] },
45 | { [TestLoggerLineType.WARN]: [warnIsWork, 4, String] },
46 | { [TestLoggerLineType.ERROR]: [errorIsWork, 5, (2.55).toFixed()] }
47 | )
48 | );
49 | });
50 |
51 | it(`Show console stack when minimal level: DEBUG`, () => {
52 | logger.level = LoggerLevel.DEBUG;
53 |
54 | logger.log(customLogOutput);
55 | logger.trace(traceIsWork, 1, { a: 1 });
56 | logger.debug(debugIsWork, 2, { b: 2 });
57 | logger.info(infoIsWork, 3, Object);
58 | logger.warn(warnIsWork, 4, String);
59 | logger.error(errorIsWork, 5, (2.55).toFixed());
60 |
61 | expect(fakeConsole.stack()).toEqual(
62 | fakeConsole.createStack(
63 | { [TestLoggerLineType.LOG]: [customLogOutput] },
64 | { [TestLoggerLineType.DEBUG]: [debugIsWork, 2, { b: 2 }] },
65 | { [TestLoggerLineType.INFO]: [infoIsWork, 3, Object] },
66 | { [TestLoggerLineType.WARN]: [warnIsWork, 4, String] },
67 | { [TestLoggerLineType.ERROR]: [errorIsWork, 5, (2.55).toFixed()] }
68 | )
69 | );
70 | });
71 |
72 | it(`Show console stack when minimal level: DEBUG`, () => {
73 | logger.level = LoggerLevel.DEBUG;
74 |
75 | logger.log(customLogOutput);
76 | logger.trace(traceIsWork, 1, { a: 1 });
77 | logger.debug(debugIsWork, 2, {});
78 | logger.info(infoIsWork, 3, Object);
79 | logger.warn(warnIsWork, 4, String);
80 | logger.error(errorIsWork, 5, (2.55).toFixed());
81 |
82 | expect(fakeConsole.stack()).toEqual(
83 | fakeConsole.createStack(
84 | { [TestLoggerLineType.LOG]: [customLogOutput] },
85 | { [TestLoggerLineType.DEBUG]: [debugIsWork, 2, {}] },
86 | { [TestLoggerLineType.INFO]: [infoIsWork, 3, Object] },
87 | { [TestLoggerLineType.WARN]: [warnIsWork, 4, String] },
88 | { [TestLoggerLineType.ERROR]: [errorIsWork, 5, (2.55).toFixed()] }
89 | )
90 | );
91 | });
92 |
93 | it(`Show console stack when minimal level: INFO`, () => {
94 | logger.level = LoggerLevel.INFO;
95 |
96 | logger.log(customLogOutput);
97 | logger.trace(traceIsWork, 1, { a: 1 });
98 | logger.debug(debugIsWork, 2, console);
99 | logger.info(infoIsWork, 3, Object);
100 | logger.warn(warnIsWork, 4, String);
101 | logger.error(errorIsWork, 5, (2.55).toFixed());
102 |
103 | expect(fakeConsole.stack()).toEqual(
104 | fakeConsole.createStack(
105 | { [TestLoggerLineType.LOG]: [customLogOutput] },
106 | { [TestLoggerLineType.INFO]: [infoIsWork, 3, Object] },
107 | { [TestLoggerLineType.WARN]: [warnIsWork, 4, String] },
108 | { [TestLoggerLineType.ERROR]: [errorIsWork, 5, (2.55).toFixed()] }
109 | )
110 | );
111 | });
112 |
113 | it(`Show console stack when minimal level: WARNING`, () => {
114 | logger.level = LoggerLevel.WARN;
115 |
116 | logger.log(customLogOutput);
117 | logger.trace(traceIsWork, 1, { a: 1 });
118 | logger.debug(debugIsWork, 2, console);
119 | logger.info(infoIsWork, 3, Object);
120 | logger.warn(warnIsWork, 4, String);
121 | logger.error(errorIsWork, 5, (2.55).toFixed());
122 |
123 | expect(fakeConsole.stack()).toEqual(
124 | fakeConsole.createStack(
125 | { [TestLoggerLineType.WARN]: [warnIsWork, 4, String] },
126 | { [TestLoggerLineType.ERROR]: [errorIsWork, 5, (2.55).toFixed()] }
127 | )
128 | );
129 | });
130 |
131 | it(`Show console stack when minimal level: ERROR`, () => {
132 | logger.level = LoggerLevel.ERROR;
133 |
134 | logger.log(customLogOutput);
135 | logger.trace(traceIsWork, 1, { a: 1 });
136 | logger.debug(debugIsWork, 2, console);
137 | logger.info(infoIsWork, 3, Object);
138 | logger.warn(warnIsWork, 4, String);
139 | logger.error(errorIsWork, 5, (2.55).toFixed());
140 |
141 | expect(fakeConsole.stack()).toEqual(
142 | fakeConsole.createStack({ [TestLoggerLineType.ERROR]: ['error is worked', 5, (2.55).toFixed()] })
143 | );
144 | });
145 |
146 | it(`Not showing data in console, level: OFF`, () => {
147 | logger.level = LoggerLevel.OFF;
148 |
149 | logger.log(customLogOutput);
150 | logger.trace(traceIsWork, 1, { a: 1 });
151 | logger.debug(debugIsWork, 2, console);
152 | logger.info(infoIsWork, 3, Object);
153 | logger.warn(warnIsWork, 4, String);
154 | logger.error(errorIsWork, 5, (2.55).toFixed());
155 |
156 | expect(fakeConsole.stack()).toEqual(fakeConsole.createStack());
157 | });
158 |
159 | it(`Clear console stack is worked`, () => {
160 | logger.level = LoggerLevel.ALL;
161 | expect(fakeConsole.stack()).toEqual(fakeConsole.createStack());
162 | });
163 |
164 | it(`Set minimal level: INFO`, () => {
165 | logger.level = LoggerLevel.INFO;
166 | expect(logger.level).toEqual(LoggerLevel.INFO);
167 | });
168 |
169 | it(`Assert: 5 is not grater than 6`, () => {
170 | logger.assert(5 > 6, '5 is not grater than 6');
171 | expect(fakeConsole.stack(0)).toEqual(
172 | fakeConsole.createStack({ [TestLoggerLineType.ASSERT]: [`5 is not grater than 6`] })
173 | );
174 | });
175 |
176 | it(`Assert: 10 is grater than 6`, () => {
177 | logger.assert(10 > 6, '10 is not grater than 6');
178 | expect(fakeConsole.stack(0)).toEqual(fakeConsole.createStack());
179 | });
180 |
181 | it(`Table`, () => {
182 | const data: ObjectKeyMap = [
183 | { name: 'Yusuf', age: 26 },
184 | { age: 34, name: 'Chen' }
185 | ];
186 |
187 | logger.table(data);
188 | expect(fakeConsole.stack(0)).toEqual(fakeConsole.createStack({ [TestLoggerLineType.TABLE]: [data] }));
189 | });
190 |
191 | it('should be equals reference context (this)', () => {
192 | const { pipe }: LoggerService = logger;
193 | expect(pipe() === logger).toEqual(true);
194 | });
195 | });
196 |
--------------------------------------------------------------------------------
/integration/tests/setupJest.ts:
--------------------------------------------------------------------------------
1 | import 'jest-preset-angular';
2 |
--------------------------------------------------------------------------------
/integration/tests/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../out-tsc/spec",
5 | "types": ["jest", "node"]
6 | },
7 | "include": ["**/*.spec.ts", "**/*.d.ts"]
8 | }
9 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | const { createTsJestConfig } = require('@angular-ru/jest-utils');
2 | const path = require('path');
3 |
4 | module.exports = createTsJestConfig({
5 | maxWorkers: 2,
6 | maxConcurrency: 2,
7 | displayName: 'Logger',
8 | rootDir: path.resolve('.'),
9 | modulePathIgnorePatterns: ['/dist/'],
10 | collectCoverageFrom: ['/lib/**/*.ts'],
11 | testMatch: ['/integration/tests/**/*.spec.ts'],
12 | tsConfigSpecPath: '/integration/tests/tsconfig.spec.json',
13 | setupFilesAfterEnv: ['/integration/tests/setupJest.ts'],
14 | tsConfigRootPath: path.resolve('./tsconfig.json')
15 | });
16 |
--------------------------------------------------------------------------------
/lib/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../node_modules/ng-packagr/ng-package.schema.json",
3 | "lib": { "entryFile": "src/public-api.ts" },
4 | "dest": "../dist/logger"
5 | }
6 |
--------------------------------------------------------------------------------
/lib/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@angular-ru/logger",
3 | "version": "1.11.0",
4 | "license": "MIT",
5 | "homepage": "https://github.com/Angular-RU/angular-logger",
6 | "repository": "https://github.com/Angular-RU/angular-logger",
7 | "peerDependencies": {
8 | "@angular/common": ">=7.0.0",
9 | "@angular/core": ">=7.0.0"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/lib/src/decorators/autobind.decorator.ts:
--------------------------------------------------------------------------------
1 | import { Any, Fn, ObjectKeyMap } from '../interfaces/logger.internal';
2 |
3 | const { defineProperty, getOwnPropertyDescriptor, getOwnPropertyNames, getOwnPropertySymbols }: ObjectKeyMap = Object;
4 |
5 | function bind(fn: Fn, context: Any): Fn {
6 | return fn.bind(context);
7 | }
8 |
9 | function getOwnKeys(descriptors: ObjectKeyMap): string[] {
10 | return getOwnPropertyNames(descriptors).concat(getOwnPropertySymbols(descriptors));
11 | }
12 |
13 | function autoBindClass(target: ObjectKeyMap): Any {
14 | const descriptors: ObjectKeyMap = getOwnPropertyDescriptors(target.prototype);
15 | const keys: string[] = getOwnKeys(descriptors);
16 |
17 | for (let i: number = 0, l: number = keys.length; i < l; i++) {
18 | const key: string = keys[i];
19 | const descriptor: Any = descriptors[key];
20 |
21 | if (typeof descriptor.value !== 'function' || key === 'constructor') {
22 | continue;
23 | }
24 |
25 | defineProperty(target.prototype, key, autoBindMethod(target.prototype, key, descriptor));
26 | }
27 | }
28 |
29 | function getOwnPropertyDescriptors(target: ObjectKeyMap): ObjectKeyMap {
30 | const descriptors: ObjectKeyMap = {};
31 |
32 | getOwnKeys(target).forEach((key: string): void => {
33 | descriptors[key] = getOwnPropertyDescriptor(target, key);
34 | });
35 |
36 | return descriptors;
37 | }
38 |
39 | // eslint-disable-next-line max-lines-per-function
40 | function autoBindMethod(
41 | target: ObjectKeyMap,
42 | key: string,
43 | { value: fn, configurable, enumerable }: Any
44 | ): PropertyDescriptor {
45 | return {
46 | configurable,
47 | enumerable,
48 |
49 | get(): Fn {
50 | if (this === target) {
51 | return fn;
52 | }
53 |
54 | const boundFn: Fn = bind(fn, this);
55 |
56 | defineProperty(this, key, {
57 | configurable: true,
58 | writable: true,
59 |
60 | enumerable: false,
61 | value: boundFn
62 | });
63 |
64 | return boundFn;
65 | },
66 | set: createDefaultSetter(key)
67 | };
68 | }
69 |
70 | function handle(args: Any[]): Any {
71 | if (args.length === 1) {
72 | return autoBindClass(args[0]);
73 | } else {
74 | // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
75 | // @ts-ignore
76 | return autoBindMethod(...args);
77 | }
78 | }
79 |
80 | export function autoBind(...args: Any[]): Any {
81 | if (args.length === 0) {
82 | return function (...argsClass: Any[]): Fn {
83 | return handle(argsClass);
84 | };
85 | } else {
86 | return handle(args);
87 | }
88 | }
89 |
90 | function createDefaultSetter(key: Any): Fn {
91 | return function set(this: Any, newValue: unknown): unknown {
92 | Object.defineProperty(this, key, {
93 | configurable: true,
94 | writable: true,
95 | enumerable: true,
96 | value: newValue
97 | });
98 |
99 | return newValue;
100 | };
101 | }
102 |
--------------------------------------------------------------------------------
/lib/src/decorators/debug.decorator.ts:
--------------------------------------------------------------------------------
1 | import { LogFn } from '../interfaces/logger.external';
2 | import { LoggerInjector } from '../logger.injector';
3 | import { LoggerService } from '../logger.service';
4 |
5 | export function DebugLog(): PropertyDecorator {
6 | return (target: unknown, propertyName: string | symbol): void => {
7 | Object.defineProperty(target, propertyName, {
8 | configurable: false,
9 | get(): LogFn {
10 | return LoggerInjector.getInjector().get(LoggerService).debug;
11 | }
12 | });
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/lib/src/decorators/error.decorator.ts:
--------------------------------------------------------------------------------
1 | import { LogFn } from '../interfaces/logger.external';
2 | import { LoggerInjector } from '../logger.injector';
3 | import { LoggerService } from '../logger.service';
4 |
5 | export function ErrorLog(): PropertyDecorator {
6 | return (target: unknown, propertyName: string | symbol): void => {
7 | Object.defineProperty(target, propertyName, {
8 | configurable: false,
9 | get(): LogFn {
10 | return LoggerInjector.getInjector().get(LoggerService).error;
11 | }
12 | });
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/lib/src/decorators/groups/group-collapsed.decorator.ts:
--------------------------------------------------------------------------------
1 | import { Type } from '@angular/core';
2 |
3 | import { GroupLevel, LoggerLevel } from '../../interfaces/logger.external';
4 | import { Any, Callback, DecoratorMethod, Fn } from '../../interfaces/logger.internal';
5 | import { groupDecoratorFactory } from './group.common';
6 |
7 | export function GroupCollapsed(title: string | Callback, level: LoggerLevel = LoggerLevel.INFO): DecoratorMethod {
8 | return (_target: Type, _key: string, descriptor: PropertyDescriptor): PropertyDescriptor => {
9 | const method: Callback = descriptor.value;
10 |
11 | descriptor.value = function (...args: Any[]): unknown {
12 | return groupDecoratorFactory(level, GroupLevel.GROUP_COLLAPSED, method as Fn, title, args, this as Any);
13 | };
14 |
15 | return descriptor;
16 | };
17 | }
18 |
--------------------------------------------------------------------------------
/lib/src/decorators/groups/group.common.ts:
--------------------------------------------------------------------------------
1 | import { Type } from '@angular/core';
2 |
3 | import { GroupLevel, GroupMethod, LoggerLevel } from '../../interfaces/logger.external';
4 | import { Any, Callback, Fn } from '../../interfaces/logger.internal';
5 | import { LoggerInjector } from '../../logger.injector';
6 | import { LoggerService } from '../../logger.service';
7 | import { GroupFactory } from '../../services/group-factory.service';
8 |
9 | // eslint-disable-next-line max-params
10 | export function groupDecoratorFactory(
11 | level: LoggerLevel,
12 | groupType: GroupLevel,
13 | method: Fn,
14 | title: string | Callback,
15 | args: Any[],
16 | target: Type
17 | ): unknown {
18 | const logger: LoggerService = LoggerInjector.getInjector().get(LoggerService);
19 | const groupFactory: GroupFactory = LoggerInjector.getInjector().get(GroupFactory);
20 | const groupMethod: GroupMethod = groupFactory[groupType].bind(groupFactory) as GroupMethod;
21 | const label: string = typeof title === 'string' ? title : title(...args);
22 |
23 | groupMethod(label, null, logger, level);
24 | const result: unknown = method.apply(target, args);
25 |
26 | if (logger.level <= level) {
27 | logger.close();
28 | }
29 |
30 | return result;
31 | }
32 |
--------------------------------------------------------------------------------
/lib/src/decorators/groups/group.decorator.ts:
--------------------------------------------------------------------------------
1 | import { Type } from '@angular/core';
2 |
3 | import { GroupLevel, LoggerLevel } from '../../interfaces/logger.external';
4 | import { Any, Callback, DecoratorMethod, Fn } from '../../interfaces/logger.internal';
5 | import { groupDecoratorFactory } from './group.common';
6 |
7 | export function Group(title: string | Callback, level: LoggerLevel = LoggerLevel.INFO): DecoratorMethod {
8 | return (_target: Type, _key: string, descriptor: PropertyDescriptor): PropertyDescriptor => {
9 | const method: Callback = descriptor.value;
10 |
11 | descriptor.value = function (...args: Any[]): unknown {
12 | return groupDecoratorFactory(level, GroupLevel.GROUP, method as Fn, title, args, this as Any);
13 | };
14 |
15 | return descriptor;
16 | };
17 | }
18 |
--------------------------------------------------------------------------------
/lib/src/decorators/info.decorator.ts:
--------------------------------------------------------------------------------
1 | import { LogFn } from '../interfaces/logger.external';
2 | import { LoggerInjector } from '../logger.injector';
3 | import { LoggerService } from '../logger.service';
4 |
5 | export function InfoLog(): PropertyDecorator {
6 | return (target: unknown, propertyName: string | symbol): void => {
7 | Object.defineProperty(target, propertyName, {
8 | configurable: false,
9 | get(): LogFn {
10 | return LoggerInjector.getInjector().get(LoggerService).info;
11 | }
12 | });
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/lib/src/decorators/log.decorator.ts:
--------------------------------------------------------------------------------
1 | import { LogFn } from '../interfaces/logger.external';
2 | import { LoggerInjector } from '../logger.injector';
3 | import { LoggerService } from '../logger.service';
4 |
5 | export function Log(): PropertyDecorator {
6 | return (target: unknown, propertyName: string | symbol): void => {
7 | Object.defineProperty(target, propertyName, {
8 | configurable: false,
9 | get(): LogFn {
10 | return LoggerInjector.getInjector().get(LoggerService).log;
11 | }
12 | });
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/lib/src/decorators/logger.decorator.ts:
--------------------------------------------------------------------------------
1 | import { LoggerInjector } from '../logger.injector';
2 | import { LoggerService } from '../logger.service';
3 |
4 | export function Logger(): PropertyDecorator {
5 | return (target: unknown, propertyName: string | symbol): void => {
6 | Object.defineProperty(target, propertyName, {
7 | configurable: false,
8 | get(): LoggerService {
9 | return LoggerInjector.getInjector().get(LoggerService);
10 | }
11 | });
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/lib/src/decorators/timer.decorator.ts:
--------------------------------------------------------------------------------
1 | import { Type } from '@angular/core';
2 |
3 | import { LoggerLevel, TimerInfo, TimerLevels } from '../interfaces/logger.external';
4 | import { Any, DecoratorMethod, Fn } from '../interfaces/logger.internal';
5 | import { LoggerInjector } from '../logger.injector';
6 | import { LoggerService } from '../logger.service';
7 |
8 | // eslint-disable-next-line max-lines-per-function
9 | export function TimerLog(
10 | title: string,
11 | level: TimerLevels = LoggerLevel.DEBUG,
12 | isMillisecond: boolean = true
13 | ): DecoratorMethod {
14 | return (_target: Type, _key: string, descriptor: PropertyDescriptor): PropertyDescriptor => {
15 | let result: PropertyDescriptor;
16 | const method: Fn = descriptor.value;
17 | descriptor.value = function (...args: Any[]): PropertyDescriptor {
18 | const info: TimerInfo | null = LoggerInjector.getInjector()
19 | .get(LoggerService)
20 | .startTime(title, level);
21 |
22 | result = method.apply(this, args) as PropertyDescriptor;
23 |
24 | LoggerInjector.getInjector().get(LoggerService).endTime(info!, level, isMillisecond);
25 | return result;
26 | };
27 | return descriptor;
28 | };
29 | }
30 |
--------------------------------------------------------------------------------
/lib/src/decorators/trace.decorator.ts:
--------------------------------------------------------------------------------
1 | import { LogFn } from '../interfaces/logger.external';
2 | import { LoggerInjector } from '../logger.injector';
3 | import { LoggerService } from '../logger.service';
4 |
5 | export function TraceLog(): PropertyDecorator {
6 | return (target: unknown, propertyName: string | symbol): void => {
7 | Object.defineProperty(target, propertyName, {
8 | configurable: false,
9 | get(): LogFn {
10 | return LoggerInjector.getInjector().get(LoggerService).trace;
11 | }
12 | });
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/lib/src/decorators/warn.decorator.ts:
--------------------------------------------------------------------------------
1 | import { LogFn } from '../interfaces/logger.external';
2 | import { LoggerInjector } from '../logger.injector';
3 | import { LoggerService } from '../logger.service';
4 |
5 | export function WarnLog(): PropertyDecorator {
6 | return (target: unknown, propertyName: string | symbol): void => {
7 | Object.defineProperty(target, propertyName, {
8 | configurable: false,
9 | get(): LogFn {
10 | return LoggerInjector.getInjector().get(LoggerService).warn;
11 | }
12 | });
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/lib/src/interfaces/logger.external.ts:
--------------------------------------------------------------------------------
1 | import { InjectionToken } from '@angular/core';
2 |
3 | import { LoggerService } from '../logger.service';
4 | import { ObjectKeyMap } from './logger.internal';
5 |
6 | export type ConsoleOperation = (message?: T, ...optionalParams: P[]) => void;
7 |
8 | export interface GroupMethods extends Function {
9 | group(label: string, pipeline?: Pipeline): LoggerService;
10 |
11 | groupCollapsed(label: string, pipeline?: Pipeline): LoggerService;
12 | }
13 |
14 | export const LOGGER_OPTIONS: InjectionToken = new InjectionToken('LOGGER_OPTIONS');
15 | export type TimerLevels =
16 | | LoggerLevel.TRACE
17 | | LoggerLevel.DEBUG
18 | | LoggerLevel.INFO
19 | | LoggerLevel.WARN
20 | | LoggerLevel.ERROR;
21 | export type LogFn = GroupMethods & ConsoleOperation;
22 |
23 | export interface FormatOutput {
24 | label: string;
25 | style: string;
26 | }
27 |
28 | // eslint-disable-next-line no-restricted-syntax
29 | export enum LoggerLevel {
30 | ALL = 1,
31 | TRACE,
32 | DEBUG,
33 | INFO,
34 | LOG,
35 | WARN,
36 | ERROR,
37 | OFF
38 | }
39 |
40 | // eslint-disable-next-line no-restricted-syntax
41 | export enum GroupLevel {
42 | GROUP = 'group',
43 | GROUP_COLLAPSED = 'groupCollapsed'
44 | }
45 |
46 | export type Pipeline = (logger: LoggerService) => T;
47 |
48 | export interface TimerInfo {
49 | title: string;
50 | startTime: number;
51 | }
52 |
53 | export type PipeOperation = GroupMethods | ConsoleOperation;
54 | export type GroupMethod = (groupTitle?: string, ...optionalParams: T[]) => unknown;
55 | export type GroupFactoryMethod = (
56 | title: string,
57 | pipeline: Pipeline | undefined,
58 | logger: LoggerService,
59 | level: LoggerLevel
60 | ) => void;
61 |
62 | export interface LoggerOptions {
63 | instance: T extends Console ? T : unknown;
64 | minLevel: LoggerLevel;
65 | globalLineStyle: string;
66 | cssClassMap: object;
67 | useLevelGroup: boolean;
68 | labelColors: ObjectKeyMap;
69 | labelNames: ObjectKeyMap;
70 |
71 | format?(label: string, style: string): FormatOutput;
72 |
73 | options?(config: Partial): LoggerOptions;
74 | }
75 |
--------------------------------------------------------------------------------
/lib/src/interfaces/logger.internal.ts:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line
2 | export type Any = any; // NOSONAR
3 | export type Fn = (...args: T[]) => U;
4 | export type Arguments = T[];
5 |
6 | export interface ObjectKeyMap {
7 | [key: string]: T;
8 | }
9 |
10 | export type DecoratorMethod = (target: Any, key: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
11 |
12 | export interface ClipboardData {
13 | setData: (type: string, value: string) => void | boolean;
14 | }
15 |
16 | export type Callback = (...args: T[]) => T;
17 | export type Descriptor = PropertyDescriptor & ThisType;
18 |
19 | export interface ConsoleServiceInterface {
20 | getTemplateWithoutLabel(): string;
21 | }
22 |
23 | export interface Clipboard {
24 | readonly clipboardSetData: SetDataType;
25 | readonly queryCommandCopy: boolean;
26 |
27 | copyOnBuffer(data: unknown): boolean;
28 |
29 | textAreaSelectData(value: string): boolean;
30 | }
31 |
32 | export type SetDataType = (format: string, data: string) => void | boolean;
33 |
--------------------------------------------------------------------------------
/lib/src/logger.config.ts:
--------------------------------------------------------------------------------
1 | import { LoggerLevel } from './interfaces/logger.external';
2 | import { ObjectKeyMap } from './interfaces/logger.internal';
3 |
4 | // eslint-disable-next-line no-restricted-syntax,@typescript-eslint/naming-convention
5 | export enum LABELS {
6 | TRACE = 'TRACE',
7 | DEBUG = 'DEBUG',
8 | INFO = 'INFO',
9 | WARN = 'WARN',
10 | ERROR = 'ERROR'
11 | }
12 |
13 | // eslint-disable-next-line no-restricted-syntax,@typescript-eslint/naming-convention
14 | export enum COLORS {
15 | TRACE = '#000080',
16 | DEBUG = '#00BFFE',
17 | INFO = '#000000',
18 | WARN = '#FF6419',
19 | ERROR = '#F1062D'
20 | }
21 |
22 | export const DEFAULT_METHODS: ObjectKeyMap = {
23 | /**
24 | * Used `debug` instead `trace` method because need
25 | * output without stack trace in console
26 | * LoggerLevel.TRACE -> console.debug
27 | */
28 | [LoggerLevel.TRACE]: 'debug',
29 | [LoggerLevel.LOG]: 'log',
30 | [LoggerLevel.DEBUG]: 'info',
31 | [LoggerLevel.INFO]: 'info',
32 | [LoggerLevel.WARN]: 'warn',
33 | [LoggerLevel.ERROR]: 'error'
34 | };
35 |
36 | // tslint:disable-next-line:max-line-length
37 | export const LexerJSON: RegExp = /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g;
38 |
--------------------------------------------------------------------------------
/lib/src/logger.injector.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, Injector } from '@angular/core';
2 |
3 | @Injectable()
4 | export class LoggerInjector {
5 | private static injector: Injector | null = null;
6 |
7 | constructor(injector: Injector) {
8 | LoggerInjector.injector = injector;
9 | }
10 |
11 | public static getInjector(): never | Injector {
12 | if (!LoggerInjector.injector) {
13 | throw new Error(`You've forgotten to import \`LoggerModule\``);
14 | }
15 |
16 | return LoggerInjector.injector;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/src/logger.module.ts:
--------------------------------------------------------------------------------
1 | import { InjectionToken, ModuleWithProviders, NgModule, Self } from '@angular/core';
2 |
3 | import { LOGGER_OPTIONS, LoggerOptions } from './interfaces/logger.external';
4 | import { LoggerInjector } from './logger.injector';
5 | import { LoggerOptionsImpl } from './logger.options';
6 | import { LoggerService } from './logger.service';
7 | import { ClipboardFactory } from './services/clipboard-factory.service';
8 | import { ConsoleService } from './services/console.service';
9 | import { CssFactory } from './services/css-factory.service';
10 | import { LoggerFactory } from './services/factory.service';
11 | import { GroupFactory } from './services/group-factory.service';
12 | import { JsonFactory } from './services/json-factory.service';
13 | import { TimerFactory } from './services/timer-factory.service';
14 |
15 | @NgModule({
16 | providers: [
17 | LoggerService,
18 | LoggerFactory,
19 | ConsoleService,
20 | GroupFactory,
21 | CssFactory,
22 | JsonFactory,
23 | ClipboardFactory,
24 | TimerFactory,
25 | LoggerInjector
26 | ]
27 | })
28 | export class LoggerModule {
29 | private static readonly ROOT_OPTIONS: InjectionToken = new InjectionToken('ROOT_OPTIONS');
30 |
31 | constructor(@Self() public loggerInjector: LoggerInjector) {}
32 |
33 | public static forRoot(config: Partial = {}): ModuleWithProviders {
34 | return {
35 | ngModule: LoggerModule,
36 | providers: [
37 | {
38 | provide: LoggerModule.ROOT_OPTIONS,
39 | useValue: config
40 | },
41 | {
42 | provide: LOGGER_OPTIONS,
43 | useFactory: LoggerModule.loggerConfigFactory,
44 | deps: [LoggerModule.ROOT_OPTIONS]
45 | }
46 | ]
47 | };
48 | }
49 |
50 | private static loggerConfigFactory(config: Partial): LoggerOptionsImpl {
51 | return Object.assign(new LoggerOptionsImpl(), config);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/src/logger.options.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 |
3 | import { FormatOutput, LoggerLevel, LoggerOptions } from './interfaces/logger.external';
4 | import { ObjectKeyMap } from './interfaces/logger.internal';
5 | import { COLORS, LABELS } from './logger.config';
6 |
7 | @Injectable()
8 | export class LoggerOptionsImpl implements LoggerOptions {
9 | public instance: Console = console;
10 | public minLevel: LoggerLevel = LoggerLevel.ALL;
11 | public globalLineStyle: string = '';
12 | public cssClassMap: ObjectKeyMap = {};
13 | public useLevelGroup: boolean = true;
14 | public labelColors: ObjectKeyMap = {
15 | [LoggerLevel.TRACE]: COLORS.TRACE,
16 | [LoggerLevel.DEBUG]: COLORS.DEBUG,
17 | [LoggerLevel.INFO]: COLORS.INFO,
18 | [LoggerLevel.WARN]: COLORS.WARN,
19 | [LoggerLevel.ERROR]: COLORS.ERROR
20 | };
21 |
22 | public labelNames: ObjectKeyMap = {
23 | [LoggerLevel.TRACE]: LABELS.TRACE,
24 | [LoggerLevel.DEBUG]: LABELS.DEBUG,
25 | [LoggerLevel.INFO]: LABELS.INFO,
26 | [LoggerLevel.WARN]: LABELS.WARN,
27 | [LoggerLevel.ERROR]: LABELS.ERROR
28 | };
29 |
30 | public format(label: string, style: string): FormatOutput {
31 | return { label: `[${label}]:`, style };
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/src/logger.service.ts:
--------------------------------------------------------------------------------
1 | import { Inject, Injectable } from '@angular/core';
2 |
3 | import { autoBind } from './decorators/autobind.decorator';
4 | import { LogFn, LOGGER_OPTIONS, LoggerLevel, Pipeline, TimerInfo } from './interfaces/logger.external';
5 | import { ObjectKeyMap } from './interfaces/logger.internal';
6 | import { LoggerOptionsImpl } from './logger.options';
7 | import { ClipboardFactory } from './services/clipboard-factory.service';
8 | import { ConsoleService } from './services/console.service';
9 | import { CssFactory } from './services/css-factory.service';
10 | import { LoggerFactory } from './services/factory.service';
11 | import { GroupFactory } from './services/group-factory.service';
12 | import { JsonFactory } from './services/json-factory.service';
13 | import { TimerFactory } from './services/timer-factory.service';
14 |
15 | @autoBind
16 | @Injectable()
17 | export class LoggerService {
18 | private readonly DEFAULT_DEPTH: number = 2;
19 |
20 | // eslint-disable-next-line max-params
21 | constructor(
22 | private readonly clipboard: ClipboardFactory,
23 | private readonly cssFactory: CssFactory,
24 | private readonly console: ConsoleService,
25 | private readonly factory: LoggerFactory,
26 | private readonly groupFactory: GroupFactory,
27 | private readonly jsonFactory: JsonFactory,
28 | private readonly timerFactory: TimerFactory,
29 | @Inject(LOGGER_OPTIONS) private readonly options: LoggerOptionsImpl
30 | ) {}
31 |
32 | public get clear(): LogFn {
33 | return this.console.instance.clear.bind(this.console.instance) as LogFn;
34 | }
35 |
36 | public get table(): LogFn {
37 | return this.console.instance.table.bind(this.console.instance) as LogFn;
38 | }
39 |
40 | public get log(): LogFn {
41 | return this.factory.createLogger(LoggerLevel.LOG, this);
42 | }
43 |
44 | public get trace(): LogFn {
45 | return this.factory.createLogger(LoggerLevel.TRACE, this);
46 | }
47 |
48 | public get assert(): LogFn {
49 | return this.console.instance.assert.bind(this.console.instance) as LogFn;
50 | }
51 |
52 | public get debug(): LogFn {
53 | return this.factory.createLogger(LoggerLevel.DEBUG, this);
54 | }
55 |
56 | public get info(): LogFn {
57 | return this.factory.createLogger(LoggerLevel.INFO, this);
58 | }
59 |
60 | public get warn(): LogFn {
61 | return this.factory.createLogger(LoggerLevel.WARN, this);
62 | }
63 |
64 | public get error(): LogFn {
65 | return this.factory.createLogger(LoggerLevel.ERROR, this);
66 | }
67 |
68 | public get level(): LoggerLevel {
69 | return this.console.minLevel;
70 | }
71 |
72 | public set level(level: LoggerLevel) {
73 | this.console.minLevel = level;
74 | }
75 |
76 | public getCurrentLineStyle(): string {
77 | return this.cssFactory.style;
78 | }
79 |
80 | public clearCssCurrentLine(): void {
81 | this.cssFactory.style = '';
82 | }
83 |
84 | public setLabels(labels: ObjectKeyMap): void {
85 | this.options.labelNames = { ...this.options.labelNames, ...labels };
86 | }
87 |
88 | public setColors(colors: ObjectKeyMap): void {
89 | this.options.labelColors = { ...this.options.labelColors, ...colors };
90 | }
91 |
92 | public pipe(...pipelines: Pipeline[]): LoggerService {
93 | if (this.groupFactory.executePipesGroup) {
94 | pipelines.forEach((pipeline: Pipeline): unknown => pipeline(this));
95 | }
96 |
97 | return this;
98 | }
99 |
100 | public groupCollapsed(title: string, pipeline?: Pipeline): LoggerService {
101 | this.groupFactory.groupCollapsed(title, pipeline, this, LoggerLevel.INFO);
102 | return this;
103 | }
104 |
105 | public close(): LoggerService {
106 | this.groupFactory.close();
107 | return this;
108 | }
109 |
110 | public closeAll(): LoggerService {
111 | this.groupFactory.closeAll();
112 | return this;
113 | }
114 |
115 | public group(title: string, pipeline?: Pipeline): LoggerService {
116 | this.groupFactory.group(title, pipeline, this, LoggerLevel.INFO);
117 | return this;
118 | }
119 |
120 | public css(style: string): LoggerService {
121 | this.cssFactory.style = style;
122 | return this;
123 | }
124 |
125 | public prettyJSON(json: ObjectKeyMap): string[] {
126 | return this.jsonFactory.colorsJSON(JSON.stringify(json, null, this.DEFAULT_DEPTH));
127 | }
128 |
129 | public cssClass(cssClassName: string): LoggerService {
130 | this.cssFactory.setClass(cssClassName);
131 | return this;
132 | }
133 |
134 | public copy(example: unknown): boolean {
135 | return this.clipboard.copyOnBuffer(example);
136 | }
137 |
138 | public startTime(title: string, level: LoggerLevel = LoggerLevel.DEBUG): TimerInfo | null {
139 | return this.timerFactory.startTime(title, level);
140 | }
141 |
142 | public endTime(
143 | info: TimerInfo | null,
144 | level: LoggerLevel = LoggerLevel.DEBUG,
145 | isMillisecond: boolean = true
146 | ): void {
147 | if (info) {
148 | this.timerFactory.endTime(info, level, isMillisecond, this);
149 | }
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/lib/src/public-api.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Public API Surface of logger
3 | */
4 |
5 | export * from './logger.service';
6 | export * from './logger.module';
7 | export * from './logger.config';
8 | export * from './decorators/logger.decorator';
9 | export * from './decorators/trace.decorator';
10 | export * from './decorators/debug.decorator';
11 | export * from './decorators/error.decorator';
12 | export * from './decorators/log.decorator';
13 | export * from './decorators/info.decorator';
14 | export * from './decorators/warn.decorator';
15 | export * from './decorators/groups/group.decorator';
16 | export * from './decorators/timer.decorator';
17 | export * from './decorators/groups/group-collapsed.decorator';
18 | export * from './interfaces/logger.external';
19 |
--------------------------------------------------------------------------------
/lib/src/services/clipboard-factory.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 |
3 | import { Clipboard, ClipboardData, SetDataType } from '../interfaces/logger.internal';
4 |
5 | declare global {
6 | interface Window {
7 | clipboardData: ClipboardData;
8 | }
9 | }
10 | declare const window: Window;
11 |
12 | @Injectable()
13 | export class ClipboardFactory implements Clipboard {
14 | private readonly DEFAULT_DEPTH: number = 4;
15 | public get clipboardSetData(): SetDataType {
16 | const clipboardData: ClipboardData = window.clipboardData;
17 | return clipboardData && clipboardData.setData;
18 | }
19 |
20 | public get queryCommandCopy(): boolean {
21 | return document.queryCommandSupported && document.queryCommandSupported('copy');
22 | }
23 |
24 | public copyOnBuffer(data: unknown): boolean {
25 | const text: string = typeof data === 'string' ? data : JSON.stringify(data, null, this.DEFAULT_DEPTH);
26 | let isExec: boolean = false;
27 |
28 | if (this.clipboardSetData) {
29 | isExec = this.clipboardSetData('Text', text) as boolean;
30 | } else if (this.queryCommandCopy) {
31 | isExec = this.textAreaSelectData(text);
32 | }
33 |
34 | return isExec;
35 | }
36 |
37 | public textAreaSelectData(value: string): boolean {
38 | const textarea: HTMLTextAreaElement = document.createElement('textarea');
39 | textarea.textContent = value;
40 | textarea.style.position = 'fixed';
41 | document.body.appendChild(textarea);
42 | textarea.select();
43 | try {
44 | return document.execCommand('copy');
45 | } catch (ex) {
46 | return false;
47 | } finally {
48 | document.body.removeChild(textarea);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/src/services/console.service.ts:
--------------------------------------------------------------------------------
1 | import { Inject, Injectable } from '@angular/core';
2 |
3 | import { ConsoleOperation, LOGGER_OPTIONS, LoggerLevel } from '../interfaces/logger.external';
4 | import { ConsoleServiceInterface } from '../interfaces/logger.internal';
5 | import { LoggerOptionsImpl } from '../logger.options';
6 |
7 | @Injectable()
8 | export class ConsoleService implements ConsoleServiceInterface {
9 | public instance: Console;
10 | public minLevel: LoggerLevel;
11 |
12 | constructor(@Inject(LOGGER_OPTIONS) public readonly options: LoggerOptionsImpl) {
13 | this.minLevel = options.minLevel;
14 | this.instance = options.instance;
15 | }
16 |
17 | public get console(): Console {
18 | return this.instance;
19 | }
20 |
21 | public set console(instance: Console) {
22 | this.instance = instance;
23 | }
24 |
25 | public get noop(): ConsoleOperation {
26 | // eslint-disable-next-line @typescript-eslint/no-empty-function
27 | return ((): void => {}) as ConsoleOperation;
28 | }
29 |
30 | public getTemplateLabel(text: string): string {
31 | return `%c${text}`;
32 | }
33 |
34 | public getFormatTemplateLabel(text: string): string {
35 | return `%c${text} %c%s`;
36 | }
37 |
38 | public getTemplateWithoutLabel(): string {
39 | return `%c%s`;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/src/services/css-factory.service.ts:
--------------------------------------------------------------------------------
1 | import { Inject, Injectable } from '@angular/core';
2 |
3 | import { LOGGER_OPTIONS, LoggerLevel } from '../interfaces/logger.external';
4 | import { LoggerOptionsImpl } from '../logger.options';
5 |
6 | @Injectable()
7 | export class CssFactory {
8 | private lineStyle: string | null = null;
9 |
10 | constructor(@Inject(LOGGER_OPTIONS) private readonly options: LoggerOptionsImpl) {}
11 |
12 | public get style(): string {
13 | const style: string = this.localStyle;
14 | this.clearLocalStyle();
15 | return `${this.globalStyles}${style}`;
16 | }
17 |
18 | public set style(css: string) {
19 | this.lineStyle = css;
20 | }
21 |
22 | private get globalStyles(): string {
23 | return this.options.globalLineStyle ? `${this.options.globalLineStyle};` : '';
24 | }
25 |
26 | private get localStyle(): string {
27 | return this.lineStyle ? `${this.lineStyle};` : '';
28 | }
29 |
30 | public getStyleLabel(level: LoggerLevel): string {
31 | const color: string = this.options.labelColors[level];
32 | return `color: ${color}; font-weight: bold`;
33 | }
34 |
35 | public setClass(cssClassName: string): void {
36 | const classList: string[] = cssClassName.split(/\s+/g);
37 | const styles: string[] = [];
38 |
39 | classList.forEach((className: string): void => {
40 | const style: string | undefined = this.options.cssClassMap[className];
41 | if (style) {
42 | styles.push(style);
43 | }
44 | });
45 |
46 | const localStyles: string = styles.length ? styles.join('; ') : '';
47 | this.lineStyle = `${this.globalStyles}${localStyles}`;
48 | }
49 |
50 | private clearLocalStyle(): void {
51 | this.lineStyle = '';
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/src/services/factory.service.ts:
--------------------------------------------------------------------------------
1 | import { Inject, Injectable } from '@angular/core';
2 |
3 | import {
4 | ConsoleOperation as Operation,
5 | GroupFactoryMethod,
6 | GroupLevel,
7 | LOGGER_OPTIONS,
8 | LoggerLevel,
9 | Pipeline,
10 | PipeOperation
11 | } from '../interfaces/logger.external';
12 | import { Any, Arguments, Descriptor, ObjectKeyMap } from '../interfaces/logger.internal';
13 | import { DEFAULT_METHODS } from '../logger.config';
14 | import { LoggerOptionsImpl } from '../logger.options';
15 | import { LoggerService } from '../logger.service';
16 | import { ConsoleService } from './console.service';
17 | import { CssFactory } from './css-factory.service';
18 | import { GroupFactory } from './group-factory.service';
19 |
20 | @Injectable()
21 | export class LoggerFactory {
22 | // eslint-disable-next-line max-params
23 | constructor(
24 | @Inject(LOGGER_OPTIONS) private readonly options: LoggerOptionsImpl,
25 | private readonly console: ConsoleService,
26 | private readonly cssFactory: CssFactory,
27 | private readonly groupFactory: GroupFactory
28 | ) {}
29 |
30 | public createLogger(level: LoggerLevel, logger: LoggerService): T {
31 | const args: Arguments = this.getArgumentsByType(level);
32 | const methodName: string = DEFAULT_METHODS[level];
33 |
34 | const operation: Operation =
35 | this.console.minLevel <= level
36 | ? (this.console.instance as Any)[methodName].bind(...args)
37 | : this.console.noop;
38 |
39 | const pipeOperation: PipeOperation = this.options.useLevelGroup
40 | ? this.defineLevelGroups(level, operation, logger)
41 | : operation;
42 |
43 | return (pipeOperation as unknown) as T;
44 | }
45 |
46 | private defineLevelGroups(level: LoggerLevel, operation: Operation, logger: LoggerService): Operation {
47 | const { GROUP, GROUP_COLLAPSED }: typeof GroupLevel = GroupLevel;
48 |
49 | Object.defineProperties(operation, {
50 | [GROUP]: this.setGroupMethod(GROUP, level, logger),
51 | [GROUP_COLLAPSED]: this.setGroupMethod(GROUP_COLLAPSED, level, logger)
52 | });
53 |
54 | return operation;
55 | }
56 |
57 | private setGroupMethod(methodName: GroupLevel, level: LoggerLevel, logger: LoggerService): Descriptor {
58 | return {
59 | enumerable: true,
60 | configurable: true,
61 | value: (label: string, pipeLine?: Pipeline): LoggerService => {
62 | const groupMethod: GroupFactoryMethod = this.groupFactory[methodName].bind(this.groupFactory);
63 | groupMethod(label, pipeLine, logger, level);
64 |
65 | return logger;
66 | }
67 | };
68 | }
69 |
70 | // eslint-disable-next-line max-lines-per-function
71 | private getArgumentsByType(level: LoggerLevel): Arguments {
72 | const styleLabel: string = this.cssFactory.getStyleLabel(level);
73 | const lineStyle: string = this.cssFactory.style;
74 | const args: Arguments = [this.console.instance];
75 | const withLabel: boolean = level !== LoggerLevel.LOG;
76 |
77 | if (withLabel) {
78 | const { label: formatLabel, style }: ObjectKeyMap = this.options.format(
79 | this.options.labelNames[level],
80 | styleLabel
81 | );
82 | if (lineStyle) {
83 | const label: string = this.console.getFormatTemplateLabel(formatLabel);
84 | args.push(label, style, lineStyle);
85 | } else {
86 | const label: string = this.console.getTemplateLabel(formatLabel);
87 | args.push(label, style);
88 | }
89 | } else if (lineStyle) {
90 | args.push(this.console.getTemplateWithoutLabel(), lineStyle);
91 | }
92 |
93 | return args;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/lib/src/services/group-factory.service.ts:
--------------------------------------------------------------------------------
1 | import { Inject, Injectable } from '@angular/core';
2 |
3 | import { FormatOutput, GroupMethod, LOGGER_OPTIONS, LoggerLevel, Pipeline } from '../interfaces/logger.external';
4 | import { Any } from '../interfaces/logger.internal';
5 | import { LoggerOptionsImpl } from '../logger.options';
6 | import { LoggerService } from '../logger.service';
7 | import { ConsoleService } from './console.service';
8 | import { CssFactory } from './css-factory.service';
9 |
10 | @Injectable()
11 | export class GroupFactory {
12 | public executePipesGroup: boolean = false;
13 | private counterOpenedGroup: number = 0;
14 |
15 | constructor(
16 | private readonly console: ConsoleService,
17 | private readonly cssFactory: CssFactory,
18 | @Inject(LOGGER_OPTIONS) public readonly options: LoggerOptionsImpl
19 | ) {}
20 |
21 | public close(): void {
22 | if (this.executePipesGroup) {
23 | this.counterOpenedGroup--;
24 | this.console.instance.groupEnd();
25 | }
26 | }
27 |
28 | public closeAll(): void {
29 | while (this.counterOpenedGroup > 0) {
30 | this.close();
31 | }
32 | }
33 |
34 | // eslint-disable-next-line max-params
35 | public group(title: string, pipeline: Pipeline | undefined, logger: LoggerService, level: LoggerLevel): T {
36 | const group: GroupMethod = this.console.instance.group.bind(this.console.instance);
37 | return this.createGroupLogger(group, title, pipeline, logger, level);
38 | }
39 |
40 | // eslint-disable-next-line max-params
41 | public groupCollapsed(
42 | title: string,
43 | pipeline: Pipeline | undefined,
44 | logger: LoggerService,
45 | level: LoggerLevel
46 | ): T {
47 | const groupCollapsed: GroupMethod = this.console.instance.groupCollapsed.bind(this.console.instance);
48 | return this.createGroupLogger(groupCollapsed, title, pipeline, logger, level);
49 | }
50 |
51 | // eslint-disable-next-line max-lines-per-function,max-params
52 | private createGroupLogger(
53 | groupType: GroupMethod,
54 | title: string,
55 | pipeline: Pipeline | undefined,
56 | logger: LoggerService,
57 | level: LoggerLevel
58 | ): T {
59 | const showGroup: boolean = this.console.minLevel <= level;
60 | let pipeLineResult: T;
61 |
62 | if (showGroup) {
63 | this.executePipesGroup = true;
64 | this.counterOpenedGroup++;
65 |
66 | const lineStyle: string = this.cssFactory.getStyleLabel(level);
67 | const { label: formatLabel, style: formatStyle }: FormatOutput = this.getLabel(
68 | LoggerLevel[level],
69 | lineStyle
70 | );
71 |
72 | groupType(`%c${formatLabel}`, formatStyle, title);
73 | if (pipeline) {
74 | const result: Any = pipeline(logger);
75 | this.close();
76 | pipeLineResult = result;
77 | }
78 | } else {
79 | this.executePipesGroup = false;
80 | }
81 |
82 | // eslint-disable-next-line @typescript-eslint/tslint/config
83 | return pipeLineResult!;
84 | }
85 |
86 | private getLabel(level: string, style: string): FormatOutput {
87 | return this.options.format(level, style);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/lib/src/services/json-factory.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 |
3 | import { LexerJSON } from '../logger.config';
4 |
5 | @Injectable()
6 | export class JsonFactory {
7 | private readonly _string: string = 'color:green';
8 | private readonly _number: string = 'color:darkorange';
9 | private readonly _boolean: string = 'color:blue';
10 | private readonly _null: string = 'color:magenta';
11 | private readonly _key: string = 'color:red';
12 | private readonly lexerTypeFinder: RegExp = LexerJSON;
13 |
14 | // eslint-disable-next-line max-lines-per-function
15 | public colorsJSON(json: string): string[] {
16 | const arr: string[] = [];
17 | json = json.replace(this.lexerTypeFinder, (match: string): string => {
18 | let style: string = this._number;
19 | if (/^"/.test(match)) {
20 | if (/:$/.test(match)) {
21 | style = this._key;
22 | } else {
23 | style = this._string;
24 | }
25 | } else if (/true|false/.test(match)) {
26 | style = this._boolean;
27 | } else if (/null/.test(match)) {
28 | style = this._null;
29 | }
30 | arr.push(style);
31 | arr.push('');
32 | return `%c${match}%c`;
33 | });
34 |
35 | arr.unshift(json);
36 |
37 | return arr;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/src/services/timer-factory.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 |
3 | import { LoggerLevel, TimerInfo } from '../interfaces/logger.external';
4 | import { Any } from '../interfaces/logger.internal';
5 | import { DEFAULT_METHODS } from '../logger.config';
6 | import { LoggerService } from '../logger.service';
7 | import { ConsoleService } from './console.service';
8 |
9 | @Injectable()
10 | export class TimerFactory {
11 | private readonly DIGITS_TO_FIX: number = 4;
12 | private readonly SECONDS: number = 1000;
13 | constructor(private readonly console: ConsoleService) {}
14 |
15 | public startTime(title: string, level: LoggerLevel): TimerInfo | null {
16 | let result: TimerInfo | null = null;
17 | const canExecute: boolean = !(this.console.minLevel > level);
18 | if (canExecute) {
19 | result = { startTime: performance.now(), title };
20 | }
21 | return result;
22 | }
23 |
24 | // eslint-disable-next-line max-params
25 | public endTime(info: TimerInfo, level: LoggerLevel, isMillisecond: boolean, logger: LoggerService): void {
26 | const canExecute: boolean = !(this.console.minLevel > level);
27 |
28 | if (canExecute) {
29 | const methodName: string = DEFAULT_METHODS[level];
30 | const time: string = this.ensureTime(info, isMillisecond);
31 | const logMethod: (...args: string[]) => void = (logger as Any)[methodName];
32 | logMethod(`TimerLog: ${info.title}`, `took ${time} to execute`);
33 | }
34 | }
35 |
36 | private ensureTime(info: TimerInfo, isMillisecond: boolean): string {
37 | const msTime: number = parseFloat((performance.now() - info.startTime).toFixed(this.DIGITS_TO_FIX));
38 | return isMillisecond ? `${msTime}ms` : `${Math.floor(msTime / this.SECONDS)}s`;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/tsconfig.lib.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../out-tsc/lib",
5 | "target": "es2015",
6 | "module": "es2015",
7 | "moduleResolution": "node",
8 | "declaration": true,
9 | "sourceMap": true,
10 | "inlineSources": true,
11 | "emitDecoratorMetadata": true,
12 | "experimentalDecorators": true,
13 | "importHelpers": true,
14 | "noUnusedParameters": true,
15 | "noUnusedLocals": true,
16 | "types": [],
17 | "lib": ["dom", "es2018"]
18 | },
19 | "angularCompilerOptions": {
20 | "fullTemplateTypeCheck": true,
21 | "annotateForClosureCompiler": true,
22 | "strictInjectionParameters": true,
23 | "skipTemplateCodegen": true,
24 | "preserveWhitespaces": true,
25 | "skipMetadataEmit": true
26 | },
27 | "exclude": ["**/*.spec.ts"]
28 | }
29 |
--------------------------------------------------------------------------------
/ngx-logger.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "logger",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "ng": "ng",
6 | "jest": "jest",
7 | "start": "ng serve",
8 | "build:lib": "ng build logger",
9 | "build:app": "ng build integration",
10 | "test": "yarn jest --config ./jest.config.js",
11 | "test:ci": "yarn jest --config ./jest.config.js --coverage",
12 | "lint": "eslint --fix \"**/*.ts\"",
13 | "format": "prettier --write \"**/*.{ts,html,css,scss,md,js,json}\"",
14 | "coverage": "jest --config ./jest.app.config.js --coverage && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
15 | },
16 | "husky": {
17 | "hooks": {
18 | "pre-commit": "npm run format"
19 | }
20 | },
21 | "private": true,
22 | "prettier": "@angular-ru/prettier-config",
23 | "devDependencies": {
24 | "@angular/animations": "8.2.14",
25 | "@angular/common": "8.2.14",
26 | "@angular/compiler": "8.2.14",
27 | "@angular/core": "8.2.14",
28 | "@angular/forms": "8.2.14",
29 | "@angular/platform-browser": "8.2.14",
30 | "@angular/platform-browser-dynamic": "8.2.14",
31 | "@angular/router": "8.2.14",
32 | "core-js": "3.6.5",
33 | "devtools-detect": "3.0.0",
34 | "lint-staged": "9.5.0",
35 | "rxjs": "6.5.5",
36 | "zone.js": "0.10.3",
37 | "@angular-ru/jest-utils": "12.19.0",
38 | "@angular-ru/eslint-config": "12.20.1",
39 | "@angular-ru/prettier-config": "12.19.1",
40 | "@angular-ru/tsconfig": "12.19.1",
41 | "@angular-devkit/build-angular": "0.803.27",
42 | "@angular-devkit/build-ng-packagr": "0.803.27",
43 | "@angular/cli": "8.3.21",
44 | "@angular/compiler-cli": "8.2.14",
45 | "@angular/language-service": "8.2.14",
46 | "@types/node": "14.0.13",
47 | "coveralls": "3.1.0",
48 | "husky": "2.7.0",
49 | "ng-packagr": "9.1.5",
50 | "ts-node": "8.10.2",
51 | "tsickle": "0.38.1",
52 | "tslib": "1.13.0",
53 | "typescript": "3.8.3"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "automerge": true,
3 | "rangeStrategy": "bump",
4 | "packageFiles": ["package.json"],
5 | "groupName": "all dependencies",
6 | "separateMajorMinor": false,
7 | "groupSlug": "all",
8 | "major": {
9 | "dependencies": { "enabled": false },
10 | "devDependencies": { "enabled": false }
11 | },
12 | "packageRules": [
13 | {
14 | "packagePatterns": ["*"],
15 | "excludePackagePatterns": ["^@angular/", "^@angular-devkit/", "typescript"],
16 | "groupName": "all dependencies",
17 | "groupSlug": "all-dependencies"
18 | },
19 | {
20 | "packagePatterns": ["typescript"],
21 | "groupName": "typescript",
22 | "updateTypes": "patch",
23 | "schedule": ["before 3:00am every 2nd week of the month"]
24 | }
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@angular-ru/tsconfig",
3 | "angularCompilerOptions": {
4 | "fullTemplateTypeCheck": true,
5 | "annotateForClosureCompiler": true,
6 | "strictInjectionParameters": true,
7 | "skipTemplateCodegen": false,
8 | "preserveWhitespaces": true,
9 | "skipMetadataEmit": false,
10 | "disableTypeScriptVersionCheck": true
11 | },
12 | "compilerOptions": {
13 | "rootDir": ".",
14 | "baseUrl": "./",
15 | "module": "esnext",
16 | "outDir": "./dist/out-tsc",
17 | "target": "es5",
18 | "typeRoots": ["node_modules/@types"],
19 | "lib": ["es2018", "dom"],
20 | "paths": {
21 | "@angular-ru/logger": ["dist/logger"]
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------