@safeaccess/inline 0.1.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 (129) hide show
  1. package/.gitattributes +16 -0
  2. package/.gitkeep +0 -0
  3. package/CHANGELOG.md +38 -0
  4. package/LICENSE +21 -0
  5. package/README.md +454 -0
  6. package/benchmarks/get.bench.ts +26 -0
  7. package/benchmarks/parse.bench.ts +41 -0
  8. package/dist/accessors/abstract-accessor.d.ts +213 -0
  9. package/dist/accessors/abstract-accessor.js +294 -0
  10. package/dist/accessors/formats/any-accessor.d.ts +35 -0
  11. package/dist/accessors/formats/any-accessor.js +44 -0
  12. package/dist/accessors/formats/array-accessor.d.ts +26 -0
  13. package/dist/accessors/formats/array-accessor.js +39 -0
  14. package/dist/accessors/formats/env-accessor.d.ts +27 -0
  15. package/dist/accessors/formats/env-accessor.js +64 -0
  16. package/dist/accessors/formats/ini-accessor.d.ts +41 -0
  17. package/dist/accessors/formats/ini-accessor.js +109 -0
  18. package/dist/accessors/formats/json-accessor.d.ts +26 -0
  19. package/dist/accessors/formats/json-accessor.js +56 -0
  20. package/dist/accessors/formats/ndjson-accessor.d.ts +28 -0
  21. package/dist/accessors/formats/ndjson-accessor.js +71 -0
  22. package/dist/accessors/formats/object-accessor.d.ts +48 -0
  23. package/dist/accessors/formats/object-accessor.js +90 -0
  24. package/dist/accessors/formats/xml-accessor.d.ts +27 -0
  25. package/dist/accessors/formats/xml-accessor.js +52 -0
  26. package/dist/accessors/formats/yaml-accessor.d.ts +29 -0
  27. package/dist/accessors/formats/yaml-accessor.js +46 -0
  28. package/dist/contracts/accessors-interface.d.ts +11 -0
  29. package/dist/contracts/accessors-interface.js +1 -0
  30. package/dist/contracts/factory-accessors-interface.d.ts +16 -0
  31. package/dist/contracts/factory-accessors-interface.js +1 -0
  32. package/dist/contracts/parse-integration-interface.d.ts +31 -0
  33. package/dist/contracts/parse-integration-interface.js +1 -0
  34. package/dist/contracts/path-cache-interface.d.ts +40 -0
  35. package/dist/contracts/path-cache-interface.js +1 -0
  36. package/dist/contracts/readable-accessors-interface.d.ts +79 -0
  37. package/dist/contracts/readable-accessors-interface.js +1 -0
  38. package/dist/contracts/security-guard-interface.d.ts +40 -0
  39. package/dist/contracts/security-guard-interface.js +1 -0
  40. package/dist/contracts/security-parser-interface.d.ts +67 -0
  41. package/dist/contracts/security-parser-interface.js +1 -0
  42. package/dist/contracts/writable-accessors-interface.d.ts +65 -0
  43. package/dist/contracts/writable-accessors-interface.js +1 -0
  44. package/dist/core/dot-notation-parser.d.ts +204 -0
  45. package/dist/core/dot-notation-parser.js +343 -0
  46. package/dist/exceptions/accessor-exception.d.ts +13 -0
  47. package/dist/exceptions/accessor-exception.js +16 -0
  48. package/dist/exceptions/invalid-format-exception.d.ts +14 -0
  49. package/dist/exceptions/invalid-format-exception.js +17 -0
  50. package/dist/exceptions/parser-exception.d.ts +14 -0
  51. package/dist/exceptions/parser-exception.js +17 -0
  52. package/dist/exceptions/path-not-found-exception.d.ts +14 -0
  53. package/dist/exceptions/path-not-found-exception.js +17 -0
  54. package/dist/exceptions/readonly-violation-exception.d.ts +15 -0
  55. package/dist/exceptions/readonly-violation-exception.js +18 -0
  56. package/dist/exceptions/security-exception.d.ts +18 -0
  57. package/dist/exceptions/security-exception.js +21 -0
  58. package/dist/exceptions/unsupported-type-exception.d.ts +14 -0
  59. package/dist/exceptions/unsupported-type-exception.js +17 -0
  60. package/dist/exceptions/yaml-parse-exception.d.ts +17 -0
  61. package/dist/exceptions/yaml-parse-exception.js +20 -0
  62. package/dist/index.d.ts +30 -0
  63. package/dist/index.js +30 -0
  64. package/dist/inline.d.ts +402 -0
  65. package/dist/inline.js +512 -0
  66. package/dist/parser/xml-parser.d.ts +46 -0
  67. package/dist/parser/xml-parser.js +288 -0
  68. package/dist/parser/yaml-parser.d.ts +94 -0
  69. package/dist/parser/yaml-parser.js +286 -0
  70. package/dist/security/forbidden-keys.d.ts +34 -0
  71. package/dist/security/forbidden-keys.js +80 -0
  72. package/dist/security/security-guard.d.ts +94 -0
  73. package/dist/security/security-guard.js +172 -0
  74. package/dist/security/security-parser.d.ts +130 -0
  75. package/dist/security/security-parser.js +192 -0
  76. package/dist/type-format.d.ts +28 -0
  77. package/dist/type-format.js +29 -0
  78. package/eslint.config.js +1 -0
  79. package/package.json +39 -0
  80. package/src/accessors/abstract-accessor.ts +353 -0
  81. package/src/accessors/formats/any-accessor.ts +51 -0
  82. package/src/accessors/formats/array-accessor.ts +45 -0
  83. package/src/accessors/formats/env-accessor.ts +79 -0
  84. package/src/accessors/formats/ini-accessor.ts +124 -0
  85. package/src/accessors/formats/json-accessor.ts +66 -0
  86. package/src/accessors/formats/ndjson-accessor.ts +82 -0
  87. package/src/accessors/formats/object-accessor.ts +100 -0
  88. package/src/accessors/formats/xml-accessor.ts +58 -0
  89. package/src/accessors/formats/yaml-accessor.ts +52 -0
  90. package/src/contracts/accessors-interface.ts +12 -0
  91. package/src/contracts/factory-accessors-interface.ts +16 -0
  92. package/src/contracts/parse-integration-interface.ts +32 -0
  93. package/src/contracts/path-cache-interface.ts +43 -0
  94. package/src/contracts/readable-accessors-interface.ts +88 -0
  95. package/src/contracts/security-guard-interface.ts +43 -0
  96. package/src/contracts/security-parser-interface.ts +74 -0
  97. package/src/contracts/writable-accessors-interface.ts +70 -0
  98. package/src/core/dot-notation-parser.ts +419 -0
  99. package/src/exceptions/accessor-exception.ts +16 -0
  100. package/src/exceptions/invalid-format-exception.ts +18 -0
  101. package/src/exceptions/parser-exception.ts +18 -0
  102. package/src/exceptions/path-not-found-exception.ts +18 -0
  103. package/src/exceptions/readonly-violation-exception.ts +19 -0
  104. package/src/exceptions/security-exception.ts +22 -0
  105. package/src/exceptions/unsupported-type-exception.ts +18 -0
  106. package/src/exceptions/yaml-parse-exception.ts +21 -0
  107. package/src/index.ts +46 -0
  108. package/src/inline.ts +570 -0
  109. package/src/parser/xml-parser.ts +334 -0
  110. package/src/parser/yaml-parser.ts +368 -0
  111. package/src/security/forbidden-keys.ts +81 -0
  112. package/src/security/security-guard.ts +195 -0
  113. package/src/security/security-parser.ts +233 -0
  114. package/src/type-format.ts +28 -0
  115. package/stryker.config.json +24 -0
  116. package/tests/accessors/accessors.test.ts +1017 -0
  117. package/tests/accessors/json-accessor.test.ts +171 -0
  118. package/tests/core/dot-notation-parser.test.ts +587 -0
  119. package/tests/exceptions/parser-exception.test.ts +31 -0
  120. package/tests/inline.test.ts +445 -0
  121. package/tests/mocks/fake-parse-integration.ts +24 -0
  122. package/tests/mocks/fake-path-cache.ts +31 -0
  123. package/tests/parity.test.ts +164 -0
  124. package/tests/parser/xml-parser.test.ts +618 -0
  125. package/tests/parser/yaml-parser.test.ts +463 -0
  126. package/tests/security/security-guard.test.ts +646 -0
  127. package/tests/security/security-parser.test.ts +391 -0
  128. package/tsconfig.json +16 -0
  129. package/vitest.config.ts +19 -0
