Skip to content

Conversation

@MarcelOlsen
Copy link

@MarcelOlsen MarcelOlsen commented Dec 24, 2025

potential fix for the nested array validation issue reported in elysiajs/elysia#1631

the problem was that optionalsInArray cleanup code was bleeding into sibling structures. when processing sibling properties (like an Object and a Record at the same level), the cleanup state from one would pollute the other, causing it to try accessing object properties on Record values.

fixed by clearing the optionalsInArray state after use in line 130:

instruction.optionalsInArray[i + 1] = []

this prevents pollution across sibling arrays/records. tested with the minimal reproduction from the issue and it works now - returns 200 with data instead of the validation error

Summary by CodeRabbit

  • Bug Fixes

    • Fixed handling of nested arrays with optional properties to prevent data contamination across sibling structures.
  • Tests

    • Added comprehensive test suite validating nested array transformations with optional properties.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 24, 2025

Walkthrough

This PR clears entries in instruction.optionalsInArray[i + 1] after they are processed in handleRecord and array/object mirror handling, preventing optional-list pollution across sibling array processing; it also adds tests for nested arrays with optional properties.

Changes

Cohort / File(s) Summary
Core cleanup in optional handling
src/index.ts
After processing optionals linked to i + 1, the code now sets instruction.optionalsInArray[i + 1] = [] in record, object-mirror, and array-mirror paths to avoid carrying optionals between siblings. Minor formatting adjustments accompany these insertions.
New tests: nested arrays & optionals
test/array-nested-optionals.test.ts
Adds a test suite using TypeBox and createMirror/TypeCompiler to validate nested-array transformations: preservation of items (including nulls), removal of undeclared props at multiple nesting levels, and correct handling of optional properties in nested arrays.

Sequence Diagram(s)

(omitted — changes are internal cleanup and tests; no new multi-component control flow warranting a sequence diagram)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰
I hopped through arrays both deep and wide,
Cleared leftover optionals that tried to hide,
Now siblings don't borrow another's stuff,
The mirror's tidy — that's enough!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: off-by-one error in array optional cleanup' accurately and specifically describes the main change: fixing a state cleanup bug in array optional handling.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/index.ts (1)

472-484: Correct fix for the off-by-one error.

The index now correctly references optionalsInArray[i] for the current array nesting level. This matches the pattern in handleRecord and resolves the same off-by-one bug.

Note: The static analysis tool suggests wrapping the const optionals declaration in a block to scope it to this switch clause. While valid, this is a minor refinement separate from the critical bug fix.

🔎 Optional: wrap declaration in block per static analysis
 		case 'array':
+			{
 			// ... existing code ...
 
 			const optionals = instruction.optionalsInArray[i]
 			if (optionals) {
 				// optional index
 				for (let oi = 0; oi < optionals.length; oi++) {
 					// since pointer is checked in object case with ternary as undefined, this is not need
 					// const pointer = `ar${i}p.${optionals[oi]}`
 
 					const target = `ar${i}v[i]${optionals[oi]}`
 
 					// we can add semi-colon here because it delimit recursive mirror
 					v += `;if(${target}===undefined)delete ${target}`
 				}
 			}
 
 			v += `}`
 
 			if (!isRoot) v += `return ar${i}v})(${property})`
 
 			break
+			}
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 80ba8a6 and 7581081.

📒 Files selected for processing (2)
  • src/index.ts
  • test/array-nested-optionals.test.ts
🧰 Additional context used
🧬 Code graph analysis (1)
test/array-nested-optionals.test.ts (1)
src/index.ts (1)
  • createMirror (537-594)
🪛 Biome (2.1.2)
src/index.ts

[error] 472-473: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

🔇 Additional comments (2)
test/array-nested-optionals.test.ts (2)

7-63: Excellent regression test coverage.

This test comprehensively validates the fix for the off-by-one bug with a realistic scenario that includes:

  • Nested arrays with optional properties
  • Union types (including null)
  • Transform operations (Date handling)
  • Extra property removal at nested levels

The assertions confirm both data preservation and proper cleanup, directly addressing the issue described in #1623.


65-104: Strong validation of multi-level nesting.

This test ensures the fix works correctly across multiple nesting levels (outer → middle → inner arrays), confirming that optionalsInArray[i] correctly tracks and removes extra properties at each level without affecting valid data.

src/index.ts Outdated
`ar${i}v[ar${i}s[i]]=${mirror(child, `ar${i}p`, instruction)}`

const optionals = instruction.optionalsInArray[i + 1]
const optionals = instruction.optionalsInArray[i]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Correct fix for the off-by-one error.

The index now correctly references optionalsInArray[i] for the current array nesting level, matching the captured index before incrementing instruction.array. This resolves the bug where i + 1 would incorrectly access optionals from the next nested level.

🤖 Prompt for AI Agents
In src/index.ts around line 122, the code currently references the wrong nesting
level when reading optionals (it used optionalsInArray[i + 1]); change that
reference to optionalsInArray[i] so it uses the captured index for the current
array nesting level (i) rather than the next level, ensuring the index is used
before any increment to instruction.array.

The issue occurred when processing sibling arrays at the same nesting level (e.g., 'pours' and 'tags' both inside data items). After processing one array's items, its optionals remained in optionalsInArray and were incorrectly applied to the next sibling array, causing cleanup code to try deleting non-existent properties.

Solution: Clear optionalsInArray[i + 1] after using it to generate cleanup code, ensuring each array only processes its own optionals.
@MarcelOlsen
Copy link
Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Dec 26, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
test/array-nested-optionals.test.ts (2)

7-63: Consider verifying the Transform behavior.

The test validates array preservation and property removal correctly. However, the Type.Transform at lines 29-33 defines both Decode and Encode functions, but the test assertions don't verify that the transformation actually occurred on the createdAt field. Consider adding an assertion to confirm the date handling works as expected.

🔎 Optional assertion to verify transform behavior

Add after line 59:

 expect(result.data[0].tags[0].name).toBe('test')
+expect(result.data[0].createdAt).toBeInstanceOf(Date)
+expect(result.data[0].createdAt.toISOString()).toBe('2025-01-01T00:00:00.000Z')

65-104: Test suite name may not fully align with test content.

The test correctly validates nested array handling and property removal across multiple nesting levels. However, the describe block is titled "Nested Array with Optional Properties," while this specific test doesn't exercise optional properties (no Type.Optional, Type.Union([Type.Null(), ...]), etc.). The first test does include optional-like patterns, but this one focuses purely on nested arrays without optionals.

Consider either adding optional properties to this test or clarifying that the suite covers both optional and non-optional nested array scenarios.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7581081 and ae57409.

📒 Files selected for processing (2)
  • src/index.ts
  • test/array-nested-optionals.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/index.ts
🧰 Additional context used
🧬 Code graph analysis (1)
test/array-nested-optionals.test.ts (1)
src/index.ts (1)
  • createMirror (545-602)
🔇 Additional comments (1)
test/array-nested-optionals.test.ts (1)

1-5: LGTM!

The imports are correct and properly structured for testing the mirror cleaning logic with TypeBox schemas.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant