syavorsky / comment-parser

Generic JSDoc-like comment parser.
MIT License
239 stars 24 forks source link

`@default []` and `@default {}` returns no `type` information #155

Closed Dan503 closed 2 years ago

Dan503 commented 2 years ago

Input

interface Test {
    /**
     * The description
     *
     * @default []
     */
    arrayValue?: Array<string>
    /**
     * The value
     *
     * @default {}
     */
    objectValue?: object
}

Output when run through prettier-plugin-jsdoc (unwanted change to the @default values)

interface Test {
    /**
     * The description
     *
     * @default
     */
    arrayValue?: Array<string>
    /**
     * The value
     *
     * @default
     */
    objectValue?: object
}

The default values are being lost because comment-parser is not recognizing [] and {} as valid @default values.

This is a continuation of this prettier-plugin-jsdoc issue: https://github.com/hosseinmd/prettier-plugin-jsdoc/issues/159

brettz9 commented 2 years ago

comment-parser is agnostic to the specific vocabulary of JSDoc.

You need to customize it something along these lines:

const commentParser = require("comment-parser")

const {
  name: nameTokenizer,
  tag: tagTokenizer,
  type: typeTokenizer,
  description: descriptionTokenizer
} = commentParser.tokenizers;

commentParser.parse(
  `/**
    * The description
    *
    * @default []
    */`,
  {
    tokenizers: [
      tagTokenizer(),
      typeTokenizer(),
      (spec) => {
        if (spec.tag === 'default') {
          return spec;
        }

        return nameTokenizer()(spec);
      },
      descriptionTokenizer('preserve')
    ]
  }
);

FWIW, for eslint-plugin-jsdoc, we are using @es-joy/jsdoccomment to give more specific awareness of JSDoc's semantics: https://github.com/es-joy/jsdoccomment/blob/main/src/parseComment.js

Dan503 commented 2 years ago

@brettz9 the solution you provided doesn't seem to work...

node code:

      const parsed = parse(commentString, {
        spacing: "preserve",
        tokenizers: [
          tagTokenizer(),
          typeTokenizer(),
          (spec) => {
            if ([DEFAULT, DEFAULT_Value].includes(spec.tag)) {

              console.log(commentString)
              console.log(spec)

              return spec;
            }
            return nameTokenizer()(spec);
          },
          descriptionTokenizer('preserve')
        ],
      })[0];

console output

    console.log
      /**
         * The value
         *
         * @default []
         */

    console.log
      {
        tag: 'default',
        name: '',
        type: '',
        optional: false,
        description: '',
        problems: [],
        source: [
          { number: 3, source: '   * @default []', tokens: [Object] },
          { number: 4, source: '   */', tokens: [Object] }
        ]
      }
    console.log
      /**
         * The value
         *
         * @default {}
         */

    console.log
      {
        tag: 'default',
        name: '',
        type: '',
        optional: false,
        description: '',
        problems: [],
        source: [
          { number: 3, source: '   * @default {}', tokens: [Object] },
          { number: 4, source: '   */', tokens: [Object] }
        ]
      }

But then even with something more meaty, it still isn't recognizing that there is a value associated with the @default tag

    console.log
      /**
         * The value
         *
         * @default [ 1, 'two', { three: true } ]
         */

    console.log
      {
        tag: 'default',
        name: '',
        type: '',
        optional: false,
        description: '',
        problems: [],
        source: [
          {
            number: 3,
            source: "   * @default [ 1, 'two', { three: true } ]",
            tokens: [Object]
          },
          { number: 4, source: '   */', tokens: [Object] }
        ]
      }
brettz9 commented 2 years ago

My original code is working as you can confirm at https://runkit.com/brettz9/62512fd3299d22000a704a39

Your code, assuming I have filled in the missing pieces correctly, also works: https://runkit.com/brettz9/62513164f03d060008371c20

Not sure if you are missing something in your full code or using an older version perhaps?

hosseinmd commented 2 years ago

@brettz9 could you create a PR for that please

brettz9 commented 2 years ago

Submitted at https://github.com/hosseinmd/prettier-plugin-jsdoc/pull/164 .

I had just been outlining the general approach, but to meet all your requirements, it is necessary to provide a custom type tokenizer (the name one wouldn't suffice the default {} case), and also to supply the "preserve" argument to that type tokenizer (as well as to the description tokenizers). Feel free to comment further on the PR (though I'll let your project figure out how to reconcile with the fact that other changes were since made). But when the approach is done as in the PR, you won't see those TypeScript errors.

Dan503 commented 2 years ago

Ok, I'll close off this issue since there is a work around and it isn't in scope for this project to have custom handling on the @default tag.