@@ -0,0 +1,171 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { JsonAccessor } from '../../src/accessors/formats/json-accessor.js';
3
+ import { DotNotationParser } from '../../src/core/dot-notation-parser.js';
4
+ import { InvalidFormatException } from '../../src/exceptions/invalid-format-exception.js';
5
+ import { PathNotFoundException } from '../../src/exceptions/path-not-found-exception.js';
6
+ import { ReadonlyViolationException } from '../../src/exceptions/readonly-violation-exception.js';
7
+
8
+ function makeAccessor(): JsonAccessor {
9
+ return new JsonAccessor(new DotNotationParser());
10
+ }
11
+
12
+ describe(JsonAccessor.name, () => {
13
+ it('parses a valid JSON string', () => {
14
+ const accessor = makeAccessor().from('{"name":"Alice","age":30}');
15
+ expect(accessor.get('name')).toBe('Alice');
16
+ expect(accessor.get('age')).toBe(30);
17
+ });
18
+
19
+ it('throws InvalidFormatException for non-string input', () => {
20
+ expect(() => makeAccessor().from(42)).toThrow(InvalidFormatException);
21
+ });
22
+
23
+ it('throws InvalidFormatException for null input', () => {
24
+ expect(() => makeAccessor().from(null)).toThrow(InvalidFormatException);
25
+ });
26
+
27
+ it('returns null for a missing path', () => {
28
+ const accessor = makeAccessor().from('{"name":"Alice"}');
29
+ expect(accessor.get('missing')).toBeNull();
30
+ });
31
+
32
+ it('returns the default value for a missing path', () => {
33
+ const accessor = makeAccessor().from('{"name":"Alice"}');
34
+ expect(accessor.get('missing', 'default')).toBe('default');
35
+ });
36
+
37
+ it('resolves a nested dot-notation path', () => {
38
+ const accessor = makeAccessor().from('{"user":{"address":{"city":"Berlin"}}}');
39
+ expect(accessor.get('user.address.city')).toBe('Berlin');
40
+ });
41
+
42
+ it('throws InvalidFormatException for malformed JSON', () => {
43
+ expect(() => makeAccessor().from('{not valid json}')).toThrow(InvalidFormatException);
44
+ });
45
+ });
46
+
47
+ describe(`${JsonAccessor.name} > has`, () => {
48
+ it('returns true when path exists', () => {
49
+ const accessor = makeAccessor().from('{"key":"value"}');
50
+ expect(accessor.has('key')).toBe(true);
51
+ });
52
+
53
+ it('returns false when path is missing', () => {
54
+ const accessor = makeAccessor().from('{"key":"value"}');
55
+ expect(accessor.has('other')).toBe(false);
56
+ });
57
+
58
+ it('returns true for nested path', () => {
59
+ const accessor = makeAccessor().from('{"a":{"b":1}}');
60
+ expect(accessor.has('a.b')).toBe(true);
61
+ });
62
+ });
63
+
64
+ describe(`${JsonAccessor.name} > getOrFail`, () => {
65
+ it('returns value when path exists', () => {
66
+ const accessor = makeAccessor().from('{"key":"value"}');
67
+ expect(accessor.getOrFail('key')).toBe('value');
68
+ });
69
+
70
+ it('throws PathNotFoundException when path is missing', () => {
71
+ const accessor = makeAccessor().from('{"key":"value"}');
72
+ expect(() => accessor.getOrFail('missing')).toThrow(PathNotFoundException);
73
+ });
74
+
75
+ it('error message contains the missing path', () => {
76
+ const accessor = makeAccessor().from('{}');
77
+ expect(() => accessor.getOrFail('user.name')).toThrow("Path 'user.name' not found.");
78
+ });
79
+ });
80
+
81
+ describe(`${JsonAccessor.name} > set`, () => {
82
+ it('sets a value and returns a new instance', () => {
83
+ const accessor = makeAccessor().from('{"name":"Alice"}');
84
+ const updated = accessor.set('name', 'Bob');
85
+ expect(updated.get('name')).toBe('Bob');
86
+ expect(accessor.get('name')).toBe('Alice'); // original unchanged
87
+ });
88
+
89
+ it('sets a nested value', () => {
90
+ const accessor = makeAccessor().from('{}');
91
+ const updated = accessor.set('user.name', 'Alice');
92
+ expect(updated.get('user.name')).toBe('Alice');
93
+ });
94
+
95
+ it('throws ReadonlyViolationException when readonly', () => {
96
+ const accessor = makeAccessor().from('{"name":"Alice"}').readonly(true);
97
+ expect(() => accessor.set('name', 'Bob')).toThrow(ReadonlyViolationException);
98
+ });
99
+ });
100
+
101
+ describe(`${JsonAccessor.name} > remove`, () => {
102
+ it('removes a key and returns a new instance', () => {
103
+ const accessor = makeAccessor().from('{"name":"Alice","age":30}');
104
+ const updated = accessor.remove('age');
105
+ expect(updated.has('age')).toBe(false);
106
+ expect(accessor.has('age')).toBe(true); // original unchanged
107
+ });
108
+
109
+ it('throws ReadonlyViolationException when readonly', () => {
110
+ const accessor = makeAccessor().from('{"name":"Alice"}').readonly(true);
111
+ expect(() => accessor.remove('name')).toThrow(ReadonlyViolationException);
112
+ });
113
+ });
114
+
115
+ describe(`${JsonAccessor.name} > all`, () => {
116
+ it('returns all parsed data', () => {
117
+ const accessor = makeAccessor().from('{"a":1,"b":2}');
118
+ expect(accessor.all()).toEqual({ a: 1, b: 2 });
119
+ });
120
+ });
121
+
122
+ describe(`${JsonAccessor.name} > keys`, () => {
123
+ it('returns root keys', () => {
124
+ const accessor = makeAccessor().from('{"a":1,"b":2}');
125
+ expect(accessor.keys()).toEqual(['a', 'b']);
126
+ });
127
+ });
128
+
129
+ describe(`${JsonAccessor.name} > count`, () => {
130
+ it('counts root keys', () => {
131
+ const accessor = makeAccessor().from('{"a":1,"b":2,"c":3}');
132
+ expect(accessor.count()).toBe(3);
133
+ });
134
+ });
135
+
136
+ describe(`${JsonAccessor.name} > getRaw`, () => {
137
+ it('returns the original raw input', () => {
138
+ const json = '{"name":"Alice"}';
139
+ const accessor = makeAccessor().from(json);
140
+ expect(accessor.getRaw()).toBe(json);
141
+ });
142
+ });
143
+
144
+ describe(`${JsonAccessor.name} > parse non-object JSON`, () => {
145
+ // Kills line 51:13/44/62 — `typeof decoded !== 'object' || decoded === null` check
146
+ // JSON.parse('null') returns null → should return {}
147
+ it('returns empty object when JSON decodes to null', () => {
148
+ const accessor = makeAccessor().from('null');
149
+ expect(accessor.all()).toEqual({});
150
+ });
151
+
152
+ // JSON.parse('42') returns number → should return {}
153
+ it('returns empty object when JSON decodes to a number', () => {
154
+ const accessor = makeAccessor().from('42');
155
+ expect(accessor.all()).toEqual({});
156
+ });
157
+
158
+ // JSON.parse('"hello"') returns string → should return {}
159
+ it('returns empty object when JSON decodes to a string', () => {
160
+ const accessor = makeAccessor().from('"hello"');
161
+ expect(accessor.all()).toEqual({});
162
+ });
163
+
164
+ // JSON.parse('[1,2,3]') returns array → should return {} (or the array as a record, depending on impl)
165
+ it('returns data when JSON decodes to an array', () => {
166
+ // arrays are typeof 'object' and not null, so they pass the check
167
+ const accessor = makeAccessor().from('[1,2,3]');
168
+ // Array access as record: valid object-ish
169
+ expect(typeof accessor.all()).toBe('object');
170
+ });
171
+ });