Skip to content

fix: nullable not respected for objects with nullable properties #533#1550

Open
bankyadam wants to merge 7 commits intoacacode:mainfrom
bankyadam:issue-533
Open

fix: nullable not respected for objects with nullable properties #533#1550
bankyadam wants to merge 7 commits intoacacode:mainfrom
bankyadam:issue-533

Conversation

@bankyadam
Copy link
Copy Markdown

@bankyadam bankyadam commented Dec 10, 2025

Summary

Fixes #533 - Resolves incorrect null handling for nullable parent objects containing nullable child properties.

Problem

When a schema defined a nullable object (type: object, nullable: true) with child properties that were also nullable, the generator was incorrectly adding an additional | null to the parent type. This happened because isNullMissingInType was detecting the | null from nested properties and incorrectly concluding that the parent type needed null added.

Example Issue

Given this schema:

{
  "type": "object",
  "nullable": true,
  "properties": {
    "email": { "type": "string", "nullable": true }
  }
}

Before: Generated redundant | null even though the parent was already properly nullable
After: Correctly generates { email?: string | null } | null

Solution

Refactored the isNullMissingInType method in src/schema-parser/schema-utils.ts to distinguish between:

  • Root-level nullable types (union with null at the top level)
  • Types with nested nullable properties (objects containing prop: string | null)

The fix uses regex patterns to detect only root-level null unions:

  • Pattern ending with | null
  • Pattern starting with null |
  • Exact match of null

This prevents false positives from nested nullable properties while correctly identifying when the parent type actually needs | null added.

Changes

Core Fix

  • src/schema-parser/schema-utils.ts: Improved isNullMissingInType logic with regex-based root-level null detection

Build Configuration

  • package.json: Changed ESM output extensions from .js to .mjs for better module resolution

Test Coverage

  • Added new test suite: tests/spec/nullable-parent-with-nullable-children/
  • Tests cover nullable parent objects with nullable child properties, nested nullable objects, and complex scenarios
  • Updated snapshots across multiple test suites to reflect correct nullable handling

Testing

All existing tests pass with updated snapshots showing correct nullable type generation. New test suite specifically validates the fix for nested nullable scenarios.


Note

Fixes null handling by only adding | null at the root type level, adds targeted tests, and updates snapshots accordingly.

  • Core Fix
    • Refactor src/schema-parser/schema-utils.ts:isNullMissingInType to detect only root-level null in unions (regex-based), avoiding false positives from nested nullable properties.
    • safeAddNullToType now leverages the corrected check to prevent duplicate | null on parent object types.
  • Tests
    • Add tests/spec/nullable-parent-with-nullable-children/ suite with schema and snapshot validating nullable parent + nullable children behavior.
    • Update snapshots (tests/__snapshots__/extended.test.ts.snap, tests/__snapshots__/simple.test.ts.snap, tests/spec/additional-properties-2.0/__snapshots__/basic.test.ts.snap) to reflect corrected nullability (e.g., unions with null, nullable record values).
  • Meta
    • Add changeset .changeset/giant-hats-work.md (patch).

Written by Cursor Bugbot for commit 6db9615. This will update automatically on new commits. Configure here.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Dec 10, 2025

🦋 Changeset detected

Latest commit: 9f211a3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
swagger-typescript-api Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@smorimoto
Copy link
Copy Markdown
Collaborator

smorimoto commented Dec 13, 2025

bugbot run

@acacode acacode deleted a comment from chatgpt-codex-connector Bot Dec 13, 2025
Comment thread src/schema-parser/schema-utils.ts Outdated
@js2me
Copy link
Copy Markdown
Member

js2me commented Mar 11, 2026

@bankyadam LGTM! Thanks!
please fix merge conflicts and tag me to merge this MR

@blinikar
Copy link
Copy Markdown

Hello, @bankyadam. I am writing to check whether you are able to resolve merge conflicts in your PR? It seems like you need to reabse only one small code snippet and it won't take long time.

If not, maybe I can rebase this PR for you?

@smorimoto
Copy link
Copy Markdown
Collaborator

@cubic-dev-ai

@cubic-dev-ai
Copy link
Copy Markdown

cubic-dev-ai Bot commented Apr 29, 2026

@cubic-dev-ai

@smorimoto I have started the AI code review. It will take a few minutes to complete.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 11 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/schema-parser/schema-utils.ts">

<violation number="1" location="src/schema-parser/schema-utils.ts:102">
P2: The regex check treats nested `| null |` as root-level null, so nullable parent object types can still be skipped when a child property union contains `null` in the middle.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Comment on lines +102 to +104
const hasRootLevelNull = new RegExp(
`(^|\\|)\\s*${nullKeyword}\\s*(\\||$)`,
).test(type);
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Apr 29, 2026

Choose a reason for hiding this comment

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

P2: The regex check treats nested | null | as root-level null, so nullable parent object types can still be skipped when a child property union contains null in the middle.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/schema-parser/schema-utils.ts, line 102:

<comment>The regex check treats nested `| null |` as root-level null, so nullable parent object types can still be skipped when a child property union contains `null` in the middle.</comment>

<file context>
@@ -85,14 +85,25 @@ export class SchemaUtils {
+    // Match null bounded by pipes and/or start/end of string
+    // This avoids false positives from nested nullable properties like { prop: string | null }
+    const nullKeyword = this.config.Ts.Keyword.Null;
+    const hasRootLevelNull = new RegExp(
+      `(^|\\|)\\s*${nullKeyword}\\s*(\\||$)`,
+    ).test(type);
</file context>
Suggested change
const hasRootLevelNull = new RegExp(
`(^|\\|)\\s*${nullKeyword}\\s*(\\||$)`,
).test(type);
const hasRootLevelNull = (() => {
let depth = 0;
let token = "";
for (const char of type) {
if (char === "{" || char === "(" || char === "[" || char === "<") depth++;
if (char === "}" || char === ")" || char === "]" || char === ">") {
depth = Math.max(depth - 1, 0);
}
if (char === "|" && depth === 0) {
if (token.trim() === nullKeyword) return true;
token = "";
continue;
}
token += char;
}
return token.trim() === nullKeyword;
})();
Fix with Cubic

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.

nullable: true ignored if type: object and a property has nullable: true

5 participants