yini-parser
Version:
Node.js parser for YINI — a clean, structured INI alternative with types, simple section nesting, comments, and strict mode.
944 lines • 52.4 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const env_1 = require("../config/env");
const YiniParserVisitor_1 = __importDefault(require("../grammar/YiniParserVisitor"));
const extractSignificantYiniLine_1 = require("../parsers/extractSignificantYiniLine");
const parseBoolean_1 = __importDefault(require("../parsers/parseBoolean"));
const parseNull_1 = __importDefault(require("../parsers/parseNull"));
const parseNumber_1 = __importDefault(require("../parsers/parseNumber"));
const parseSectionHeader_1 = __importDefault(require("../parsers/parseSectionHeader"));
const parseString_1 = __importDefault(require("../parsers/parseString"));
const print_1 = require("../utils/print");
const string_1 = require("../utils/string");
const yiniHelpers_1 = require("../yiniHelpers");
const ErrorDataHandler_1 = require("./ErrorDataHandler");
/**
* This interface defines a complete generic visitor for a parse tree produced
* by `YiniParser`.
*
* @param <IResult> The return type of the visit operation. Use `void` for
* operations with no return type.
*/
class YINIVisitor extends YiniParserVisitor_1.default {
constructor(errorHandler, isStrict) {
super();
//export default class YINIVisitor extends YiniParserVisitor<any> {
this.reversedTree = [];
this.errorHandler = null;
this.lastActiveSectionAtLevels = [];
this.lastActiveSectionNameAtLevels = []; // Last active section name at each level.
this.numOfLevelOnes = 0; // Num of Level-1 sections.
this.level = 0;
this.prevLevel = 0;
this.prevSectionName = ''; // For error reporting purposes.
this.meta_numOfSections = 0; // For stats.
this.meta_numOfMembers = 0; // For stats.
this.meta_numOfChains = 0; // For stats.
this.meta_maxLevelSection = 0; // For stats.
// private existingSectionTitles: Map<string, boolean> = new Map()
this.existingSectionTitlesAtLevels = [];
this.hasDefinedSectionTitle = (sectionName, level) => {
const mapAtCurrentLevel = this.existingSectionTitlesAtLevels[level - 1];
return mapAtCurrentLevel === null || mapAtCurrentLevel === void 0 ? void 0 : mapAtCurrentLevel.has(sectionName);
};
this.setDefineSectionTitle = (sectionName, level) => {
let mapAtCurrentLevel = this.existingSectionTitlesAtLevels[level - 1];
if (!mapAtCurrentLevel) {
mapAtCurrentLevel = new Map();
this.existingSectionTitlesAtLevels[level - 1] = mapAtCurrentLevel;
}
mapAtCurrentLevel.set(sectionName, true);
};
this.pushOnTree = (ctx, sReslult) => {
if ((0, env_1.isDebug)()) {
console.log();
(0, print_1.debugPrint)('--- In pushOnTree(..) --------');
(0, print_1.debugPrint)('sReslult:');
(0, print_1.printObject)(sReslult);
}
const key = sReslult.level + '-' + sReslult.name;
(0, print_1.debugPrint)('KKKKKK, key = ' + key);
// if (this.existingSectionTitles.has(key)) {
if (this.hasDefinedSectionTitle(key, sReslult.level)) {
this.errorHandler.pushOrBail(ctx, 'Syntax-Error', 'Section name already exists', 'Cannot redefine section name: "' +
sReslult.name +
'" at level ' +
sReslult.level +
'.');
}
else {
if (sReslult.members === undefined) {
(0, print_1.debugPrint)('This sReslult does not hold any valid members (=undefined)');
}
else {
// this.existingSectionTitles.set(key, true)
this.setDefineSectionTitle(key, sReslult.level);
// printObject(this.existingSectionTitles)
}
}
// if (
// sReslult.level === 0 &&
// (!sReslult.name || sReslult.name === 'undefined')
// ) {
// // NOTE: This is a nasty fix, should try to do another way!
// debugPrint('HIT, Doing NASTY fix!!')
// // A memberless section, e.g. `^ Section` and then input ends.
// // Lift up the member in "members" to top.
// // --- Get the key-name of the entry in "members" ----------
// // "members": {
// // "Title": {}
// // }
// const sectionName = Object.keys(sReslult.members)[0]
// // ---------------------------------------------------------
// debugPrint('sectionName = ' + sectionName)
// const chain: IChainContainer = {
// originLevel: 1,
// chain: { [sectionName]: {} },
// }
// this.reversedTree.push(chain)
// } else {
const chain = {
originLevel: sReslult.level,
chain: { [(0, string_1.trimBackticks)(sReslult.name)]: sReslult.members },
};
this.reversedTree.push(chain);
// }
this.meta_numOfChains++;
(0, print_1.debugPrint)('this.reversedTree: [list]');
(0, print_1.printObject)(this.reversedTree);
(0, print_1.debugPrint)('--- /end of pushOnTree(..) --------');
};
this.getDepthOfLevels = () => {
return this.lastActiveSectionNameAtLevels.length;
};
this.setLastActiveSection = (atLevel, sectionName) => {
if (atLevel >= 1) {
this.lastActiveSectionNameAtLevels[atLevel - 1] = sectionName;
}
else {
// Note, after pushing processing may continue or exit, depending on the error and/or the bail threshold.
this.errorHandler.pushOrBail(null, 'Internal-Error', 'Invalid section level (<1), level: ' +
atLevel +
', sectionName: "' +
sectionName +
'"');
}
};
/**
* Visit a parse tree produced by `YiniParser.yini`.
* @param ctx the parse tree
* @return the visitor result
*/
// visitYini?: (ctx: YiniContext) => IResult;
// visitYini = (ctx: YiniContext): IResult => {
this.visitYini = (ctx, isStrict = false) => {
var _a;
if (!this.errorHandler) {
// Note, after pushing processing may continue or exit, depending on the error and/or the bail threshold.
new ErrorDataHandler_1.ErrorDataHandler().pushOrBail(null, 'Fatal-Error', 'Has no ErrorDataHandler instance when calling visitYini(..)', 'Something in the code is done incorrectly in order for this to happen... :S');
}
(0, print_1.debugPrint)();
(0, print_1.debugPrint)('abcde99');
(0, env_1.isDebug)() && console.log();
(0, print_1.debugPrint)('-> Entered visitYini(..) in YINIVisitor');
(0, print_1.debugPrint)('QQQQ');
(_a = ctx.section_list()) === null || _a === void 0 ? void 0 : _a.forEach((section) => {
// ctx?.section_list()?.forEach((section: any) => {
(0, print_1.debugPrint)('\nStart of each element in forEeach(..) of section_list():');
const topSectionResult = this.visitSection(section);
this.pushOnTree(ctx, topSectionResult);
const topSectionName = topSectionResult === null || topSectionResult === void 0 ? void 0 : topSectionResult.name;
const topSectionMembers = topSectionResult === null || topSectionResult === void 0 ? void 0 : topSectionResult.members;
const topSectionLevel = topSectionResult === null || topSectionResult === void 0 ? void 0 : topSectionResult.level; // This must have a value of 1.
(0, print_1.debugPrint)('\ntopSectionResult (visitSection(..)):');
if ((0, env_1.isDebug)()) {
console.log(topSectionResult);
}
(0, print_1.debugPrint)('Found section head, topSectionName = "' + topSectionName + '"');
topSectionMembers &&
(0, print_1.debugPrint)('Num of Props of topSectionResult?.members: ' +
Object.keys(topSectionResult === null || topSectionResult === void 0 ? void 0 : topSectionResult.members).length);
(0, print_1.debugPrint)('topSectionMembers:');
if ((0, env_1.isDebug)()) {
console.log(topSectionMembers);
}
if (topSectionName) {
(0, print_1.debugPrint)();
(0, print_1.debugPrint)('-- Just extracted TOP/FIRST section info ---------------------------');
(0, print_1.debugPrint)(' TOP/FIRST topSectionName = ' + topSectionName);
(0, print_1.debugPrint)(' topSectionLevel = ' + topSectionLevel);
(0, print_1.debugPrint)(' this.level = ' + this.level);
(0, print_1.debugPrint)('Mounted/assigned section onto resultSections...');
}
(0, print_1.debugPrint)('\n=== resultSections: =====================================');
if ((0, env_1.isDebug)()) {
console.log('2222222222222');
console.log(`lastActiveSectionAtLevels[${this.level - 1}]`);
(0, print_1.printObject)(this.lastActiveSectionAtLevels[this.level - 1]);
}
(0, print_1.debugPrint)('==============================================\n');
(0, print_1.debugPrint)('End of each element in forEeach(..) of section_list().');
(0, print_1.debugPrint)();
});
const syntaxTree = this.reversedTree.reverse();
if ((0, env_1.isDebug)()) {
console.log();
console.log('=========================================================================');
console.log('=== syntaxTree: ==========================================================');
(0, print_1.printObject)(syntaxTree);
console.log('=========================================================================');
console.log('=========================================================================');
console.log();
}
const hasTerminal = !!ctx.terminal_line();
// Returns an Intermediate Tree (could even be an AST).
const syntaxTreeC = {
// _base: this.resultSections,
_syntaxTree: syntaxTree, // The Intermediate Tree, or AST.
_hasTerminal: hasTerminal,
_meta_numOfSections: this.meta_numOfSections,
_meta_numOfMembers: this.meta_numOfMembers,
_meta_numOfChains: this.meta_numOfChains,
};
return syntaxTreeC;
};
/**
* Will visit here on EVERY section.
* @param ctx the parse tree
* @returns { [sectionName]: sectionObj }
*/
// visitSection?: (ctx: SectionContext) => IResult;
this.visitSection = (ctx) => {
// let headMarkerType: TSectionHeaderType =
// 'Classic-Header-Marker'
var _a, _b, _c;
(0, env_1.isDebug)() && console.log();
(0, print_1.debugPrint)('-> Entered visitSection(..)');
const res = {};
(0, print_1.debugPrint)('start');
(0, print_1.debugPrint)('XXXX0:ctx.getText() = ' + ctx.getText());
(0, print_1.debugPrint)('XXXX1:ctx.SECTION_HEAD() = ' + ctx.SECTION_HEAD());
(0, print_1.debugPrint)('XXXX1:SECTION_HEAD().getText() = ' +
((_a = ctx.SECTION_HEAD()) === null || _a === void 0 ? void 0 : _a.getText().trim()));
(0, print_1.debugPrint)('end\n');
let line = '';
try {
(0, print_1.debugPrint)('S1');
line = ((_b = ctx.SECTION_HEAD()) === null || _b === void 0 ? void 0 : _b.getText().trim()) || '';
(0, print_1.debugPrint)('S2, line: >>>' + line + '<<<');
}
catch (error) {
const msgWhat = `Unexpected syntax while parsing a member or section head`;
const msgWhy = `Found unexpected syntax while trying to read a key-value pair or a section header (such as a section marker or section name).`;
// Note, after pushing processing may continue or exit, depending on the error and/or the bail threshold.
this.errorHandler.pushOrBail(ctx, 'Syntax-Error', msgWhat, msgWhy);
}
// If no section head can be found in the above SECTION_HEAD(),
// try alternative method of reading the section content.
(0, print_1.debugPrint)('S3, line: >>>' + line + '<<<');
if (!line) {
(0, print_1.debugPrint)();
(0, print_1.debugPrint)('Nothing in SECTION_HEAD() is found, trying to read the section content directly...');
(0, print_1.debugPrint)('--- Start: parse line from section content-----------------');
// const sectionContent = '' + ctx.getText().trim()
const sectionContent = ctx.getText().trim();
(0, print_1.debugPrint)('Section content: ' + ctx.getText());
line = (0, extractSignificantYiniLine_1.extractYiniLine)(sectionContent);
// const contentLines = splitLines(sectionContent)
// if (isDebug()) {
// console.log('contentLines:')
// printObject(contentLines)
// }
// // contentLines.forEach((row: string) => {
// for (let row of contentLines) {
// debugPrint('---')
// debugPrint('row (a): >>>' + row + '<<<')
// row = stripNLAndAfter(row)
// debugPrint('row (b): >>>' + row + '<<<')
// row = stripCommentsAndAfter(row)
// debugPrint('row (c): >>>' + row + '<<<')
// row = row.trim()
// debugPrint('row (d): >>>' + row + '<<<')
// if (row) {
// debugPrint(
// 'Found some content in split row (non-comments).',
// )
// debugPrint('Split row: >>>' + row + '<<<')
// // Use this as input in line.
// line = row
// debugPrint('Will use row as line input')
// break
// }
// }
// debugPrint(
// '--- End: parse line from section content-----------------',
// )
// debugPrint()
}
(0, print_1.debugPrint)('S4, line: >>>' + line + '<<<');
if (!line) {
(0, print_1.debugPrint)('*** ERROR: Nothing to parse in section line');
}
this.prevLevel = this.level;
let { sectionName, sectionLevel } = (0, parseSectionHeader_1.default)(line, this.errorHandler, ctx);
this.level = sectionLevel;
this.meta_numOfSections++;
// ---------------------------------------------------------------
let nestDirection;
if (this.level === this.prevLevel) {
nestDirection = 'same';
}
else if (this.level < this.prevLevel) {
nestDirection = 'lower';
}
else {
nestDirection = 'higher';
}
(0, print_1.debugPrint)('-- In visitSection(..) ---------------------------');
(0, print_1.debugPrint)(' sectionName = ' + sectionName);
(0, print_1.debugPrint)(' sectionLevel = ' + sectionLevel);
(0, print_1.debugPrint)(' this.level = ' + this.level);
(0, print_1.debugPrint)(' this.prevLevel = ' + this.prevLevel);
(0, print_1.debugPrint)(' this.prevSectionName = ' + this.prevSectionName);
(0, print_1.debugPrint)(' nestDirection = ' + nestDirection);
(0, print_1.debugPrint)(' this.numOfLevelOnes = ' + this.numOfLevelOnes);
(0, print_1.debugPrint)('this.getDepthOfLevels() = ' + this.getDepthOfLevels());
(0, print_1.debugPrint)();
if (nestDirection === 'higher') {
(0, print_1.debugPrint)(`Is level skipping: ${this.level - this.prevLevel} >= 2?`);
// if (Math.abs(this.prevLevel - this.level) >= 2) {
if (this.level - this.prevLevel >= 2) {
if (this.level === 2) {
// Note, after pushing processing may continue or exit, depending on the error and/or the bail threshold.
this.errorHandler.pushOrBail(ctx, 'Syntax-Error', 'Invalid section header level ' +
this.level +
', with section name "' +
sectionName, 'A section header may not start directly at level ' +
this.level +
', skipping previous section levels. Please start with one level further down.');
}
else {
// Note, after pushing processing may continue or exit, depending on the error and/or the bail threshold.
this.errorHandler.pushOrBail(ctx, 'Syntax-Error', 'Invalid section level jump of section header "' +
sectionName +
'"', 'Section header name "' +
sectionName +
'" with level ' +
this.level +
' may not jump over (skip) intermediate section levels, from section header name "' +
this.prevSectionName +
'" with level ' +
this.prevLevel +
'. Section levels should increase one at a time. Please adjust your section headers accordingly.');
}
}
}
this.prevSectionName = sectionName;
(0, print_1.debugPrint)('About to visit members of section...');
let members;
if (!ctx.section_members()) {
(0, print_1.debugPrint)('(!) Section has no members!');
}
else {
members = this.visitSection_members(ctx.section_members());
}
// ---------------------------------------------------------------
(_c = ctx.children) === null || _c === void 0 ? void 0 : _c.forEach((child) => {
(0, print_1.debugPrint)('* child: ' + child);
});
if (this.level === 1) {
this.numOfLevelOnes++;
}
//------------------------
// if (nestDirection === 'higher') {
// debugPrint(
// `Is level skipping: ${this.level - this.prevLevel} >= 2?`,
// )
// // if (Math.abs(this.prevLevel - this.level) >= 2) {
// if (this.level - this.prevLevel >= 2) {
// // Note, after pushing processing may continue or exit, depending on the error and/or the bail threshold.
// this.errorHandler!.pushOrBail(
// ctx,
// 'Syntax-Error',
// 'Invalid section level jump of section header "' +
// sectionName +
// '"',
// 'Section header name "' +
// sectionName +
// '" with level ' +
// this.prevLevel +
// ' may not jump over previous section levels, from a section with level ' +
// this.level +
// ' (section name: "' +
// this.prevSectionName +
// '").',
// )
// }
// }
// this.prevSectionName = sectionName
if (nestDirection !== 'higher') {
(0, print_1.debugPrint)('About to reset result');
(0, print_1.printObject)({ [sectionName]: members });
(0, print_1.debugPrint)(`Current lastActiveSectionAtLevels[${this.level - 1}]`);
(0, print_1.printObject)(this.lastActiveSectionAtLevels[this.level - 1]);
if (
// (level === 0 && !sectionName) ||
// (sectionName === 'undefined' && !!members)
sectionLevel === 0 &&
sectionName === 'undefined' &&
!!members) {
(0, print_1.debugPrint)('HIT2!!!!');
(0, print_1.debugPrint)('(!) Detected a member (that does not have a sectionName), but a memberless object in "members"');
sectionName = Object.keys(members)[0];
(0, print_1.debugPrint)('sectionName = ' + sectionName);
members = {};
// this.lastActiveSectionAtLevels[0] = { [sectionName]: {} }
// this.pushOnTree({ level: 1, name: sectionName, members: {} })
(0, print_1.debugPrint)('(!) Skipping mounted since this is actually a memberless section');
(0, print_1.debugPrint)();
(0, print_1.debugPrint)('<- Leaving visitSection(..) EARLY');
if ((0, env_1.isDebug)()) {
console.log('returning (a memberless section):');
console.log({
level: 1,
name: sectionName,
members: members,
});
console.log();
}
return {
level: 1,
name: sectionName,
members: members,
};
}
else {
// Mount as append
this.lastActiveSectionAtLevels[this.level - 1] = {
[sectionName]: Object.assign({}, members),
};
this.pushOnTree(ctx, {
level: sectionLevel,
name: sectionName,
members,
});
// this.lastActiveSectionNameAtLevels.push(sectionName)
(0, print_1.debugPrint)('Mounted as append');
}
(0, print_1.debugPrint)(`After: lastActiveSectionAtLevels[${this.level - 1}]`);
(0, print_1.printObject)(this.lastActiveSectionAtLevels[this.level - 1]);
if ((0, env_1.isDebug)()) {
console.log(`After append lastActiveSectionAtLevels[${this.level - 1}]`);
(0, print_1.printObject)(this.lastActiveSectionAtLevels[this.level - 1]);
(0, print_1.debugPrint)('Before this.lastActiveSectionNameAtLevels:');
(0, print_1.printObject)(this.lastActiveSectionNameAtLevels);
// Reset.
let i = this.level;
while (this.lastActiveSectionNameAtLevels[i]) {
this.lastActiveSectionNameAtLevels[i++] = undefined;
}
(0, print_1.debugPrint)('After this.lastActiveSectionNameAtLevels:');
(0, print_1.printObject)(this.lastActiveSectionNameAtLevels);
}
(0, print_1.debugPrint)('HIT!!! - Just a lower or same level section, a continues full (nested) section,');
(0, print_1.debugPrint)(`Has above in lastActiveSectionAtLevels[${this.level - 1}]`);
(0, print_1.debugPrint)(' this.level: ' + this.level);
(0, print_1.debugPrint)('this.prevLevel: ' + this.prevLevel);
(0, print_1.debugPrint)(' this.level: ' + this.level);
(0, print_1.debugPrint)();
(0, print_1.debugPrint)(' HERE.... Should mount section to correct section at this.level: ' +
this.level);
//this.lastActiveSectionNameAtLevels[this.level - 1] = sectionName
(0, print_1.debugPrint)();
(0, print_1.debugPrint)('Resetted local result');
sectionName = '';
members = undefined;
}
//------------------------
(0, print_1.debugPrint)();
if ((0, env_1.isDebug)()) {
if (members) {
(0, print_1.printObject)({ [sectionName]: members });
this.lastActiveSectionAtLevels[this.level - 1] = Object.assign({}, members);
// this.lastActiveSectionNameAtLevels[this.level - 1] = sectionName
(0, print_1.debugPrint)('Mounted as assigned');
(0, print_1.debugPrint)(`lastActiveSectionAtLevels[${this.level - 1}]`);
(0, print_1.printObject)(this.lastActiveSectionAtLevels[this.level - 1]);
}
}
(0, print_1.debugPrint)('-----------------------');
if ((0, env_1.isDebug)()) {
console.log('At end of visitSection(..), this.lastActiveSectionNameAtLevels:');
(0, print_1.printObject)(this.lastActiveSectionNameAtLevels);
(0, print_1.debugPrint)(' this.level: ' + this.level);
(0, print_1.debugPrint)('this.prevLevel: ' + this.prevLevel);
(0, print_1.debugPrint)(' this.level: ' + this.level);
(0, print_1.debugPrint)('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
(0, print_1.debugPrint)('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
console.log();
}
(0, print_1.debugPrint)('<- Leaving visitSection(..)');
if ((0, env_1.isDebug)()) {
console.log('returning:');
console.log({
sectionLevel: sectionLevel,
name: sectionName,
members: members,
});
console.log();
}
return {
level: sectionLevel,
name: sectionName,
members: members,
};
};
/**
* Visit a parse tree produced by `YiniParser.bad_member`.
* @param ctx the parse tree
* @return the visitor result
*/
this.visitBad_member = (ctx) => {
ctx.REST;
this.errorHandler.pushOrBail(ctx, 'Syntax-Error', 'Invalid or malformed member found.', `Offending text: ${ctx.getText()}`);
};
/**
* Visit a parse tree produced by `YiniParser.section_members`.
* In here will mount object onto members object.
* @param ctx the parse tree
* @returns { key: value, ... }
*/
// visitSection_members = (ctx: Section_membersContext): Record<string, any> => {
// visitSection_members = (ctx: Section_membersContext): any => {
this.visitSection_members = (ctx) => {
(0, env_1.isDebug)() && console.log();
(0, print_1.debugPrint)('************************************************************');
(0, print_1.debugPrint)('-> Entered visitSection_members(..)');
const members = {};
(0, print_1.debugPrint)('Will loop through each member (or section head)...');
ctx.member_list().forEach((member) => {
const { type, key, value } = this.visitMember(member);
(0, print_1.debugPrint)('+++++++++++++++++++++++++++++++++++++++++++++++++++++');
(0, print_1.debugPrint)('* Item of member_list:');
if ((0, env_1.isDebug)()) {
console.log(value);
}
(0, print_1.debugPrint)(' type = >>>' + type + '<<<');
(0, print_1.debugPrint)(' key = >>>' + key + '<<<');
(0, print_1.debugPrint)('value = >>>' + value + '<<<');
(0, print_1.debugPrint)('value[key] = >>>' + (value === null || value === void 0 ? void 0 : value[key]) + '<<<');
(0, print_1.debugPrint)('--');
if (key === '') {
(0, print_1.debugPrint)('Skipping this member, due to key = ""');
}
else {
if (members[key] !== undefined) {
// Note, after pushing processing may continue or exit, depending on the error and/or the bail threshold.
this.errorHandler.pushOrBail(ctx, 'Syntax-Error', 'Key already exists in this section scope (in this main section), key name: ' +
key);
}
else {
this.meta_numOfMembers++;
// if ((value?.type as TDataType) === 'Null') {
if (type === 'Null') {
members[key] = null;
}
else {
(0, env_1.isDebug)() && console.log();
// NOTE: (!) Only if nested section.
(0, print_1.debugPrint)('About to mount a single member or section onto members...');
(0, env_1.isDebug)() && console.log({ [key]: value });
// if ((type as TDataType) === 'Object') {
// const isExistingSectionName =
// this.hasDefinedSectionTitle(key, this.level)
// debugPrint(' type = "' + type + '"')
// debugPrint('this.level = "' + this.level + '"')
// debugPrint(
// 'DDDDDDDD: sectionName / objectKey: ' + key,
// )
// debugPrint(
// 'Is already defined at this level? ' +
// isExistingSectionName,
// )
// if (!isExistingSectionName) {
// this.setDefineSectionTitle(key, this.level)
// }
// }
Object.assign(members, { [key]: value });
(0, print_1.debugPrint)('+ Added member or section onto members: "' +
key +
'"');
}
}
}
});
if ((0, env_1.isDebug)()) {
(0, print_1.debugPrint)('~~~ After mounting in visitSection_members(..) ~~~~~~~~~~');
(0, print_1.debugPrint)('this.resultSections:');
(0, print_1.debugPrint)('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
}
//@todo handle member colon list
// ctx..member_colon_list().forEach((mcl) => {
// const { key, value } = this.visit(mcl)
// members[key] = value
// })
(0, print_1.debugPrint)();
(0, print_1.debugPrint)('<- Leaving visitSection_members(..)');
if ((0, env_1.isDebug)()) {
console.log('returning:');
console.log(members);
console.log();
}
return members;
};
/**
* Visit every single section or member (any key-value pair such as
* key=value or key=[...] etc.).
* @returns {
type: resultType,
key: resultKey,
value: resultValue,
}: IResult
*/
// visitMember?: (ctx: MemberContext) => IResult;
this.visitMember = (ctx) => {
var _a, _b, _c, _d;
(0, env_1.isDebug)() && console.log();
(0, print_1.debugPrint)('-> Entered visitMember(..)');
(0, print_1.debugPrint)(' key = ' + ((_a = ctx.KEY()) === null || _a === void 0 ? void 0 : _a.getText().trim()));
(0, print_1.debugPrint)('Or, section head = ' +
((_b = ctx.SECTION_HEAD()) === null || _b === void 0 ? void 0 : _b.getText().trim()) +
' (head WITHOUT any members (ONLY detected here))');
(0, print_1.debugPrint)(' ctx.value() = ' + ctx.value());
// For logging and debugging purposes.
let entityType = 'Unknown';
let resultType = undefined;
let resultKey = '';
let resultValue = {};
let followingSection = null;
// NOTE: (!) It can never be both a key and section head.
if ((_c = ctx.KEY()) === null || _c === void 0 ? void 0 : _c.getText().trim()) {
entityType = 'Member-Key';
try {
resultKey = ctx.KEY().getText();
}
catch (error) {
(0, print_1.debugPrint)('in catch..');
const msg = `Unexpected syntax while parsing a member (key-value pair)`;
// Note, after pushing processing may continue or exit, depending on the error and/or the bail threshold.
this.errorHandler.pushOrBail(ctx, 'Syntax-Error', msg);
}
const result = ctx.value()
? this.visitValue(ctx.value())
: null;
resultType = result === null || result === void 0 ? void 0 : result.type;
resultValue = result === null || result === void 0 ? void 0 : result.value;
(0, print_1.debugPrint)(' type = ' + resultType + ' @visitValue(..)');
(0, print_1.debugPrint)('value = ' + resultValue + ' @visitValue(..)');
}
else if ((_d = ctx.SECTION_HEAD()) === null || _d === void 0 ? void 0 : _d.getText().trim()) {
entityType = 'Section-Head';
//NOTE: There might be an issue here that some subsection gets missing!!
// const line = '' + ctx.SECTION_HEAD().getText().trim()
const line = ctx.SECTION_HEAD().getText().trim();
(0, print_1.debugPrint)('(!) Detected a section head instead: ' + line);
followingSection = this.visitSection(ctx);
// Object.assign(members, sectionObj)
(0, print_1.debugPrint)('Got constructed object of builtSection (visitSection(..):');
if ((0, env_1.isDebug)()) {
console.log(followingSection);
}
//@todo (Is this fixed now? 2025-07-10) Mount the nested object correctly!
resultType = 'Object';
// resultValue[nestedSection?.name] = nestedSection?.members
resultValue = (followingSection === null || followingSection === void 0 ? void 0 : followingSection.members) || {};
resultKey = followingSection.name;
(0, print_1.debugPrint)("resultKey = '" + resultKey + "'");
(0, print_1.debugPrint)('resultValue:');
if ((0, env_1.isDebug)()) {
(0, print_1.printObject)(resultValue);
}
(0, print_1.debugPrint)('Mounted/assigned a section onto resultValue...');
// Object.assign(value, { dummy: 6767 })
// Object.assign(resultValue, {
// dummy: 'That was detected a section head instead!',
// })
(0, print_1.debugPrint)();
}
(0, print_1.debugPrint)();
(0, print_1.debugPrint)("entity = '" + entityType + "'");
(0, print_1.debugPrint)("resultType = '" + resultType + "'");
(0, print_1.debugPrint)("resultKey = '" + resultKey + "'");
if (resultKey) {
(0, print_1.debugPrint)();
(0, print_1.debugPrint)('Has a key... Validate it either as a simple or a backticked ident...');
if ((0, string_1.isEnclosedInBackticks)(resultKey)) {
if (!(0, yiniHelpers_1.isValidBacktickedIdent)(resultKey)) {
this.errorHandler.pushOrBail(ctx, 'Syntax-Error', 'Invalid key name of this member, backticked key/identifier: "' +
resultKey +
'"', 'Section name should be backticked like e.g. `My section name`.');
}
resultKey = (0, string_1.trimBackticks)(resultKey);
(0, print_1.debugPrint)("resultKey = '" + resultKey + "' (trimBackticks)");
}
else {
if (!(0, yiniHelpers_1.isValidSimpleIdent)(resultKey)) {
this.errorHandler.pushOrBail(ctx, 'Syntax-Error', 'Invalid key name of this member, key/identifier: "' +
resultKey +
'"', 'Section name must start with: A-Z, a-z, or _, unless enclosed in backticks e.g. `' +
resultKey +
'`, `My key name`.');
}
}
}
if (resultValue === undefined) {
(0, print_1.debugPrint)('Detected value as undefined');
if (!this.isStrict) {
(0, print_1.debugPrint)('Overloading undefined value with null');
resultValue = null;
}
else {
this.errorHandler.pushOrBail(ctx, 'Syntax-Error', 'Encountered an empty/missing value in strict mode', 'Expected a value but found nothing, strict mode does not allow implicit null.', 'If you intend to have a null value, please specify "null" explicitly as the value.');
}
}
(0, print_1.debugPrint)('*** Constructed JS object ***');
(0, print_1.debugPrint)('resultValue:');
if ((0, env_1.isDebug)()) {
console.log(resultValue);
}
(0, print_1.debugPrint)();
(0, print_1.debugPrint)('<- About to leave visitMember(..)');
if ((0, env_1.isDebug)()) {
console.log('returning:');
console.log({
type: resultType,
key: resultKey,
value: resultValue,
});
console.log();
}
if (!resultType && !resultKey) {
// Note, after pushing processing may continue or exit, depending on the error and/or the bail threshold.
this.errorHandler.pushOrBail(ctx, 'Syntax-Error', 'Unknown input');
}
// if (!isValidSimpleIdent(resultKey)) {
// if (resultType !== 'Object' && !isValidSimpleIdent(resultKey)) {
// this.errorHandler!.pushOrBail(
// ctx,
// 'Syntax-Error',
// 'Invalid name of this key of a member, key name: "' +
// resultKey +
// '"',
// 'Key name must start with: A-Z, a-z, or _, unless enclosed in backticks e.g. `' +
// resultKey +
// '`, `My key name`.',
// )
// }
(0, print_1.debugPrint)();
(0, print_1.debugPrint)('<- Leaving visitMember(..)');
if ((0, env_1.isDebug)()) {
console.log('returning:');
console.log({
type: resultType,
key: resultKey,
value: resultValue,
});
console.log();
}
return {
type: resultType,
key: resultKey,
value: resultValue,
};
};
/**
* Visit a parse tree produced by `YiniParser.member_colon_list`.
* @param ctx the parse tree
* @return the visitor result
*/
//visitMember_colon_list?: (ctx: Member_colon_listContext) => IResult
this.visitMember_colon_list = (ctx) => {
(0, env_1.isDebug)() && console.log();
(0, print_1.debugPrint)('-> Entered visitMember_colon_list(..)');
const key = ctx.KEY().getText();
const values = this.visit(ctx.elements());
return { key, value: values };
};
/**
* Visit a parse tree produced by `YiniParser.value`.
* @param ctx the parse tree
* @return the visitor result
*/
// visitValue?: (ctx: ValueContext) => IResult
this.visitValue = (ctx) => {
(0, env_1.isDebug)() && console.log();
(0, print_1.debugPrint)('-> Entered visitValue(..)');
if (ctx.string_literal())
return this.visit(ctx.string_literal());
if (ctx.number_literal())
return this.visit(ctx.number_literal());
if (ctx.boolean_literal())
return this.visit(ctx.boolean_literal());
if (ctx.null_literal())
return this.visit(ctx.null_literal());
if (ctx.object_literal())
return this.visit(ctx.object_literal());
if (ctx.list_in_brackets())
return this.visit(ctx.list_in_brackets());
// if (ctx.string_concat()) return this.visit(ctx.string_concat())
return null;
};
/**
* Visit a parse tree produced by `YiniParser.string_literal`.
* @param ctx the parse tree
* @return the visitor result
*/
// visitString_literal?: (ctx: String_literalContext) => Result
this.visitString_literal = (ctx) => {
(0, print_1.debugPrint)('-> Entered visitString_literal(..)');
const raw = ctx.getText();
(0, print_1.debugPrint)('raw = >>>' + raw + '<<<');
const value = (0, parseString_1.default)(raw);
return { type: 'String', value };
};
/**
* Visit a parse tree produced by `YiniParser.number_literal`.
* @param ctx the parse tree
* @return the visitor result
*/
// visitNumber_literal?: (ctx: Number_literalContext) => IResult
this.visitNumber_literal = (ctx) => {
(0, print_1.debugPrint)('-> Entered visitNumber_literal(..)');
const txt = ctx.getText();
const { type, value } = (0, parseNumber_1.default)(txt);
return { type, value };
};
/**
* Visit a parse tree produced by `YiniParser.boolean_literal`.
* @param ctx the parse tree
* @return the visitor result
*/
//visitBoolean_literal?: (ctx: Boolean_literalContext) => IResult
this.visitBoolean_literal = (ctx) => {
(0, print_1.debugPrint)('-> Entered visitBoolean_literal(..)');
const txt = ctx.getText().toLowerCase();
// return ['true', 'yes', 'on'].includes(text) as IResult
const value = (0, parseBoolean_1.default)(txt);
return { type: 'Boolean', value };
};
/**
* Visit a parse tree produced by `YiniParser.null_literal`.
* @param ctx the parse tree
* @return the visitor result
*/
this.visitNull_literal = (ctx) => {
(0, print_1.debugPrint)('-> Entered visitNull_literal(..)');
const txt = ctx.getText();
const value = (0, parseNull_1.default)(txt);
return { type: 'Null', value };
};
/**
* Visit a parse tree produced by `YiniParser.object_literal`.
* @param ctx the parse tree
* @return the visitor result
*/
// visitObject_literal?: (ctx: Object_literalContext) => IResult
this.visitObject_literal = (ctx) => {
const members = ctx.objectMemberList()
? this.visit(ctx.objectMemberList())
: {};
return { type: 'Object', value: members };
};
/**
* Visit a parse tree produced by `YiniParser.objectMemberList`.
* @param ctx the parse tree
* @return the visitor result
*/
//visitObjectMemberList?: (ctx: ObjectMemberListContext) => IResult
this.visitObjectMemberList = (ctx) => {
const obj = {};
ctx.objectMember_list().forEach((member) => {
const { key, value } = this.visit(member);
obj[key] = value;
});
return obj;
};
/**
* Visit a parse tree produced by `YiniParser.objectMember`.
* @param ctx the parse tree
* @return the visitor result
*/
// visitObjectMember?: (ctx: ObjectMemberContext) => IResult
this.visitObjectMember = (ctx) => {
const key = ctx.KEY().getText();
const value = ctx.value() ? this.visit(ctx.value()) : null;
return { key, value };
};
/**
* Visit a parse tree produced by `YiniParser.list`.
* @param ctx the parse tree
* @return the visitor result
*/
// visitList?: (ctx: ListContext) => IResult
this.visitList = (ctx) => this.visit(ctx.list_in_brackets());
/**
* Visit a parse tree produced by `YiniParser.list_in_brackets`.
* @param ctx the parse tree
* @return the visitor result
*/
// visitList_in_brackets?: (ctx: List_in_bracketsContext) => IResult
this.visitList_in_brackets = (ctx) => {
(0, print_1.debugPrint)('-> Entered visitList_in_brackets(..)');
let elements = [];
if (!ctx.elements()) {
(0, print_1.debugPrint)('Detected elements() is [], in list brackets');
// elements = []
return { type: 'List', value: [] };
}
else {
(0, print_1.debugPrint)('Detected elements() has items, in list brackets');
elements = this.visit(ctx.elements());
}
(0, print_1.debugPrint)('<- Leaving visitList_in_brackets(..)');
if ((0, env_1.isDebug)()) {
console.log('returning:');
console.log({ type: 'List', value: elements.value });
console.log();
}
return { type: 'List', value: elements.value };
};
/**
* Visit a parse tree produced by `YiniParser.elements`.
* @param ctx the parse tree
* @return the visitor result
*/
this.visitElements = (ctx) => {
(0, print_1.debugPrint)('-> Entered visitElements(..)');
const firstElem = ctx.element();
let elements = [];
(0, print_1.debugPrint)(' element = ' + firstElem);
(0, print_1.debugPrint)(' element.getText() = ' + firstElem.getText());
(0, print_1.debugPrint)(' elements = ' + !!ctx.elements());
const resultElem = ctx.element()
? this.visitElement(ctx.element())
: null;
const resultTypeElem = resultElem === null || resultElem === void 0 ? void 0 : resultElem.type;
const resultValueElem = resultElem === null || resultElem === void 0 ? void 0 : resultElem.value;
(0, print_1.debugPrint)(' elem type = ' + resultTypeElem + ' @visitElements(..)');
(0, print_1.debugPrint)(' elem value = ' + resultValueElem + ' @visitElements(..)');
const resultElems = ctx.elements()
? this.visitElements(ctx.elements())
: null;
const resultTypeElems = resultElems === null || resultElems === void 0 ? void 0 : resultElems.type;
const resultValueElems = resultElems === null || resultElems === void 0 ? void 0 : resultElems.value;
(0, print_1.debugPrint)(' elems type = ' +
resultTypeElems +
' @visitElements(..)');
(0, print_1.debugPrint)(' elems value = ' +
resultValueElems +
' @visitElements(..)');
if (!ctx.elements()) {
(0, print_1.debugPrint)('In visitElements(.