| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, | ||
| parameters: ReadonlyArray<ParameterDeclaration>, | ||
| type: TypeNode | undefined, | ||
| equalsGreaterThanTokenOrBody: Token<SyntaxKind.EqualsGreaterThanToken> | ConciseBody, |
There was a problem hiding this comment.
Need to ensure that we use the => from the new tree, which has a correct position. The => from the old tree has a different position that causes assertion errors in the formatter.
Sorry, something went wrong.
There was a problem hiding this comment.
Can we add it at the end instead?
Sorry, something went wrong.
There was a problem hiding this comment.
We should always keep elements in the create/update methods in the order they are parsed.
Sorry, something went wrong.
|
#18091 does not seem related, is that the right bug? Nevermind, your initial paragraph indicated the bug was an infinite loop which is not what #18091 is discussing, but this does address #18091. |
Sorry, something went wrong.
| emit(node.typeParameter.constraint); | ||
| write("]"); | ||
|
|
||
| if (onEmitNode) { |
There was a problem hiding this comment.
We really should avoid calling onEmitNode directly, and should be calling emit instead, except in this case we need to emit a type parameter in a different fashion. For anyone writing a custom transform, they won't know whether their onEmitNode is being called against a normal TypeParameter or the TypeParameter of a MappedType. That is the reason we have EmitHint, as it allows us to provide a hint as to the context in which we are emitting a node.
I would recommend we add MappedTypeParameter to the EmitHint enum and add a branch to pipelineEmitWithHint for that branch that calls emitMappedTypeParameter. Then we can replace this code with a call to pipelineEmitWithNotification(EmitHint.MappedTypeParameter, node.typeParameter).
Sorry, something went wrong.
| } | ||
|
|
||
| function emitMappedTypeParameter(_hint: EmitHint, node: TypeParameterDeclaration) { | ||
| write("["); |
There was a problem hiding this comment.
We parse the opening and closing brackets in parseMappedType, so their tokens do not belong to the type parameter. Writing the [ and ] tokens should happen in emitMappedType.
Sorry, something went wrong.
| function emitYieldExpression(node: YieldExpression) { | ||
| write(node.asteriskToken ? "yield*" : "yield"); | ||
| write("yield"); | ||
| if (node.asteriskToken) { |
There was a problem hiding this comment.
No need to guard against undefined, as that is already handled in emit
Sorry, something went wrong.
| emitDecorators(node, node.decorators); | ||
| emitModifiers(node, node.modifiers); | ||
| write(node.asteriskToken ? "function* " : "function "); | ||
| write("function"); |
There was a problem hiding this comment.
No need to guard against undefined as that is already handled in emit
Edit: I was incorrect. Apparently emit does not have this guard.
Sorry, something went wrong.
There was a problem hiding this comment.
I get a test failure in the test PrinterAPI printFile removeComments if I try to emit the asterisk unconditionally. emit doesn't seem to check for an undefined node.
Sorry, something went wrong.
| emitList(parentNode, parameters, ListFormat.IndexSignatureParameters); | ||
| } | ||
|
|
||
| function emitSingleElementList(list: NodeArray<Node>) { |
There was a problem hiding this comment.
Can you craft suitable ListFormat bitmasks to use instead and just call emitList where applicable instead of creating a special cased list emit function?
Sorry, something went wrong.
| } | ||
|
|
||
| function writeTokenNode(node: Node) { | ||
| function writeTokenAndCallCallbacks(node: Node, text: string) { |
There was a problem hiding this comment.
Maybe we can simplify this by replacing all calls to writeIfPresent with emit, as emit already guards against undefined, will in turn eventually call writeTokenNode, and may give us better comment preservation and source-maps.
Sorry, something went wrong.
| return array.hasOwnProperty("pos") | ||
| && array.hasOwnProperty("end"); | ||
| const res = array.hasOwnProperty("pos") && array.hasOwnProperty("end"); | ||
| if (res) { |
There was a problem hiding this comment.
We possibly call this a lot between visitor and factory. Do the added checks have any perf impact?
Sorry, something went wrong.
| condition: Expression, | ||
| whenTrue: Expression, | ||
| whenFalse: Expression, | ||
| questionToken: Token<SyntaxKind.QuestionToken> = node.questionToken, |
There was a problem hiding this comment.
We should always keep these arguments in the same order they are parsed.
Sorry, something went wrong.
| typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, | ||
| parameters: ReadonlyArray<ParameterDeclaration>, | ||
| type: TypeNode | undefined, | ||
| equalsGreaterThanTokenOrBody: Token<SyntaxKind.EqualsGreaterThanToken> | ConciseBody, |
There was a problem hiding this comment.
We should always keep elements in the create/update methods in the order they are parsed.
Sorry, something went wrong.
| } | ||
| body: ConciseBody, | ||
| // Optional for backwards-compatibility only -- should always provide this. | ||
| equalsGreaterThanToken: Token<SyntaxKind.EqualsGreaterThanToken> = node.equalsGreaterThanToken): ArrowFunction { |
There was a problem hiding this comment.
As complex as it was, the previous version was better. We should always keep these arguments in the same order as they would be parsed/visited.
Sorry, something went wrong.
There was a problem hiding this comment.
nit: realign the surrounding comments
Sorry, something went wrong.
| visitNode((<ConditionalExpression>node).whenTrue, visitor, isExpression), | ||
| visitNode((<ConditionalExpression>node).whenFalse, visitor, isExpression)); | ||
| visitNode((<ConditionalExpression>node).whenFalse, visitor, isExpression), | ||
| visitNode((<ConditionalExpression>node).questionToken, visitor, n => n.kind === SyntaxKind.QuestionToken), |
There was a problem hiding this comment.
I would just use isToken rather than be overly concerned about the specific token. No need to allocate a new function object every time this is called.
Sorry, something went wrong.
| visitNode((<ConditionalExpression>node).whenFalse, visitor, isExpression)); | ||
| visitNode((<ConditionalExpression>node).whenFalse, visitor, isExpression), | ||
| visitNode((<ConditionalExpression>node).questionToken, visitor, n => n.kind === SyntaxKind.QuestionToken), | ||
| visitNode((<ConditionalExpression>node).colonToken, visitor, n => n.kind === SyntaxKind.ColonToken)); |
There was a problem hiding this comment.
I would just use isToken rather than be overly concerned about the specific token. No need to allocate a new function object every time this is called.
Sorry, something went wrong.
| visitNode((<ArrowFunction>node).equalsGreaterThanToken, visitor, n => n.kind === SyntaxKind.EqualsGreaterThanToken), | ||
| visitFunctionBody((<ArrowFunction>node).body, visitor, context)); | ||
| visitFunctionBody((<ArrowFunction>node).body, visitor, context), | ||
| visitNode((<ArrowFunction>node).equalsGreaterThanToken, visitor, n => n.kind === SyntaxKind.EqualsGreaterThanToken)); |
There was a problem hiding this comment.
I would just use isToken rather than be overly concerned about the specific token. No need to allocate a new function object every time this is called.
Sorry, something went wrong.
|
Ran the perf tests and saw no slowdown due to this PR. |
Sorry, something went wrong.
There was a problem hiding this comment.
I'd still rather not have emitSingleElementList if possible, but we can remove it later.
Sorry, something went wrong.
| emitIdentifier(<Identifier>node); | ||
| } | ||
|
|
||
| function pipelineEmitMappedTypeParameter(node: TypeParameterDeclaration): void { |
There was a problem hiding this comment.
Just call this emitMappedTypeParameter.
Sorry, something went wrong.
* Ensure that emitter calls calbacks * Move new parameter to end of parameters * Fix for ConditionalExpression * Make suggested changes to emitter * Fix parameter ordering * Respond to minor comments * Remove potentially expensive assertion * More emitter cleanup
|
Andy (Andrewkraft) (@Andy-MS) we will need to port this to release-2.5 |
Sorry, something went wrong.
* Ensure that emitter calls calbacks * Move new parameter to end of parameters * Fix for ConditionalExpression * Make suggested changes to emitter * Fix parameter ordering * Respond to minor comments * Remove potentially expensive assertion * More emitter cleanup
| Back | FazBrowse Home | New Git URL |
Fixes #18091
The bug was happening because in formatting.ts, in processChildNodes, we continue scanning until getting to nodes.pos. Since this is a dynamically typed language, nodes.pos may be undefined despite our best efforts to type it, so the loop continued forever, thinking it was inside of the typeParameters of the generated function declaration; which meant it didn't know that it was actually nested several levels deep and should have been indenting more.
The problem was that in textChanges.ts, the function getPos promised to return a number but was implemented with (<any>n)["__pos"], which wasn't always defined. I added an assertion that it was, which brought up more problems.
In textChanges, we rely on callbacks like onBeforeEmitNodeArray to set "__pos". But there were many situations in which the emitter did not call these callbacks, so those all had to be updated; otherwise we don't set "__pos", and then the new nodes have missing or incorrect positions.