yini-parser 1.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +0 -0
  2. package/LICENSE +201 -0
  3. package/README.md +120 -0
  4. package/dist/src/YINI.js +122 -0
  5. package/dist/src/config/env.js +15 -0
  6. package/dist/src/core/ErrorDataHandler.js +207 -0
  7. package/dist/src/core/YINIVisitor.js +856 -0
  8. package/dist/src/core/objectBuilder.js +166 -0
  9. package/dist/src/core/types.js +36 -0
  10. package/dist/src/grammar/YiniLexer.js +370 -0
  11. package/dist/src/grammar/YiniParser.js +2106 -0
  12. package/dist/src/grammar/YiniParserVisitor.js +14 -0
  13. package/dist/src/index.js +189 -0
  14. package/dist/src/parseEntry.js +155 -0
  15. package/dist/src/parsers/extractHeaderParts.js +103 -0
  16. package/dist/src/parsers/extractSignificantYiniLine.js +68 -0
  17. package/dist/src/parsers/parseBoolean.js +12 -0
  18. package/dist/src/parsers/parseNull.js +11 -0
  19. package/dist/src/parsers/parseNumber.js +49 -0
  20. package/dist/src/parsers/parseSectionHeader.js +111 -0
  21. package/dist/src/parsers/parseString.js +40 -0
  22. package/dist/src/utils/pathAndFileName.js +15 -0
  23. package/dist/src/utils/string.js +97 -0
  24. package/dist/src/utils/system.js +23 -0
  25. package/dist/src/yiniHelpers.js +141 -0
  26. package/dist/tests/integration/1-core-parsing/parse-bigger-section-nesting-as-object.test.js +83 -0
  27. package/dist/tests/integration/1-core-parsing/parse-section-nesting-w-classic-markers.test.js +170 -0
  28. package/dist/tests/integration/1-core-parsing/parse-section-nesting-w-nsh-markers.test.js +27 -0
  29. package/dist/tests/integration/1-core-parsing/read some values from level 1 and 2.test.js +77 -0
  30. package/dist/tests/integration/1-core-parsing/throw on bad section heads.test.js +162 -0
  31. package/dist/tests/integration/10-special-validation-modes/validation-modes.test.js +38 -0
  32. package/dist/tests/integration/2-file-structure-and-error/able to parse mixed case filenames.test.js +72 -0
  33. package/dist/tests/integration/2-file-structure-and-error/throw error on bad file extensions.test.js +36 -0
  34. package/dist/tests/integration/2-file-structure-and-error/throw error parsing bad content.test.js +80 -0
  35. package/dist/tests/smoke/A-general-smoke.test.js +259 -0
  36. package/dist/tests/smoke/B-parse-inline-smoke.test.js +270 -0
  37. package/dist/tests/smoke/C-traverse-file-smoke.test.js +141 -0
  38. package/dist/tests/smoke/D-parse-file-smoke.test.js +134 -0
  39. package/dist/tests/unit/parsers/extractHeaderParts.unit.test.js +490 -0
  40. package/dist/tests/unit/parsers/parseSectionHeader-classic.unit.test.js +421 -0
  41. package/dist/tests/unit/parsers/parseSectionHeader-nsh.unit.test.js +436 -0
  42. package/dist/tests/unit/parsers/parseSectionHeader-throw-on-invalid.unit.test.js +168 -0
  43. package/dist/tests/unit/utils/utils-pathAndFileName.unit.test.js +80 -0
  44. package/dist/tests/unit/utils/utils-string.unit.test.js +185 -0
  45. package/dist/tests/unit/yiniHelpers.unit.test.js +306 -0
  46. package/package.json +94 -0
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ // Generated from grammar/v1.0.0-beta.7x/YiniParser.g4 by ANTLR 4.13.2
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const antlr4_1 = require("antlr4");
5
+ /**
6
+ * This interface defines a complete generic visitor for a parse tree produced
7
+ * by `YiniParser`.
8
+ *
9
+ * @param <Result> The return type of the visit operation. Use `void` for
10
+ * operations with no return type.
11
+ */
12
+ class YiniParserVisitor extends antlr4_1.ParseTreeVisitor {
13
+ }
14
+ exports.default = YiniParserVisitor;
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ // import { isDebug&&console.log } from './utils/general'
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ var _a, _b, _c;
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.default = void 0;
9
+ /*
10
+ https://pauloe-me.medium.com/typescript-npm-package-publishing-a-beginners-guide-40b95908e69c
11
+
12
+ Run the code with the following command:
13
+ npx ts-node index
14
+ or
15
+ npm start
16
+
17
+ /END
18
+ */
19
+ const env_1 = require("./config/env");
20
+ const system_1 = require("./utils/system");
21
+ const YINI_1 = __importDefault(require("./YINI"));
22
+ var YINI_2 = require("./YINI");
23
+ Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(YINI_2).default; } });
24
+ if ((0, env_1.isDev)() || (0, env_1.isDebug)()) {
25
+ console.log('process.env?.NODE_ENV = ' + ((_a = process.env) === null || _a === void 0 ? void 0 : _a.NODE_ENV));
26
+ console.log('process.env?.APP_ENV = ' + ((_b = process.env) === null || _b === void 0 ? void 0 : _b.APP_ENV));
27
+ console.log('process.env?.IS_DEBUG = ' + ((_c = process.env) === null || _c === void 0 ? void 0 : _c.IS_DEBUG));
28
+ }
29
+ // console.log('NODE_ENV = ' + NODE_ENV)
30
+ // console.log('APP_ENV = ' + APP_ENV)
31
+ (0, system_1.debugPrint)();
32
+ (0, system_1.debugPrint)('-> Entered index.ts');
33
+ (0, system_1.debugPrint)();
34
+ const debugTestObj = {
35
+ name: 'e_test',
36
+ lang: 'TypeScript',
37
+ };
38
+ (0, system_1.debugPrint)('debugTestObj:');
39
+ (0, system_1.debugPrint)(debugTestObj);
40
+ (0, system_1.debugPrint)();
41
+ if ((0, env_1.isProd)()) {
42
+ // Do nothing, and exit.
43
+ }
44
+ else {
45
+ const invalidInput1 = `
46
+ ^ Settings
47
+ fruit = "Pear"
48
+ number = 5
49
+ value q= "something"
50
+ `;
51
+ const invalidInput2 = `
52
+ ^ Config
53
+ varAge = 30
54
+ varName = abcd
55
+ varNull = NULL
56
+ `;
57
+ const input1 = `
58
+ ^ SectionName
59
+ varBool = true
60
+ varBool2 = off
61
+ varInt = 30
62
+ varFloat = 12.34
63
+ varStr = "Alice"
64
+ listItems = ["a", "b", "c"]
65
+ varE1 = 1e4
66
+ varE2 = 1.23e4
67
+ varE3 = 6.5E23
68
+ /END
69
+ `;
70
+ const input2 = `
71
+ ^ Config
72
+ varAge = 30
73
+ varName = "Alice"
74
+ varNull = NULL
75
+ listItems = ["a", "b", "c"]
76
+ ^^Extra
77
+ isExtra = true
78
+ /END
79
+ `;
80
+ // const input = `
81
+ // # Config`;
82
+ // debugPrint('input2:')
83
+ // if (isDebug()) {
84
+ // console.debug(input2)
85
+ // }
86
+ // YINI.parse(input2)
87
+ // debugPrint('invalidInput1:')
88
+ // if (isDebug()) {
89
+ // console.debug(invalidInput1)
90
+ // }
91
+ // YINI.parse(invalidInput1)
92
+ if (env_1.APP_ENV === 'local' && env_1.NODE_ENV !== 'test') {
93
+ /*
94
+ YINI.parse(`
95
+ --^ Section0
96
+ --value = 0
97
+ ^ Section1
98
+ value = 1
99
+
100
+ ^^ Section11
101
+ value = 11
102
+
103
+ ^^^ Section111
104
+ value = 111
105
+ //^^^^ Section2104
106
+ value = 24
107
+
108
+ ^ Section2
109
+ value = 2
110
+ `)
111
+ }
112
+ */
113
+ // YINI.parse(`number = 42`)
114
+ /*
115
+ Expected JS output:
116
+ {
117
+ Section1: { value: 1, Section2: { value: 11 }},
118
+ Section2: { value: 2 }
119
+ }
120
+
121
+ */
122
+ /*
123
+ YINI.parse(
124
+ `
125
+ // Using numeric shorthand section markers.
126
+
127
+ @yini
128
+
129
+ // This whole line is a comment.
130
+ ^SectionName# This part is a comment.
131
+ // This whole line is a comment.
132
+ --x=1
133
+ `,
134
+ false,
135
+ 2,
136
+ )
137
+ */
138
+ // YINI.parse(`^1 SectionName`, false, 2)
139
+ // const validYini = `
140
+ // ~ user
141
+ // username = 'tester two'
142
+ // isSysOp = YES
143
+ // ~~ prefs
144
+ // theme = "light"
145
+ // notifications = OFF
146
+ // ^1 user2
147
+ // ^2 prefs
148
+ // ^3 deepSection
149
+ // ^4 deeperSection
150
+ // key = "Level 4 section"
151
+ // ^5 yetDeeperSection
152
+ // key = "Level 5 section"
153
+ // item = 77
154
+ // ~1 user3
155
+ // username = 'tester three'
156
+ // isSysOp = NO
157
+ // ~~2 prefs
158
+ // theme = "special-dark"
159
+ // notifications = ON
160
+ // `
161
+ // // Act.
162
+ // const result = YINI.parse(validYini)
163
+ // debugPrint(result)
164
+ // const validYini = `^ App
165
+ // id = 32403 # The correct app id.
166
+ // title = "My Program"
167
+ // `
168
+ const validYini = `
169
+ ~1 user3
170
+ username = 'tester three'
171
+ isSysOp = NO
172
+
173
+ ~~2 prefs // NOT OK, bad section marker, cannot mix marker types.
174
+ theme = "special-dark"
175
+ notifications = ON
176
+ `;
177
+ YINI_1.default.parse(validYini, false, 'auto', true);
178
+ // YINI.parse(`
179
+ // ^ Section1
180
+ // ^^ Section2
181
+ // ^^^ Section3
182
+ // ^^^^ Section4 // Level 4.
183
+ // ^^^^^ Section5
184
+ // ^^^^^^ Section6
185
+ // ^^^^^^^ Section7
186
+ // strVar = "These section header are valid!"
187
+ // `)
188
+ }
189
+ }
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.parseMain = void 0;
7
+ const antlr4_1 = require("antlr4");
8
+ const env_1 = require("./config/env");
9
+ const ErrorDataHandler_1 = require("./core/ErrorDataHandler");
10
+ const objectBuilder_1 = require("./core/objectBuilder");
11
+ const YINIVisitor_1 = __importDefault(require("./core/YINIVisitor"));
12
+ const YiniLexer_1 = __importDefault(require("./grammar/YiniLexer"));
13
+ const YiniParser_1 = __importDefault(require("./grammar/YiniParser"));
14
+ const system_1 = require("./utils/system");
15
+ class MyErrorListener {
16
+ constructor(errorHandler) {
17
+ this.errors = [];
18
+ this.errorHandler = errorHandler;
19
+ }
20
+ syntaxError(recognizer, offendingSymbol, line, charPositionInLine, msg, e) {
21
+ (0, system_1.debugPrint)('ANTLR grammar cached an error');
22
+ this.errors.push(`Line ${line}:${charPositionInLine} ${msg}`);
23
+ const msgWhat = `Syntax error, at line: ${line}`;
24
+ const msgWhy = `At about column ${1 + charPositionInLine} ${msg}`;
25
+ this.errorHandler.pushOrBail(null, 'Syntax-Error', msgWhat, msgWhy);
26
+ }
27
+ // The following are required for the interface, but can be left empty.
28
+ reportAmbiguity(...args) { }
29
+ reportAttemptingFullContext(...args) { }
30
+ reportContextSensitivity(...args) { }
31
+ }
32
+ const parseMain = (yiniContent, options = {
33
+ isStrict: false,
34
+ bailSensitivityLevel: 0,
35
+ isIncludeMeta: false,
36
+ isWithDiagnostics: false,
37
+ isWithTiming: false,
38
+ }) => {
39
+ (0, system_1.debugPrint)();
40
+ (0, system_1.debugPrint)('-> Entered parseMain(..) in parseEntry');
41
+ (0, system_1.debugPrint)(' isStrict mode = ' + options.isStrict);
42
+ (0, system_1.debugPrint)('bailSensitivityLevel = ' + options.bailSensitivityLevel);
43
+ let persistThreshold;
44
+ switch (options.bailSensitivityLevel) {
45
+ case 0:
46
+ persistThreshold = '0-Ignore-Errors';
47
+ break;
48
+ case 1:
49
+ persistThreshold = '1-Abort-on-Errors';
50
+ break;
51
+ default:
52
+ persistThreshold = '2-Abort-Even-on-Warnings';
53
+ }
54
+ (0, env_1.isDebug)() && console.log();
55
+ (0, system_1.debugPrint)('=== Phase 1 ===================================================');
56
+ const inputStream = antlr4_1.CharStreams.fromString(yiniContent);
57
+ const lexer = new YiniLexer_1.default(inputStream);
58
+ const tokenStream = new antlr4_1.CommonTokenStream(lexer);
59
+ const parser = new YiniParser_1.default(tokenStream);
60
+ const errorHandler = new ErrorDataHandler_1.ErrorDataHandler(persistThreshold);
61
+ const errorListener = new MyErrorListener(errorHandler);
62
+ parser.removeErrorListeners(); // Removes the default console error output.
63
+ parser.addErrorListener(errorListener);
64
+ (0, system_1.debugPrint)();
65
+ (0, system_1.debugPrint)('--- Starting parsing... ---');
66
+ const parseTree = parser.yini(); // The function yini() is the start rule.
67
+ if (errorListener.errors.length > 0) {
68
+ (0, system_1.debugPrint)('*** ERROR detected ***');
69
+ if ((0, env_1.isDebug)()) {
70
+ // Handle or display syntax errors
71
+ console.error('Syntax errors detected:', errorListener.errors);
72
+ //process.exit(1)
73
+ }
74
+ }
75
+ (0, system_1.debugPrint)('--- Parsing done. ---');
76
+ (0, system_1.debugPrint)('=== Ended phase 1 =============================================');
77
+ (0, env_1.isDebug)() && console.log();
78
+ (0, system_1.debugPrint)('=== Phase 2 ===================================================');
79
+ // const errorHandler = new ErrorDataHandler(persistThreshold)
80
+ const visitor = new YINIVisitor_1.default(errorHandler, options.isStrict);
81
+ const syntaxTreeC = visitor.visit(parseTree);
82
+ if ((0, env_1.isDebug)()) {
83
+ console.log();
84
+ console.log('**************************************************************************');
85
+ console.log('*** syntaxTreeContainer: *************************************************');
86
+ (0, system_1.printObject)(syntaxTreeC);
87
+ console.log('**************************************************************************');
88
+ console.log('**************************************************************************');
89
+ console.log();
90
+ }
91
+ (0, system_1.debugPrint)('=== Ended phase 2 =============================================');
92
+ (0, env_1.isDebug)() && console.log();
93
+ (0, system_1.debugPrint)('=== Phase 3 ===================================================');
94
+ // Construct.
95
+ const finalJSResult = (0, objectBuilder_1.constructFinalObject)(syntaxTreeC, errorHandler);
96
+ (0, system_1.debugPrint)('=== Ended phase 3 =============================================');
97
+ (0, system_1.debugPrint)('visitor.visit(..): finalJSResult:');
98
+ (0, env_1.isDebug)() && console.debug(finalJSResult);
99
+ (0, system_1.debugPrint)();
100
+ if (options.isStrict) {
101
+ //throw Error('ERROR: Strict-mode not yet implemented')
102
+ errorHandler.pushOrBail(null, 'Syntax-Warning', 'WARNING: Strict-mode not yet fully implemented', '', '');
103
+ }
104
+ else {
105
+ (0, system_1.debugPrint)('visitor.visit(..): finalJSResult:');
106
+ (0, env_1.isDebug)() && console.debug(finalJSResult);
107
+ }
108
+ // Construct meta data.
109
+ const metaData = {
110
+ strictMode: options.isStrict,
111
+ hasTerminal: syntaxTreeC._hasTerminal,
112
+ sections: syntaxTreeC._meta_numOfSections,
113
+ members: syntaxTreeC._meta_numOfMembers,
114
+ sectionChains: syntaxTreeC._meta_numOfChains,
115
+ keysParsed: null,
116
+ timing: {
117
+ totalMs: null,
118
+ phase1Ms: null,
119
+ phase2Ms: null,
120
+ phase3Ms: null,
121
+ },
122
+ };
123
+ if (options.isWithDiagnostics) {
124
+ // Attach optional diagnostics.
125
+ metaData.diagnostics = {
126
+ bailSensitivityLevel: options.bailSensitivityLevel,
127
+ errors: errorHandler.getNumOfErrors(),
128
+ warnings: errorHandler.getNumOfWarnings(),
129
+ infoAndNotices: errorHandler.getNumOfInfoAndNotices(),
130
+ };
131
+ }
132
+ if (options.isWithTiming) {
133
+ // Attach optional timing data.
134
+ metaData.timing = {
135
+ totalMs: null,
136
+ phase1Ms: null,
137
+ phase2Ms: null,
138
+ phase3Ms: null,
139
+ };
140
+ }
141
+ (0, system_1.debugPrint)('getNumOfErrors(): ' + errorHandler.getNumOfErrors());
142
+ if (errorHandler.getNumOfErrors()) {
143
+ console.log();
144
+ console.log('Parsing is complete, but some problems were detected. Please see the errors above for details.');
145
+ console.log('Number of errors found: ' + errorHandler.getNumOfErrors());
146
+ }
147
+ if (options.isIncludeMeta) {
148
+ return {
149
+ result: finalJSResult,
150
+ meta: metaData,
151
+ };
152
+ }
153
+ return finalJSResult;
154
+ };
155
+ exports.parseMain = parseMain;
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const system_1 = require("../utils/system");
4
+ const yiniHelpers_1 = require("../yiniHelpers");
5
+ const extractSignificantYiniLine_1 = require("./extractSignificantYiniLine");
6
+ /**
7
+ * Check and identify the section header parts via tokenizing the parts and return them as strings.
8
+ * @param rawHeaderLine Raw line with the section header where the header
9
+ * marker will be identified. E.g. does the header start with '^^^' or '^3'
10
+ * and then some identifier.
11
+ *
12
+ * Below, copied from YINI Specification v1.0.0 Beta 7.
13
+ * Form 1: Identifier of Simple Form:
14
+ * - Keys must be non-empty.
15
+ * - Keys are case-sensitive (`Title` and `title` are different).
16
+ * - Can only contain letters (a-z or A-Z), digits (0-9) and underscores `_`.
17
+ * - Must begin with a letter or an underscore `_`.
18
+ * - Note: Cannot contain hyphens (`-`) or periods (`.`).
19
+ *
20
+ * Form 2: Backticked Identifier:
21
+ * - A phrase is a name wrapped in backticks ``` ` ```.
22
+ * - Backticked identifiers must be on a single line and must not contain tabs or new lines unless using escaping codes, except for ordinary spaces.
23
+ * - Special control characters (U+0000–U+001F) must be escaped.
24
+ *
25
+ * @note Returns the parts as strings; each part needs to be analyzed separately against the contraints in the specifications.
26
+ * @returns An object with the identified header parts: marker characters, parsed name, and parsed level string.
27
+ */
28
+ const extractHeaderParts = (rawLine, errorHandler = null, ctx = null) => {
29
+ (0, system_1.debugPrint)('-> Entered extractHeaderParts(..)');
30
+ rawLine = rawLine.trim();
31
+ const str = (0, extractSignificantYiniLine_1.extractYiniLine)(rawLine);
32
+ (0, system_1.debugPrint)('rawLine: >>>' + rawLine + '<<<');
33
+ (0, system_1.debugPrint)(' str: >>>' + str + '<<<');
34
+ // Edge case: empty line.
35
+ if (!str) {
36
+ errorHandler.pushOrBail(ctx, 'Internal-Error', 'Received blank argument in extractHeaderParts(..)', 'Sorry, an unintended internal error happened.');
37
+ }
38
+ let pos = 0;
39
+ const len = str.length;
40
+ let markerCharsPart = '';
41
+ let numberPart = '';
42
+ let sectionNamePart = '';
43
+ let isBacktickedName = false;
44
+ // 1. Skip leading whitespace.
45
+ while (pos < len && (str[pos] === ' ' || str[pos] === '\t'))
46
+ pos++;
47
+ // 2. Collect marker(s): ^, ~, §, €.
48
+ while (pos < len && (0, yiniHelpers_1.isMarkerCharacter)(str[pos])) {
49
+ markerCharsPart += str[pos];
50
+ pos++;
51
+ }
52
+ // 3. Numeric part (for numeric shorthand; only if single marker found).
53
+ if (markerCharsPart.length === 1 &&
54
+ pos < len &&
55
+ str[pos] >= '1' &&
56
+ str[pos] <= '9') {
57
+ // Start collecting number part.
58
+ while (pos < len && str[pos] >= '0' && str[pos] <= '9') {
59
+ numberPart += str[pos];
60
+ pos++;
61
+ }
62
+ markerCharsPart += numberPart; // E.g., "^7".
63
+ }
64
+ // 4. Skip whitespace between marker and section name.
65
+ while (pos < len && (str[pos] === ' ' || str[pos] === '\t'))
66
+ pos++;
67
+ // 5. Collect section name (identifier or backticked).
68
+ if (pos < len && str[pos] === '`') {
69
+ // Backticked identifier.
70
+ let start = pos;
71
+ pos++; // Skip initial backtick.
72
+ while (pos < len && str[pos] !== '`')
73
+ pos++;
74
+ pos++; // Include the closing backtick (if found).
75
+ sectionNamePart = str.slice(start, pos).trim();
76
+ isBacktickedName = true;
77
+ }
78
+ else {
79
+ // Non-backticked: take the rest of the line, trim off any trailing comments, etc.
80
+ sectionNamePart = str.slice(pos).trim();
81
+ // Optionally, strip trailing comments or newlines here if needed.
82
+ }
83
+ if (isBacktickedName) {
84
+ (0, system_1.debugPrint)('Backticed sectionNamePart: ' + sectionNamePart);
85
+ // sectionNamePart = trimBackticks(sectionNamePart)
86
+ }
87
+ (0, system_1.debugPrint)();
88
+ (0, system_1.debugPrint)('------');
89
+ (0, system_1.debugPrint)('<- About to leave extractHeaderParts(..)');
90
+ (0, system_1.debugPrint)();
91
+ (0, system_1.debugPrint)(' markerCharsPart: >>>' + markerCharsPart + '<<<');
92
+ (0, system_1.debugPrint)(' sectionNamePart: >>>' + sectionNamePart + '<<<');
93
+ (0, system_1.debugPrint)(' numberPart: >>>' + numberPart + '<<<');
94
+ (0, system_1.debugPrint)(' isBacktickedName: ' + isBacktickedName);
95
+ (0, system_1.debugPrint)();
96
+ return {
97
+ strMarkerChars: markerCharsPart,
98
+ strSectionName: sectionNamePart,
99
+ strNumberPart: numberPart,
100
+ isBacktickedName,
101
+ };
102
+ };
103
+ exports.default = extractHeaderParts;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractYiniLine = void 0;
4
+ const env_1 = require("../config/env");
5
+ const string_1 = require("../utils/string");
6
+ const system_1 = require("../utils/system");
7
+ const yiniHelpers_1 = require("../yiniHelpers");
8
+ /**
9
+ * Extract significant YINI line from YINI content (that may be surrounded by comments.).
10
+ * @param rawYiniContent For example:
11
+ * // This whole line is a comment.
12
+ * ^SectionName# This part is a comment.
13
+ * // This whole line is a comment.
14
+ * @returns Will filter out any comments (before or after) and return only one single significant YINI line.
15
+ */
16
+ const extractYiniLine = (rawYiniContent) => {
17
+ (0, system_1.debugPrint)('-> Entered extractSignificantYiniCode(..)');
18
+ const significantLines = [];
19
+ let resultLine = '';
20
+ (0, system_1.debugPrint)('rawYiniContent: >>>' + rawYiniContent + '<<<');
21
+ const contentLines = (0, string_1.splitLines)(rawYiniContent);
22
+ if ((0, env_1.isDebug)()) {
23
+ console.log(`contentLines: (len: ${contentLines.length})`);
24
+ (0, system_1.printObject)(contentLines);
25
+ }
26
+ // contentLines.forEach((row: string) => {
27
+ for (const line of contentLines) {
28
+ let row = line;
29
+ (0, system_1.debugPrint)('---');
30
+ // debugPrint('row (a): >>>' + row + '<<<')
31
+ // row = stripNLAndAfter(row)
32
+ (0, system_1.debugPrint)('row (b): >>>' + row + '<<<');
33
+ row = (0, yiniHelpers_1.stripCommentsAndAfter)(row);
34
+ (0, system_1.debugPrint)('row (c): >>>' + row + '<<<');
35
+ row = row.trim();
36
+ (0, system_1.debugPrint)('row (d): >>>' + row + '<<<');
37
+ if (row) {
38
+ (0, system_1.debugPrint)('Found some content in split row (non-comments).');
39
+ (0, system_1.debugPrint)('Split row: >>>' + row + '<<<');
40
+ // Use this as input in line.
41
+ // line = row
42
+ significantLines.push(row);
43
+ // break
44
+ }
45
+ }
46
+ (0, system_1.debugPrint)('--- End: parse line from section content-----------------');
47
+ (0, system_1.debugPrint)();
48
+ switch (significantLines.length) {
49
+ case 0:
50
+ resultLine = '';
51
+ break;
52
+ case 1:
53
+ (0, system_1.debugPrint)('Did only find one significant lines in rawYiniContent, OK');
54
+ resultLine = significantLines[0];
55
+ break;
56
+ default:
57
+ (0, system_1.debugPrint)('(!) Did find several significant lines in rawYiniContent! - Maybe internal error...');
58
+ // throw new Error(
59
+ // 'Internal error: Detected several row lines in rawYiniContent: >>>' +
60
+ // rawYiniContent +
61
+ // '<<<',
62
+ // )
63
+ }
64
+ (0, system_1.debugPrint)('<- About to leave extractSignificantYiniCode(..):');
65
+ (0, system_1.debugPrint)('resultLine: >>>' + resultLine + '<<<');
66
+ return resultLine;
67
+ };
68
+ exports.extractYiniLine = extractYiniLine;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const system_1 = require("../utils/system");
4
+ /**
5
+ * Extract boolean literal.
6
+ */
7
+ const parseBooleanLiteral = (txt) => {
8
+ (0, system_1.debugPrint)('-> Entered parseBooleanLiteral(..)');
9
+ const value = !!(txt === 'true' || txt === 'yes' || txt === 'on');
10
+ return value;
11
+ };
12
+ exports.default = parseBooleanLiteral;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const system_1 = require("../utils/system");
4
+ const parseNullLiteral = (txt) => {
5
+ (0, system_1.debugPrint)('-> Entered parseNullLiteral(..)');
6
+ if (txt.toLowerCase() !== 'null') {
7
+ throw Error('Syntax Error: Unexpected token or character; expected `Null` literal (case-insensitive)');
8
+ }
9
+ return null;
10
+ };
11
+ exports.default = parseNullLiteral;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const system_1 = require("../utils/system");
4
+ const parseNumberLiteral = (txt) => {
5
+ (0, system_1.debugPrint)('-> Entered parseNumberLiteral(..), txt: ' + txt);
6
+ if (/^0[xX]|#/.test(txt)) {
7
+ // Prefix: 0x, 0X, #
8
+ (0, system_1.debugPrint)('* Identified as a hex number');
9
+ return {
10
+ type: 'Number-Integer',
11
+ // value: parseInt(txt.replace('#', '0x'), 16),
12
+ value: parseInt(txt.replace(/^0[xX]|#/, ''), 16),
13
+ };
14
+ }
15
+ if (/^0[bB]|%/.test(txt)) {
16
+ // Prefix: 0b, 0B, %
17
+ (0, system_1.debugPrint)('* Identified as a bin number');
18
+ return {
19
+ type: 'Number-Integer',
20
+ value: parseInt(txt.replace(/^0[bB]|%/, ''), 2),
21
+ };
22
+ }
23
+ if (/^0[oO]/.test(txt)) {
24
+ // Prefix: 0o, 0O
25
+ (0, system_1.debugPrint)('* Identified as a ord number');
26
+ return {
27
+ type: 'Number-Integer',
28
+ value: parseInt(txt.replace(/^0[oO]/, ''), 8),
29
+ };
30
+ }
31
+ if (/^0[zZ]/.test(txt)) {
32
+ // Prefix: 0z, 0Z
33
+ (0, system_1.debugPrint)('* Identified as a duodecimal number');
34
+ return {
35
+ type: 'Number-Integer',
36
+ value: parseInt(txt.replace(/^0[zZ]/, ''), 12),
37
+ };
38
+ }
39
+ // In a regex literal the dot must be escaped (\.) to match a literal '.'
40
+ if (/\./.test(txt)) {
41
+ (0, system_1.debugPrint)('* Identified as a float number');
42
+ return { type: 'Number-Float', value: parseFloat(txt) };
43
+ }
44
+ // TODO: Depending, on mode, below continue or break on error
45
+ //console.error('Error: Failed to parse number value: ' + txt)
46
+ (0, system_1.debugPrint)('* Identified as a int number');
47
+ return { type: 'Number-Integer', value: parseInt(txt) };
48
+ };
49
+ exports.default = parseNumberLiteral;