Skip to content

fix: removeFMTableNames types - #68

Merged
eluce2 merged 2 commits into
mainfrom
08-21-fix_removefmtablenames_types
Aug 22, 2025
Merged

fix: removeFMTableNames types#68
eluce2 merged 2 commits into
mainfrom
08-21-fix_removefmtablenames_types

Conversation

@eluce2

@eluce2 eluce2 commented Aug 21, 2025

Copy link
Copy Markdown
Collaborator

fix: removeFMTableNames types

fix: update FM table names for consistency

Summary by CodeRabbit

  • New Release

    • Patch release for improved reliability in data handling.
  • Refactor

    • Enhanced type-safety and stability of the key-stripping logic used for cleaning field names, with no expected impact on typical usage.
  • Tests

    • Added comprehensive runtime and type-level tests to verify correct key stripping and preservation of non-prefixed fields.
  • Chores

    • Introduced dedicated TypeScript configurations for tests.
    • Added a release note entry describing the patch.

@eluce2
eluce2 marked this pull request as ready for review August 21, 2025 14:56

eluce2 commented Aug 21, 2025

Copy link
Copy Markdown
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@vercel

vercel Bot commented Aug 21, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
proofkit-docs Ready Ready Preview Aug 21, 2025 2:59pm

@pkg-pr-new

pkg-pr-new Bot commented Aug 21, 2025

Copy link
Copy Markdown

Open in StackBlitz

@proofkit/better-auth

pnpm add https://pkg.pr.new/proofgeist/proofkit/@proofkit/better-auth@68

@proofkit/cli

pnpm add https://pkg.pr.new/proofgeist/proofkit/@proofkit/cli@68

create-proofkit

pnpm add https://pkg.pr.new/proofgeist/proofkit/create-proofkit@68

@proofkit/fmdapi

pnpm add https://pkg.pr.new/proofgeist/proofkit/@proofkit/fmdapi@68

@proofkit/typegen

pnpm add https://pkg.pr.new/proofgeist/proofkit/@proofkit/typegen@68

@proofkit/webviewer

pnpm add https://pkg.pr.new/proofgeist/proofkit/@proofkit/webviewer@68

commit: a8d88ef

@coderabbitai

coderabbitai Bot commented Aug 21, 2025

Copy link
Copy Markdown

Walkthrough

Refactors removeFMTableNames in packages/fmdapi/src/utils.ts to use a mapped-type approach for key stripping and updates its generic constraint. Adds unit and type-checking tests for this behavior and introduces test-specific TypeScript configurations. Adds a changeset entry documenting a patch release for @proofkit/fmdapi.

Changes

Cohort / File(s) Summary
Release notes
.changeset/swift-swans-rush.md
Adds a patch changeset for @proofkit/fmdapi noting the updated removeFMTableNames type-safety.
Utilities refactor
packages/fmdapi/src/utils.ts
Replaces ts-toolbelt-based types with mapped types; implements key suffix stripping (after "::") in removeFMTableNames; updates signature to T extends object and returns TransformedFields.
Tests
packages/fmdapi/tests/removeFMTableNames.test.ts, packages/fmdapi/tests/tsconfig.json, packages/fmdapi/tests/tsconfig.typecheck.json
Adds runtime and type-level tests for key stripping; introduces test tsconfigs for vitest and isolated type-checking.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Caller
  participant Utils as removeFMTableNames
  Caller->>Utils: removeFMTableNames(obj: T)
  activate Utils
  Note right of Utils: Iterate Object.entries(obj)
  loop for each [key, value]
    Utils->>Utils: Compute mappedKey = key without "::..." suffix (if present)
    Utils->>Utils: Assign newObj[mappedKey] = value
  end
  Utils-->>Caller: newObj as TransformedFields<T>
  deactivate Utils
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • chriscors

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 08-21-fix_removefmtablenames_types

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (5)
packages/fmdapi/tests/tsconfig.typecheck.json (1)

2-13: Type-check config looks solid; consider trimming JSX and tightening compiler flags.

  • "jsx": "react-jsx" is unnecessary for a pure type-check suite without JSX. Removing it avoids pulling React typings accidentally.
  • Optional hardening that often catches subtle issues in mapped-type-heavy code:
    • exactOptionalPropertyTypes: true
    • verbatimModuleSyntax: true

Apply this diff if you agree:

   "compilerOptions": {
     "strict": true,
     "target": "ES2022",
     "module": "ESNext",
     "moduleResolution": "Bundler",
-    "jsx": "react-jsx",
     "skipLibCheck": true,
     "noEmit": true,
     "isolatedModules": true,
-    "types": ["node"]
+    "types": ["node"],
+    "verbatimModuleSyntax": true,
+    "exactOptionalPropertyTypes": true
   },
