ts-to-zod icon indicating copy to clipboard operation
ts-to-zod copied to clipboard

JSDoc are ignored

Open bisubus opened this issue 3 years ago • 11 comments

Bug description

JSDoc are ignored and not processed in schema output. I couldn't investigate why this happens but it appears that parsed jsDoc array is always empty at this line. The parser doesn't recognize other JSDoc (@type) at this point.

The library runs programmatically:

  generate({
      sourceText: data,
      keepComments: true,
    });

Same for CLI, with and without keepComments option.

Input

The same example as in documentation:

export interface HeroContact {
  /**
   * The email of the hero.
   *
   * @format email
   */
  email: string;

  /**
   * The name of the hero.
   *
   * @minLength 2
   * @maxLength 50
   */
  name: string;

  /**
   * The phone number of the hero.
   *
   * @pattern ^([+]?d{1,2}[-s]?|)d{3}[-s]?d{3}[-s]?d{4}$
   */
  phoneNumber: string;

  /**
   * Does the hero has super power?
   *
   * @default true
   */
  hasSuperPower?: boolean;

  /**
   * The age of the hero
   *
   * @minimum 0
   * @maximum 500
   */
  age: number;
}

Expected output

Should be same as in docs:

export const heroContactSchema = z.object({
  /**
   * The email of the hero.
   *
   * @format email
   */
  email: z.string().email(),

  /**
   * The name of the hero.
   *
   * @minLength 2
   * @maxLength 50
   */
  name: z.string().min(2).max(50),

  /**
   * The phone number of the hero.
   *
   * @pattern ^([+]?d{1,2}[-s]?|)d{3}[-s]?d{3}[-s]?d{4}$
   */
  phoneNumber: z.string().regex(/^([+]?d{1,2}[-s]?|)d{3}[-s]?d{3}[-s]?d{4}$/),

  /**
   * Does the hero has super power?
   *
   * @default true
   */
  hasSuperPower: z.boolean().default(true),

  /**
   * The age of the hero
   *
   * @minimum 0
   * @maximum 500
   */
  age: z.number().min(0).max(500),
});

Actual output

JSDocs are ignored in schema output:

export const heroContactSchema = z.object({
    /**
     * The email of the hero.
     *
     * @format email
     */
    email: z.string(),
    /**
     * The name of the hero.
     *
     * @minLength 2
     * @maxLength 50
     */
    name: z.string(),
    /**
     * The phone number of the hero.
     *
     * @pattern ^([+]?d{1,2}[-s]?|)d{3}[-s]?d{3}[-s]?d{4}$
     */
    phoneNumber: z.string(),
    /**
     * Does the hero has super power?
     *
     * @default true
     */
    hasSuperPower: z.boolean(),
    /**
     * The age of the hero
     *
     * @minimum 0
     * @maximum 500
     */
    age: z.number()
});

Intermediate type output contains no changes, only indentation:

export interface HeroContact {
    /**
     * The email of the hero.
     *
     * @format email
     */
    email: string;
    /**
     * The name of the hero.
     *
     * @minLength 2
     * @maxLength 50
     */
    name: string;
    /**
     * The phone number of the hero.
     *
     * @pattern ^([+]?d{1,2}[-s]?|)d{3}[-s]?d{3}[-s]?d{4}$
     */
    phoneNumber: string;
    /**
     * Does the hero has super power?
     *
     * @default true
     */
    hasSuperPower: boolean;
    /**
     * The age of the hero
     *
     * @minimum 0
     * @maximum 500
     */
    age: number;
}

Versions

  • node v14.17.3
  • ts-to-zod: v1.5.2
  • Typescript: v4.2.3 (ts-to-zod own dependency)
  • Zod: v3.11.2 (ts-to-zod own dependency)

bisubus avatar Oct 24 '21 18:10 bisubus

Very very strange 🤔 Can you clone the repo and run the tests? or tell me more about your setup, I just tried, and I can’t repro (with or without keepComments) and we have a lot of unit tests on this part, so I’m very confused 😕

fabien0102 avatar Oct 25 '21 14:10 fabien0102

The repro is here, https://github.com/bisubus/tsutil-demo . I isolated the problem. It was that tsutil was hoisted from node_modules/ts-to-zod/tsutils (located next to node_modules/ts-to-zod/typescript v4.2.3) to node_modules/tsutils (located next to node_modules/typescript v4.4.3). The problem goes away when node_modules/typescript is replaced with v4.2.3

yarn why tsutils:

