yini-parser
Version:
Node.js parser for YINI — a clean, structured INI alternative with types, simple section nesting, comments, and strict mode.
186 lines (185 loc) • 8.33 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseMain = void 0;
const antlr4_1 = require("antlr4");
const env_1 = require("./config/env");
const ErrorDataHandler_1 = require("./core/ErrorDataHandler");
const objectBuilder_1 = require("./core/objectBuilder");
const YINIVisitor_1 = __importDefault(require("./core/YINIVisitor"));
const YiniLexer_1 = __importDefault(require("./grammar/YiniLexer"));
const YiniParser_1 = __importDefault(require("./grammar/YiniParser"));
const print_1 = require("./utils/print");
class MyParserErrorListener {
constructor(errorHandler) {
this.errors = [];
this.errorHandler = errorHandler;
}
syntaxError(recognizer, offendingSymbol, line, charPositionInLine, msg, e) {
(0, print_1.debugPrint)('ANTLR parser cached an error');
this.errors.push(`Line ${line}:${charPositionInLine} ${msg}`);
const msgWhat = `Syntax error, at line: ${line}`;
const msgWhy = `At about column ${1 + charPositionInLine} ${msg}`;
this.errorHandler.pushOrBail(null, 'Syntax-Error', msgWhat, msgWhy);
}
// The following are required for the interface, but can be left empty.
reportAmbiguity(...args) { }
reportAttemptingFullContext(...args) { }
reportContextSensitivity(...args) { }
}
class MyLexerErrorListener {
constructor(errorHandler) {
this.errors = [];
this.errorHandler = errorHandler;
}
syntaxError(recognizer, offendingSymbol, line, charPositionInLine, msg, e) {
// Handle the error as you want:
(0, print_1.debugPrint)('ANTLR parser cached an error');
this.errors.push(`Line ${line}:${charPositionInLine} ${msg}`);
const msgWhat = `Syntax error, at line: ${line}`;
const msgWhy = `At about column ${1 + charPositionInLine} ${msg}`;
this.errorHandler.pushOrBail(null, 'Syntax-Error', msgWhat, msgWhy);
}
}
const parseMain = (yiniContent, options = {
isStrict: false,
bailSensitivityLevel: 0,
isIncludeMeta: false,
isWithDiagnostics: false,
isWithTiming: false,
}) => {
(0, print_1.debugPrint)();
(0, print_1.debugPrint)('-> Entered parseMain(..) in parseEntry');
(0, print_1.debugPrint)(' isStrict mode = ' + options.isStrict);
(0, print_1.debugPrint)('bailSensitivityLevel = ' + options.bailSensitivityLevel);
let persistThreshold;
switch (options.bailSensitivityLevel) {
case 0:
persistThreshold = '0-Ignore-Errors';
break;
case 1:
persistThreshold = '1-Abort-on-Errors';
break;
default:
persistThreshold = '2-Abort-Even-on-Warnings';
}
(0, env_1.isDebug)() && console.log();
(0, print_1.debugPrint)('=== Phase 1 ===================================================');
const inputStream = antlr4_1.CharStreams.fromString(yiniContent);
const lexer = new YiniLexer_1.default(inputStream);
const tokenStream = new antlr4_1.CommonTokenStream(lexer);
const parser = new YiniParser_1.default(tokenStream);
const errorHandler = new ErrorDataHandler_1.ErrorDataHandler(persistThreshold);
// Remove the default ConsoleErrorListener
lexer.removeErrorListeners(); // Removes the default lexer console error output.
const lexerErrorListener = new MyLexerErrorListener(errorHandler);
lexer.addErrorListener(lexerErrorListener);
// const errorListener = new MyParserErrorListener(errorHandler)
parser.removeErrorListeners(); // Removes the default parser console error output.
const parserErrorListener = new MyParserErrorListener(errorHandler);
parser.addErrorListener(parserErrorListener);
(0, print_1.debugPrint)();
(0, print_1.debugPrint)('--- Starting parsing... ---');
const parseTree = parser.yini(); // The function yini() is the start rule.
if (parserErrorListener.errors.length > 0 ||
lexerErrorListener.errors.length > 0) {
(0, print_1.debugPrint)('*** ERROR detected ***');
if ((0, env_1.isDebug)()) {
// Handle or display syntax errors
console.error('Syntax errors detected:', parserErrorListener.errors, lexerErrorListener.errors);
//process.exit(1)
}
}
(0, print_1.debugPrint)('--- Parsing done. ---');
(0, print_1.debugPrint)('=== Ended phase 1 =============================================');
(0, env_1.isDebug)() && console.log();
(0, print_1.debugPrint)('=== Phase 2 ===================================================');
// const errorHandler = new ErrorDataHandler(persistThreshold)
const visitor = new YINIVisitor_1.default(errorHandler, options.isStrict);
const syntaxTreeC = visitor.visit(parseTree);
if ((0, env_1.isDebug)()) {
console.log();
console.log('**************************************************************************');
console.log('*** syntaxTreeContainer: *************************************************');
(0, print_1.printObject)(syntaxTreeC);
console.log('**************************************************************************');
console.log('**************************************************************************');
console.log();
}
(0, print_1.debugPrint)('=== Ended phase 2 =============================================');
(0, env_1.isDebug)() && console.log();
(0, print_1.debugPrint)('=== Phase 3 ===================================================');
// Construct.
const finalJSResult = (0, objectBuilder_1.constructFinalObject)(syntaxTreeC, errorHandler);
(0, print_1.debugPrint)('=== Ended phase 3 =============================================');
(0, print_1.debugPrint)('visitor.visit(..): finalJSResult:');
(0, env_1.isDebug)() && console.debug(finalJSResult);
(0, print_1.debugPrint)();
if (options.isStrict) {
//throw Error('ERROR: Strict-mode not yet implemented')
errorHandler.pushOrBail(null, 'Syntax-Warning', 'WARNING: Strict-mode not yet fully implemented', '', '');
}
else {
(0, print_1.debugPrint)('visitor.visit(..): finalJSResult:');
(0, env_1.isDebug)() && console.debug(finalJSResult);
}
// Construct meta data.
const metaData = {
strictMode: options.isStrict,
hasTerminal: syntaxTreeC._hasTerminal,
sections: syntaxTreeC._meta_numOfSections,
members: syntaxTreeC._meta_numOfMembers,
sectionChains: syntaxTreeC._meta_numOfChains,
keysParsed: null,
timing: {
totalMs: null,
phase1Ms: null,
phase2Ms: null,
phase3Ms: null,
},
};
if (options.isWithDiagnostics) {
// Attach optional diagnostics.
metaData.diagnostics = {
bailSensitivityLevel: options.bailSensitivityLevel,
errors: errorHandler.getNumOfErrors(),
warnings: errorHandler.getNumOfWarnings(),
infoAndNotices: errorHandler.getNumOfInfoAndNotices(),
envs: {
NODE_ENV: process.env.NODE_ENV,
APP_ENV: process.env.APP_ENV,
libNodeEnv: env_1.localNodeEnv,
libAppEnv: env_1.localAppEnv,
},
libFlags: {
isDev: (0, env_1.isDev)(),
isDebug: (0, env_1.isDebug)(),
},
};
}
if (options.isWithTiming) {
// Attach optional timing data.
metaData.timing = {
totalMs: null,
phase1Ms: null,
phase2Ms: null,
phase3Ms: null,
};
}
(0, print_1.debugPrint)('getNumOfErrors(): ' + errorHandler.getNumOfErrors());
if (errorHandler.getNumOfErrors()) {
console.log();
console.log('Parsing is complete, but some problems were detected. Please see the errors above for details.');
console.log('Number of errors found: ' + errorHandler.getNumOfErrors());
}
if (options.isIncludeMeta) {
return {
result: finalJSResult,
meta: metaData,
};
}
return finalJSResult;
};
exports.parseMain = parseMain;