@chubbyts/chubbyts-negotiation
Version:
A simple negotiation library.
55 lines (54 loc) • 2.18 kB
JavaScript
import { resolveHeaderToMap } from './negotiation.js';
const escapeStringRegexp = (regex) => {
return regex.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
};
const compareMediaTypeWithTypeOnly = (supportedValues, mediaType, attributes) => {
const mediaTypeParts = mediaType.match(/([^/+]+)\/\*/);
if (null === mediaTypeParts) {
return undefined;
}
for (const supportedValue of supportedValues) {
if (null !== supportedValue.match(new RegExp('^' + escapeStringRegexp(mediaTypeParts[1]) + '/'))) {
return { value: supportedValue, attributes };
}
}
return undefined;
};
const compareMediaTypes = (supportedValues, suffixSupportedValues, headerToMap) => {
for (const [mediaType, attributes] of headerToMap.entries()) {
if (-1 !== supportedValues.indexOf(mediaType)) {
return { value: mediaType, attributes };
}
}
for (const [mediaType, attributes] of headerToMap.entries()) {
if (suffixSupportedValues.has(mediaType)) {
return { value: suffixSupportedValues.get(mediaType), attributes };
}
}
for (const [mediaType, attributes] of headerToMap.entries()) {
const negotiatedValue = compareMediaTypeWithTypeOnly(supportedValues, mediaType, attributes);
if (undefined !== negotiatedValue) {
return negotiatedValue;
}
}
if (headerToMap.has('*/*')) {
return { value: supportedValues[0], attributes: headerToMap.get('*/*') };
}
return undefined;
};
export const createAcceptNegotiator = (supportedValues) => {
const suffixSupportedValues = new Map(supportedValues.map((supportedValue) => {
const supportedValueParts = supportedValue.match(/([^/+]+)\/([^/+]+)\+([^/+]+)/);
return [
null !== supportedValueParts ? supportedValueParts[1] + '/' + supportedValueParts[3] : undefined,
supportedValue,
];
}));
return {
negotiate: (header) => {
const headerToMap = resolveHeaderToMap(header);
return compareMediaTypes(supportedValues, suffixSupportedValues, headerToMap);
},
supportedValues,
};
};