packages/fmdapi/src/utils.ts (1)

19-21: Minor: avoid intermediate array allocation.

If you keep “first ::” semantics, prefer indexOf + slice over split to reduce allocations in hot paths.

-    const mappedKey = (
-      typeof key === "string" && key.includes("::") ? key.split("::")[1] : key
-    ) as keyof TransformedFields<T>;
+    const mappedKey = (() => {
+      if (typeof key !== "string") return key;
+      const i = key.indexOf("::");
+      return (i === -1 ? key : key.slice(i + 2)) as keyof TransformedFields<T>;
+    })();
.changeset/swift-swans-rush.md (1)

1-6: Changelog entry reads well and matches the patch scope.

Clear and concise. If you adopt the “last ::” semantics (or any behavior change), consider explicitly noting it to help downstream consumers.

packages/fmdapi/tests/tsconfig.json (1)

1-10: Test tsconfig looks appropriate for Vitest; optional small hardening.

  • Consider adding verbatimModuleSyntax: true to better align with “Bundler” resolution in modern setups.
  • You can also exclude transpiled artifacts like ../coverage if produced by CI.
   "compilerOptions": {
     "noEmit": true,
     "types": ["vitest", "node"],
-    "isolatedModules": true
+    "isolatedModules": true,
+    "verbatimModuleSyntax": true
   },
-  "include": ["./**/*.ts"],
-  "exclude": ["../dist", "../schema"]
+  "include": ["./**/*.ts"],
+  "exclude": ["../dist", "../schema", "../coverage"]
packages/fmdapi/tests/removeFMTableNames.test.ts (1)

5-20: Add a guard-rail test for multiple '::' segments and key collisions.

To lock semantics and detect regressions related to the type/runtime split logic, add:

   it("strips FM table prefixes from keys and preserves values", () => {
     // existing…
   });
+
+  it("handles multiple '::' segments and resolves collisions deterministically", () => {
+    const input = {
+      "A::B::name": "v1",
+      "A::name": "v2",
+    } as const;
+    const out = removeFMTableNames(input);
+    // Decide on semantics (first or last '::'); adjust expectation accordingly.
+    // If last '::': both map to "name" and the latter wins in insertion order.
+    expect(out).toEqual({ name: "v2" });
+  });

This locks ordering and “first vs last” behavior explicitly.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2031c21 and a8d88ef.

