@citation-js/core
Version:
Convert different bibliographic metadata sources
100 lines • 2.95 kB
JavaScript
function createConditionEval(condition) {
return function conditionEval(input) {
if (typeof condition === 'boolean') {
return condition;
}
return Object.keys(condition).every(prop => {
const value = condition[prop];
if (value === true) {
return prop in input;
} else if (value === false) {
return !(prop in input);
} else if (typeof value === 'function') {
return value(input[prop]);
} else if (Array.isArray(value)) {
return value.includes(input[prop]);
} else {
return input[prop] === value;
}
});
};
}
function parsePropStatement(prop, toSource) {
let inputProp;
let outputProp;
let convert;
let condition;
if (typeof prop === 'string') {
inputProp = outputProp = prop;
} else if (prop) {
inputProp = toSource ? prop.target : prop.source;
outputProp = toSource ? prop.source : prop.target;
if (prop.convert) {
convert = toSource ? prop.convert.toSource : prop.convert.toTarget;
}
if (prop.when) {
condition = toSource ? prop.when.target : prop.when.source;
if (condition != null) {
condition = createConditionEval(condition);
}
}
} else {
return null;
}
inputProp = [].concat(inputProp).filter(Boolean);
outputProp = [].concat(outputProp).filter(Boolean);
return {
inputProp,
outputProp,
convert,
condition
};
}
function createConverter(props, toSource) {
toSource = toSource === Translator.CONVERT_TO_SOURCE;
props = props.map(prop => parsePropStatement(prop, toSource)).filter(Boolean);
return function converter(input) {
const output = {};
for (const {
inputProp,
outputProp,
convert,
condition
} of props) {
if (outputProp.length === 0) {
continue;
} else if (condition && !condition(input)) {
continue;
} else if (inputProp.length !== 0 && inputProp.every(prop => !(prop in input))) {
continue;
}
let outputData = inputProp.map(prop => input[prop]);
if (convert) {
try {
const converted = convert.apply(input, outputData);
outputData = outputProp.length === 1 ? [converted] : converted;
} catch (cause) {
throw new Error(`Failed to convert ${inputProp} to ${outputProp}`, {
cause
});
}
}
outputProp.forEach((prop, index) => {
const value = outputData[index];
if (value !== undefined) {
output[prop] = value;
}
});
}
return output;
};
}
class Translator {
constructor(props) {
this.convertToSource = createConverter(props, Translator.CONVERT_TO_SOURCE);
this.convertToTarget = createConverter(props, Translator.CONVERT_TO_TARGET);
}
}
Translator.CONVERT_TO_SOURCE = Symbol('convert to source');
Translator.CONVERT_TO_TARGET = Symbol('convert to target');
export { Translator };