Skip to content

Unification of Diagnostics#3113

Merged
RobinTail merged 13 commits intomasterfrom
unify-diagnostics
Dec 4, 2025
Merged

Unification of Diagnostics#3113
RobinTail merged 13 commits intomasterfrom
unify-diagnostics

Conversation

@RobinTail
Copy link
Copy Markdown
Owner

@RobinTail RobinTail commented Dec 2, 2025

Summary by CodeRabbit

  • Refactor

    • Consolidated diagnostics into a single per-endpoint validation flow for clearer, simpler checks.
    • Added lazy caching of flattened input schemas to reduce repeated work and improve runtime performance.
    • Enhanced logging context to include method, path and parameter details without mutating state.
  • Breaking Changes

    • Removed the separate public schema- and path-parameter check calls in favor of a single consolidated diagnostics entry — update integrations accordingly.

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

@RobinTail RobinTail added the refactoring The better way to achieve the same result label Dec 2, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 2, 2025

Walkthrough

Unified per-endpoint diagnostic state into a WeakMap of Findings; moved schema and path-parameter checks into private helpers and exposed a single public check OnEndpoint handler. Routing now calls doc.check(method, path, endpoint) instead of two separate checks. (≤50 words)

Changes

Cohort / File(s) Summary
Diagnostics core
express-zod-api/src/diagnostics.ts
Replaced multiple per-endpoint tracking structures with #verified: WeakMap<AbstractEndpoint, Findings> holding isSchemaChecked, optional cached flat schema, and verified paths; removed public checkSchema/checkPathParams; added private helpers #checkSchema / #checkPathParams that operate on a Findings ref; added public check: OnEndpoint to initialize/update Findings and delegate validation; added lazy ref.flat flattening/caching and ref.hasValidSchema short-circuiting; switched two logging context updates to object-spread ({ ...ctx, reason }) and updated param logging to include method, path, param.
Routing integration
express-zod-api/src/routing.ts
Replaced separate diagnostic calls with a single doc.check(method, path, endpoint) invocation for each endpoint, preserving per-endpoint handling but consolidating validation into the new check method.
Manifest
package.json
Present in diff metadata; no API surface changes reported.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

  • Inspect Findings lifecycle and mutation in diagnostics.ts (initialization, caching, flags).
  • Verify #checkSchema / #checkPathParams correctly reuse ref.flat and isSchemaChecked semantics.
  • Confirm logging context changes preserve content and that routing's single doc.check keeps prior error ordering/details.

Possibly related PRs

Poem

🐇 I hopped through maps and cached a clue,
One check to call, one lighter view.
I flattened fields and marked the trails,
No duplicated work, no tangled tails.
Thump-thump — diagnostics, done anew. 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Unification of Diagnostics' directly and clearly describes the main change: consolidating separate diagnostic checks into a unified approach via a new 'check' method.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch unify-diagnostics

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.

@coveralls-official
Copy link
Copy Markdown

coveralls-official Bot commented Dec 2, 2025

Coverage Status

coverage: 100.0%. remained the same
when pulling 41a74a5 on unify-diagnostics
into 631efdf on master.

@RobinTail RobinTail marked this pull request as ready for review December 3, 2025 10:05
Copy link
Copy Markdown
Contributor

@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 (1)
express-zod-api/src/diagnostics.ts (1)

12-20: Per-endpoint Cache + WeakMap design is sound; consider Set for paths as a minor improvement

The new Cache structure and #verified WeakMap give you clear per-endpoint state with proper garbage collection semantics and avoid recomputing diagnostics. That fits the “validate once per endpoint” intent well.

If you ever expect a single endpoint instance to be reused across many route paths, you could consider changing paths: string[] to a Set<string> to make membership checks (ref.paths.includes(path)) and updates more explicit and O(1):

