Skip to content
This repository was archived by the owner on Jun 18, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"vendorChunk": true,
"buildOptimizer": true,
"budgets": [
{
Expand Down
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion projects/logger/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@angular-ru/logger",
"version": "1.5.0",
"version": "1.8.0",
"license": "MIT",
"homepage": "https://github.com/Angular-RU/angular-logger",
"repository": "https://github.com/Angular-RU/angular-logger",
Expand Down
144 changes: 144 additions & 0 deletions projects/logger/src/lib/decorators/autobind.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { Any, Fn, ObjectKeyMap } from '../logger.interfaces';

const { getPrototypeOf }: ObjectKeyMap = Object;
let mapStore: ObjectKeyMap;

const { defineProperty, getOwnPropertyDescriptor, getOwnPropertyNames, getOwnPropertySymbols }: ObjectKeyMap = Object;

function getBoundSuper(obj: ObjectKeyMap, fn: Fn): Fn {
if (typeof WeakMap === 'undefined') {
throw new Error(
`Using @autobind on ${fn.name}() requires WeakMap support due to its use of super.${fn.name}()
See https://github.com/jayphelps/core-decorators.js/issues/20`
);
}

if (!mapStore) {
mapStore = new WeakMap();
}

if (mapStore.has(obj) === false) {
mapStore.set(obj, new WeakMap());
}

const superStore: ObjectKeyMap = mapStore.get(obj);

if (superStore.has(fn) === false) {
superStore.set(fn, bind(fn, obj));
}

return superStore.get(fn);
}

function bind(fn: Fn, context: Any): Fn {
if (fn.bind) {
return fn.bind(context);
} else {
return function __autobind__(): Fn {
return fn.apply(context, arguments);
};
}
}

const getOwnKeys: Fn<Any, Any> = getOwnPropertySymbols
? function(object: ObjectKeyMap): string[] {
return getOwnPropertyNames(object).concat(getOwnPropertySymbols(object));
}
: getOwnPropertyNames;

function autobindClass(klass: ObjectKeyMap): Any {
const descs: ObjectKeyMap = getOwnPropertyDescriptors(klass.prototype);
const keys: Any = getOwnKeys(descs);

for (let i: number = 0, l: number = keys.length; i < l; i++) {
const key: string = keys[i];
const desc: Any = descs[key];

if (typeof desc.value !== 'function' || key === 'constructor') {
continue;
}

defineProperty(klass.prototype, key, autobindMethod(klass.prototype, key, desc));
}
}

function getOwnPropertyDescriptors(obj: ObjectKeyMap): ObjectKeyMap {
const descs: ObjectKeyMap = {};

getOwnKeys(obj).forEach((key: Any) => (descs[key] = getOwnPropertyDescriptor(obj, key)));

return descs;
}

function autobindMethod(target: Any, key: Any, { value: fn, configurable, enumerable }: Any): PropertyDescriptor {
if (typeof fn !== 'function') {
throw new SyntaxError(`@autobind can only be used on functions, not: ${fn}`);
}

const { constructor }: Any = target;

return {
configurable,
enumerable,

get(): Fn {
if (this === target) {
return fn;
}

if (this.constructor !== constructor && getPrototypeOf(this).constructor === constructor) {
return fn;
}

if (this.constructor !== constructor && key in this.constructor.prototype) {
return getBoundSuper(this, fn);
}

const boundFn: Fn = bind(fn, this);

defineProperty(this, key, {
configurable: true,
writable: true,

enumerable: false,
value: boundFn
});

return boundFn;
},
set: createDefaultSetter(key)
};
}

function handle(args: Any[]): Fn {
if (args.length === 1) {
return autobindClass(args[0]);
} else {
// @ts-ignore
return autobindMethod(...args);
}
}

export function autobind(...args: Any[]): Any {
if (args.length === 0) {
return function(...argsClass: Any[]): Fn {
return handle(argsClass);
};
} else {
return handle(args);
}
}

function createDefaultSetter(key: Any): Fn {
return function set(newValue: unknown): unknown {
Object.defineProperty(this, key, {
configurable: true,
writable: true,

enumerable: true,
value: newValue
});

return newValue;
};
}
7 changes: 5 additions & 2 deletions projects/logger/src/lib/logger.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import { JsonFactory } from './services/json-factory.service';
import { ClipboardFactory } from './services/clipboard-factory.service';
import { TimerFactory } from './services/timer-factory.service';
import { LoggerOptionsImpl } from './logger.options';
import { autobind } from './decorators/autobind.decorator';

@autobind
@Injectable()
export class LoggerService {
private readonly DEFAULT_DEPTH: number = 2;

constructor(
public readonly clipboard: ClipboardFactory,
public readonly cssFactory: CssFactory,
private readonly clipboard: ClipboardFactory,
private readonly cssFactory: CssFactory,
private readonly console: ConsoleService,
private readonly factory: LoggerFactory,
private readonly groupFactory: GroupFactory,
Expand Down
9 changes: 7 additions & 2 deletions projects/logger/tests/clipboard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ConsoleFake } from '../../../helpers/console-fake';
import { TestBed } from '@angular/core/testing';
import { LoggerModule } from '../src/lib/logger.module';
import { ObjectKeyMap } from '../src/lib/logger.interfaces';
import { LoggerInjector } from '../src/lib/logger.injector';

describe('[TEST]: Check clipboard', () => {
let logger: LoggerService;
Expand Down Expand Up @@ -66,7 +67,9 @@ describe('[TEST]: Check clipboard', () => {
});

const JsonValue: ObjectKeyMap = { a: 1, b: [1, 2, 3] };
const isExec: boolean = logger.clipboard.copyOnBuffer(JsonValue);
const isExec: boolean = LoggerInjector.getInjector()
.get<LoggerService>(LoggerService)
.copy(JsonValue);

expect(isExec).toEqual(true);
expect(buffer).toEqual(JSON.stringify(JsonValue, null, 4));
Expand All @@ -76,7 +79,9 @@ describe('[TEST]: Check clipboard', () => {
createMockQueryCommands(textarea);

const JsonValue: ObjectKeyMap = { a: 1, b: [1, 2, 3] };
const isExec: boolean = logger.clipboard.copyOnBuffer(JsonValue);
const isExec: boolean = LoggerInjector.getInjector()
.get<LoggerService>(LoggerService)
.copy(JsonValue);

expect(isExec).toEqual(false);
expect(buffer).toEqual(null);
Expand Down