in lib/generator/exampleGenerator.ts [271:367]
private unifyCommonProperty(example: any) {
if (!example || !example.parameters || !example.responses) {
return;
}
type pathNode = string | number;
type pathNodes = pathNode[];
const requestPaths = _.paths(example.parameters, { pathFormat: "array" }).map((v) =>
(v as pathNode[]).reverse()
);
/**
* construct a inverted index , the key is leaf property key, value is reverse of the path from the root to the leaf property.
*/
const invertedIndex = new Map<string | number, pathNodes[]>();
requestPaths.forEach((v) => {
if (v.length && typeof v[0] === "string") {
const parentPaths = invertedIndex.get(v[0]);
if (!parentPaths) {
invertedIndex.set(v[0], [v.slice(1)]);
} else {
parentPaths.push(v.slice(1));
}
}
});
/**
* get two paths' common properties' count
*/
const getMatchedNodeCnt = (baseNode: pathNodes, destNode: pathNodes) => {
let count = 0;
baseNode.some((v, k) => {
if (k < destNode.length && destNode[k] === v) {
count++;
return false;
} else {
return true;
}
});
return count;
};
/**
* update the property value of response using the same value which is found in the request
*/
const res = _.mapValuesDeep(
example.responses,
(value, key, parentValue, context) => {
if (!parentValue) {
log.warn(`parent is null`);
}
if (
["integer", "number", "string"].some((type) => typeof value === type) &&
typeof key === "string"
) {
const possiblePaths = invertedIndex.get(key);
if (context.path && possiblePaths) {
const basePath = (context.path as pathNodes).slice().reverse().slice(1);
/**
* to find out the most matchable path in the parameters
*/
const candidates = possiblePaths.filter(
(apiPath) => getMatchedNodeCnt(basePath, apiPath) > 1
);
if (candidates.length === 0) {
return value;
}
/**
* if only one matched one path, just use it.
*/
if (candidates.length === 1) {
const pathOfParameter = _.pathToString([key, ...candidates[0]].reverse());
const parameterValue = _.get(example.parameters, pathOfParameter);
// console.debug(`use path ${pathOfParameter} ,value :${parameterValue}
// -- original path:${_.pathToString(context.path as pathNodes)},value:${value}`);
return parameterValue;
}
const mostMatched = candidates.reduce((previous, current) => {
const countPrevious = getMatchedNodeCnt(basePath, previous);
const countCurrent = getMatchedNodeCnt(basePath, current);
return countPrevious < countCurrent ? current : previous;
});
return _.get(example.parameters, _.pathToString([key, ...mostMatched].reverse()));
}
}
return value;
},
{
leavesOnly: true,
pathFormat: "array",
}
);
// console.debug(`unify common properties end!`);
example.responses = res;
return example;
}