enolib
Version:
The eno standard library
160 lines (139 loc) • 6.14 kB
JavaScript
const { ValidationError } = require('../error_types.js');
const { cursor, DOCUMENT_BEGIN, selection, selectComments, selectElement, selectKey } = require('./selections.js');
const {
BEGIN,
END,
DOCUMENT,
FIELD,
FIELDSET_ENTRY,
FIELD_OR_FIELDSET_OR_LIST,
LIST_ITEM,
MULTILINE_FIELD_BEGIN
} = require('../constants.js');
// TODO: Here and prominently also elsewhere - consider replacing instruction.ranges.line with instruction[LINE_RANGE] (where LINE_RANGE = Symbol('descriptive'))
exports.errors = {
commentError: (context, message, element) => {
return new ValidationError(
context.messages.commentError(message),
new context.reporter(context).reportComments(element).snippet(),
selectComments(element)
);
},
elementError: (context, message, element) => {
return new ValidationError(
message,
new context.reporter(context).reportElement(element).snippet(),
selectElement(element)
);
},
keyError: (context, message, element) => {
return new ValidationError(
context.messages.keyError(message),
new context.reporter(context).reportLine(element).snippet(),
selectKey(element)
);
},
missingComment: (context, element) => {
return new ValidationError(
context.messages.missingComment,
new context.reporter(context).reportLine(element).snippet(), // TODO: Question-tag an empty line before an element with missing comment
selection(element, 'line', BEGIN)
);
},
missingElement: (context, key, parent, message) => {
return new ValidationError(
key === null ? context.messages[message] : context.messages[message + 'WithKey'](key),
new context.reporter(context).reportMissingElement(parent).snippet(),
parent.type === DOCUMENT ? DOCUMENT_BEGIN : selection(parent, 'line', END)
);
},
// TODO: Revisit and polish the two core value errors again at some point (missingValue / valueError)
// (In terms of quality of results and architecture - DRY up probably)
// Share best implementation among other eno libraries
missingValue: (context, element) => {
let message;
const selection = {};
if(element.type === FIELD || element.type === FIELD_OR_FIELDSET_OR_LIST || element.type === MULTILINE_FIELD_BEGIN) {
message = context.messages.missingFieldValue(element.key);
if(element.ranges.hasOwnProperty('template')) {
selection.from = cursor(element, 'template', END);
} else if(element.ranges.hasOwnProperty('elementOperator')) {
selection.from = cursor(element, 'elementOperator', END);
} else {
selection.from = cursor(element, 'line', END);
}
} else if(element.type === FIELDSET_ENTRY) {
message = context.messages.missingFieldsetEntryValue(element.key);
selection.from = cursor(element, 'entryOperator', END);
} else if(element.type === LIST_ITEM) {
message = context.messages.missingListItemValue(element.parent.key);
selection.from = cursor(element, 'itemOperator', END);
}
const snippet = new context.reporter(context).reportElement(element).snippet();
if(element.type === FIELD && element.continuations.length > 0) {
selection.to = cursor(element.continuations[element.continuations.length - 1], 'line', END);
} else {
selection.to = cursor(element, 'line', END);
}
return new ValidationError(message, snippet, selection);
},
unexpectedElement: (context, message, element) => {
return new ValidationError(
message || context.messages.unexpectedElement,
new context.reporter(context).reportElement(element).snippet(),
selectElement(element)
);
},
unexpectedMultipleElements: (context, key, elements, message) => {
return new ValidationError(
key === null ? context.messages[message] : context.messages[message + 'WithKey'](key),
new context.reporter(context).reportElements(elements).snippet(),
selectElement(elements[0])
);
},
unexpectedElementType: (context, key, section, message) => {
return new ValidationError(
key === null ? context.messages[message] : context.messages[message + 'WithKey'](key),
new context.reporter(context).reportElement(section).snippet(),
selectElement(section)
);
},
valueError: (context, message, element) => {
let snippet, select;
if(element.mirror) {
snippet = new context.reporter(context).reportLine(element).snippet();
select = selectKey(element);
} else if(element.type === MULTILINE_FIELD_BEGIN) {
if(element.lines.length > 0) {
snippet = new context.reporter(context).reportMultilineValue(element).snippet();
select = selection(element.lines[0], 'line', BEGIN, element.lines[element.lines.length - 1], 'line', END);
} else {
snippet = new context.reporter(context).reportElement(element).snippet();
select = selection(element, 'line', END);
}
} else {
snippet = new context.reporter(context).reportElement(element).snippet();
select = {};
if(element.ranges.hasOwnProperty('value')) {
select.from = cursor(element, 'value', BEGIN);
} else if(element.ranges.hasOwnProperty('elementOperator')) {
select.from = cursor(element, 'elementOperator', END);
} else if(element.ranges.hasOwnProperty('entryOperator')) {
select.from = cursor(element, 'entryOperator', END);
} else if(element.type === LIST_ITEM) {
select.from = cursor(element, 'itemOperator', END);
} else {
// TODO: Possibly never reached - think through state permutations
select.from = cursor(element, 'line', END);
}
if(element.continuations.length > 0) {
select.to = cursor(element.continuations[element.continuations.length - 1], 'line', END);
} else if(element.ranges.hasOwnProperty('value')) {
select.to = cursor(element, 'value', END);
} else {
select.to = cursor(element, 'line', END);
}
}
return new ValidationError(context.messages.valueError(message), snippet, select);
}
};