[1/4] Why do we have the module "tsutils"...?                                                                                              
[2/4] Initialising dependency graph...                                                                                                     
[3/4] Finding dependency...                                                                                                                
[4/4] Calculating file sizes...                                                                                                            
=> Found "[email protected]"                                                                                                                  
info Reasons this module exists                                                                                                            
   - "@typescript-eslint#eslint-plugin" depends on it                                                                                      
   - Hoisted from "@typescript-eslint#eslint-plugin#tsutils"                                                                               
   - Hoisted from "ts-to-zod#tsutils"                                                                                                      
   - Hoisted from "@typescript-eslint#eslint-plugin#@typescript-eslint#experimental-utils#@typescript-eslint#typescript-estree#tsutils"    
info Disk size without dependencies: "648KB"                                                                                               
info Disk size with unique dependencies: "720KB"                                                                                           
info Disk size with transitive dependencies: "720KB"                                                                                       
info Number of shared dependencies: 1                                                                                                      

Also got the same problem with @typescript-eslint/eslint-plugin because it's not workable when tsutils is hoisted.

bisubus avatar Oct 25 '21 15:10 bisubus

I ended up with the fix on my side:

  "devDependencies": {
    "tsutils": "1.0.0",
  },
  "resolutions": {
    "ts-to-zod/typescript": "4.2.3",
    "ts-to-zod/tsutils/typescript": "4.2.3"
  },

a) provide level 1 dummy tsutils dep that prevents [email protected] from being hoisted from nested deps

b) force [email protected] for ts-to-zod because [email protected] somehow installed [email protected] at ts-to-zod/node_modules/tsutils/node_modules/typescript , likely because of its loose peer dependency on typescript, although the reasoning for this never came up, probably a quirk of Yarn

I'm not sure whether this can be fixed on package level. Probably by informing users of possible implications if they install it locally together with other TS libs. I'm aware of hoisting problem, but this is the first time it messed up things for me in a very obscure way.

bisubus avatar Oct 25 '21 21:10 bisubus

@bisubus Thanks for this amazing debugging!

Indeed, when I run your repro repo with npm instead of yarn, this is working as expected: image

I’m also not sure how to fix this at the package level 😕 I will try to see what I can do to at least warn the user.

Thanks again for reporting & debugging this! 🎉

fabien0102 avatar Oct 26 '21 08:10 fabien0102

Probably needs to be checked that tsutil and its sibling typescript resolved paths are the same as typecript resolved path, and trigger a warning/error. JSDoc support could be enabled with a flag. The lib is extremely useful but I'm not sure if JSDoc feature is demanded; also can not work as expected #54 and should be disabled. I actually needed it, but I fixed JSDoc generation only to figure out that I need to preprocess TS and remove them because generated code is broken

bisubus avatar Oct 26 '21 08:10 bisubus

For anyone in the future facing the same problem:

A local fix is to run:

cd node_modules/ts-to-zod/
npm install

After this it will parse JSDoc correctly. Cheers!

DrummerHead avatar Aug 24 '23 16:08 DrummerHead

Issue occurs also in a pnpm env itself.

Used version: "ts-to-zod": "3.1.3",

Source typescript

/**
 * CurrencyCode
 * Standard currency 3-letter code (e.g. USD, EUR)
 * @minLength 3
 * @maxLength 3
 */
export type CurrencyCode = string | null

Generated zod schema

/**
 * CurrencyCode
 * Standard currency 3-letter code (e.g. USD, EUR)
 * @minLength 3
 * @maxLength 3
 */
export const currencyCodeSchema = z.string().nullable()
❯ pnpm -v
8.3.1

PeterMK85 avatar Sep 06 '23 05:09 PeterMK85

The solutions above don't work for me with bun. Bun currently doesn't support nested resolutions which might be why.

It would be great to have a fix for this if possible.

noorvir avatar Oct 30 '23 00:10 noorvir

@noorvir If you have any solution in mind, please give a try! We could embed the dependency or something like this… I really don't have the bandwidth to deal with this issue.

fabien0102-crabnebula avatar Oct 30 '23 09:10 fabien0102-crabnebula

yarn add tsutils helped me get the fix i was looking for

adamwdennis avatar Jan 11 '24 13:01 adamwdennis

I ended up with the fix on my side:

  "devDependencies": {
    "tsutils": "1.0.0",
  },
  "resolutions": {
    "ts-to-zod/typescript": "4.2.3",
    "ts-to-zod/tsutils/typescript": "4.2.3"
  },

a) provide level 1 dummy tsutils dep that prevents [email protected] from being hoisted from nested deps

b) force [email protected] for ts-to-zod because [email protected] somehow installed [email protected] at ts-to-zod/node_modules/tsutils/node_modules/typescript , likely because of its loose peer dependency on typescript, although the reasoning for this never came up, probably a quirk of Yarn

I'm not sure whether this can be fixed on package level. Probably by informing users of possible implications if they install it locally together with other TS libs. I'm aware of hoisting problem, but this is the first time it messed up things for me in a very obscure way.

This fixed mine. Thanks

THEO-184 avatar Mar 22 '24 19:03 THEO-184