📒 Files selected for processing (5)
  • .changeset/swift-swans-rush.md (1 hunks)
  • packages/fmdapi/src/utils.ts (1 hunks)
  • packages/fmdapi/tests/removeFMTableNames.test.ts (1 hunks)
  • packages/fmdapi/tests/tsconfig.json (1 hunks)
  • packages/fmdapi/tests/tsconfig.typecheck.json (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/fmdapi/tests/removeFMTableNames.test.ts (1)
packages/fmdapi/src/utils.ts (1)
  • removeFMTableNames (12-29)
⏰ 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
  • GitHub Check: build
🔇 Additional comments (3)
packages/fmdapi/src/utils.ts (2)

8-11: Mapped-type remap is clean and precise.

Key remapping via TransformedFields is concise and correctly preserves value types (with unions on collisions). LGTM.


12-14: Confirm acceptable inputs for T extends object (arrays, functions, class instances).

Shifting from Record<string, any> to object admits arrays, functions, and instances. Runtime iterates keys and may produce surprising shapes for arrays (stringified indices) and will ignore non-enumerables on class instances.

  • If only plain records are intended, consider narrowing to Record<PropertyKey, unknown> or add a runtime check to exclude arrays.
  • Otherwise, add a test demonstrating expected behavior for arrays and symbol keys.
packages/fmdapi/tests/removeFMTableNames.test.ts (1)

5-20: Runtime behavior test is clear and valuable.

Covers positive case and ensures prefixed keys are removed. Nice.

Comment on lines +4 to +6
type StripFMTableName<K extends PropertyKey> = K extends `${string}::${infer R}`
? R
: K;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Type/runtime mismatch: StripFMTableName uses “last ::” while runtime uses “first ::”.

Currently, the type-level mapper strips after the last '::' (due to ${string}::${infer R} greediness), while the runtime uses key.split("::")[1] (after the first). For keys containing multiple '::', the returned object’s keys won’t match its static type.

Pick ONE of the following to align behavior:

Option A — make runtime match the type (strip after the last '::'):

-    const mappedKey = (
-      typeof key === "string" && key.includes("::") ? key.split("::")[1] : key
-    ) as keyof TransformedFields<T>;
+    const idx = key.lastIndexOf("::");
+    const mappedKey = (
+      typeof key === "string" && idx !== -1 ? key.slice(idx + 2) : key
+    ) as keyof TransformedFields<T>;

Option B — make the type match the runtime (strip after the first '::'):

-type StripFMTableName<K extends PropertyKey> = K extends `${string}::${infer R}`
+type StripFMTableName<K extends PropertyKey> = K extends `${infer _}::${infer R}`
   ? R
   : K;

If you have domain certainty that keys never contain more than one '::', add a test to lock that invariant; otherwise, I recommend Option A (safer in the presence of extra qualifiers).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
type StripFMTableName<K extends PropertyKey> = K extends `${string}::${infer R}`
? R
: K;
type StripFMTableName<K extends PropertyKey> = K extends `${infer _}::${infer R}`
? R
: K;

Comment on lines 16 to 27
for (const key in obj) {
if (key.includes("::")) {
const newKey = key.split("::")[1];
newObj[newKey as keyof TransformedFields<T>] = obj[key];
} else {
newObj[key] = obj[key];
}
const originalKey = key as keyof T;
const value = obj[originalKey];
const mappedKey = (
typeof key === "string" && key.includes("::") ? key.split("::")[1] : key
) as keyof TransformedFields<T>;

// Use a temporary index signature cast to assign without any
(newObj as unknown as Record<PropertyKey, unknown>)[
mappedKey as unknown as PropertyKey
] = value as unknown;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid copying inherited enumerable properties; restrict to own keys.

for..in iterates inherited enumerable props. That can silently pull in prototype properties. Add a hasOwnProperty guard (minimal change), or iterate Object.keys/Reflect.ownKeys instead.

Minimal, surgical fix:

-  for (const key in obj) {
+  for (const key in obj) {
+    if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
     const originalKey = key as keyof T;
     const value = obj[originalKey];

If you want to also preserve symbol keys (currently dropped), consider Reflect.ownKeys:

-  for (const key in obj) {
-    const originalKey = key as keyof T;
-    const value = obj[originalKey];
+  for (const k of Reflect.ownKeys(obj)) {
+    const key = k as keyof T;
+    const value = (obj as Record<PropertyKey, unknown>)[k];

…and keep the mappedKey logic the same (only transform when typeof k === "string").

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (const key in obj) {
if (key.includes("::")) {
const newKey = key.split("::")[1];
newObj[newKey as keyof TransformedFields<T>] = obj[key];
} else {
newObj[key] = obj[key];
}
const originalKey = key as keyof T;
const value = obj[originalKey];
const mappedKey = (
typeof key === "string" && key.includes("::") ? key.split("::")[1] : key
) as keyof TransformedFields<T>;
// Use a temporary index signature cast to assign without any
(newObj as unknown as Record<PropertyKey, unknown>)[
mappedKey as unknown as PropertyKey
] = value as unknown;
}
for (const key in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
const originalKey = key as keyof T;
const value = obj[originalKey];
const mappedKey = (
typeof key === "string" && key.includes("::") ? key.split("::")[1] : key
) as keyof TransformedFields<T>;
// Use a temporary index signature cast to assign without any
(newObj as unknown as Record<PropertyKey, unknown>)[
mappedKey as unknown as PropertyKey
] = value as unknown;
}
🤖 Prompt for AI Agents
In packages/fmdapi/src/utils.ts around lines 16 to 27, the for..in loop
currently iterates inherited enumerable properties; change it to only process
the object's own keys by either adding a hasOwnProperty guard inside the loop
(if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;) or replace the
loop with Object.keys(obj).forEach(...) to iterate own string keys; if you need
to preserve symbol keys instead use Reflect.ownKeys(obj).forEach and keep the
existing mappedKey transformation logic unchanged.

Comment on lines +22 to +49
it("produces a type with stripped keys", () => {
type Input = {
"Customer::first_name": string;
last_name: string;
"Portal::recordId": number;
};

const input: Input = {
"Customer::first_name": "Bob",
last_name: "Builder",
"Portal::recordId": 42,
};
const out = removeFMTableNames(input);

// Type-level assertions via assignment
const first: string = out.first_name;
const last: string = out.last_name;
const recId: number = out.recordId;
expect(first).toBe("Bob");
expect(last).toBe("Builder");
expect(recId).toBe(42);

// Old keys should not exist on the resulting type
// @ts-expect-error - old FM-prefixed key should not exist on result type
out["Customer::first_name"];
// @ts-expect-error - old FM-prefixed key should not exist on result type
out["Portal::recordId"];
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

ts-expect-error in runtime tests isn’t enforced by Vitest; wire up the dedicated type-check instead.

Vitest (via esbuild) doesn’t type-check by default, so the @ts-expect-error assertions here won’t fail builds. You already added a dedicated type-check config—great. Ensure CI runs it.

Run locally/CI:

Optionally, move the @ts-expect-error assertions to packages/fmdapi/tests/type/removeFMTableNames.typecheck.ts to keep runtime tests focused.


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Type-check only:
npx -y tsc -p packages/fmdapi/tests/tsconfig.typecheck.json --noEmit

Length of output: 556


Type-check setup is broken – CI will fail until it’s fixed

The dedicated type-check command (npx tsc -p packages/fmdapi/tests/tsconfig.typecheck.json --noEmit) currently errors out:

  • TS2688: Cannot find type definition file for 'node'
  • TS6053: File packages/fmdapi/tests/type/removeFMTableNames.typecheck.ts not found

You need to:

  • Add the missing Node type defs (npm install -D @types/node) so tsc can find the node library.
  • Either create the expected type-check file (packages/fmdapi/tests/type/removeFMTableNames.typecheck.ts)—moving just the @ts-expect-error lines from the runtime test into it—or update tsconfig.typecheck.json’s files list to point at your existing .test.ts file.

Once the above is addressed, ensure your CI invokes:

npx tsc -p packages/fmdapi/tests/tsconfig.typecheck.json --noEmit

so that any stray or missing @ts-expect-error assertions will fail the build rather than slip through Vitest’s runtime tests.

🤖 Prompt for AI Agents
packages/fmdapi/tests/removeFMTableNames.test.ts lines 22-49: Type-check CI is
failing because Node type defs are missing and the type-check harness expects a
separate file; install dev dependency @types/node (npm i -D @types/node) so tsc
finds the node lib, then either create
packages/fmdapi/tests/type/removeFMTableNames.typecheck.ts containing the two
@ts-expect-error lines moved out of the runtime test OR update
packages/fmdapi/tests/tsconfig.typecheck.json’s "files" array to point at the
existing .test.ts file, and finally ensure CI invokes npx tsc -p
packages/fmdapi/tests/tsconfig.typecheck.json --noEmit so type-level
@ts-expect-error assertions fail the build if incorrect.

Comment on lines +2 to +13
"compilerOptions": {
"strict": true,
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"jsx": "react-jsx",
"skipLibCheck": true,
"noEmit": true,
"isolatedModules": true,
"types": ["node"]
},
"files": ["./type/removeFMTableNames.typecheck.ts"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Ensure your toolchain TS version supports moduleResolution: "Bundler".

Bundler resolution requires a relatively recent TypeScript. Please confirm your CI/runner uses a compatible TS version; otherwise, this config will be ignored or fail.

You can verify with:


🏁 Script executed:

#!/bin/bash
# Expect TS >= 5.x supporting "Bundler" moduleResolution.
npx -y tsc -v
# Also prove the typecheck config compiles:
npx -y tsc -p packages/fmdapi/tests/tsconfig.typecheck.json --noEmit

Length of output: 677


Fix TypeScript type‐check configuration errors

Verification shows your CI is using TypeScript 5.9.2, so moduleResolution: "Bundler" is supported. However, the type-check step is failing:

• TS2688: Cannot find type definition file for ‘node’.
• TS6053: File ‘packages/fmdapi/tests/type/removeFMTableNames.typecheck.ts’ not found.

To resolve:

  • Ensure Node.js type definitions are installed for this project. For example, in packages/fmdapi, run:
    npm install --save-dev @types/node
    or add "@types/node": "…" under devDependencies.
  • Correct the path in packages/fmdapi/tests/tsconfig.typecheck.json so it matches where the .typecheck.ts file actually lives. For example, if the file is in tests/types/, update:
      "compilerOptions": {
        "types": ["node"],
        …
      },
      "files": [
    -   "./type/removeFMTableNames.typecheck.ts"
    +   "./types/removeFMTableNames.typecheck.ts"
      ]
    Otherwise, adjust to the correct subdirectory or move the file.

After making these fixes, re-run:

npx tsc -v
npx tsc -p packages/fmdapi/tests/tsconfig.typecheck.json --noEmit
🤖 Prompt for AI Agents
packages/fmdapi/tests/tsconfig.typecheck.json lines 2-13: The typecheck config
is failing because Node.js types are missing (TS2688) and the referenced
typecheck file path is incorrect (TS6053); install or add "@types/node" to
devDependencies in packages/fmdapi (e.g., npm install --save-dev @types/node or
add the exact version to package.json) and update the "files" entry to the real
location of removeFMTableNames.typecheck.ts (or move the file to match the path)
so tsc can find it, then re-run the typecheck command.

@eluce2
eluce2 merged commit d9de836 into main Aug 22, 2025
7 checks passed
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