@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,46 @@
1
+ import { AbstractAccessor } from '../abstract-accessor.js';
2
+ import { InvalidFormatException } from '../../exceptions/invalid-format-exception.js';
3
+ import { YamlParser } from '../../parser/yaml-parser.js';
4
+ /**
5
+ * Accessor for YAML-encoded strings.
6
+ *
7
+ * Uses the internal YamlParser for safe YAML parsing without
8
+ * depending on external YAML libraries. Tags, anchors, aliases, and
9
+ * merge keys are blocked as unsafe constructs.
10
+ *
11
+ * @example
12
+ * const accessor = new YamlAccessor(parser).from('key: value\nnested:\n a: 1');
13
+ * accessor.get('nested.a'); // 1
14
+ */
15
+ export class YamlAccessor extends AbstractAccessor {
16
+ /**
17
+ * Hydrate from a YAML string.
18
+ *
19
+ * @param data - YAML string input.
20
+ * @returns Populated accessor instance.
21
+ * @throws {InvalidFormatException} When input is not a string or YAML is malformed.
22
+ * @throws {YamlParseException} When unsafe YAML constructs are present.
23
+ * @throws {SecurityException} When payload size exceeds limit.
24
+ *
25
+ * @example
26
+ * accessor.from('name: Alice\nage: 30');
27
+ */
28
+ from(data) {
29
+ if (typeof data !== 'string') {
30
+ /* Stryker disable StringLiteral -- error message content is cosmetic */
31
+ throw new InvalidFormatException(`YamlAccessor expects a YAML string, got ${typeof data}`);
32
+ /* Stryker restore StringLiteral */
33
+ }
34
+ return this.ingest(data);
35
+ }
36
+ /** {@inheritDoc} */
37
+ parse(raw) {
38
+ /* Stryker disable next-line ConditionalExpression,BlockStatement,StringLiteral -- unreachable: from() always validates string before ingest() */
39
+ /* c8 ignore start */
40
+ if (typeof raw !== 'string') {
41
+ return {};
42
+ }
43
+ /* c8 ignore stop */
44
+ return new YamlParser().parse(raw);
45
+ }
46
+ }
@@ -0,0 +1,11 @@
1
+ import type { ReadableAccessorsInterface } from './readable-accessors-interface.js';
2
+ import type { WritableAccessorsInterface } from './writable-accessors-interface.js';
3
+ import type { FactoryAccessorsInterface } from './factory-accessors-interface.js';
4
+ /**
5
+ * Unified contract combining read, write, and factory capabilities.
6
+ *
7
+ * Marker interface that aggregates all accessor responsibilities into
8
+ * a single type, used as the base contract for AbstractAccessor.
9
+ */
10
+ export interface AccessorsInterface extends ReadableAccessorsInterface, WritableAccessorsInterface, FactoryAccessorsInterface {
11
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Contract for creating accessor instances from raw input.
3
+ *
4
+ * Note: this `from(data)` is the per-accessor hydrator, not
5
+ * {@link Inline.from} which selects an accessor by TypeFormat.
6
+ */
7
+ export interface FactoryAccessorsInterface {
8
+ /**
9
+ * Hydrate the accessor from raw input data.
10
+ *
11
+ * @param data - Raw input in the format expected by the accessor.
12
+ * @returns Populated accessor instance.
13
+ * @throws {InvalidFormatException} When the input cannot be parsed.
14
+ */
15
+ from(data: unknown): this;
16
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Contract for custom format detection and parsing integration.
3
+ *
4
+ * Enables the {@link AnyAccessor} to accept arbitrary input by delegating
5
+ * format validation and parsing to a user-provided implementation.
6
+ *
7
+ * @example
8
+ * class CsvIntegration implements ParseIntegrationInterface {
9
+ * assertFormat(raw: unknown): boolean { return typeof raw === 'string' && raw.includes(','); }
10
+ * parse(raw: unknown): Record<string, unknown> { ... }
11
+ * }
12
+ * const accessor = Inline.withParserIntegration(new CsvIntegration()).fromAny(csvString);
13
+ */
14
+ export interface ParseIntegrationInterface {
15
+ /**
16
+ * Determine whether the given raw input is in a supported format.
17
+ *
18
+ * @param raw - Raw input data to validate.
19
+ * @returns `true` if the input can be parsed by this integration.
20
+ */
21
+ assertFormat(raw: unknown): boolean;
22
+ /**
23
+ * Parse raw input data into a normalized plain object.
24
+ *
25
+ * Called only after {@link assertFormat} returns `true`.
26
+ *
27
+ * @param raw - Raw input data previously validated by {@link assertFormat}.
28
+ * @returns Parsed data as a nested plain object.
29
+ */
30
+ parse(raw: unknown): Record<string, unknown>;
31
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Contract for a path-segment cache.
3
+ *
4
+ * Provides O(1) lookup for previously parsed dot-notation path strings,
5
+ * avoiding repeated segment parsing on hot paths.
6
+ *
7
+ * Note: JS segments are flat `string[]` (from `path.split('.')`), whereas
8
+ * PHP segments are structured `array<int, array<string, mixed>>` containing
9
+ * SegmentType metadata. This architectural difference reflects each
10
+ * language's parser implementation.
11
+ */
12
+ export interface PathCacheInterface {
13
+ /**
14
+ * Retrieve cached segments for a path string.
15
+ *
16
+ * @param path - Dot-notation path string.
17
+ * @returns Cached segment array, or null if not cached.
18
+ */
19
+ get(path: string): string[] | null;
20
+ /**
21
+ * Store parsed segments for a path string.
22
+ *
23
+ * @param path - Dot-notation path string.
24
+ * @param segments - Parsed segment array to cache.
25
+ */
26
+ set(path: string, segments: string[]): void;
27
+ /**
28
+ * Check whether a path exists in the cache.
29
+ *
30
+ * @param path - Dot-notation path string.
31
+ * @returns `true` if segments are cached for this path.
32
+ */
33
+ has(path: string): boolean;
34
+ /**
35
+ * Clear all cached entries.
36
+ *
37
+ * @returns Same instance for fluent chaining.
38
+ */
39
+ clear(): this;
40
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Contract for read-only data access operations.
3
+ *
4
+ * Defines methods for retrieving, checking existence, counting,
5
+ * and inspecting keys within the accessor's internal data store.
6
+ */
7
+ export interface ReadableAccessorsInterface {
8
+ /**
9
+ * Retrieve the original raw input data before parsing.
10
+ *
11
+ * @returns Original input passed to {@link FactoryAccessorsInterface.from}.
12
+ */
13
+ getRaw(): unknown;
14
+ /**
15
+ * Retrieve a value at a dot-notation path.
16
+ *
17
+ * @param path - Dot-notation path (e.g. "user.name").
18
+ * @param defaultValue - Fallback when the path does not exist.
19
+ * @returns Resolved value or the default.
20
+ */
21
+ get(path: string, defaultValue?: unknown): unknown;
22
+ /**
23
+ * Retrieve a value or throw when the path does not exist.
24
+ *
25
+ * @param path - Dot-notation path.
26
+ * @returns Resolved value.
27
+ * @throws {PathNotFoundException} When the path is missing.
28
+ */
29
+ getOrFail(path: string): unknown;
30
+ /**
31
+ * Retrieve a value using pre-parsed key segments.
32
+ *
33
+ * @param segments - Ordered list of keys.
34
+ * @param defaultValue - Fallback when the path does not exist.
35
+ * @returns Resolved value or the default.
36
+ */
37
+ getAt(segments: Array<string | number>, defaultValue?: unknown): unknown;
38
+ /**
39
+ * Check whether a dot-notation path exists.
40
+ *
41
+ * @param path - Dot-notation path.
42
+ * @returns True if the path resolves to a value.
43
+ */
44
+ has(path: string): boolean;
45
+ /**
46
+ * Check whether a path exists using pre-parsed key segments.
47
+ *
48
+ * @param segments - Ordered list of keys.
49
+ * @returns True if the path resolves to a value.
50
+ */
51
+ hasAt(segments: Array<string | number>): boolean;
52
+ /**
53
+ * Retrieve multiple values by their paths with individual defaults.
54
+ *
55
+ * @param paths - Map of path to default value.
56
+ * @returns Map of path to resolved value.
57
+ */
58
+ getMany(paths: Record<string, unknown>): Record<string, unknown>;
59
+ /**
60
+ * Return all parsed data as a plain object.
61
+ *
62
+ * @returns Complete internal data.
63
+ */
64
+ all(): Record<string, unknown>;
65
+ /**
66
+ * Count elements at a path, or the root if undefined.
67
+ *
68
+ * @param path - Dot-notation path, or undefined for root.
69
+ * @returns Number of elements.
70
+ */
71
+ count(path?: string): number;
72
+ /**
73
+ * Retrieve array keys at a path, or root keys if undefined.
74
+ *
75
+ * @param path - Dot-notation path, or undefined for root.
76
+ * @returns List of keys.
77
+ */
78
+ keys(path?: string): string[];
79
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Contract for validating keys against a forbidden-key security list.
3
+ *
4
+ * Prevents injection attacks by rejecting prototype pollution vectors,
5
+ * legacy prototype manipulation methods, stream wrapper / protocol URI schemes,
6
+ * and Node.js globals during data access and mutation operations.
7
+ */
8
+ export interface SecurityGuardInterface {
9
+ /**
10
+ * Check whether a key is in the forbidden list.
11
+ *
12
+ * @param key - Key name to check.
13
+ * @returns True if the key is forbidden.
14
+ */
15
+ isForbiddenKey(key: string): boolean;
16
+ /**
17
+ * Assert that a single key is safe, throwing on violation.
18
+ *
19
+ * @param key - Key name to validate.
20
+ * @throws {SecurityException} When the key is forbidden.
21
+ */
22
+ assertSafeKey(key: string): void;
23
+ /**
24
+ * Recursively assert that all keys in a data structure are safe.
25
+ *
26
+ * @param data - Data to scan for forbidden keys.
27
+ * @param depth - Current recursion depth (internal use).
28
+ * @throws {SecurityException} When a forbidden key is found or depth is exceeded.
29
+ */
30
+ assertSafeKeys(data: unknown, depth?: number): void;
31
+ /**
32
+ * Remove all forbidden keys from a data structure recursively.
33
+ *
34
+ * @param data - Data to sanitize.
35
+ * @param depth - Current recursion depth.
36
+ * @returns Sanitized data without forbidden keys.
37
+ * @throws {SecurityException} When recursion depth exceeds the limit.
38
+ */
39
+ sanitize(data: Record<string, unknown>, depth?: number): Record<string, unknown>;
40
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Contract for security validation during parsing and path resolution.
3
+ *
4
+ * Defines methods for asserting payload size, maximum key counts,
5
+ * and recursion depth limits to prevent resource exhaustion and
6
+ * injection attacks during data access operations.
7
+ */
8
+ export interface SecurityParserInterface {
9
+ /**
10
+ * Assert that a raw string payload does not exceed the byte limit.
11
+ *
12
+ * @param input - Raw input string to measure.
13
+ * @param maxBytes - Override limit, or undefined to use configured default.
14
+ * @throws {SecurityException} When the payload exceeds the limit.
15
+ */
16
+ assertPayloadSize(input: string, maxBytes?: number): void;
17
+ /**
18
+ * Assert that resolve depth does not exceed the configured limit.
19
+ *
20
+ * @param depth - Current depth counter.
21
+ * @throws {SecurityException} When depth exceeds the maximum.
22
+ */
23
+ assertMaxResolveDepth(depth: number): void;
24
+ /**
25
+ * Assert that total key count does not exceed the limit.
26
+ *
27
+ * @param data - Data to count keys in.
28
+ * @param maxKeys - Override limit, or undefined to use configured default.
29
+ * @param maxCountDepth - Override recursion depth limit, or undefined for default.
30
+ * @throws {SecurityException} When key count exceeds the limit.
31
+ */
32
+ assertMaxKeys(data: Record<string, unknown>, maxKeys?: number, maxCountDepth?: number): void;
33
+ /**
34
+ * Assert that current recursion depth does not exceed the limit.
35
+ *
36
+ * @param currentDepth - Current depth counter.
37
+ * @param maxDepth - Override limit, or undefined to use configured default.
38
+ * @throws {SecurityException} When the depth exceeds the limit.
39
+ */
40
+ assertMaxDepth(currentDepth: number, maxDepth?: number): void;
41
+ /**
42
+ * Assert that structural nesting depth does not exceed the policy limit.
43
+ *
44
+ * @param data - Data to measure structural depth of.
45
+ * @param maxDepth - Maximum allowed structural depth.
46
+ * @throws {SecurityException} When structural depth exceeds the limit.
47
+ */
48
+ assertMaxStructuralDepth(data: unknown, maxDepth: number): void;
49
+ /**
50
+ * Return the configured maximum structural nesting depth.
51
+ *
52
+ * @returns Maximum allowed depth.
53
+ */
54
+ getMaxDepth(): number;
55
+ /**
56
+ * Return the configured maximum path-resolve recursion depth.
57
+ *
58
+ * @returns Maximum allowed resolve depth.
59
+ */
60
+ getMaxResolveDepth(): number;
61
+ /**
62
+ * Return the configured maximum total key count.
63
+ *
64
+ * @returns Maximum allowed key count.
65
+ */
66
+ getMaxKeys(): number;
67
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Contract for immutable write operations on accessor data.
3
+ *
4
+ * All mutations return a new instance with the modification applied,
5
+ * preserving the original accessor instance.
6
+ */
7
+ export interface WritableAccessorsInterface {
8
+ /**
9
+ * Set a value at a dot-notation path.
10
+ *
11
+ * @param path - Dot-notation path.
12
+ * @param value - Value to assign.
13
+ * @returns New accessor instance with the value set.
14
+ * @throws {ReadonlyViolationException} When the accessor is readonly.
15
+ * @throws {SecurityException} When the path contains forbidden keys.
16
+ */
17
+ set(path: string, value: unknown): this;
18
+ /**
19
+ * Set a value using pre-parsed key segments.
20
+ *
21
+ * @param segments - Ordered list of keys.
22
+ * @param value - Value to assign.
23
+ * @returns New accessor instance with the value set.
24
+ * @throws {ReadonlyViolationException} When the accessor is readonly.
25
+ * @throws {SecurityException} When segments contain forbidden keys.
26
+ */
27
+ setAt(segments: Array<string | number>, value: unknown): this;
28
+ /**
29
+ * Remove a value at a dot-notation path.
30
+ *
31
+ * @param path - Dot-notation path to remove.
32
+ * @returns New accessor instance without the specified path.
33
+ * @throws {ReadonlyViolationException} When the accessor is readonly.
34
+ * @throws {SecurityException} When the path contains forbidden keys.
35
+ */
36
+ remove(path: string): this;
37
+ /**
38
+ * Remove a value using pre-parsed key segments.
39
+ *
40
+ * @param segments - Ordered list of keys.
41
+ * @returns New accessor instance without the specified path.
42
+ * @throws {ReadonlyViolationException} When the accessor is readonly.
43
+ * @throws {SecurityException} When segments contain forbidden keys.
44
+ */
45
+ removeAt(segments: Array<string | number>): this;
46
+ /**
47
+ * Deep-merge an object into the value at a dot-notation path.
48
+ *
49
+ * @param path - Dot-notation path to the merge target.
50
+ * @param value - Object to merge into the existing value.
51
+ * @returns New accessor instance with merged data.
52
+ * @throws {ReadonlyViolationException} When the accessor is readonly.
53
+ * @throws {SecurityException} When the path or values contain forbidden keys.
54
+ */
55
+ merge(path: string, value: Record<string, unknown>): this;
56
+ /**
57
+ * Deep-merge an object into the root data.
58
+ *
59
+ * @param value - Object to merge into the root.
60
+ * @returns New accessor instance with merged data.
61
+ * @throws {ReadonlyViolationException} When the accessor is readonly.
62
+ * @throws {SecurityException} When values contain forbidden keys.
63
+ */
64
+ mergeAll(value: Record<string, unknown>): this;
65
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,204 @@
1
+ import type { SecurityGuardInterface } from '../contracts/security-guard-interface.js';
2
+ import type { SecurityParserInterface } from '../contracts/security-parser-interface.js';
3
+ import type { PathCacheInterface } from '../contracts/path-cache-interface.js';
4
+ /**
5
+ * Core dot-notation parser for reading, writing, and removing nested values.
6
+ *
7
+ * Provides path-based access to plain objects using dot-separated keys.
8
+ * Delegates security validation to SecurityGuard and SecurityParser.
9
+ *
10
+ * @example
11
+ * const parser = new DotNotationParser();
12
+ * parser.get({ user: { name: 'Alice' } }, 'user.name'); // 'Alice'
13
+ */
14
+ export declare class DotNotationParser {
15
+ private readonly securityGuard;
16
+ private readonly securityParser;
17
+ private readonly pathCache;
18
+ /**
19
+ * @param securityGuard - Key-safety guard. Defaults to a new SecurityGuard instance.
20
+ * @param securityParser - Parser depth and size limits. Defaults to a new SecurityParser instance.
21
+ * @param pathCache - Optional path segment cache for repeated lookups.
22
+ */
23
+ constructor(securityGuard?: SecurityGuardInterface, securityParser?: SecurityParserInterface, pathCache?: PathCacheInterface);
24
+ /**
25
+ * Resolve a dot-notation path against data, returning the matched value.
26
+ *
27
+ * @param data - Source data object.
28
+ * @param path - Dot-notation path string (e.g. "user.name").
29
+ * @param defaultValue - Fallback returned when the path does not exist.
30
+ * @returns Resolved value or the default.
31
+ *
32
+ * @example
33
+ * parser.get({ a: { b: 1 } }, 'a.b'); // 1
34
+ * parser.get({ a: 1 }, 'a.b', 'default'); // 'default'
35
+ */
36
+ get(data: Record<string, unknown>, path: string, defaultValue?: unknown): unknown;
37
+ /**
38
+ * Set a value at a dot-notation path, returning a new object.
39
+ *
40
+ * @param data - Source data object.
41
+ * @param path - Dot-notation path string.
42
+ * @param value - Value to assign.
43
+ * @returns New object with the value set at the path.
44
+ *
45
+ * @example
46
+ * parser.set({}, 'user.name', 'Alice'); // { user: { name: 'Alice' } }
47
+ */
48
+ set(data: Record<string, unknown>, path: string, value: unknown): Record<string, unknown>;
49
+ /**
50
+ * Check whether a dot-notation path exists in the data.
51
+ *
52
+ * @param data - Source data object.
53
+ * @param path - Dot-notation path string.
54
+ * @returns True if the path resolves to a value.
55
+ *
56
+ * @example
57
+ * parser.has({ a: { b: 1 } }, 'a.b'); // true
58
+ * parser.has({ a: 1 }, 'a.b'); // false
59
+ */
60
+ has(data: Record<string, unknown>, path: string): boolean;
61
+ /**
62
+ * Remove a value at a dot-notation path, returning a new object.
63
+ *
64
+ * @param data - Source data object.
65
+ * @param path - Dot-notation path string.
66
+ * @returns New object with the path removed.
67
+ *
68
+ * @example
69
+ * parser.remove({ a: { b: 1 } }, 'a.b'); // { a: {} }
70
+ */
71
+ remove(data: Record<string, unknown>, path: string): Record<string, unknown>;
72
+ /**
73
+ * Resolve a pre-parsed segment array against data.
74
+ *
75
+ * @param data - Source data object.
76
+ * @param segments - Ordered list of keys.
77
+ * @param defaultValue - Fallback returned when the path does not exist.
78
+ * @returns Resolved value or the default.
79
+ *
80
+ * @example
81
+ * parser.getAt({ a: { b: 1 } }, ['a', 'b']); // 1
82
+ */
83
+ getAt(data: Record<string, unknown>, segments: Array<string | number>, defaultValue?: unknown): unknown;
84
+ /**
85
+ * Set a value using pre-parsed key segments, returning a new object.
86
+ *
87
+ * @param data - Source data object.
88
+ * @param segments - Ordered list of keys.
89
+ * @param value - Value to assign.
90
+ * @returns New object with the value set.
91
+ *
92
+ * @example
93
+ * parser.setAt({}, ['user', 'name'], 'Alice'); // { user: { name: 'Alice' } }
94
+ */
95
+ setAt(data: Record<string, unknown>, segments: Array<string | number>, value: unknown): Record<string, unknown>;
96
+ /**
97
+ * Check whether a path exists using pre-parsed key segments.
98
+ *
99
+ * @param data - Source data object.
100
+ * @param segments - Ordered list of keys.
101
+ * @returns True if the path resolves to a value.
102
+ *
103
+ * @example
104
+ * parser.hasAt({ a: { b: 1 } }, ['a', 'b']); // true
105
+ */
106
+ hasAt(data: Record<string, unknown>, segments: Array<string | number>): boolean;
107
+ /**
108
+ * Remove a value using pre-parsed key segments, returning a new object.
109
+ *
110
+ * @param data - Source data object.
111
+ * @param segments - Ordered list of keys.
112
+ * @returns New object without the specified path.
113
+ *
114
+ * @example
115
+ * parser.removeAt({ a: { b: 1 } }, ['a', 'b']); // { a: {} }
116
+ */
117
+ removeAt(data: Record<string, unknown>, segments: Array<string | number>): Record<string, unknown>;
118
+ /**
119
+ * Deep-merge an object into the value at a dot-notation path.
120
+ *
121
+ * @param data - Source data object.
122
+ * @param path - Dot-notation path to the merge target, or empty string for root merge.
123
+ * @param value - Object to merge into the existing value.
124
+ * @returns New object with merged data.
125
+ *
126
+ * @example
127
+ * parser.merge({ a: { b: 1 } }, 'a', { c: 2 }); // { a: { b: 1, c: 2 } }
128
+ */
129
+ merge(data: Record<string, unknown>, path: string, value: Record<string, unknown>): Record<string, unknown>;
130
+ /**
131
+ * Run all security validations on a parsed data structure.
132
+ *
133
+ * @param data - Data to validate.
134
+ * @throws {SecurityException} When a security violation is detected.
135
+ *
136
+ * @example
137
+ * parser.validate({ name: 'Alice' }); // OK
138
+ * parser.validate({ __construct: 'bad' }); // throws SecurityException
139
+ */
140
+ validate(data: Record<string, unknown>): void;
141
+ /**
142
+ * Assert that a string payload does not exceed the configured byte limit.
143
+ *
144
+ * @param input - Raw input string to measure.
145
+ * @throws {SecurityException} When the payload exceeds the limit.
146
+ *
147
+ * @example
148
+ * parser.assertPayload('small text'); // OK
149
+ */
150
+ assertPayload(input: string): void;
151
+ /**
152
+ * Return the configured maximum structural nesting depth.
153
+ *
154
+ * @returns Maximum allowed depth from the security parser.
155
+ */
156
+ getMaxDepth(): number;
157
+ /**
158
+ * Return the configured maximum total key count.
159
+ *
160
+ * @returns Maximum allowed key count from the security parser.
161
+ */
162
+ getMaxKeys(): number;
163
+ /**
164
+ * Parse a dot-notation path into segments, using cache when available.
165
+ *
166
+ * @param path - Dot-notation path string.
167
+ * @returns Array of path segments.
168
+ */
169
+ private parsePath;
170
+ /**
171
+ * Recursively write a value at the given key path.
172
+ *
173
+ * @param data - Current level data.
174
+ * @param segments - Flat key segments.
175
+ * @param index - Current depth index.
176
+ * @param value - Value to write.
177
+ * @returns Modified copy of the data.
178
+ *
179
+ * @throws {SecurityException} When a key violates security rules.
180
+ */
181
+ private writeAt;
182
+ /**
183
+ * Recursively remove a key at the given key path.
184
+ *
185
+ * @param data - Current level data.
186
+ * @param segments - Flat key segments.
187
+ * @param index - Current depth index.
188
+ * @returns Modified copy of the data.
189
+ *
190
+ * @throws {SecurityException} When a key violates security rules.
191
+ */
192
+ private eraseAt;
193
+ /**
194
+ * Recursively merge source into target, preserving nested structures.
195
+ *
196
+ * @param target - Base data.
197
+ * @param source - Data to merge on top.
198
+ * @param depth - Current recursion depth.
199
+ * @returns Merged result.
200
+ *
201
+ * @throws {SecurityException} When max resolve depth is exceeded.
202
+ */
203
+ private deepMerge;
204
+ }