awesome-ajv-errors
Version:
Prettified AJV errors
111 lines (110 loc) • 4.94 kB
JavaScript
import leven from 'leven';
import { getValueType, getTypedValueKey, getTypedValue, } from './types.js';
import { uniq } from './util.js';
const defaultLimit = (length) => length < 3 ? 1 : length < 5 ? 2 : 3;
export function suggest(value, possibles, opts = {}) {
if (!possibles)
return undefined;
value = `${value}`;
const { length } = value;
const { limit = defaultLimit, referenceValue } = opts;
const distanceLimit = typeof limit === 'number' ? limit : limit(length);
const suggestions = [];
const rest = [];
possibles
.map(possible => getTypedValue(possible))
.map(valueType => ({
...valueType,
distance: valueType.isSimple
? leven(value, `${valueType.value}`)
: Infinity,
}))
.sort((a, b) => a.distance === b.distance ? 0 : a.distance < b.distance ? -1 : 1)
.forEach(({ distance, type, value, isSimple }) => {
const suggest = distanceLimit === -1 || distance <= distanceLimit;
if (suggest)
suggestions.push({ type, value, isSimple });
else
rest.push({ type, value, isSimple });
});
// The rest should be alphabetically ordered, it's easier to grasp
rest.sort((a, b) => `${a.value}`.localeCompare(`${b.value}`));
const ret = {
suggestions,
rest,
referenceValue,
best: suggestions === null || suggestions === void 0 ? void 0 : suggestions[0],
};
return ret;
}
export function formatSuggestions(list, context, opts = {}) {
var _a, _b;
if (!list)
return '';
const { styleManager: { style, formatTypedValue, printEnum } } = context;
const ifSuggestResult = Array.isArray(list === null || list === void 0 ? void 0 : list.rest)
? list
: undefined;
const rest = (_a = ifSuggestResult === null || ifSuggestResult === void 0 ? void 0 : ifSuggestResult.rest) !== null && _a !== void 0 ? _a : [];
const suggestions = (_b = ifSuggestResult === null || ifSuggestResult === void 0 ? void 0 : ifSuggestResult.suggestions) !== null && _b !== void 0 ? _b : list;
const { untyped: defaultUntyped, referenceValue = ifSuggestResult === null || ifSuggestResult === void 0 ? void 0 : ifSuggestResult.referenceValue, isSuggestion, isConst = false, } = opts;
const referenceType = referenceValue === undefined
? undefined
: getValueType(referenceValue);
const useUntyped = () => defaultUntyped !== null && defaultUntyped !== void 0 ? defaultUntyped : false;
const useType = (suggestion) => referenceValue === undefined
? false
: referenceType !== suggestion.type;
const formatUntyped = (suggestion) => formatTypedValue(suggestion, {
untyped: useUntyped(),
includeType: useType(suggestion),
});
const uniqSuggestions = uniq(suggestions, getTypedValueKey);
const allSuggestions = [...uniqSuggestions, ...rest];
const styledSuggestion = allSuggestions.length === 1
? formatUntyped(allSuggestions[0])
: allSuggestions.length === 2
?
formatUntyped(allSuggestions[0]) +
style.title(" or ") +
formatUntyped(allSuggestions[1])
:
style.title("any of:") + "\n" +
printEnum([
...uniqSuggestions.map(suggestion => formatUntyped(suggestion)),
...(rest.length === 0 ? [] : [
"other available values:",
...printEnum(rest.map(suggestion => formatUntyped(suggestion)), { indent: 2, bullet: false })
])
])
.join("\n");
const isQuestion = allSuggestions.length !== 1 && !isConst;
return (!isSuggestion ? '' :
style.title(`, ${isQuestion ? 'did you mean' : 'it must be'} `)) +
styledSuggestion +
(isQuestion && isSuggestion && uniqSuggestions.length < 3
? style.title('?')
: '');
}
export function formatBestSuggestion({ best, referenceValue }, context) {
if (!best)
return undefined;
const includeType = referenceValue === undefined
? false
: getValueType(referenceValue) !== best.type;
return context.styleManager.formatTypedValue(best, { untyped: false, includeType });
}
export function suggestTypedValue(value, types, context) {
if (typeof value === 'string' && types.includes("number"))
return {
type: "number",
value: context.styleManager.formatTypedValue({ value, type: 'number', isSimple: true }),
};
else if (typeof value === 'number' && types.includes("string"))
return {
type: "string",
value: context.styleManager.formatTypedValue({ value: `${value}`, type: 'string', isSimple: true }),
};
else
return undefined;
}