UNPKG

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
"use strict"; 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;