Skip to content

Zip @param tags and parameters together instead of looking for a name - #18832

Closed
Deleted user (ghost) wants to merge 4 commits into
masterfrom
jsdocparam
Closed

Zip @param tags and parameters together instead of looking for a name#18832
Deleted user (ghost) wants to merge 4 commits into
masterfrom
jsdocparam

Conversation

@ghost

@ghost Deleted user (ghost) commented Sep 28, 2017

Copy link
Copy Markdown

Avoids O(n^2) lookup in the usual case that @param tags are in the same order as parameters.
As a side-effect, we can now bind a @param tag to a bind expression if they have the same index.

Also fixes #17217.

@ghost
ghost force-pushed the jsdocparam branch from fa89a44 to bdba8a3 Compare September 29, 2017 17:00
@ghost

Copy link
Copy Markdown
Author

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is a good idea, but I don't think the current code in the binder is correct. I also want to see what shifting the work up-front does to performance. Except I don't think we have much (any?) jsdoc in our performance tests.

Comment thread src/compiler/binder.ts

// Clear any previous binding
for (const p of parameters) {
p.jsdocParamTags = undefined;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why do we need to do this? Is it because the binder is retained between edits?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The source tree node may have been reused from a previous version of the AST so its properties must be reset.

Comment thread src/compiler/types.ts
questionToken?: QuestionToken; // Present on optional parameter
type?: TypeNode; // Optional type annotation
initializer?: Expression; // Optional initializer
/* @internal */ jsdocParamTags?: JSDocParameterTag[];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

how does doing this in the binder instead of the checker affect performance? I don't understand the performance characteristics of the binder well enough to predict, so maybe a perf test is in order.

Comment thread src/compiler/binder.ts
}

let paramIndex = 0;
for (const tag of getJSDocTags(parent)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is going to be O(mn) where m = |tags| and n = |params|. That's because, for each tag, we examine every parameter starting at 0. Is this necessary? I think it would suffice to increment paramIndex until a single matching tag is found.

Even better, you could iterate over the parameters instead and keep a non-restarting index into the tags. You can give up when the tags run out.

zip :: [Tag] -> [Param] -> [Param]
zip (t:tags) (p:params) | name t == name p = p { tags = Just t } : zip tags params
zip (t:tags) params = zip tags params
zip [] params = params
zip tags [] = []

Note that the Haskell version doesn't side-effect, it just assumes there is a field tags :: Maybe Tag that is set to Nothing when this function is called.

let tagIndex = 0;
for (const param of parameters) {
  while (tags[tagIndex].name.escapedText !== param.name.escapedText && tagIndex < tags.length) {
    tagIndex++;
  }
  if (tagIndex >= tags.length) {
    break;
  }
  if (tags[tagIndex].name.escapedText === param.name.escapedText) {
    param.jsdocParamTags = append(param.jsdocParamTags, tags[tagIndex]);
  }
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

We want to keep supporting out-of-order @param tags, but in the case where they are in order this will be O(n) because we start looking at the previous paramIndex so usually we only go through the loop once.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see. I misunderstood the const startParamIndex = paramIndex. This is better than what I proposed, then.

@mhegazy

Copy link
Copy Markdown
Contributor

Andy (Andrewkraft) (@Andy-MS) can you please refresh and address the comments above.

@sandersn

Copy link
Copy Markdown
Member

Andy (Andrewkraft) (@Andy-MS) I've seen destructuring with JSDoc in code bases like webpack, which would benefit from this. Can you bring this back up to date and then I can take another look?

@sandersn

Copy link
Copy Markdown
Member

When running our existing performance tests, the binder got slower for Angular, but it got faster for Compiler w/Unions. But everything got a lot faster for the Compiler w/Unions, which doesn't make sense, since jsdoc params shouldn't be checked for types at all in typescript.

I'm going to try adding a javascript project to the performance tests and see if I can learn anything.

@sandersn

Copy link
Copy Markdown
Member

I ran another couple of perf tests, the last with me away from the computer. The binder is definitely slower for Angular -- about 10%. The binder runs in about a second, so it's easy to get swamped in the noise; TFS is slower but just barely significant for exactly that reason.

Everything is a little bit slower, but not enough to be significant. I think it may becase this change double caches: getJSDocTags caches into jsdocCache. Then during binding, bindJSDocParameters caches into jsdocParamTags ... after it calls getJSDocTags. That might be enough to slow everything down a little bit.

@typescript-bot

Copy link
Copy Markdown
Contributor

Thanks for your contribution. This PR has not been updated in a while and cannot be automatically merged at the time being. For housekeeping purposes we are closing stale PRs. If you'd still like to continue working on this PR, please leave a message and one of the maintainers can reopen it.

@jakebailey
Jake Bailey (jakebailey) deleted the jsdocparam branch November 7, 2022 17:32
@microsoft Microsoft (microsoft) locked as resolved and limited conversation to collaborators Oct 21, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Find-all-references for JSDoc @param in property assignment

3 participants