yini-parser
Version:
Node.js parser for YINI — a clean, structured INI alternative with types, simple section nesting, comments, and strict mode.
204 lines (202 loc) • 10.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ErrorDataHandler = void 0;
const env_1 = require("../config/env");
const print_1 = require("../utils/print");
// All the issue titles are defined here to get a quick overview of all
// titles, and to easier check that all titles match with relation to
// the other titles.
const issueTitle = [
'FATAL ERROR!',
'Internal error!', // 'Internal-Error'.
'Syntax error.', // 'Syntax-Error'.
'Syntax warning.',
'Notice:',
'Info:',
];
/**
* This class handles all error/notice reporting and processes exit/throwing.
*/
class ErrorDataHandler {
/** '1-Abort-on-Errors' is the default.
Below is from the YINI spec:
**Abort Sensitivity Levels** while parsing a YINI document:
(AKA severity threshold)
- Level 0 = ignore errors and try parse anyway (may remap falty key/section names)
- Level 1 = abort on errors only
- Level 2 = abort even on warnings
*/
constructor(threshold = '1-Abort-on-Errors') {
this.numFatalErrors = 0;
this.numInternalErrors = 0;
this.numSyntaxErrors = 0;
this.numSyntaxWarnings = 0;
this.numNotices = 0;
this.numInfos = 0;
this.makeIssuePayload = (type, msgWhat, lineNum, startCol, endCol) => {
const issue = {
type,
msgWhat,
// msgHintOrFix: string = '', // Hint or wow to fix.
start: {
line: lineNum,
column: startCol,
},
end: {
line: lineNum,
column: endCol,
},
};
(0, print_1.debugPrint)('issue:');
(0, env_1.isDebug)() && console.log(issue);
return issue;
};
/**
* After pushing processing may continue or exit, depending on the error
* and/or the bail threshold (that can be optionally set my the user).
*
* @note This function MIGHT result in a return, throw, or exit depending
* on the bail policy (set my the user).
*
* @param ctx
* @param type
* @param msgWhat Name of the specific error or what failed. E.g. "Key already exists in this section scope".
* @param msgWhy More details and more specific info about the issue/error.
* @param msgHint Hint or HUMBLE description on how to fix the issue.
*/
this.pushOrBail = (ctx, type, msgWhat, msgWhy = '', msgHint = '') => {
var _a, _b, _c, _d, _e, _f;
(0, print_1.debugPrint)('-> pushOrBail(..)');
(0, print_1.debugPrint)('ctx.exception?.name =' + ((_a = ctx === null || ctx === void 0 ? void 0 : ctx.exception) === null || _a === void 0 ? void 0 : _a.name));
(0, print_1.debugPrint)('ctx.exception?.message = ' + ((_b = ctx === null || ctx === void 0 ? void 0 : ctx.exception) === null || _b === void 0 ? void 0 : _b.message));
(0, print_1.debugPrint)('exception?.offendingToken = ' + ((_c = ctx === null || ctx === void 0 ? void 0 : ctx.exception) === null || _c === void 0 ? void 0 : _c.offendingToken));
(0, print_1.debugPrint)();
(0, print_1.debugPrint)('ctx.ruleIndex = ' + (ctx === null || ctx === void 0 ? void 0 : ctx.start.channel));
(0, print_1.debugPrint)('ctx.ruleIndex = ' + (ctx === null || ctx === void 0 ? void 0 : ctx.ruleIndex));
(0, print_1.debugPrint)('ctx.ruleContext = ' + (ctx === null || ctx === void 0 ? void 0 : ctx.ruleContext));
(0, print_1.debugPrint)('ctx.stop?.line = ' + ((_d = ctx === null || ctx === void 0 ? void 0 : ctx.stop) === null || _d === void 0 ? void 0 : _d.line));
(0, print_1.debugPrint)('ctx.stop?.column = ' + ((_e = ctx === null || ctx === void 0 ? void 0 : ctx.stop) === null || _e === void 0 ? void 0 : _e.column));
const lineNum = (ctx === null || ctx === void 0 ? void 0 : ctx.start.line) || 0; // Column (1-based).
const startCol = !ctx ? 0 : ++ctx.start.column; // Column (0-based).
const endCol = (((_f = ctx === null || ctx === void 0 ? void 0 : ctx.stop) === null || _f === void 0 ? void 0 : _f.column) || 0) + 1; // Column (0-based).
// Patch message with the offending line number.
msgWhat += ', at line: ' + lineNum;
if (process.env.NODE_ENV === 'test') {
msgWhat += `\nAt line: ${lineNum}, column(s): ${startCol}-${endCol}`;
}
(0, print_1.debugPrint)('persistThreshold = ' + this.persistThreshold);
(0, print_1.debugPrint)('lineNum = ' + lineNum);
(0, print_1.debugPrint)();
const issue = this.makeIssuePayload(type, msgWhat, lineNum, startCol, endCol);
switch (type) {
case 'Internal-Error':
this.numInternalErrors++;
this.emitInternalError(msgWhat, msgWhy, msgHint);
if (this.persistThreshold === '1-Abort-on-Errors' ||
this.persistThreshold === '2-Abort-Even-on-Warnings') {
// if (process.env.NODE_ENV === 'test') {
// In test, throw an error instead of exiting.
throw new Error(`Internal-Error: ${msgWhat}`);
// } else {
// process.exit(2)
// }
}
break;
case 'Syntax-Error':
this.numSyntaxErrors++;
this.emitSyntaxError(msgWhat, msgWhy, msgHint);
if (this.persistThreshold === '1-Abort-on-Errors' ||
this.persistThreshold === '2-Abort-Even-on-Warnings') {
// if (process.env.NODE_ENV === 'test') {
// In test, throw an error instead of exiting.
throw new Error(`Syntax-Error: ${'' + msgWhat}`);
// } else {
// process.exit(3)
// }
}
break;
case 'Syntax-Warning':
this.numSyntaxWarnings++;
this.emitSyntaxWarning(msgWhat, msgWhy, msgHint);
if (this.persistThreshold === '2-Abort-Even-on-Warnings') {
// if (process.env.NODE_ENV === 'test') {
// In test, throw an error instead of exiting.
throw new Error(`Syntax-Warning: ${msgWhat}`);
// } else {
// process.exit(4)
// }
}
break;
case 'Notice':
this.numNotices++;
this.emitNotice(msgWhat, msgWhy, msgHint);
break;
case 'Info':
this.numInfos++;
this.emitInfo(msgWhat, msgWhy, msgHint);
break;
default: // Including 'Internal-Error'.
this.numFatalErrors++;
this.emitFatalError(msgWhat, msgWhy, msgHint);
// CANNOT recover fatal errors, will lead to an exit!
// if (process.env.NODE_ENV === 'test') {
// In test, throw an error instead of exiting.
throw new Error(`Internal-Error: ${msgWhat}`);
// } else {
// process.exit(1)
// (!) Not sure about the below yet, if it's preferable in this case...
// Use this instead of process.exit(1), this will
// lead to that the current thread(s) will exit as well.
// process.exitCode = 1
// }
}
};
this.emitFatalError = (msgWhat = 'Something went wrong!', msgWhy = '', msgHint = '') => {
console.error(issueTitle[0]); // Print the issue title.
msgWhat && console.error(msgWhat);
msgWhy && console.log(msgWhy);
msgHint && console.log(msgHint);
};
this.emitInternalError = (msgWhat = 'Something went wrong!', msgWhy = '', msgHint = '') => {
console.error(issueTitle[1]); // Print the issue title.
msgWhat && console.error(msgWhat);
msgWhy && console.log(msgWhy);
msgHint && console.log(msgHint);
};
this.emitSyntaxError = (msgWhat, msgWhy = '', msgHint = '') => {
console.error(issueTitle[2]); // Print the issue title.
msgWhat && console.error(msgWhat);
msgWhy && console.log(msgWhy);
msgHint && console.log(msgHint);
};
this.emitSyntaxWarning = (msgWhat, msgWhy = '', msgHint = '') => {
console.warn(issueTitle[3]); // Print the issue title.
msgWhat && console.warn(msgWhat);
msgWhy && console.log(msgWhy);
msgHint && console.log(msgHint);
};
this.emitNotice = (msgWhat, msgWhy = '', msgHint = '') => {
console.warn(issueTitle[4]); // Print the issue title.
msgWhat && console.warn(msgWhat);
msgWhy && console.log(msgWhy);
msgHint && console.log(msgHint);
};
this.emitInfo = (msgWhat, msgWhy = '', msgHint = '') => {
console.info(issueTitle[5]); // Print the issue title.
msgWhat && console.info(msgWhat);
msgWhy && console.log(msgWhy);
msgHint && console.log(msgHint);
};
this.persistThreshold = threshold;
}
getNumOfErrors() {
return (this.numFatalErrors + this.numInternalErrors + this.numSyntaxErrors);
}
getNumOfWarnings() {
return this.numSyntaxWarnings;
}
getNumOfInfoAndNotices() {
return this.numNotices + this.numInfos;
}
}
exports.ErrorDataHandler = ErrorDataHandler;