-interface Cache {
-  hasValidSchema: boolean;
-  flat?: ReturnType<typeof flattenIO>;
-  paths: string[];
-}
+interface Cache {
+  hasValidSchema: boolean;
+  flat?: ReturnType<typeof flattenIO>;
+  paths: Set<string>;
+}
...
-    if (!ref) {
-      ref = { hasValidSchema: false, paths: [] };
+    if (!ref) {
+      ref = { hasValidSchema: false, paths: new Set() };
       this.#verified.set(endpoint, ref);
     }
...
-    if (ref.paths.includes(path)) return;
+    if (ref.paths.has(path)) return;
...
-    ref.paths.push(path);
+    ref.paths.add(path);

Purely optional; current array-based approach is fine for typical route counts.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 631efdf and 354782d.

📒 Files selected for processing (2)
  • express-zod-api/src/diagnostics.ts (3 hunks)
  • express-zod-api/src/routing.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-05-28T18:58:10.064Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2428
File: express-zod-api/src/index.ts:44-44
Timestamp: 2025-05-28T18:58:10.064Z
Learning: The type-only import `import type {} from "qs";` in express-zod-api/src/index.ts is necessary to avoid TS2742 errors for exported functions like attachRouting, makeRequestMock, testEndpoint, and testMiddleware that have types depending on types/qs. This import provides the reference TypeScript needs to infer portable type names.

Applied to files:

  • express-zod-api/src/routing.ts
  • express-zod-api/src/diagnostics.ts
📚 Learning: 2025-06-14T16:42:52.972Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2736
File: express-zod-api/tsup.config.ts:12-26
Timestamp: 2025-06-14T16:42:52.972Z
Learning: In express-zod-api tsup configurations, the direct mutation of `options.supported` in the `esbuildOptions` callback is intentional behavior and should not be flagged as a side effect issue.

Applied to files:

  • express-zod-api/src/routing.ts
📚 Learning: 2025-05-28T07:58:09.853Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2546
File: express-zod-api/src/documentation-helpers.ts:508-512
Timestamp: 2025-05-28T07:58:09.853Z
Learning: In express-zod-api, when working with Zod's JSON schema override callbacks, using `delete` to mutate `ctx.jsonSchema` is the recommended approach per Zod's official documentation, even if it triggers performance linting warnings. This is preferable to creating copies with `undefined` values, especially for snapshot testing.

Applied to files:

  • express-zod-api/src/diagnostics.ts
🧬 Code graph analysis (1)
express-zod-api/src/diagnostics.ts (5)
express-zod-api/src/json-schema-helpers.ts (1)
  • flattenIO (30-91)
express-zod-api/src/logger-helpers.ts (1)
  • ActualLogger (35-35)
express-zod-api/src/index.ts (1)
  • Method (45-45)
express-zod-api/src/common-helpers.ts (1)
  • getRoutePathParams (36-37)
express-zod-api/src/routing-walker.ts (1)
  • OnEndpoint (8-12)
🔇 Additional comments (3)
express-zod-api/src/routing.ts (1)

70-79: Unified diagnostics hook in onEndpoint looks correct

doc?.check(method, path, endpoint) cleanly aligns routing.ts with the new unified Diagnostics.check API, preserves dev-only behavior via isProduction(), and keeps onEndpoint consistent with the OnEndpoint signature from routing-walker. No issues spotted here.

express-zod-api/src/diagnostics.ts (2)

23-63: #checkSchema gating and enriched context look correct

Guarding the body with if (ref.hasValidSchema) return; ensures each endpoint’s input/output schema and JSON-compatibility checks run only once, regardless of how many routes reference that endpoint. Passing { method, path } (and { ...ctx, reason } for incompatibility warnings) into logger.warn nicely standardizes diagnostic context without mutating the ctx object. Overall, the unified schema check logic and caching flag are consistent and correct.


65-98: Path-parameter diagnostics and lazy flattenIO caching behave as intended

#checkPathParams now:

  • Skips already-seen (endpoint, path) pairs via ref.paths.
  • Avoids unnecessary work for routes without :params.
  • Lazily computes ref.flat with flattenIO and reuses it across all paths for the same endpoint.
  • Warns with { method, path, param } when a route path param is missing from the flattened input schema.

public check wires this up correctly by creating (or retrieving) the cache, then calling #checkSchema before #checkPathParams, so schema diagnostics always run at least once before any path-param analysis for a given endpoint. The overall flow matches the new unified OnEndpoint interface and integrates cleanly with routing.ts.

Copy link
Copy Markdown
Contributor

@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 (1)
express-zod-api/src/diagnostics.ts (1)

65-88: Path‑param checks and flattenIO caching are correct; consider minor tightening

The logic here looks good:

  • ref.paths dedupes checks per (endpoint, path) pair.
  • flattenIO is computed lazily only when there are actual :params in the path and then reused via ref.flat ??= ..., avoiding repeated JSON‑schema flattening for the same endpoint.
  • Using getRoutePathParams(path) and then checking param in ref.flat.properties is consistent with how flattenIO constructs its properties.

One small optional refinement for readability and type‑narrowing:

-    ref.flat ??= flattenIO(
-      z.toJSONSchema(endpoint.inputSchema, {
-        unrepresentable: "any",
-        io: "input",
-      }),
-    );
+    const flat =
+      (ref.flat ??=
+        flattenIO(
+          z.toJSONSchema(endpoint.inputSchema, {
+            unrepresentable: "any",
+            io: "input",
+          }),
+        ));
@@
-    for (const param of params) {
-      if (param in ref.flat.properties) continue;
+    for (const param of params) {
+      if (param in flat.properties) continue;
       this.logger.warn(
         "The input schema of the endpoint is most likely missing the parameter of the path it's assigned to.",
         { method, path, param },
       );

This keeps the flatten result in a clearly non‑optional local (flat) while still benefiting from the cache on ref.flat.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 354782d and b7ca6e2.

📒 Files selected for processing (1)
  • express-zod-api/src/diagnostics.ts (3 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-05-28T18:58:10.064Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2428
File: express-zod-api/src/index.ts:44-44
Timestamp: 2025-05-28T18:58:10.064Z
Learning: The type-only import `import type {} from "qs";` in express-zod-api/src/index.ts is necessary to avoid TS2742 errors for exported functions like attachRouting, makeRequestMock, testEndpoint, and testMiddleware that have types depending on types/qs. This import provides the reference TypeScript needs to infer portable type names.

Applied to files:

  • express-zod-api/src/diagnostics.ts
📚 Learning: 2025-06-14T16:42:52.972Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2736
File: express-zod-api/tsup.config.ts:12-26
Timestamp: 2025-06-14T16:42:52.972Z
Learning: In express-zod-api tsup configurations, the direct mutation of `options.supported` in the `esbuildOptions` callback is intentional behavior and should not be flagged as a side effect issue.

Applied to files:

  • express-zod-api/src/diagnostics.ts
📚 Learning: 2025-05-28T07:58:09.853Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2546
File: express-zod-api/src/documentation-helpers.ts:508-512
Timestamp: 2025-05-28T07:58:09.853Z
Learning: In express-zod-api, when working with Zod's JSON schema override callbacks, using `delete` to mutate `ctx.jsonSchema` is the recommended approach per Zod's official documentation, even if it triggers performance linting warnings. This is preferable to creating copies with `undefined` values, especially for snapshot testing.

Applied to files:

  • express-zod-api/src/diagnostics.ts
🧬 Code graph analysis (1)
express-zod-api/src/diagnostics.ts (6)
express-zod-api/src/json-schema-helpers.ts (1)
  • flattenIO (30-91)
express-zod-api/src/logger-helpers.ts (1)
  • ActualLogger (35-35)
express-zod-api/src/index.ts (1)
  • Method (45-45)
express-zod-api/src/endpoint.ts (1)
  • params (264-284)
express-zod-api/src/common-helpers.ts (1)
  • getRoutePathParams (36-37)
express-zod-api/src/routing-walker.ts (1)
  • OnEndpoint (8-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build (24.x)
  • GitHub Check: build (22.12.0)
🔇 Additional comments (4)
express-zod-api/src/diagnostics.ts (4)

3-11: Imports and new public callback shape look consistent

The added imports (getRoutePathParams, Method, OnEndpoint) line up with the new unified check(method, path, endpoint) callback and the existing helper APIs, and keep type usage centralized in routing-walker.


12-20: Per-endpoint Cache + WeakMap design is sound

The Cache interface and #verified = new WeakMap<AbstractEndpoint, Cache>() cleanly centralize per-endpoint diagnostics state (schema validity flag, flattened input schema, and visited paths) without risking leaks. This unifies previous ad-hoc tracking while ensuring GC can still reclaim endpoints.


23-63: Schema check short‑circuiting and enriched log context look correct

  • Guarding #checkSchema with if (ref.hasValidSchema) return; correctly ensures each endpoint’s schemas are scanned only once per Diagnostics instance, independent of how many routes point to it.
  • Passing { method, path } and then { ...ctx, reason } into logger.warn keeps log context structured and avoids mutating the original ctx object, which is safer if it’s ever reused.
  • Finalizing with ref.hasValidSchema = true after all checks ensures JSON‑compat issues are still reported on first invocation while preventing redundant work later.

No functional or type-safety issues apparent in this block.


90-98: Unified check entry point aligns with OnEndpoint and cache usage

The new public check: OnEndpoint = (method, path, endpoint) => { ... } correctly:

  • Reuses or initializes a single Cache per AbstractEndpoint.
  • Delegates to #checkSchema and #checkPathParams with the right arguments and context.
  • Matches the OnEndpoint type used by the routing walker, so integration should remain type‑safe.

This provides a clean, single diagnostics hook for routing.

Copy link
Copy Markdown
Owner Author

@RobinTail RobinTail left a comment

Choose a reason for hiding this comment

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

🏁 ready

Copy link
Copy Markdown
Contributor

@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 (1)
express-zod-api/src/diagnostics.ts (1)

89-97: Clean public API with unified diagnostic flow.

The new check method provides a single entry point that consolidates schema and path-parameter validation. The implementation correctly initializes or reuses the per-endpoint Findings state and delegates to the private helpers.

Minor observation: The context passed to the private helpers differs slightly—#checkSchema receives { method, path } while #checkPathParams receives { method } (with path added later in the log statement). This is intentional since path is a required parameter for #checkPathParams logic, but you could consider passing { method, path } to both for consistency. The current approach is valid and works correctly.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a860225 and 41a74a5.

📒 Files selected for processing (1)
  • express-zod-api/src/diagnostics.ts (3 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-05-28T07:58:09.853Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2546
File: express-zod-api/src/documentation-helpers.ts:508-512
Timestamp: 2025-05-28T07:58:09.853Z
Learning: In express-zod-api, when working with Zod's JSON schema override callbacks, using `delete` to mutate `ctx.jsonSchema` is the recommended approach per Zod's official documentation, even if it triggers performance linting warnings. This is preferable to creating copies with `undefined` values, especially for snapshot testing.

Applied to files:

  • express-zod-api/src/diagnostics.ts
📚 Learning: 2025-05-28T18:58:10.064Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2428
File: express-zod-api/src/index.ts:44-44
Timestamp: 2025-05-28T18:58:10.064Z
Learning: The type-only import `import type {} from "qs";` in express-zod-api/src/index.ts is necessary to avoid TS2742 errors for exported functions like attachRouting, makeRequestMock, testEndpoint, and testMiddleware that have types depending on types/qs. This import provides the reference TypeScript needs to infer portable type names.

Applied to files:

  • express-zod-api/src/diagnostics.ts
🧬 Code graph analysis (1)
express-zod-api/src/diagnostics.ts (3)
express-zod-api/src/json-schema-helpers.ts (1)
  • flattenIO (30-91)
express-zod-api/src/common-helpers.ts (2)
  • FlatObject (20-20)
  • getRoutePathParams (36-37)
express-zod-api/src/routing-walker.ts (1)
  • OnEndpoint (8-12)
🔇 Additional comments (4)
express-zod-api/src/diagnostics.ts (4)

9-15: Excellent consolidation of diagnostic state.

The new Findings interface elegantly unifies per-endpoint tracking. Using an optional flat property enables lazy initialization, and the Set<string> for paths provides efficient lookups.


18-18: LGTM: WeakMap provides automatic cleanup.

Using WeakMap<AbstractEndpoint, Findings> ensures that diagnostic state is garbage collected when endpoints are no longer referenced, preventing memory leaks.


22-62: LGTM: Good encapsulation and improved immutability.

Making this method private and operating on a Findings reference consolidates state management. The switch from Object.assign(ctx, { reason }) to { ...ctx, reason } (lines 45, 56) is a nice improvement that avoids mutating the context object.


64-87: LGTM: Excellent lazy initialization optimization.

The lazy initialization of ref.flat (lines 73-78) using the nullish coalescing assignment operator is a smart performance optimization—the expensive flattening only happens when path parameters exist and haven't been checked yet. The early returns and state tracking via ref ensure efficient, non-redundant validation.

@RobinTail RobinTail merged commit 9cca6e9 into master Dec 4, 2025
13 checks passed
@RobinTail RobinTail deleted the unify-diagnostics branch December 4, 2025 07:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactoring The better way to achieve the same result

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant