@@ -271,6 +271,109 @@ describe("fmodata generateODataTypes preserves user customizations", () => {
271271 }
272272 } ) ;
273273
274+ it ( "preserves top-level validator helpers referenced by field chains" , async ( ) => {
275+ const tmpDir = await fs . mkdtemp ( path . join ( os . tmpdir ( ) , "proofkit-fmodata-preserve-" ) ) ;
276+
277+ try {
278+ const entitySetName = "User" ;
279+ const entityTypeName = "NS.User" ;
280+ const metadata = makeMetadata ( {
281+ entitySetName,
282+ entityTypeName,
283+ fields : [ { name : "contact_json" , type : "Edm.String" , fieldId : "F1" } ] ,
284+ } ) ;
285+
286+ const existingFilePath = path . join ( tmpDir , "User.ts" ) ;
287+ await fs . writeFile (
288+ existingFilePath ,
289+ [
290+ `import { fmTableOccurrence, textField } from "@proofkit/fmodata";` ,
291+ `import { z } from "zod/v4";` ,
292+ "" ,
293+ "const ZContactJson = z.union([z.string(), z.null(), z.undefined()]).transform((s) => s);" ,
294+ "" ,
295+ `export const User = fmTableOccurrence("User", {` ,
296+ ` contact_json: textField().entityId("F1").readValidator(ZContactJson),` ,
297+ "}, {" ,
298+ ` entityId: "T1",` ,
299+ "});" ,
300+ "" ,
301+ ] . join ( "\n" ) ,
302+ "utf8" ,
303+ ) ;
304+
305+ await generateODataTypes ( metadata , {
306+ type : "fmodata" ,
307+ path : tmpDir ,
308+ clearOldFiles : false ,
309+ tables : [ { tableName : "User" } ] ,
310+ } ) ;
311+
312+ const regenerated = await fs . readFile ( existingFilePath , "utf8" ) ;
313+ expect ( regenerated ) . toContain ( "const ZContactJson = z" ) ;
314+ expect ( regenerated ) . toContain ( ".union([z.string(), z.null(), z.undefined()])" ) ;
315+ expect ( regenerated ) . toContain ( ".transform((s) => s);" ) ;
316+ expect ( regenerated ) . toContain ( `contact_json: textField().entityId("F1").readValidator(ZContactJson)` ) ;
317+ } finally {
318+ await fs . rm ( tmpDir , { recursive : true , force : true } ) ;
319+ }
320+ } ) ;
321+
322+ it ( "preserves unrelated top-level imports and helper code" , async ( ) => {
323+ const tmpDir = await fs . mkdtemp ( path . join ( os . tmpdir ( ) , "proofkit-fmodata-preserve-" ) ) ;
324+
325+ try {
326+ const entitySetName = "Project" ;
327+ const entityTypeName = "NS.Project" ;
328+ const metadata = makeMetadata ( {
329+ entitySetName,
330+ entityTypeName,
331+ fields : [ { name : "status" , type : "Edm.String" , fieldId : "F1" } ] ,
332+ } ) ;
333+
334+ const existingFilePath = path . join ( tmpDir , "Project.ts" ) ;
335+ await fs . writeFile (
336+ existingFilePath ,
337+ [
338+ `import { fmTableOccurrence, textField } from "@proofkit/fmodata";` ,
339+ `import { DateTime } from "luxon";` ,
340+ "" ,
341+ `const STATUS_LABELS = new Map([["open", "Open"]]);` ,
342+ `function getGeneratedAt() {` ,
343+ ` return DateTime.utc().toISO();` ,
344+ `}` ,
345+ "" ,
346+ `export const generatedAt = getGeneratedAt();` ,
347+ "" ,
348+ `export const Project = fmTableOccurrence("Project", {` ,
349+ ` status: textField().entityId("F1"),` ,
350+ "}, {" ,
351+ ` entityId: "T1",` ,
352+ "});" ,
353+ "" ,
354+ ] . join ( "\n" ) ,
355+ "utf8" ,
356+ ) ;
357+
358+ await generateODataTypes ( metadata , {
359+ type : "fmodata" ,
360+ path : tmpDir ,
361+ clearOldFiles : false ,
362+ tables : [ { tableName : "Project" } ] ,
363+ } ) ;
364+
365+ const regenerated = await fs . readFile ( existingFilePath , "utf8" ) ;
366+ expect ( regenerated ) . toContain ( `import { DateTime } from "luxon";` ) ;
367+ expect ( regenerated ) . toContain ( `const STATUS_LABELS = new Map([["open", "Open"]]);` ) ;
368+ expect ( regenerated ) . toContain ( `function getGeneratedAt()` ) ;
369+ expect ( regenerated ) . toContain ( `return DateTime.utc().toISO();` ) ;
370+ expect ( regenerated ) . toContain ( `export const generatedAt = getGeneratedAt();` ) ;
371+ expect ( regenerated ) . toContain ( `status: textField().entityId("F1")` ) ;
372+ } finally {
373+ await fs . rm ( tmpDir , { recursive : true , force : true } ) ;
374+ }
375+ } ) ;
376+
274377 it ( "preserves custom validators and removes stale files when clearOldFiles is true" , async ( ) => {
275378 const tmpDir = await fs . mkdtemp ( path . join ( os . tmpdir ( ) , "proofkit-fmodata-preserve-" ) ) ;
276379
0 commit comments