ngx-object-diff
Version:
An Angular 2+ library to compare and show object differences.
464 lines (457 loc) • 14.4 kB
JavaScript
import { SecurityContext, Injectable, ɵɵdefineInjectable, ɵɵinject, Component, Input, NgModule } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
/**
* @fileoverview added by tsickle
* Generated from: lib/ngx-object-diff.service.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class NgxObjectDiffService {
/**
* @param {?} sanitizer
*/
constructor(sanitizer) {
this.sanitizer = sanitizer;
this.openChar = '{';
this.closeChar = '}';
}
/* service methods */
/**
* @param {?} char
* @return {?}
*/
setOpenChar(char) {
this.openChar = char;
}
/**
* @param {?} char
* @return {?}
*/
setCloseChar(char) {
this.closeChar = char;
}
/**
* diff between object a and b
* @param {?} a
* @param {?} b
* @param {?=} shallow
* @param {?=} isOwn
* @return {?}
*/
diff(a, b, shallow, isOwn) {
if (a === b) {
return this.equalObj(a);
}
/** @type {?} */
let diffValue = {};
/** @type {?} */
let equal = true;
for (let key in a) {
if ((!isOwn && key in b) || (isOwn && typeof b != 'undefined' && b.hasOwnProperty(key))) {
if (a[key] === b[key]) {
diffValue[key] = this.equalObj(a[key]);
}
else {
if (!shallow && this.isValidAttr(a[key], b[key])) {
/** @type {?} */
let valueDiff = this.diff(a[key], b[key], shallow, isOwn);
if (valueDiff.changed == 'equal') {
diffValue[key] = this.equalObj(a[key]);
}
else {
equal = false;
diffValue[key] = valueDiff;
}
}
else {
equal = false;
diffValue[key] = {
changed: 'primitive change',
removed: a[key],
added: b[key]
};
}
}
}
else {
equal = false;
diffValue[key] = {
changed: 'removed',
value: a[key]
};
}
}
for (let key in b) {
if ((!isOwn && !(key in a)) || (isOwn && typeof a != 'undefined' && !a.hasOwnProperty(key))) {
equal = false;
diffValue[key] = {
changed: 'added',
value: b[key]
};
}
}
if (equal) {
return this.equalObj(a);
}
else {
return {
changed: 'object change',
value: diffValue
};
}
}
/**
* compare and build the difference of two objects taking only its own properties into account
* @param {?} a
* @param {?} b
* @param {?=} shallow
* @return {?}
*/
diffOwnProperties(a, b, shallow) {
return this.diff(a, b, shallow, true);
}
/**
* Convert to a readable xml/html Json structure
* @param {?} changes
* @param {?=} shallow
* @return {?}
*/
toJsonView(changes, shallow) {
return this.formatToJsonXMLString(changes, shallow);
}
/**
* Convert to a readable xml/html Json structure
* @param {?} object
* @param {?=} shallow
* @return {?}
*/
objToJsonView(object, shallow) {
return this.formatObjToJsonXMLString(object, shallow);
}
/**
* Convert to a readable xml/html Json structure
* @param {?} changes
* @param {?=} shallow
* @return {?}
*/
toJsonDiffView(changes, shallow) {
return this.formatChangesToXMLString(changes, shallow);
}
/**
* Convert to a readable xml/html Json structure
* Convert to a readable xml/html Json structure
* @private
* @param {?} obj
* @param {?} shallow
* @return {?}
*/
formatObjToJsonXMLString(obj, shallow) {
return this.sanitizer.bypassSecurityTrustHtml(this.inspect(obj, shallow));
}
/**
* Convert to a readable xml/html Json structure
* @private
* @param {?} changes
* @param {?=} shallow
* @return {?}
*/
formatToJsonXMLString(changes, shallow) {
/** @type {?} */
let properties = [];
/** @type {?} */
let diff = changes.value;
if (changes.changed == 'equal') {
return this.sanitizer.sanitize(SecurityContext.HTML, this.sanitizer.bypassSecurityTrustHtml(this.inspect(diff, shallow)));
}
for (let key in diff) {
properties.push(this.formatChange(key, diff[key], shallow));
}
return this.sanitizer.sanitize(SecurityContext.HTML, this.sanitizer.bypassSecurityTrustHtml('<span>' + this.openChar + '</span>\n<div class="diff-level">' + properties.join('<span>,</span>\n') + '\n</div><span>' + this.closeChar + '</span>'));
}
/**
* @private
* @param {?} changes
* @param {?=} shallow
* @return {?}
*/
formatChangesToXMLString(changes, shallow) {
/** @type {?} */
var properties = [];
if (changes.changed == 'equal') {
return '';
}
/** @type {?} */
var diff = changes.value;
for (var key in diff) {
/** @type {?} */
var changed = diff[key].changed;
if (changed !== 'equal')
properties.push(this.formatChange(key, diff[key], shallow, true));
}
return this.sanitizer.sanitize(SecurityContext.HTML, this.sanitizer.bypassSecurityTrustHtml('<span>' + this.openChar + '</span>\n<div class="diff-level">' + properties.join('<span>,</span>\n') + '\n</div><span>' + this.closeChar + '</span>'));
}
/**
* @private
* @param {?} key
* @param {?} diffItem
* @param {?} shallow
* @param {?=} diffOnly
* @return {?}
*/
formatChange(key, diffItem, shallow, diffOnly) {
/** @type {?} */
var changed = diffItem.changed;
/** @type {?} */
var property;
switch (changed) {
case 'equal':
property = (this.stringifyObjectKey(this.escapeHTML(key)) + '<span>: </span>' + this.inspect(diffItem.value));
break;
case 'removed':
property = ('<del class="diff">' + this.stringifyObjectKey(this.escapeHTML(key)) + '<span>: </span>' + this.inspect(diffItem.value) + '</del>');
break;
case 'added':
property = ('<ins class="diff">' + this.stringifyObjectKey(this.escapeHTML(key)) + '<span>: </span>' + this.inspect(diffItem.value) + '</ins>');
break;
case 'primitive change':
/** @type {?} */
var prefix = this.stringifyObjectKey(this.escapeHTML(key)) + '<span>: </span>';
property = ('<del class="diff diff-key">' + prefix + this.inspect(diffItem.removed) + '</del><span>,</span>\n' +
'<ins class="diff diff-key">' + prefix + this.inspect(diffItem.added) + '</ins>');
break;
case 'object change':
property = shallow ? '' : (this.stringifyObjectKey(key) + '<span>: </span>' + (diffOnly ? this.formatChangesToXMLString(diffItem) : this.formatToJsonXMLString(diffItem)));
break;
}
return property;
}
/**
* @private
* @param {?} obj
* @param {?=} shallow
* @return {?}
*/
inspect(obj, shallow) {
return this._inspect('', obj, shallow);
}
/**
* @see http://jsperf.com/continuation-passing-style/3
* @private
* @param {?} accumulator
* @param {?} obj
* @param {?=} shallow
* @return {?}
*/
_inspect(accumulator, obj, shallow) {
switch (typeof obj) {
case 'object':
if (!obj) {
accumulator += 'null';
break;
}
if (shallow) {
accumulator += '[object]';
break;
}
/** @type {?} */
let keys = Object.keys(obj);
/** @type {?} */
let length = keys.length;
if (length === 0) {
accumulator += '<span>' + this.openChar + this.closeChar + '</span>';
}
else {
accumulator += '<span>' + this.openChar + '</span>\n<div class="diff-level">';
for (let i = 0; i < length; i++) {
/** @type {?} */
let key = keys[i];
accumulator = this._inspect(accumulator + this.stringifyObjectKey(this.escapeHTML(key)) + '<span>: </span>', obj[key]);
if (i < length - 1) {
accumulator += '<span>,</span>\n';
}
}
accumulator += '\n</div><span>' + this.closeChar + '</span>';
}
break;
case 'string':
accumulator += JSON.stringify(this.escapeHTML(obj));
break;
case 'undefined':
accumulator += 'undefined';
break;
default:
accumulator += this.escapeHTML(String(obj));
break;
}
return accumulator;
}
/**
* @private
* @param {?} key
* @return {?}
*/
stringifyObjectKey(key) {
return /^[a-z0-9_$]*$/i.test(key) ?
key :
JSON.stringify(key);
}
/**
* @private
* @param {?} string
* @return {?}
*/
escapeHTML(string) {
return string.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
}
/**
* @private
* @param {?} obj
* @return {?}
*/
equalObj(obj) {
return {
changed: 'equal',
value: obj
};
}
/**
* @private
* @param {?} a
* @param {?} b
* @return {?}
*/
isValidAttr(a, b) {
/** @type {?} */
let typeA = typeof a;
/** @type {?} */
let typeB = typeof b;
return (a && b && (typeA == 'object' || typeA == 'function') && (typeB == 'object' || typeB == 'function'));
}
}
NgxObjectDiffService.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */
NgxObjectDiffService.ctorParameters = () => [
{ type: DomSanitizer }
];
/** @nocollapse */ NgxObjectDiffService.ngInjectableDef = ɵɵdefineInjectable({ factory: function NgxObjectDiffService_Factory() { return new NgxObjectDiffService(ɵɵinject(DomSanitizer)); }, token: NgxObjectDiffService, providedIn: "root" });
if (false) {
/**
* @type {?}
* @private
*/
NgxObjectDiffService.prototype.openChar;
/**
* @type {?}
* @private
*/
NgxObjectDiffService.prototype.closeChar;
/**
* @type {?}
* @private
*/
NgxObjectDiffService.prototype.sanitizer;
}
/**
* @fileoverview added by tsickle
* Generated from: lib/ngx-object-diff.component.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class NgxObjectDiffComponent {
}
NgxObjectDiffComponent.decorators = [
{ type: Component, args: [{
selector: 'ngx-object-diff',
template: `
<pre [innerHTML]="obj"></pre>
`,
styles: [`
pre{
display: block;
padding: 9.5px;
margin: 0 0 10px;
font-size: 13px;
line-height: 1.428571429;
color: #333;
word-break: break-all;
word-wrap: break-word;
background-color: #f5f5f5;
border: 1px solid #ccc;
border-radius: 4px;
}
:host >>> .diff {
display: inline-block;
}
:host >>> .diff-level {
margin-left: 1.6em;
}
:host >>> .diff-holder {
color: #666;
margin: 0;
}
:host >>> .diff-holder span {
color: #AAA;
}
:host >>> del.diff {
text-decoration: none;
color: #b30000;
background: #fadad7;
}
:host >>> ins.diff {
background: #eaf2c2;
color: #406619;
text-decoration: none;
}
:host >>> del.diff-key {
border: 1px solid #f8a4a4;
}
:host >>> ins.diff-key {
border: 1px solid #a3ce4c;
margin-top: -1px;
position: relative;
}
:host >>> ins.diff span {
color: #AABF40;
}
:host >>> del.diff span {
color: #EE8177;
}
`]
}] }
];
NgxObjectDiffComponent.propDecorators = {
obj: [{ type: Input }]
};
if (false) {
/** @type {?} */
NgxObjectDiffComponent.prototype.obj;
}
/**
* @fileoverview added by tsickle
* Generated from: lib/ngx-object-diff.module.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class NgxObjectDiffModule {
}
NgxObjectDiffModule.decorators = [
{ type: NgModule, args: [{
declarations: [NgxObjectDiffComponent],
imports: [],
providers: [NgxObjectDiffService],
exports: [NgxObjectDiffComponent]
},] }
];
/**
* @fileoverview added by tsickle
* Generated from: public-api.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* Generated from: ngx-object-diff.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
export { NgxObjectDiffComponent, NgxObjectDiffModule, NgxObjectDiffService };
//# sourceMappingURL=ngx-object-diff.js.map