yini-parser 1.5.0 → 1.6.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 (90) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/LICENSE +1 -1
  3. package/README.md +199 -37
  4. package/dist/YINI.d.ts +22 -7
  5. package/dist/YINI.js +104 -0
  6. package/dist/core/astBuilder.d.ts +94 -15
  7. package/dist/core/astBuilder.js +396 -364
  8. package/dist/core/errorDataHandler.d.ts +29 -1
  9. package/dist/core/errorDataHandler.js +120 -63
  10. package/dist/core/internalTypes.d.ts +10 -1
  11. package/dist/core/objectBuilder.js +21 -6
  12. package/dist/core/options/defaultParserOptions.d.ts +3 -2
  13. package/dist/core/options/defaultParserOptions.js +2 -1
  14. package/dist/core/options/optionsFunctions.js +5 -1
  15. package/dist/core/pipeline/pipeline.js +31 -12
  16. package/dist/core/runtime.js +29 -34
  17. package/dist/grammar/generated/YiniLexer.d.ts +28 -35
  18. package/dist/grammar/generated/YiniLexer.js +323 -310
  19. package/dist/grammar/generated/YiniParser.d.ts +158 -80
  20. package/dist/grammar/generated/YiniParser.js +1141 -620
  21. package/dist/grammar/generated/YiniParserVisitor.d.ts +77 -14
  22. package/dist/grammar/generated/YiniParserVisitor.js +1 -1
  23. package/dist/index.d.ts +4 -1
  24. package/dist/index.js +6 -3
  25. package/dist/parsers/extractHeaderParts.d.ts +12 -19
  26. package/dist/parsers/extractHeaderParts.js +57 -46
  27. package/dist/parsers/parseNumber.d.ts +24 -6
  28. package/dist/parsers/parseNumber.js +114 -49
  29. package/dist/parsers/parseSectionHeader.d.ts +11 -3
  30. package/dist/parsers/parseSectionHeader.js +55 -43
  31. package/dist/parsers/parseString.js +42 -21
  32. package/dist/parsers/validateShebangPlacement.d.ts +4 -0
  33. package/dist/parsers/validateShebangPlacement.js +115 -0
  34. package/dist/types/index.d.ts +19 -2
  35. package/dist/utils/print.d.ts +1 -0
  36. package/dist/utils/print.js +5 -1
  37. package/dist/utils/string.d.ts +1 -0
  38. package/dist/utils/string.js +17 -1
  39. package/dist/utils/system.d.ts +1 -0
  40. package/dist/utils/system.js +6 -1
  41. package/dist/utils/yiniHelpers.d.ts +44 -2
  42. package/dist/utils/yiniHelpers.js +134 -46
  43. package/examples/basic.yini +1 -0
  44. package/examples/compare-formats.md +1 -1
  45. package/examples/nested.yini +1 -1
  46. package/examples/parse-example.ts +1 -0
  47. package/package.json +11 -3
  48. package/dist/YINI.js.map +0 -1
  49. package/dist/config/env.js.map +0 -1
  50. package/dist/core/astBuilder.js.map +0 -1
  51. package/dist/core/errorDataHandler.js.map +0 -1
  52. package/dist/core/internalTypes.js.map +0 -1
  53. package/dist/core/objectBuilder.js.map +0 -1
  54. package/dist/core/options/defaultParserOptions.js.map +0 -1
  55. package/dist/core/options/failLevel.js.map +0 -1
  56. package/dist/core/options/optionsFunctions.js.map +0 -1
  57. package/dist/core/parsingRules/modeFromRulesMatcher.js.map +0 -1
  58. package/dist/core/parsingRules/rulesConstAndGuards.js.map +0 -1
  59. package/dist/core/pipeline/errorListeners.js.map +0 -1
  60. package/dist/core/pipeline/pipeline.js.map +0 -1
  61. package/dist/core/resultMetadataBuilder.js.map +0 -1
  62. package/dist/core/runtime.js.map +0 -1
  63. package/dist/dev/main.d.ts +0 -1
  64. package/dist/dev/main.js +0 -139
  65. package/dist/dev/main.js.map +0 -1
  66. package/dist/dev/quick-test-samples/defect-inputs.d.ts +0 -37
  67. package/dist/dev/quick-test-samples/defect-inputs.js +0 -106
  68. package/dist/dev/quick-test-samples/defect-inputs.js.map +0 -1
  69. package/dist/dev/quick-test-samples/valid-inputs.d.ts +0 -21
  70. package/dist/dev/quick-test-samples/valid-inputs.js +0 -422
  71. package/dist/dev/quick-test-samples/valid-inputs.js.map +0 -1
  72. package/dist/grammar/generated/YiniLexer.js.map +0 -1
  73. package/dist/grammar/generated/YiniParser.js.map +0 -1
  74. package/dist/grammar/generated/YiniParserVisitor.js.map +0 -1
  75. package/dist/index.js.map +0 -1
  76. package/dist/parsers/extractHeaderParts.js.map +0 -1
  77. package/dist/parsers/extractSignificantYiniLine.js.map +0 -1
  78. package/dist/parsers/parseBoolean.js.map +0 -1
  79. package/dist/parsers/parseNull.js.map +0 -1
  80. package/dist/parsers/parseNumber.js.map +0 -1
  81. package/dist/parsers/parseSectionHeader.js.map +0 -1
  82. package/dist/parsers/parseString.js.map +0 -1
  83. package/dist/types/index.js.map +0 -1
  84. package/dist/utils/number.js.map +0 -1
  85. package/dist/utils/object.js.map +0 -1
  86. package/dist/utils/pathAndFileName.js.map +0 -1
  87. package/dist/utils/print.js.map +0 -1
  88. package/dist/utils/string.js.map +0 -1
  89. package/dist/utils/system.js.map +0 -1
  90. package/dist/utils/yiniHelpers.js.map +0 -1
