@finnair/diff
Version:
Object Diff Based on Paths And Valudes of an Object
116 lines (115 loc) • 4.13 kB
JavaScript
import { parsePath, parsePathMatcher } from '@finnair/path-parser';
import { Diff } from './Diff.js';
const NO_PREVIOUS_VALUES = Object.freeze({});
export class VersionInfo {
current;
previous;
_changes;
_paths;
_previousValues;
config;
constructor(current, previous, config) {
this.current = current;
this.previous = previous;
this.config = config ?? { diff: new Diff({}) };
}
map(fn, config) {
return new VersionInfo(fn(this.current), this.previous ? fn(this.previous) : undefined, config ?? this.config);
}
async mapAsync(fn, config) {
return new VersionInfo(await fn(this.current), this.previous ? await fn(this.previous) : undefined, config ?? this.config);
}
get changes() {
if (this.previous) {
if (this._changes === undefined) {
this._changes = this.config.diff.changeset(this.previous, this.current);
}
return this._changes;
}
return undefined;
}
get changedPaths() {
if (this.previous) {
if (this._paths === undefined) {
this._paths = new Set(this.changes.keys());
}
return this._paths;
}
return undefined;
}
get paths() {
if (this._paths === undefined) {
if (this.previous) {
this._paths = this.changedPaths;
}
else {
this._paths = new Set(this.config.diff.allPaths(this.current));
}
}
return this._paths;
}
get previousValues() {
if (this.previous && this.config.previousValues?.length) {
if (this._previousValues === undefined) {
this._previousValues = NO_PREVIOUS_VALUES;
for (const [key, value] of this.changes) {
const path = parsePath(key);
if (this.config.previousValues.some((matcher) => matcher.match(path))) {
if (this._previousValues === NO_PREVIOUS_VALUES) {
this._previousValues = Array.isArray(this.previous) ? [] : {};
}
path.set(this._previousValues, value.oldValue);
}
}
}
return this._previousValues === NO_PREVIOUS_VALUES ? undefined : this._previousValues;
}
return undefined;
}
matches(pathExpression) {
const matcher = VersionInfo.toMatcher(pathExpression);
if (this.previous) {
const changedPaths = VersionInfo.parsePaths(this.changedPaths);
return VersionInfo.matchesAnyPath(matcher, changedPaths);
}
else {
return matcher.findFirst(this.current) !== undefined;
}
}
matchesAny(pathExpressions) {
if (this.previous) {
const changedPaths = VersionInfo.parsePaths(this.changedPaths);
return pathExpressions.some((pathExpression) => {
const matcher = VersionInfo.toMatcher(pathExpression);
return VersionInfo.matchesAnyPath(matcher, changedPaths);
});
}
else {
return pathExpressions.some((pathExpression) => {
const matcher = VersionInfo.toMatcher(pathExpression);
return matcher.findFirst(this.current) !== undefined;
});
}
}
toJSON() {
const changedPaths = this.changedPaths;
return {
current: this.current,
changedPaths: changedPaths && Array.from(changedPaths),
previous: this.previousValues,
};
}
static parsePaths(paths) {
const result = [];
for (const path of paths) {
result.push(parsePath(path));
}
return result;
}
static matchesAnyPath(matcher, paths) {
return paths.some((path) => matcher.prefixMatch(path));
}
static toMatcher(pathExpression) {
return typeof pathExpression === 'string' ? parsePathMatcher(pathExpression) : pathExpression;
}
}