@finnair/path
Version:
Simple object path as array of strings and numbers
105 lines (104 loc) • 3.69 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Projection = void 0;
exports.projection = projection;
const PathMatcher_js_1 = require("./PathMatcher.js");
const jsonClone_js_1 = require("./jsonClone.js");
class Projection {
includes;
excludes;
always;
replacer;
allowGaps;
constructor(includes, excludes, always, replacer) {
this.includes = includes;
this.excludes = excludes;
this.always = always;
this.replacer = replacer;
this.allowGaps = this.includes.some(expression => expression.allowGaps)
|| this.excludes.some(expression => expression.allowGaps)
|| this.always.some(expression => expression.allowGaps);
Object.freeze(this.includes);
Object.freeze(this.excludes);
Object.freeze(this.always);
Object.freeze(this);
}
map(input) {
// Clone input for safety: nothing invisible to JSON should be accessible!
let safeInput = (0, jsonClone_js_1.jsonClone)(input, this.replacer);
if (typeof safeInput !== 'object' || safeInput === null) {
throw new Error(`Expected JSON of the input to be non-null object, got ${safeInput}`);
}
let output;
if (this.includes.length) {
output = Array.isArray(safeInput) ? [] : {};
this.includes.forEach(expression => include(safeInput, expression, output));
}
else if (this.excludes.length) {
output = safeInput;
}
else {
return safeInput;
}
this.excludes.forEach(expression => exclude(output, expression));
if (this.includes.length || this.excludes.length) {
this.always.forEach(expression => include(input, expression, output));
}
if (this.allowGaps) {
return removeGaps(output);
}
return output;
}
match(path) {
if (this.always.some(expression => expression.prefixMatch(path))) {
return true;
}
if (this.includes.length && !this.includes.some(expression => expression.partialMatch(path))) {
return false;
}
if (this.excludes.some(expression => expression.prefixMatch(path))) {
return false;
}
return true;
}
static of(includes, excludes, always, replacer) {
includes = includes ? includes.map(validatePathMatcher) : [];
excludes = excludes ? excludes.map(validatePathMatcher) : [];
always = always ? always.map(validatePathMatcher) : [];
return new Projection(includes, excludes, always, replacer);
}
}
exports.Projection = Projection;
function projection(includes, excludes, always, replacer) {
const projection = Projection.of(includes, excludes, always, replacer);
return (input) => projection.map(input);
}
function validatePathMatcher(value) {
if (value instanceof PathMatcher_js_1.PathMatcher) {
return value;
}
else {
throw new Error(`Expected an instance of PathMatcher, got ${value}`);
}
}
function include(input, matcher, output) {
matcher.find(input, (path, value) => path.set(output, value));
}
function exclude(output, matcher) {
matcher.find(output, (path) => path.unset(output));
}
function removeGaps(value) {
if (typeof value === 'object') {
if (Array.isArray(value)) {
value = value
.filter(item => item !== undefined)
.map(removeGaps);
}
else {
for (const key in value) {
value[key] = removeGaps(value[key]);
}
}
}
return value;
}