@@ -16,8 +16,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
16
16
  var _YiniRuntime_runtime;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.YiniRuntime = void 0;
19
+ // src/core/runtime.ts
19
20
  const fs_1 = __importDefault(require("fs"));
20
21
  const env_1 = require("../config/env");
22
+ const validateShebangPlacement_1 = require("../parsers/validateShebangPlacement");
21
23
  const pathAndFileName_1 = require("../utils/pathAndFileName");
22
24
  const print_1 = require("../utils/print");
23
25
  const string_1 = require("../utils/string");
@@ -54,6 +56,7 @@ class YiniRuntime {
54
56
  timeIoMs: null,
55
57
  preferredBailSensitivity: null,
56
58
  sha256: null,
59
+ preflightIssues: [],
57
60
  };
58
61
  }
59
62
  // --- Single implementation --------------------------------------------
@@ -62,21 +65,6 @@ class YiniRuntime {
62
65
  runParse(yiniContent, arg2, // strictMode | options
63
66
  failLevel = 'auto', includeMetadata = false) {
64
67
  (0, print_1.debugPrint)('-> Entered runParse(..) in YiniRuntime class\n');
65
- // Handle optional UTF-8 BOM content of file.
66
- if (yiniContent.startsWith('\uFEFF')) {
67
- // (!) NOTE: slice(1) only because UTF-8 BOM appears as one single Unicode code characte, even though it is 3 bytes (EF BB BF) on disk.
68
- yiniContent = yiniContent.slice(1);
69
- (0, print_1.devPrint)('runParse(..): BOM was detected and stripped BOM in UTF-8 content');
70
- }
71
- // Handle optional shebang line (if line starts with "#!").
72
- if (yiniContent.startsWith('#!')) {
73
- const newlineIndex = yiniContent.indexOf('\n');
74
- (0, print_1.devPrint)('runParse(..): Shebang detected at first line, stripped line 1.');
75
- if (newlineIndex < 2) {
76
- throw new Error('Syntax-Error: Unexpected YINI input');
77
- }
78
- yiniContent = yiniContent.slice(newlineIndex + 1);
79
- }
80
68
  // Runtime guard to catch illegal/ambiguous calls coming from JS or any-cast code
81
69
  if ((0, optionsFunctions_1.isOptionsObjectForm)(arg2) &&
82
70
  (failLevel !== 'auto' || includeMetadata !== false)) {
@@ -102,6 +90,20 @@ class YiniRuntime {
102
90
  includeMetadata,
103
91
  };
104
92
  }
93
+ const shebangIssue = (0, validateShebangPlacement_1.getShebangPlacementIssue)(yiniContent, userOpts.strictMode);
94
+ if (shebangIssue) {
95
+ __classPrivateFieldGet(this, _YiniRuntime_runtime, "f").preflightIssues.push(shebangIssue);
96
+ }
97
+ const originalContent = yiniContent;
98
+ yiniContent = (0, validateShebangPlacement_1.stripBomAndValidShebang)(yiniContent);
99
+ yiniContent = (0, validateShebangPlacement_1.normalizeShebangCommentLines)(yiniContent);
100
+ if (originalContent.startsWith('\uFEFF')) {
101
+ (0, print_1.devPrint)('runParse(..): BOM was detected and stripped from UTF-8 content.');
102
+ }
103
+ if (originalContent.startsWith('#!') ||
104
+ originalContent.startsWith('\uFEFF#!')) {
105
+ (0, print_1.devPrint)('runParse(..): Shebang detected on first line and ignored.');
106
+ }
105
107
  if (userOpts.includeMetadata && __classPrivateFieldGet(this, _YiniRuntime_runtime, "f").sourceType === 'Inline') {
106
108
  const lineCount = yiniContent.split(/\r?\n/).length; // Counts the lines.
107
109
  const sha256 = (0, string_1.computeSha256)(yiniContent); // NOTE: Compute BEFORE any possible tampering of content.
@@ -111,9 +113,13 @@ class YiniRuntime {
111
113
  }
112
114
  // NOTE: Important: Do not trim or mutate the yiniContent here, due
113
115
  // to it will mess up the line numbers in error reporting.
114
- if (!yiniContent) {
115
- throw new Error('Syntax-Error: Unexpected blank YINI input');
116
+ // if (!yiniContent) {
117
+ // throw new Error('Syntax-Error: Unexpected blank YINI input')
118
+ // }
119
+ if (yiniContent === null || yiniContent === undefined) {
120
+ throw new Error('Syntax-Error: Missing YINI input');
116
121
  }
122
+ // IMPORTANT: Makes sure input ends with an empty NL!
117
123
  if (!yiniContent.endsWith('\n')) {
118
124
  yiniContent += '\n';
119
125
  }
@@ -166,13 +172,6 @@ class YiniRuntime {
166
172
  };
167
173
  }
168
174
  if ((0, pathAndFileName_1.getFileNameExtension)(filePath).toLowerCase() !== '.yini') {
169
- // IMPORTANT: If "silent" option is set, do not log anything to console!
170
- if (!userOpts.silent) {
171
- // In quiet-mode we still show errors (these are fine).
172
- console.error('Invalid file extension for YINI file:');
173
- console.error(`"${filePath}"`);
174
- console.error('File does not have a valid ".yini" extension (case-insensitive).');
175
- }
176
175
  throw new Error('Error: Unexpected file extension for YINI file');
177
176
  }
178
177
  // ---- Phase 0: I/O ----
@@ -192,22 +191,18 @@ class YiniRuntime {
192
191
  __classPrivateFieldGet(this, _YiniRuntime_runtime, "f").preferredBailSensitivity = userOpts.failLevel;
193
192
  __classPrivateFieldGet(this, _YiniRuntime_runtime, "f").sha256 = (0, string_1.computeSha256)(content); // NOTE: Compute BEFORE any possible tampering of content.
194
193
  }
195
- let hasNoNewlineAtEOF = false;
196
194
  if (!content.endsWith('\n')) {
195
+ __classPrivateFieldGet(this, _YiniRuntime_runtime, "f").preflightIssues.push({
196
+ locInput: undefined,
197
+ type: 'Syntax-Warning',
198
+ msgWhat: 'No newline at end of file.',
199
+ msgWhy: `It's recommended to end a YINI file with a newline. File: "${filePath}"`,
200
+ });
197
201
  content += '\n';
198
- hasNoNewlineAtEOF = true;
199
202
  }
200
203
  const result = this.runParse(content, {
201
204
  ...userOpts,
202
205
  });
203
- // if (hasNoNewlineAtEOF && !userOpts.quiet && !userOpts.silent) {
204
- if (hasNoNewlineAtEOF && !userOpts.quiet) {
205
- // IMPORTANT: If "silent" option is set, do not log anything to console!
206
- if (!userOpts.silent) {
207
- //@todo: (or maybe not, 20250917) Maybe let errorHandler emit message
208
- console.warn(`No newline at end of file, it's recommended to end a file with a newline. File:\n"${filePath}"`);
209
- }
210
- }
211
206
  return result;
212
207
  }
213
208
  }
@@ -1,4 +1,4 @@
1
- import { ATN, CharStream, DFA, Lexer, RuleContext } from "antlr4";
1
+ import { ATN, CharStream, DFA, Lexer } from "antlr4";
2
2
  export default class YiniLexer extends Lexer {
3
3
  static readonly SHEBANG = 1;
4
4
  static readonly YINI_TOKEN = 2;
@@ -13,44 +13,39 @@ export default class YiniLexer extends Lexer {
13
13
  static readonly EMPTY_OBJECT = 11;
14
14
  static readonly EMPTY_LIST = 12;
15
15
  static readonly STRING = 13;
16
- static readonly TRIPLE_QUOTED_STRING = 14;
17
- static readonly SINGLE_OR_DOUBLE = 15;
18
- static readonly R_AND_C_STRING = 16;
19
- static readonly HYPER_STRING = 17;
20
- static readonly NUMBER = 18;
21
- static readonly SS = 19;
22
- static readonly CARET = 20;
23
- static readonly GT = 21;
24
- static readonly LT = 22;
25
- static readonly EQ = 23;
26
- static readonly HASH = 24;
27
- static readonly COMMA = 25;
28
- static readonly COLON = 26;
29
- static readonly OB = 27;
30
- static readonly CB = 28;
31
- static readonly OC = 29;
32
- static readonly CC = 30;
33
- static readonly PLUS = 31;
34
- static readonly DOLLAR = 32;
35
- static readonly PC = 33;
36
- static readonly AT = 34;
37
- static readonly SEMICOLON = 35;
38
- static readonly NL = 36;
39
- static readonly WS = 37;
40
- static readonly BLOCK_COMMENT = 38;
41
- static readonly LINE_COMMENT = 39;
42
- static readonly INLINE_COMMENT = 40;
43
- static readonly KEY = 41;
44
- static readonly IDENT_INVALID = 42;
45
- static readonly REST = 43;
46
- static readonly META_INVALID = 44;
16
+ static readonly NUMBER = 14;
17
+ static readonly CARET = 15;
18
+ static readonly SS = 16;
19
+ static readonly GT = 17;
20
+ static readonly LT = 18;
21
+ static readonly EQ = 19;
22
+ static readonly COMMA = 20;
23
+ static readonly COLON = 21;
24
+ static readonly OB = 22;
25
+ static readonly CB = 23;
26
+ static readonly OC = 24;
27
+ static readonly CC = 25;
28
+ static readonly PLUS = 26;
29
+ static readonly DOLLAR = 27;
30
+ static readonly PC = 28;
31
+ static readonly AT = 29;
32
+ static readonly SEMICOLON = 30;
33
+ static readonly NL = 31;
34
+ static readonly WS = 32;
35
+ static readonly BLOCK_COMMENT = 33;
36
+ static readonly DISABLED_LINE = 34;
37
+ static readonly FULL_LINE_COMMENT = 35;
38
+ static readonly INLINE_COMMENT = 36;
39
+ static readonly KEY = 37;
40
+ static readonly IDENT_INVALID = 38;
41
+ static readonly REST = 39;
42
+ static readonly META_INVALID = 40;
47
43
  static readonly EOF: number;
48
44
  static readonly channelNames: string[];
49
45
  static readonly literalNames: (string | null)[];
50
46
  static readonly symbolicNames: (string | null)[];
51
47
  static readonly modeNames: string[];
52
48
  static readonly ruleNames: string[];
53
- atLineStart(): boolean;
54
49
  constructor(input: CharStream);
55
50
  get grammarFileName(): string;
56
51
  get literalNames(): (string | null)[];
@@ -59,8 +54,6 @@ export default class YiniLexer extends Lexer {
59
54
  get serializedATN(): number[];
60
55
  get channelNames(): string[];
61
56
  get modeNames(): string[];
62
- sempred(localctx: RuleContext, ruleIndex: number, predIndex: number): boolean;
63
- private LINE_COMMENT_sempred;
64
57
  static readonly _serializedATN: number[];
65
58
  private static __ATN;
66
59
  static get _ATN(): ATN;