diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 48abb6ae3e3..14d49604f67 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -866,6 +866,7 @@ namespace ts { this.end = end; this.flags = NodeFlags.None; this.parent = undefined; + this.original = undefined; } export let objectAllocator: ObjectAllocator = { diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 06eb4b98b9c..d838288ef25 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -1,53 +1,134 @@ -/// +/// /// -/* @internal */ + namespace ts { - export function createNodeArray(elements?: T[], location?: TextRange): NodeArray; - export function createNodeArray>(elements: TArray, location?: TextRange): TArray; - export function createNodeArray>(elements?: T[], location?: TextRange): TArray { - const array = (elements || []); - if (location) { - array.pos = location.pos; - array.end = location.end; - } - else if (array.pos === undefined || array.end === undefined) { - array.pos = -1; - array.end = -1; - } + let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + export function createNode(kind: SyntaxKind, pos?: number, end?: number): Node { + if (kind === SyntaxKind.SourceFile) { + return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, pos, end); + } + else { + return new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, pos, end); + } + } + + /* @internal */ + export function createNodeArray(elements?: T[], pos?: number, end?: number): NodeArray { + const array = >(elements || []); + array.pos = pos; + array.end = end; + array.arrayKind = ArrayKind.NodeArray; return array; } - export function createNodeArrayNode(elements?: (T | NodeArrayNode)[]): NodeArrayNode { - const array = >createNodeArray(elements); - array.kind = SyntaxKind.NodeArrayNode; + /* @internal */ + export function createModifiersArray(elements?: Modifier[], pos?: number, end?: number): ModifiersArray { + const array = (elements || []); + array.pos = pos; + array.end = end; + array.arrayKind = ArrayKind.ModifiersArray; + array.flags = 0; return array; } + /* @internal */ + export function createSynthesizedNode(kind: SyntaxKind, startsOnNewLine?: boolean): Node { + const node = createNode(kind, /*pos*/ -1, /*end*/ -1); + node.startsOnNewLine = startsOnNewLine; + return node; + } + + /* @internal */ + export function createSynthesizedNodeArray(elements?: T[]): NodeArray { + return createNodeArray(elements, /*pos*/ -1, /*end*/ -1); + } + + /* @internal */ + export function createSynthesizedModifiersArray(elements?: Modifier[]): ModifiersArray { + return createModifiersArray(elements, /*pos*/ -1, /*end*/ -1); + } + + /** + * Creates a shallow, memberwise clone of a node. The "kind", "pos", "end", "flags", and "parent" + * properties are excluded by default, and can be provided via the "location", "flags", and + * "parent" parameters. + * + * @param node The node to clone. + * @param location An optional TextRange to use to supply the new position. + * @param flags The NodeFlags to use for the cloned node. + * @param parent The parent for the new node. + * @param original An optional pointer to the original source tree node. + */ + /* @internal */ + export function cloneNode(node: T, location?: TextRange, flags?: NodeFlags, parent?: Node, original?: Node): T { + // We don't use "clone" from core.ts here, as we need to preserve the prototype chain of + // the original node. We also need to exclude specific properties and only include own- + // properties (to skip members already defined on the shared prototype). + const clone = location !== undefined + ? createNode(node.kind, location.pos, location.end) + : createSynthesizedNode(node.kind); + + for (const key in node) { + if (clone.hasOwnProperty(key) || !node.hasOwnProperty(key)) { + continue; + } + + (clone)[key] = (node)[key]; + } + + if (flags !== undefined) { + clone.flags = flags; + } + + if (parent !== undefined) { + clone.parent = parent; + } + + if (original !== undefined) { + clone.original = original; + } + + return clone; + } + + /* @internal */ + export function createNodeArrayNode(elements: T[]): NodeArrayNode { + const node = >createSynthesizedNode(SyntaxKind.NodeArrayNode); + node.nodes = createNodeArray(elements); + return node; + } + + /* @internal */ export function createReturn(expression?: Expression): ReturnStatement { const node = createSynthesizedNode(SyntaxKind.ReturnStatement); node.expression = expression; return node; } + /* @internal */ export function createStatement(expression: Expression): ExpressionStatement { const node = createSynthesizedNode(SyntaxKind.ExpressionStatement); node.expression = expression; return node; } + /* @internal */ export function createVariableStatement(declarationList: VariableDeclarationList): VariableStatement { const node = createSynthesizedNode(SyntaxKind.VariableStatement); node.declarationList = declarationList; return node; } + /* @internal */ export function createVariableDeclarationList(declarations: VariableDeclaration[]): VariableDeclarationList { const node = createSynthesizedNode(SyntaxKind.VariableDeclarationList); node.declarations = createNodeArray(declarations); return node; } + /* @internal */ export function createBlock(statements: Statement[]): Block { const block = createSynthesizedNode(SyntaxKind.Block); block.statements = createNodeArray(statements); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index f866b86fca2..1d9f9fe2305 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1,21 +1,10 @@ /// /// +/// namespace ts { /* @internal */ export let parseTime = 0; - let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; - let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; - - export function createNode(kind: SyntaxKind, pos?: number, end?: number): Node { - if (kind === SyntaxKind.SourceFile) { - return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, pos, end); - } - else { - return new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, pos, end); - } - } - function visitNode(cbNode: (node: Node) => T, node: Node): T { if (node) { return cbNode(node); @@ -875,7 +864,7 @@ namespace ts { /** Invokes the provided callback then unconditionally restores the parser to the state it * was in immediately prior to invoking the callback. The result of invoking the callback - * is returned from this function. + * is returned from this function. */ function lookAhead(callback: () => T): T { return speculationHelper(callback, /*isLookAhead*/ true); @@ -989,6 +978,29 @@ namespace ts { return new NodeConstructor(kind, pos, pos); } + function createNodeArray(elements?: T[], pos?: number): NodeArray { + const array = >(elements || []); + if (!(pos >= 0)) { + pos = getNodePos(); + } + array.pos = pos; + array.end = pos; + array.arrayKind = ArrayKind.NodeArray; + return array; + } + + function createModifiersArray(elements?: Modifier[], pos?: number): ModifiersArray { + const array = (elements || []); + if (!(pos >= 0)) { + pos = getNodePos(); + } + array.pos = pos; + array.end = pos; + array.arrayKind = ArrayKind.ModifiersArray; + array.flags = 0; + return array; + } + function finishNode(node: T, end?: number): T { node.end = end === undefined ? scanner.getStartPos() : end; @@ -1374,8 +1386,7 @@ namespace ts { function parseList(kind: ParsingContext, parseElement: () => T): NodeArray { const saveParsingContext = parsingContext; parsingContext |= 1 << kind; - const result = >[]; - result.pos = getNodePos(); + const result = createNodeArray(); while (!isListTerminator(kind)) { if (isListElement(kind, /*inErrorRecovery*/ false)) { @@ -1722,8 +1733,7 @@ namespace ts { function parseDelimitedList(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimeter?: boolean): NodeArray { const saveParsingContext = parsingContext; parsingContext |= 1 << kind; - const result = >[]; - result.pos = getNodePos(); + const result = createNodeArray(); let commaStart = -1; // Meaning the previous token was not a comma while (true) { @@ -1778,12 +1788,8 @@ namespace ts { return result; } - function createMissingList(): NodeArray { - const pos = getNodePos(); - const result = >[]; - result.pos = pos; - result.end = pos; - return result; + function createMissingList(): NodeArray { + return createNodeArray(); } function parseBracketedList(kind: ParsingContext, parseElement: () => T, open: SyntaxKind, close: SyntaxKind): NodeArray { @@ -1848,8 +1854,7 @@ namespace ts { template.head = parseTemplateLiteralFragment(); Debug.assert(template.head.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind"); - const templateSpans = >[]; - templateSpans.pos = getNodePos(); + const templateSpans = createNodeArray(); do { templateSpans.push(parseTemplateSpan()); @@ -2425,8 +2430,7 @@ namespace ts { function parseUnionOrIntersectionType(kind: SyntaxKind, parseConstituentType: () => TypeNode, operator: SyntaxKind): TypeNode { let type = parseConstituentType(); if (token === operator) { - const types = >[type]; - types.pos = type.pos; + const types = createNodeArray([type], type.pos); while (parseOptional(operator)) { types.push(parseConstituentType()); } @@ -2781,8 +2785,7 @@ namespace ts { parameter.name = identifier; finishNode(parameter); - node.parameters = >[parameter]; - node.parameters.pos = parameter.pos; + node.parameters = createNodeArray([parameter], parameter.pos); node.parameters.end = parameter.end; node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, "=>"); @@ -3557,8 +3560,7 @@ namespace ts { } function parseJsxChildren(openingTagName: EntityName): NodeArray { - const result = >[]; - result.pos = scanner.getStartPos(); + const result = createNodeArray(); const saveParsingContext = parsingContext; parsingContext |= 1 << ParsingContext.JsxChildren; @@ -4922,14 +4924,15 @@ namespace ts { break; } - if (!decorators) { - decorators = >[]; - decorators.pos = decoratorStart; - } - const decorator = createNode(SyntaxKind.Decorator, decoratorStart); decorator.expression = doInDecoratorContext(parseLeftHandSideExpressionOrHigher); - decorators.push(finishNode(decorator)); + finishNode(decorator); + if (!decorators) { + decorators = createNodeArray([decorator], decoratorStart); + } + else { + decorators.push(decorator); + } } if (decorators) { decorators.end = getNodeEnd(); @@ -4953,7 +4956,7 @@ namespace ts { if (token === SyntaxKind.ConstKeyword && permitInvalidConstAsModifier) { // We need to ensure that any subsequent modifiers appear on the same line - // so that when 'const' is a standalone declaration, we don't issue an error. + // so that when 'const' is a standalone declaration, we don't issue an error. if (!tryParse(nextTokenIsOnSameLineAndCanFollowModifier)) { break; } @@ -4964,13 +4967,14 @@ namespace ts { } } - if (!modifiers) { - modifiers = []; - modifiers.pos = modifierStart; - } - flags |= modifierToFlag(modifierKind); - modifiers.push(finishNode(createNode(modifierKind, modifierStart))); + const modifier = finishNode(createNode(modifierKind, modifierStart)); + if (!modifiers) { + modifiers = createModifiersArray([modifier], modifierStart); + } + else { + modifiers.push(modifier); + } } if (modifiers) { modifiers.flags = flags; @@ -4980,17 +4984,14 @@ namespace ts { } function parseModifiersForArrowFunction(): ModifiersArray { - let flags = 0; let modifiers: ModifiersArray; if (token === SyntaxKind.AsyncKeyword) { const modifierStart = scanner.getStartPos(); const modifierKind = token; nextToken(); - modifiers = []; - modifiers.pos = modifierStart; - flags |= modifierToFlag(modifierKind); - modifiers.push(finishNode(createNode(modifierKind, modifierStart))); - modifiers.flags = flags; + const modifier = finishNode(createNode(modifierKind, modifierStart)); + modifiers = createModifiersArray([modifier], modifierStart); + modifiers.flags = modifierToFlag(modifierKind); modifiers.end = scanner.getStartPos(); } @@ -5216,7 +5217,7 @@ namespace ts { node.decorators = decorators; setModifiers(node, modifiers); if (token === SyntaxKind.GlobalKeyword) { - // parse 'global' as name of global scope augmentation + // parse 'global' as name of global scope augmentation node.name = parseIdentifier(); node.flags |= NodeFlags.GlobalAugmentation; } @@ -5848,10 +5849,8 @@ namespace ts { function parseJSDocTypeList(firstType: JSDocType) { Debug.assert(!!firstType); - const types = >[]; - types.pos = firstType.pos; + const types = createNodeArray([firstType], firstType.pos); - types.push(firstType); while (parseOptional(SyntaxKind.BarToken)) { types.push(parseJSDocType()); } @@ -6059,11 +6058,11 @@ namespace ts { function addTag(tag: JSDocTag): void { if (tag) { if (!tags) { - tags = >[]; - tags.pos = tag.pos; + tags = createNodeArray([tag], tag.pos); + } + else { + tags.push(tag); } - - tags.push(tag); tags.end = tag.end; } } @@ -6156,8 +6155,7 @@ namespace ts { } // Type parameter list looks like '@template T,U,V' - const typeParameters = >[]; - typeParameters.pos = scanner.getStartPos(); + const typeParameters = createNodeArray(); while (true) { const name = parseJSDocIdentifier(); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d2d436f545f..177934fc13b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -454,12 +454,27 @@ namespace ts { /* @internal */ localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes) } - export interface NodeArray extends Array, TextRange { + export const enum ArrayKind { + NodeArray = 1, + ModifiersArray = 2, + } + + export interface NodeArray extends Array, TextRange { + arrayKind: ArrayKind; hasTrailingComma?: boolean; } + /** + * A NodeArrayNode is a transient node used during transformations to indicate that more than + * one node will substitute a single node in the source. When the source is a NodeArray (as + * part of a call to `visitNodes`), the nodes of a NodeArrayNode will be spread into the + * result array. When the source is a Node (as part of a call to `visitNode`), the NodeArrayNode + * must be converted into a compatible node via the `lift` callback. + */ + /* @internal */ // @kind(SyntaxKind.NodeArrayNode) - export interface NodeArrayNode extends Node, NodeArray> { + export interface NodeArrayNode extends Node { + nodes: NodeArray; } export interface ModifiersArray extends NodeArray { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 9fe32c89a69..a6df27bc3b9 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1647,47 +1647,6 @@ namespace ts { return isFunctionLike(n) || n.kind === SyntaxKind.ModuleDeclaration || n.kind === SyntaxKind.SourceFile; } - /** - * Creates a shallow, memberwise clone of a node. The "kind", "pos", "end", "flags", and "parent" - * properties are excluded by default, and can be provided via the "location", "flags", and - * "parent" parameters. - * @param node The node to clone. - * @param location An optional TextRange to use to supply the new position. - * @param flags The NodeFlags to use for the cloned node. - * @param parent The parent for the new node. - * @param original An optional pointer to the original node. - */ - export function cloneNode(node: T, location?: TextRange, flags?: NodeFlags, parent?: Node, original?: Node): T { - // We don't use "clone" from core.ts here, as we need to preserve the prototype chain of - // the original node. We also need to exclude specific properties and only include own- - // properties (to skip members already defined on the shared prototype). - const clone = location !== undefined - ? createNode(node.kind, location.pos, location.end) - : createSynthesizedNode(node.kind); - - for (const key in node) { - if (key === "parent" || key === "flags" || clone.hasOwnProperty(key) || !node.hasOwnProperty(key)) { - continue; - } - - (clone)[key] = (node)[key]; - } - - if (flags !== undefined) { - clone.flags = flags; - } - - if (parent !== undefined) { - clone.parent = parent; - } - - if (original !== undefined) { - clone.original = original; - } - - return clone; - } - /** * Creates a deep clone of an EntityName, with new parent pointers. * @param node The EntityName to clone. @@ -1719,19 +1678,6 @@ namespace ts { return !(pos >= 0); } - export function createSynthesizedNode(kind: SyntaxKind, startsOnNewLine?: boolean): Node { - const node = createNode(kind, /* pos */ -1, /* end */ -1); - node.startsOnNewLine = startsOnNewLine; - return node; - } - - export function createSynthesizedNodeArray(): NodeArray { - const array = >[]; - array.pos = -1; - array.end = -1; - return array; - } - export function getOriginalNode(node: Node): Node { while (node.original !== undefined) { node = node.original; @@ -2728,12 +2674,12 @@ namespace ts { return false; } - export function isModifiersArray(nodes: NodeArray): nodes is ModifiersArray { - return !isNodeArrayNode(nodes) && typeof (nodes).flags === "number"; + export function isModifiersArray(array: NodeArray): array is ModifiersArray { + return array.arrayKind === ArrayKind.ModifiersArray; } - export function isNodeArrayNode(value: Node | NodeArray>): value is NodeArrayNode { - return (value).kind === SyntaxKind.NodeArrayNode; + export function isNodeArrayNode(node: Node): node is NodeArrayNode { + return node.kind === SyntaxKind.NodeArrayNode; } export function getLocalSymbolForExportDefault(symbol: Symbol) { diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 30717578eb8..a75e79565c5 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -1,5 +1,5 @@ /// -/// + /* @internal */ namespace ts { /** Additional context provided to `visitEachChild` */ @@ -15,9 +15,6 @@ namespace ts { * Describes an edge of a Node, used when traversing a syntax tree. */ interface NodeEdge { - /** Indicates that the edge is a NodeArray. */ - array?: boolean; - /** Indicates that the result is optional. */ optional?: boolean; @@ -25,7 +22,7 @@ namespace ts { test?: (node: Node) => node is Node; /** A callback used to lift a NodeArrayNode into a valid node. */ - lift?: (nodes: NodeArrayNode) => Node; + lift?: (nodes: NodeArray) => Node; }; /** @@ -55,8 +52,8 @@ namespace ts { expression: { test: isExpressionNode }, }, [SyntaxKind.Parameter]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, name: { test: isBindingPatternOrIdentifier }, type: { test: isTypeNodeNode, optional: true }, initializer: { test: isExpressionNode, optional: true }, @@ -65,52 +62,52 @@ namespace ts { expression: { test: isLeftHandSideExpression }, }, [SyntaxKind.PropertyDeclaration]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, name: { test: isPropertyName }, type: { test: isTypeNodeNode, optional: true }, initializer: { test: isExpressionNode, optional: true }, }, [SyntaxKind.MethodDeclaration]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, name: { test: isPropertyName }, - typeParameters: { test: isTypeParameter, array: true }, - parameters: { test: isParameter, array: true }, + typeParameters: { test: isTypeParameter }, + parameters: { test: isParameter }, type: { test: isTypeNodeNode, optional: true }, body: { test: isBlock, optional: true }, }, [SyntaxKind.Constructor]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, - typeParameters: { test: isTypeParameter, array: true }, - parameters: { test: isParameter, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, + typeParameters: { test: isTypeParameter }, + parameters: { test: isParameter }, type: { test: isTypeNodeNode, optional: true }, body: { test: isBlock, optional: true }, }, [SyntaxKind.GetAccessor]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, name: { test: isPropertyName }, - typeParameters: { test: isTypeParameter, array: true }, - parameters: { test: isParameter, array: true }, + typeParameters: { test: isTypeParameter }, + parameters: { test: isParameter }, type: { test: isTypeNodeNode, optional: true }, body: { test: isBlock, optional: true }, }, [SyntaxKind.SetAccessor]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, name: { test: isPropertyName }, - typeParameters: { test: isTypeParameter, array: true }, - parameters: { test: isParameter, array: true }, + typeParameters: { test: isTypeParameter }, + parameters: { test: isParameter }, type: { test: isTypeNodeNode, optional: true }, body: { test: isBlock, optional: true }, }, [SyntaxKind.ObjectBindingPattern]: { - elements: { test: isBindingElement, array: true }, + elements: { test: isBindingElement }, }, [SyntaxKind.ArrayBindingPattern]: { - elements: { test: isBindingElement, array: true }, + elements: { test: isBindingElement }, }, [SyntaxKind.BindingElement]: { propertyName: { test: isPropertyName, optional: true }, @@ -118,10 +115,10 @@ namespace ts { initializer: { test: isExpressionNode, optional: true }, }, [SyntaxKind.ArrayLiteralExpression]: { - elements: { test: isExpressionNode, array: true }, + elements: { test: isExpressionNode }, }, [SyntaxKind.ObjectLiteralExpression]: { - properties: { test: isObjectLiteralElement, array: true }, + properties: { test: isObjectLiteralElement }, }, [SyntaxKind.PropertyAccessExpression]: { expression: { test: isLeftHandSideExpression }, @@ -133,13 +130,13 @@ namespace ts { }, [SyntaxKind.CallExpression]: { expression: { test: isLeftHandSideExpression }, - typeArguments: { test: isTypeNodeNode, array: true }, - arguments: { test: isExpressionNode, array: true }, + typeArguments: { test: isTypeNodeNode }, + arguments: { test: isExpressionNode }, }, [SyntaxKind.NewExpression]: { expression: { test: isLeftHandSideExpression }, - typeArguments: { test: isTypeNodeNode, array: true }, - arguments: { test: isExpressionNode, array: true }, + typeArguments: { test: isTypeNodeNode }, + arguments: { test: isExpressionNode }, }, [SyntaxKind.TaggedTemplateExpression]: { tag: { test: isLeftHandSideExpression }, @@ -153,19 +150,19 @@ namespace ts { expression: { test: isExpressionNode }, }, [SyntaxKind.FunctionExpression]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, name: { test: isIdentifierNode, optional: true }, - typeParameters: { test: isTypeParameter, array: true }, - parameters: { test: isParameter, array: true }, + typeParameters: { test: isTypeParameter }, + parameters: { test: isParameter }, type: { test: isTypeNodeNode, optional: true }, body: { test: isBlock, optional: true }, }, [SyntaxKind.ArrowFunction]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, - typeParameters: { test: isTypeParameter, array: true }, - parameters: { test: isParameter, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, + typeParameters: { test: isTypeParameter }, + parameters: { test: isParameter }, type: { test: isTypeNodeNode, optional: true }, body: { test: isConciseBody, lift: liftToBlock }, }, @@ -198,7 +195,7 @@ namespace ts { }, [SyntaxKind.TemplateExpression]: { head: { test: isTemplateLiteralFragment }, - templateSpans: { test: isTemplateSpan, array: true }, + templateSpans: { test: isTemplateSpan }, }, [SyntaxKind.YieldExpression]: { expression: { test: isExpressionNode, optional: true }, @@ -207,16 +204,16 @@ namespace ts { expression: { test: isExpressionNode }, }, [SyntaxKind.ClassExpression]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, name: { test: isIdentifierNode, optional: true }, - typeParameters: { test: isTypeParameter, array: true }, - heritageClauses: { test: isHeritageClause, array: true }, - members: { test: isClassElement, array: true }, + typeParameters: { test: isTypeParameter }, + heritageClauses: { test: isHeritageClause }, + members: { test: isClassElement }, }, [SyntaxKind.ExpressionWithTypeArguments]: { expression: { test: isLeftHandSideExpression }, - typeArguments: { test: isTypeNodeNode, array: true }, + typeArguments: { test: isTypeNodeNode }, }, [SyntaxKind.AsExpression]: { expression: { test: isExpressionNode }, @@ -227,11 +224,11 @@ namespace ts { literal: { test: isTemplateLiteralFragment }, }, [SyntaxKind.Block]: { - statements: { test: isStatementNode, array: true }, + statements: { test: isStatementNode }, }, [SyntaxKind.VariableStatement]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, declarationList: { test: isVariableDeclarationList }, }, [SyntaxKind.ExpressionStatement]: { @@ -301,52 +298,52 @@ namespace ts { initializer: { test: isExpressionNode, optional: true }, }, [SyntaxKind.VariableDeclarationList]: { - declarations: { test: isVariableDeclaration, array: true }, + declarations: { test: isVariableDeclaration }, }, [SyntaxKind.FunctionDeclaration]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, name: { test: isIdentifierNode, optional: true }, - typeParameters: { test: isTypeParameter, array: true }, - parameters: { test: isParameter, array: true }, + typeParameters: { test: isTypeParameter }, + parameters: { test: isParameter }, type: { test: isTypeNodeNode, optional: true }, body: { test: isBlock, optional: true }, }, [SyntaxKind.ClassDeclaration]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, name: { test: isIdentifierNode, optional: true }, - typeParameters: { test: isTypeParameter, array: true }, - heritageClauses: { test: isHeritageClause, array: true }, - members: { test: isClassElement, array: true }, + typeParameters: { test: isTypeParameter }, + heritageClauses: { test: isHeritageClause }, + members: { test: isClassElement }, }, [SyntaxKind.EnumDeclaration]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, name: { test: isIdentifierNode }, - members: { test: isEnumMember, array: true }, + members: { test: isEnumMember }, }, [SyntaxKind.ModuleDeclaration]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, name: { test: isModuleName }, body: { test: isModuleBody }, }, [SyntaxKind.ModuleBlock]: { - statements: { test: isStatementNode, array: true }, + statements: { test: isStatementNode }, }, [SyntaxKind.CaseBlock]: { - clauses: { test: isCaseOrDefaultClause, array: true }, + clauses: { test: isCaseOrDefaultClause }, }, [SyntaxKind.ImportEqualsDeclaration]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, name: { test: isIdentifierNode }, moduleReference: { test: isModuleReference }, }, [SyntaxKind.ImportDeclaration]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, importClause: { test: isImportClause, optional: true }, moduleSpecifier: { test: isExpressionNode }, }, @@ -358,25 +355,25 @@ namespace ts { name: { test: isIdentifierNode }, }, [SyntaxKind.NamedImports]: { - elements: { test: isImportSpecifier, array: true }, + elements: { test: isImportSpecifier }, }, [SyntaxKind.ImportSpecifier]: { propertyName: { test: isIdentifierNode, optional: true }, name: { test: isIdentifierNode }, }, [SyntaxKind.ExportAssignment]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, expression: { test: isExpressionNode }, }, [SyntaxKind.ExportDeclaration]: { - decorators: { test: isDecorator, array: true }, - modifiers: { test: isModifier, array: true }, + decorators: { test: isDecorator }, + modifiers: { test: isModifier }, exportClause: { test: isNamedExports, optional: true }, moduleSpecifier: { test: isExpressionNode, optional: true }, }, [SyntaxKind.NamedExports]: { - elements: { test: isExportSpecifier, array: true }, + elements: { test: isExportSpecifier }, }, [SyntaxKind.ExportSpecifier]: { propertyName: { test: isIdentifierNode, optional: true }, @@ -387,16 +384,16 @@ namespace ts { }, [SyntaxKind.JsxElement]: { openingElement: { test: isJsxOpeningElement }, - children: { test: isJsxChild, array: true }, + children: { test: isJsxChild }, closingElement: { test: isJsxClosingElement }, }, [SyntaxKind.JsxSelfClosingElement]: { tagName: { test: isEntityName }, - attributes: { test: isJsxAttributeOrJsxSpreadAttribute, array: true }, + attributes: { test: isJsxAttributeOrJsxSpreadAttribute }, }, [SyntaxKind.JsxOpeningElement]: { tagName: { test: isEntityName }, - attributes: { test: isJsxAttributeOrJsxSpreadAttribute, array: true }, + attributes: { test: isJsxAttributeOrJsxSpreadAttribute }, }, [SyntaxKind.JsxClosingElement]: { tagName: { test: isEntityName }, @@ -413,13 +410,13 @@ namespace ts { }, [SyntaxKind.CaseClause]: { expression: { test: isExpressionNode }, - statements: { test: isStatementNode, array: true }, + statements: { test: isStatementNode }, }, [SyntaxKind.DefaultClause]: { - statements: { test: isStatementNode, array: true }, + statements: { test: isStatementNode }, }, [SyntaxKind.HeritageClause]: { - types: { test: isExpressionWithTypeArguments, array: true }, + types: { test: isExpressionWithTypeArguments }, }, [SyntaxKind.CatchClause]: { variableDeclaration: { test: isVariableDeclaration }, @@ -438,7 +435,7 @@ namespace ts { initializer: { test: isExpressionNode, optional: true }, }, [SyntaxKind.SourceFile]: { - statements: { test: isStatementNode, array: true }, + statements: { test: isStatementNode }, }, }; @@ -462,13 +459,9 @@ namespace ts { for (const propertyName in edgeTraversalPath) { const value = (>node)[propertyName]; if (value !== undefined) { - const edge = edgeTraversalPath[propertyName]; - if (edge.array) { - result = reduceLeft(>value, f, result); - } - else { - result = f(result, value); - } + result = isArray(value) + ? reduceLeft(>value, f, result) + : f(result, value); } } } @@ -485,7 +478,7 @@ namespace ts { * @param lift A callback to execute to lift a NodeArrayNode into a valid Node. * @param optional A value indicating whether the Node is optional. */ - export function visitNode(node: T, visitor: (node: Node) => Node, test?: (node: Node) => boolean, lift?: (node: NodeArrayNode) => T, optional?: boolean): T { + export function visitNode(node: T, visitor: (node: Node) => Node, test?: (node: Node) => boolean, lift?: (node: NodeArray) => T, optional?: boolean): T { if (node === undefined) { return undefined; } @@ -501,10 +494,7 @@ namespace ts { return undefined; } - if (test !== undefined) { - Debug.assert(test(visited), "Wrong node type after visit."); - } - + Debug.assert(test === undefined || test(visited), "Wrong node type after visit."); return visited; } @@ -520,7 +510,7 @@ namespace ts { return undefined; } - let updated: TArray; + let updated: NodeArray | ModifiersArray; for (let i = 0, len = nodes.length; i < len; i++) { const node = nodes[i]; if (node === undefined) { @@ -530,7 +520,9 @@ namespace ts { const visited = visitor(node); if (updated !== undefined || visited === undefined || visited !== node) { if (updated === undefined) { - updated = createNodeArray(nodes.slice(0, i), /*location*/ nodes); + updated = isModifiersArray(nodes) + ? createModifiersArray(nodes.slice(0, i), nodes.pos, nodes.end) + : createNodeArray(nodes.slice(0, i), nodes.pos, nodes.end); } if (visited === undefined) { @@ -541,22 +533,22 @@ namespace ts { spreadNodeArrayNode(visited, updated, test); } else if (visited !== undefined) { - Debug.assert(test(visited), "Wrong node type after visit."); + Debug.assert(test === undefined || test(visited), "Wrong node type after visit."); updated.push(visited); } } } - if (updated && isModifiersArray(nodes)) { + if (updated && isModifiersArray(updated)) { let flags: NodeFlags = 0; for (const node of updated) { flags |= modifierToFlag(node.kind); } - (>updated).flags = flags; + updated.flags = flags; } - return updated || nodes; + return updated || nodes; } /** @@ -592,8 +584,8 @@ namespace ts { updated[propertyName] = visited; } - if (visited && edge.array && isModifiersArray(>visited)) { - updated.flags |= (visited).flags; + if (visited && isArray(visited) && isModifiersArray(visited)) { + updated.flags |= visited.flags; } } } @@ -621,7 +613,7 @@ namespace ts { * @param visitor A callback used to visit the node. */ function visitEdge(edge: NodeEdge, value: Node | NodeArray, visitor: (node: Node) => Node) { - return edge.array + return isArray(value) ? visitNodes(>value, visitor, edge.test) : visitNode(value, visitor, edge.test, edge.lift, edge.optional); } @@ -634,18 +626,13 @@ namespace ts { * @param test The node test used to validate each node. */ function spreadNodeArrayNode(source: NodeArrayNode, dest: NodeArray, test: (node: Node) => boolean) { - for (const element of source) { + for (const element of source.nodes) { if (element === undefined) { continue; } - if (isNodeArrayNode(element)) { - spreadNodeArrayNode(element, dest, test); - } - else { - Debug.assert(test === undefined || test(element), "Wrong node type after visit."); - dest.push(element); - } + Debug.assert(test === undefined || test(element), "Wrong node type after visit."); + dest.push(element); } } @@ -724,7 +711,7 @@ namespace ts { * Merge generated declarations of a lexical environment into a NodeArray of Statement. */ function mergeStatements(statements: NodeArray, declarations: Statement[]) { - return createNodeArray(statements.concat(declarations), /*location*/ statements); + return createNodeArray(statements.concat(declarations), statements.pos, statements.end); } /** @@ -734,13 +721,13 @@ namespace ts { * @param node The visited Node. * @param options Options used to control lift behavior. */ - function liftNode(node: Node, lifter: (nodes: NodeArrayNode) => Node): Node { + function liftNode(node: Node, lifter: (nodes: NodeArray) => Node): Node { if (node === undefined) { return undefined; } else if (isNodeArrayNode(node)) { const lift = lifter || extractSingleNode; - return lift(node); + return lift(node.nodes); } else { return node; diff --git a/src/services/breakpoints.ts b/src/services/breakpoints.ts index 4cd361734e3..1c4d5957a02 100644 --- a/src/services/breakpoints.ts +++ b/src/services/breakpoints.ts @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0. +// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0. // See LICENSE.txt in the project root for complete license information. /// @@ -19,8 +19,8 @@ namespace ts.BreakpointResolver { if (sourceFile.getLineAndCharacterOfPosition(tokenAtLocation.getStart(sourceFile)).line > lineOfPosition) { // Get previous token if the token is returned starts on new line // eg: let x =10; |--- cursor is here - // let y = 10; - // token at position will return let keyword on second line as the token but we would like to use + // let y = 10; + // token at position will return let keyword on second line as the token but we would like to use // token on same line if trailing trivia (comments or white spaces on same line) part of the last token on that line tokenAtLocation = findPrecedingToken(tokenAtLocation.pos, sourceFile); @@ -56,7 +56,7 @@ namespace ts.BreakpointResolver { return spanInNode(otherwiseOnNode); } - function spanInNodeArray(nodeArray: NodeArray) { + function spanInNodeArray(nodeArray: NodeArray) { return createTextSpanFromBounds(skipTrivia(sourceFile.text, nodeArray.pos), nodeArray.end); } @@ -259,13 +259,13 @@ namespace ts.BreakpointResolver { if (isArrayLiteralOrObjectLiteralDestructuringPattern(node)) { return spanInArrayLiteralOrObjectLiteralDestructuringPattern(node); } - + // Set breakpoint on identifier element of destructuring pattern - // a or ...c or d: x from + // a or ...c or d: x from // [a, b, ...c] or { a, b } or { d: x } from destructuring pattern if ((node.kind === SyntaxKind.Identifier || - node.kind == SyntaxKind.SpreadElementExpression || - node.kind === SyntaxKind.PropertyAssignment || + node.kind == SyntaxKind.SpreadElementExpression || + node.kind === SyntaxKind.PropertyAssignment || node.kind === SyntaxKind.ShorthandPropertyAssignment) && isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent)) { return textSpan(node); @@ -275,7 +275,7 @@ namespace ts.BreakpointResolver { const binaryExpression = node; // Set breakpoint in destructuring pattern if its destructuring assignment // [a, b, c] or {a, b, c} of - // [a, b, c] = expression or + // [a, b, c] = expression or // {a, b, c} = expression if (isArrayLiteralOrObjectLiteralDestructuringPattern(binaryExpression.left)) { return spanInArrayLiteralOrObjectLiteralDestructuringPattern( @@ -285,8 +285,8 @@ namespace ts.BreakpointResolver { if (binaryExpression.operatorToken.kind === SyntaxKind.EqualsToken && isArrayLiteralOrObjectLiteralDestructuringPattern(binaryExpression.parent)) { // Set breakpoint on assignment expression element of destructuring pattern - // a = expression of - // [a = expression, b, c] = someExpression or + // a = expression of + // [a = expression, b, c] = someExpression or // { a = expression, b, c } = someExpression return textSpan(node); } @@ -325,14 +325,14 @@ namespace ts.BreakpointResolver { break; } } - + // If this is name of property assignment, set breakpoint in the initializer if (node.parent.kind === SyntaxKind.PropertyAssignment && - (node.parent).name === node && + (node.parent).name === node && !isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent.parent)) { return spanInNode((node.parent).initializer); } - + // Breakpoint in type assertion goes to its operand if (node.parent.kind === SyntaxKind.TypeAssertionExpression && (node.parent).type === node) { return spanInNextNode((node.parent).type); @@ -386,7 +386,7 @@ namespace ts.BreakpointResolver { if (variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement) { return spanInNode(variableDeclaration.parent.parent); } - + // If this is a destructuring pattern set breakpoint in binding pattern if (isBindingPattern(variableDeclaration.name)) { return spanInBindingPattern(variableDeclaration.name); @@ -403,7 +403,7 @@ namespace ts.BreakpointResolver { let declarations = variableDeclaration.parent.declarations; if (declarations && declarations[0] !== variableDeclaration) { // If we cant set breakpoint on this declaration, set it on previous one - // Because the variable declaration may be binding pattern and + // Because the variable declaration may be binding pattern and // we would like to set breakpoint in last binding element if thats the case, // use preceding token instead return spanInNode(findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent)); @@ -549,7 +549,7 @@ namespace ts.BreakpointResolver { return spanInNode(firstBindingElement); } - // Could be ArrayLiteral from destructuring assignment or + // Could be ArrayLiteral from destructuring assignment or // just nested element in another destructuring assignment // set breakpoint on assignment when parent is destructuring assignment // Otherwise set breakpoint for this element @@ -686,7 +686,7 @@ namespace ts.BreakpointResolver { function spanInColonToken(node: Node): TextSpan { // Is this : specifying return annotation of the function declaration if (isFunctionLike(node.parent) || - node.parent.kind === SyntaxKind.PropertyAssignment || + node.parent.kind === SyntaxKind.PropertyAssignment || node.parent.kind === SyntaxKind.Parameter) { return spanInPreviousNode(node); } diff --git a/src/services/services.ts b/src/services/services.ts index 85b2bfb58e8..373d0c3a8ff 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -186,6 +186,7 @@ namespace ts { public end: number; public flags: NodeFlags; public parent: Node; + public original: Node; private _children: Node[]; constructor(kind: SyntaxKind, pos: number, end: number) { @@ -194,6 +195,7 @@ namespace ts { this.end = end; this.flags = NodeFlags.None; this.parent = undefined; + this.original = undefined; } public getSourceFile(): SourceFile { @@ -1876,7 +1878,7 @@ namespace ts { options.isolatedModules = true; - // transpileModule does not write anything to disk so there is no need to verify that there are no conflicts between input and output paths. + // transpileModule does not write anything to disk so there is no need to verify that there are no conflicts between input and output paths. options.suppressOutputPathCheck = true; // Filename can be non-ts file. @@ -6102,7 +6104,7 @@ namespace ts { } } - // For export specifiers, it can be a local symbol, e.g. + // For export specifiers, it can be a local symbol, e.g. // import {a} from "mod"; // export {a as somethingElse} // We want the local target of the export (i.e. the import symbol) and not the final target (i.e. "mod".a) diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.leadingAsterisk.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.leadingAsterisk.json new file mode 100644 index 00000000000..fbc795c1cb8 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.leadingAsterisk.json @@ -0,0 +1,37 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 27, + "tags": { + "0": { + "kind": "JSDocTypeTag", + "pos": 8, + "end": 22, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 13, + "text": "type" + }, + "typeExpression": { + "kind": "JSDocTypeExpression", + "pos": 14, + "end": 22, + "type": { + "kind": "NumberKeyword", + "pos": 15, + "end": 21 + } + } + }, + "length": 1, + "pos": 8, + "end": 22, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noLeadingAsterisk.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noLeadingAsterisk.json new file mode 100644 index 00000000000..fbc795c1cb8 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noLeadingAsterisk.json @@ -0,0 +1,37 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 27, + "tags": { + "0": { + "kind": "JSDocTypeTag", + "pos": 8, + "end": 22, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 13, + "text": "type" + }, + "typeExpression": { + "kind": "JSDocTypeExpression", + "pos": 14, + "end": 22, + "type": { + "kind": "NumberKeyword", + "pos": 15, + "end": 21 + } + } + }, + "length": 1, + "pos": 8, + "end": 22, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noReturnType.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noReturnType.json new file mode 100644 index 00000000000..118fedcc381 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noReturnType.json @@ -0,0 +1,27 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 20, + "tags": { + "0": { + "kind": "JSDocReturnTag", + "pos": 8, + "end": 15, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 15, + "text": "return" + } + }, + "length": 1, + "pos": 8, + "end": 15, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noType.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noType.json new file mode 100644 index 00000000000..98453fb802e --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noType.json @@ -0,0 +1,27 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 18, + "tags": { + "0": { + "kind": "JSDocTypeTag", + "pos": 8, + "end": 13, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 13, + "text": "type" + } + }, + "length": 1, + "pos": 8, + "end": 13, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.oneParamTag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.oneParamTag.json new file mode 100644 index 00000000000..d0c036bea74 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.oneParamTag.json @@ -0,0 +1,43 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 34, + "tags": { + "0": { + "kind": "JSDocParameterTag", + "pos": 8, + "end": 29, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 14, + "text": "param" + }, + "typeExpression": { + "kind": "JSDocTypeExpression", + "pos": 15, + "end": 23, + "type": { + "kind": "NumberKeyword", + "pos": 16, + "end": 22 + } + }, + "postParameterName": { + "kind": "Identifier", + "pos": 24, + "end": 29, + "text": "name1" + } + }, + "length": 1, + "pos": 8, + "end": 29, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTag1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTag1.json new file mode 100644 index 00000000000..e05c296e10b --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTag1.json @@ -0,0 +1,43 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 59, + "tags": { + "0": { + "kind": "JSDocParameterTag", + "pos": 8, + "end": 29, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 14, + "text": "param" + }, + "typeExpression": { + "kind": "JSDocTypeExpression", + "pos": 15, + "end": 23, + "type": { + "kind": "NumberKeyword", + "pos": 16, + "end": 22 + } + }, + "postParameterName": { + "kind": "Identifier", + "pos": 24, + "end": 29, + "text": "name1" + } + }, + "length": 1, + "pos": 8, + "end": 29, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName1.json new file mode 100644 index 00000000000..f731abb0a8e --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName1.json @@ -0,0 +1,44 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 61, + "tags": { + "0": { + "kind": "JSDocParameterTag", + "pos": 8, + "end": 31, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 14, + "text": "param" + }, + "typeExpression": { + "kind": "JSDocTypeExpression", + "pos": 15, + "end": 23, + "type": { + "kind": "NumberKeyword", + "pos": 16, + "end": 22 + } + }, + "postParameterName": { + "kind": "Identifier", + "pos": 25, + "end": 30, + "text": "name1" + }, + "isBracketed": true + }, + "length": 1, + "pos": 8, + "end": 31, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName2.json new file mode 100644 index 00000000000..e230dfcd46c --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName2.json @@ -0,0 +1,44 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 66, + "tags": { + "0": { + "kind": "JSDocParameterTag", + "pos": 8, + "end": 36, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 14, + "text": "param" + }, + "typeExpression": { + "kind": "JSDocTypeExpression", + "pos": 15, + "end": 23, + "type": { + "kind": "NumberKeyword", + "pos": 16, + "end": 22 + } + }, + "postParameterName": { + "kind": "Identifier", + "pos": 26, + "end": 31, + "text": "name1" + }, + "isBracketed": true + }, + "length": 1, + "pos": 8, + "end": 36, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType1.json new file mode 100644 index 00000000000..44173787d27 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType1.json @@ -0,0 +1,43 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 34, + "tags": { + "0": { + "kind": "JSDocParameterTag", + "pos": 8, + "end": 29, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 14, + "text": "param" + }, + "preParameterName": { + "kind": "Identifier", + "pos": 15, + "end": 20, + "text": "name1" + }, + "typeExpression": { + "kind": "JSDocTypeExpression", + "pos": 21, + "end": 29, + "type": { + "kind": "NumberKeyword", + "pos": 22, + "end": 28 + } + } + }, + "length": 1, + "pos": 8, + "end": 29, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType2.json new file mode 100644 index 00000000000..224eba3501e --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType2.json @@ -0,0 +1,43 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 46, + "tags": { + "0": { + "kind": "JSDocParameterTag", + "pos": 8, + "end": 29, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 14, + "text": "param" + }, + "preParameterName": { + "kind": "Identifier", + "pos": 15, + "end": 20, + "text": "name1" + }, + "typeExpression": { + "kind": "JSDocTypeExpression", + "pos": 21, + "end": 29, + "type": { + "kind": "NumberKeyword", + "pos": 22, + "end": 28 + } + } + }, + "length": 1, + "pos": 8, + "end": 29, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramWithoutType.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramWithoutType.json new file mode 100644 index 00000000000..0a78384e3e7 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramWithoutType.json @@ -0,0 +1,33 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 23, + "tags": { + "0": { + "kind": "JSDocParameterTag", + "pos": 8, + "end": 18, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 14, + "text": "param" + }, + "preParameterName": { + "kind": "Identifier", + "pos": 15, + "end": 18, + "text": "foo" + } + }, + "length": 1, + "pos": 8, + "end": 18, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag1.json new file mode 100644 index 00000000000..bac9b2a02ef --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag1.json @@ -0,0 +1,37 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 29, + "tags": { + "0": { + "kind": "JSDocReturnTag", + "pos": 8, + "end": 24, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 15, + "text": "return" + }, + "typeExpression": { + "kind": "JSDocTypeExpression", + "pos": 16, + "end": 24, + "type": { + "kind": "NumberKeyword", + "pos": 17, + "end": 23 + } + } + }, + "length": 1, + "pos": 8, + "end": 24, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag2.json new file mode 100644 index 00000000000..6f7fb02b529 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag2.json @@ -0,0 +1,37 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 54, + "tags": { + "0": { + "kind": "JSDocReturnTag", + "pos": 8, + "end": 24, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 15, + "text": "return" + }, + "typeExpression": { + "kind": "JSDocTypeExpression", + "pos": 16, + "end": 24, + "type": { + "kind": "NumberKeyword", + "pos": 17, + "end": 23 + } + } + }, + "length": 1, + "pos": 8, + "end": 24, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnsTag1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnsTag1.json new file mode 100644 index 00000000000..d64b56b0a21 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnsTag1.json @@ -0,0 +1,37 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 30, + "tags": { + "0": { + "kind": "JSDocReturnTag", + "pos": 8, + "end": 25, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 16, + "text": "returns" + }, + "typeExpression": { + "kind": "JSDocTypeExpression", + "pos": 17, + "end": 25, + "type": { + "kind": "NumberKeyword", + "pos": 18, + "end": 24 + } + } + }, + "length": 1, + "pos": 8, + "end": 25, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag.json new file mode 100644 index 00000000000..6be165c0c76 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag.json @@ -0,0 +1,44 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 24, + "tags": { + "0": { + "kind": "JSDocTemplateTag", + "pos": 8, + "end": 19, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 17, + "text": "template" + }, + "typeParameters": { + "0": { + "kind": "TypeParameter", + "pos": 18, + "end": 19, + "name": { + "kind": "Identifier", + "pos": 18, + "end": 19, + "text": "T" + } + }, + "length": 1, + "pos": 17, + "end": 19, + "arrayKind": 1 + } + }, + "length": 1, + "pos": 8, + "end": 19, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag2.json new file mode 100644 index 00000000000..85485b25143 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag2.json @@ -0,0 +1,55 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 26, + "tags": { + "0": { + "kind": "JSDocTemplateTag", + "pos": 8, + "end": 21, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 17, + "text": "template" + }, + "typeParameters": { + "0": { + "kind": "TypeParameter", + "pos": 18, + "end": 19, + "name": { + "kind": "Identifier", + "pos": 18, + "end": 19, + "text": "K" + } + }, + "1": { + "kind": "TypeParameter", + "pos": 20, + "end": 21, + "name": { + "kind": "Identifier", + "pos": 20, + "end": 21, + "text": "V" + } + }, + "length": 2, + "pos": 17, + "end": 21, + "arrayKind": 1 + } + }, + "length": 1, + "pos": 8, + "end": 21, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag3.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag3.json new file mode 100644 index 00000000000..e846f5daada --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag3.json @@ -0,0 +1,55 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 27, + "tags": { + "0": { + "kind": "JSDocTemplateTag", + "pos": 8, + "end": 22, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 17, + "text": "template" + }, + "typeParameters": { + "0": { + "kind": "TypeParameter", + "pos": 18, + "end": 19, + "name": { + "kind": "Identifier", + "pos": 18, + "end": 19, + "text": "K" + } + }, + "1": { + "kind": "TypeParameter", + "pos": 21, + "end": 22, + "name": { + "kind": "Identifier", + "pos": 21, + "end": 22, + "text": "V" + } + }, + "length": 2, + "pos": 17, + "end": 22, + "arrayKind": 1 + } + }, + "length": 1, + "pos": 8, + "end": 22, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag4.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag4.json new file mode 100644 index 00000000000..e846f5daada --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag4.json @@ -0,0 +1,55 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 27, + "tags": { + "0": { + "kind": "JSDocTemplateTag", + "pos": 8, + "end": 22, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 17, + "text": "template" + }, + "typeParameters": { + "0": { + "kind": "TypeParameter", + "pos": 18, + "end": 19, + "name": { + "kind": "Identifier", + "pos": 18, + "end": 19, + "text": "K" + } + }, + "1": { + "kind": "TypeParameter", + "pos": 21, + "end": 22, + "name": { + "kind": "Identifier", + "pos": 21, + "end": 22, + "text": "V" + } + }, + "length": 2, + "pos": 17, + "end": 22, + "arrayKind": 1 + } + }, + "length": 1, + "pos": 8, + "end": 22, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag5.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag5.json new file mode 100644 index 00000000000..245ed626980 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag5.json @@ -0,0 +1,55 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 28, + "tags": { + "0": { + "kind": "JSDocTemplateTag", + "pos": 8, + "end": 23, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 17, + "text": "template" + }, + "typeParameters": { + "0": { + "kind": "TypeParameter", + "pos": 18, + "end": 19, + "name": { + "kind": "Identifier", + "pos": 18, + "end": 19, + "text": "K" + } + }, + "1": { + "kind": "TypeParameter", + "pos": 22, + "end": 23, + "name": { + "kind": "Identifier", + "pos": 22, + "end": 23, + "text": "V" + } + }, + "length": 2, + "pos": 17, + "end": 23, + "arrayKind": 1 + } + }, + "length": 1, + "pos": 8, + "end": 23, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag6.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag6.json new file mode 100644 index 00000000000..323770c644e --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag6.json @@ -0,0 +1,55 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 60, + "tags": { + "0": { + "kind": "JSDocTemplateTag", + "pos": 8, + "end": 23, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 17, + "text": "template" + }, + "typeParameters": { + "0": { + "kind": "TypeParameter", + "pos": 18, + "end": 19, + "name": { + "kind": "Identifier", + "pos": 18, + "end": 19, + "text": "K" + } + }, + "1": { + "kind": "TypeParameter", + "pos": 22, + "end": 23, + "name": { + "kind": "Identifier", + "pos": 22, + "end": 23, + "text": "V" + } + }, + "length": 2, + "pos": 17, + "end": 23, + "arrayKind": 1 + } + }, + "length": 1, + "pos": 8, + "end": 23, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTag2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTag2.json new file mode 100644 index 00000000000..95c96531bdf --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTag2.json @@ -0,0 +1,75 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 60, + "tags": { + "0": { + "kind": "JSDocParameterTag", + "pos": 8, + "end": 29, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 14, + "text": "param" + }, + "typeExpression": { + "kind": "JSDocTypeExpression", + "pos": 15, + "end": 23, + "type": { + "kind": "NumberKeyword", + "pos": 16, + "end": 22 + } + }, + "postParameterName": { + "kind": "Identifier", + "pos": 24, + "end": 29, + "text": "name1" + } + }, + "1": { + "kind": "JSDocParameterTag", + "pos": 34, + "end": 55, + "atToken": { + "kind": "AtToken", + "pos": 34, + "end": 35 + }, + "tagName": { + "kind": "Identifier", + "pos": 35, + "end": 40, + "text": "param" + }, + "typeExpression": { + "kind": "JSDocTypeExpression", + "pos": 41, + "end": 49, + "type": { + "kind": "NumberKeyword", + "pos": 42, + "end": 48 + } + }, + "postParameterName": { + "kind": "Identifier", + "pos": 50, + "end": 55, + "text": "name2" + } + }, + "length": 2, + "pos": 8, + "end": 55, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTagOnSameLine.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTagOnSameLine.json new file mode 100644 index 00000000000..93b84f00324 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTagOnSameLine.json @@ -0,0 +1,43 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 56, + "tags": { + "0": { + "kind": "JSDocParameterTag", + "pos": 8, + "end": 29, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 14, + "text": "param" + }, + "typeExpression": { + "kind": "JSDocTypeExpression", + "pos": 15, + "end": 23, + "type": { + "kind": "NumberKeyword", + "pos": 16, + "end": 22 + } + }, + "postParameterName": { + "kind": "Identifier", + "pos": 24, + "end": 29, + "text": "name1" + } + }, + "length": 1, + "pos": 8, + "end": 29, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typeTag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typeTag.json new file mode 100644 index 00000000000..fbc795c1cb8 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typeTag.json @@ -0,0 +1,37 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 27, + "tags": { + "0": { + "kind": "JSDocTypeTag", + "pos": 8, + "end": 22, + "atToken": { + "kind": "AtToken", + "pos": 8, + "end": 9 + }, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 13, + "text": "type" + }, + "typeExpression": { + "kind": "JSDocTypeExpression", + "pos": 14, + "end": 22, + "type": { + "kind": "NumberKeyword", + "pos": 15, + "end": 21 + } + } + }, + "length": 1, + "pos": 8, + "end": 22, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.allType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.allType.json new file mode 100644 index 00000000000..68081a1b9e4 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.allType.json @@ -0,0 +1,5 @@ +{ + "kind": "JSDocAllType", + "pos": 1, + "end": 2 +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.arrayType1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.arrayType1.json new file mode 100644 index 00000000000..cd9255d392c --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.arrayType1.json @@ -0,0 +1,16 @@ +{ + "kind": "JSDocArrayType", + "pos": 1, + "end": 4, + "elementType": { + "kind": "JSDocTypeReference", + "pos": 1, + "end": 2, + "name": { + "kind": "Identifier", + "pos": 1, + "end": 2, + "text": "a" + } + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.arrayType2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.arrayType2.json new file mode 100644 index 00000000000..1fe6d184599 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.arrayType2.json @@ -0,0 +1,21 @@ +{ + "kind": "JSDocArrayType", + "pos": 1, + "end": 6, + "elementType": { + "kind": "JSDocArrayType", + "pos": 1, + "end": 4, + "elementType": { + "kind": "JSDocTypeReference", + "pos": 1, + "end": 2, + "name": { + "kind": "Identifier", + "pos": 1, + "end": 2, + "text": "a" + } + } + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.arrayType3.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.arrayType3.json new file mode 100644 index 00000000000..2fe27c67a1b --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.arrayType3.json @@ -0,0 +1,26 @@ +{ + "kind": "JSDocOptionalType", + "pos": 1, + "end": 7, + "type": { + "kind": "JSDocArrayType", + "pos": 1, + "end": 6, + "elementType": { + "kind": "JSDocArrayType", + "pos": 1, + "end": 4, + "elementType": { + "kind": "JSDocTypeReference", + "pos": 1, + "end": 2, + "name": { + "kind": "Identifier", + "pos": 1, + "end": 2, + "text": "a" + } + } + } + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionReturnType1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionReturnType1.json new file mode 100644 index 00000000000..e02b9ab7dd9 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionReturnType1.json @@ -0,0 +1,31 @@ +{ + "kind": "JSDocFunctionType", + "pos": 1, + "end": 26, + "parameters": { + "0": { + "kind": "Parameter", + "pos": 10, + "end": 16, + "type": { + "kind": "StringKeyword", + "pos": 10, + "end": 16 + } + }, + "1": { + "kind": "Parameter", + "pos": 17, + "end": 25, + "type": { + "kind": "BooleanKeyword", + "pos": 17, + "end": 25 + } + }, + "length": 2, + "pos": 10, + "end": 25, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionType1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionType1.json new file mode 100644 index 00000000000..94fe0ec2978 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionType1.json @@ -0,0 +1,11 @@ +{ + "kind": "JSDocFunctionType", + "pos": 1, + "end": 11, + "parameters": { + "length": 0, + "pos": 10, + "end": 10, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionType2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionType2.json new file mode 100644 index 00000000000..e02b9ab7dd9 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionType2.json @@ -0,0 +1,31 @@ +{ + "kind": "JSDocFunctionType", + "pos": 1, + "end": 26, + "parameters": { + "0": { + "kind": "Parameter", + "pos": 10, + "end": 16, + "type": { + "kind": "StringKeyword", + "pos": 10, + "end": 16 + } + }, + "1": { + "kind": "Parameter", + "pos": 17, + "end": 25, + "type": { + "kind": "BooleanKeyword", + "pos": 17, + "end": 25 + } + }, + "length": 2, + "pos": 10, + "end": 25, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.keyword1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.keyword1.json new file mode 100644 index 00000000000..80b1378b291 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.keyword1.json @@ -0,0 +1,12 @@ +{ + "kind": "JSDocTypeReference", + "pos": 1, + "end": 4, + "name": { + "kind": "Identifier", + "pos": 1, + "end": 4, + "originalKeywordKind": "VarKeyword", + "text": "var" + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.keyword2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.keyword2.json new file mode 100644 index 00000000000..91972325847 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.keyword2.json @@ -0,0 +1,12 @@ +{ + "kind": "JSDocTypeReference", + "pos": 1, + "end": 5, + "name": { + "kind": "Identifier", + "pos": 1, + "end": 5, + "originalKeywordKind": "NullKeyword", + "text": "null" + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.keyword3.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.keyword3.json new file mode 100644 index 00000000000..f7624064826 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.keyword3.json @@ -0,0 +1,11 @@ +{ + "kind": "JSDocTypeReference", + "pos": 1, + "end": 10, + "name": { + "kind": "Identifier", + "pos": 1, + "end": 10, + "text": "undefined" + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.newType1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.newType1.json new file mode 100644 index 00000000000..194037970c5 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.newType1.json @@ -0,0 +1,27 @@ +{ + "kind": "JSDocConstructorType", + "pos": 1, + "end": 8, + "type": { + "kind": "JSDocTypeReference", + "pos": 5, + "end": 8, + "name": { + "kind": "FirstNode", + "pos": 5, + "end": 8, + "left": { + "kind": "Identifier", + "pos": 5, + "end": 6, + "text": "a" + }, + "right": { + "kind": "Identifier", + "pos": 7, + "end": 8, + "text": "b" + } + } + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nonNullableType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nonNullableType.json new file mode 100644 index 00000000000..e089754a0de --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nonNullableType.json @@ -0,0 +1,10 @@ +{ + "kind": "JSDocNonNullableType", + "pos": 1, + "end": 8, + "type": { + "kind": "NumberKeyword", + "pos": 2, + "end": 8 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nonNullableType2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nonNullableType2.json new file mode 100644 index 00000000000..377b19d0f70 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nonNullableType2.json @@ -0,0 +1,10 @@ +{ + "kind": "JSDocNonNullableType", + "pos": 1, + "end": 8, + "type": { + "kind": "NumberKeyword", + "pos": 1, + "end": 7 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nullableType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nullableType.json new file mode 100644 index 00000000000..9c4457fba12 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nullableType.json @@ -0,0 +1,10 @@ +{ + "kind": "JSDocNullableType", + "pos": 1, + "end": 8, + "type": { + "kind": "NumberKeyword", + "pos": 2, + "end": 8 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nullableType2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nullableType2.json new file mode 100644 index 00000000000..03aea7be8c5 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nullableType2.json @@ -0,0 +1,10 @@ +{ + "kind": "JSDocNullableType", + "pos": 1, + "end": 8, + "type": { + "kind": "NumberKeyword", + "pos": 1, + "end": 7 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.optionalNullable.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.optionalNullable.json new file mode 100644 index 00000000000..f4940c28475 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.optionalNullable.json @@ -0,0 +1,10 @@ +{ + "kind": "JSDocOptionalType", + "pos": 1, + "end": 3, + "type": { + "kind": "JSDocUnknownType", + "pos": 1, + "end": 2 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.optionalType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.optionalType.json new file mode 100644 index 00000000000..6069107cc6e --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.optionalType.json @@ -0,0 +1,10 @@ +{ + "kind": "JSDocOptionalType", + "pos": 1, + "end": 8, + "type": { + "kind": "NumberKeyword", + "pos": 1, + "end": 7 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType1.json new file mode 100644 index 00000000000..929f0046cff --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType1.json @@ -0,0 +1,11 @@ +{ + "kind": "JSDocRecordType", + "pos": 1, + "end": 3, + "members": { + "length": 0, + "pos": 2, + "end": 2, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType2.json new file mode 100644 index 00000000000..8e6eb1fa11a --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType2.json @@ -0,0 +1,22 @@ +{ + "kind": "JSDocRecordType", + "pos": 1, + "end": 6, + "members": { + "0": { + "kind": "JSDocRecordMember", + "pos": 2, + "end": 5, + "name": { + "kind": "Identifier", + "pos": 2, + "end": 5, + "text": "foo" + } + }, + "length": 1, + "pos": 2, + "end": 5, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType3.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType3.json new file mode 100644 index 00000000000..ce5dedcaf56 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType3.json @@ -0,0 +1,27 @@ +{ + "kind": "JSDocRecordType", + "pos": 1, + "end": 14, + "members": { + "0": { + "kind": "JSDocRecordMember", + "pos": 2, + "end": 13, + "name": { + "kind": "Identifier", + "pos": 2, + "end": 5, + "text": "foo" + }, + "type": { + "kind": "NumberKeyword", + "pos": 6, + "end": 13 + } + }, + "length": 1, + "pos": 2, + "end": 13, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType4.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType4.json new file mode 100644 index 00000000000..1192b2a3a3c --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType4.json @@ -0,0 +1,33 @@ +{ + "kind": "JSDocRecordType", + "pos": 1, + "end": 11, + "members": { + "0": { + "kind": "JSDocRecordMember", + "pos": 2, + "end": 5, + "name": { + "kind": "Identifier", + "pos": 2, + "end": 5, + "text": "foo" + } + }, + "1": { + "kind": "JSDocRecordMember", + "pos": 6, + "end": 10, + "name": { + "kind": "Identifier", + "pos": 6, + "end": 10, + "text": "bar" + } + }, + "length": 2, + "pos": 2, + "end": 10, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType5.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType5.json new file mode 100644 index 00000000000..b31585c8e37 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType5.json @@ -0,0 +1,38 @@ +{ + "kind": "JSDocRecordType", + "pos": 1, + "end": 19, + "members": { + "0": { + "kind": "JSDocRecordMember", + "pos": 2, + "end": 13, + "name": { + "kind": "Identifier", + "pos": 2, + "end": 5, + "text": "foo" + }, + "type": { + "kind": "NumberKeyword", + "pos": 6, + "end": 13 + } + }, + "1": { + "kind": "JSDocRecordMember", + "pos": 14, + "end": 18, + "name": { + "kind": "Identifier", + "pos": 14, + "end": 18, + "text": "bar" + } + }, + "length": 2, + "pos": 2, + "end": 18, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType6.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType6.json new file mode 100644 index 00000000000..81ee5b53451 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType6.json @@ -0,0 +1,38 @@ +{ + "kind": "JSDocRecordType", + "pos": 1, + "end": 19, + "members": { + "0": { + "kind": "JSDocRecordMember", + "pos": 2, + "end": 5, + "name": { + "kind": "Identifier", + "pos": 2, + "end": 5, + "text": "foo" + } + }, + "1": { + "kind": "JSDocRecordMember", + "pos": 6, + "end": 18, + "name": { + "kind": "Identifier", + "pos": 6, + "end": 10, + "text": "bar" + }, + "type": { + "kind": "NumberKeyword", + "pos": 11, + "end": 18 + } + }, + "length": 2, + "pos": 2, + "end": 18, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType7.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType7.json new file mode 100644 index 00000000000..595798b1a83 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType7.json @@ -0,0 +1,43 @@ +{ + "kind": "JSDocRecordType", + "pos": 1, + "end": 27, + "members": { + "0": { + "kind": "JSDocRecordMember", + "pos": 2, + "end": 13, + "name": { + "kind": "Identifier", + "pos": 2, + "end": 5, + "text": "foo" + }, + "type": { + "kind": "NumberKeyword", + "pos": 6, + "end": 13 + } + }, + "1": { + "kind": "JSDocRecordMember", + "pos": 14, + "end": 26, + "name": { + "kind": "Identifier", + "pos": 14, + "end": 18, + "text": "bar" + }, + "type": { + "kind": "NumberKeyword", + "pos": 19, + "end": 26 + } + }, + "length": 2, + "pos": 2, + "end": 26, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json new file mode 100644 index 00000000000..b4d00c873ce --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json @@ -0,0 +1,23 @@ +{ + "kind": "JSDocRecordType", + "pos": 1, + "end": 11, + "members": { + "0": { + "kind": "JSDocRecordMember", + "pos": 2, + "end": 10, + "name": { + "kind": "Identifier", + "pos": 2, + "end": 10, + "originalKeywordKind": "FunctionKeyword", + "text": "function" + } + }, + "length": 1, + "pos": 2, + "end": 10, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.thisType1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.thisType1.json new file mode 100644 index 00000000000..f0b8038b586 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.thisType1.json @@ -0,0 +1,27 @@ +{ + "kind": "JSDocThisType", + "pos": 1, + "end": 9, + "type": { + "kind": "JSDocTypeReference", + "pos": 6, + "end": 9, + "name": { + "kind": "FirstNode", + "pos": 6, + "end": 9, + "left": { + "kind": "Identifier", + "pos": 6, + "end": 7, + "text": "a" + }, + "right": { + "kind": "Identifier", + "pos": 8, + "end": 9, + "text": "b" + } + } + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.topLevelNoParenUnionType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.topLevelNoParenUnionType.json new file mode 100644 index 00000000000..dd1b017da00 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.topLevelNoParenUnionType.json @@ -0,0 +1,21 @@ +{ + "kind": "JSDocUnionType", + "pos": 1, + "end": 14, + "types": { + "0": { + "kind": "NumberKeyword", + "pos": 1, + "end": 7 + }, + "1": { + "kind": "StringKeyword", + "pos": 8, + "end": 14 + }, + "length": 2, + "pos": 1, + "end": 14, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType0.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType0.json new file mode 100644 index 00000000000..dbb6f35ab00 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType0.json @@ -0,0 +1,11 @@ +{ + "kind": "JSDocTupleType", + "pos": 1, + "end": 3, + "types": { + "length": 0, + "pos": 2, + "end": 2, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType1.json new file mode 100644 index 00000000000..1ab9530626d --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType1.json @@ -0,0 +1,16 @@ +{ + "kind": "JSDocTupleType", + "pos": 1, + "end": 9, + "types": { + "0": { + "kind": "NumberKeyword", + "pos": 2, + "end": 8 + }, + "length": 1, + "pos": 2, + "end": 8, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType2.json new file mode 100644 index 00000000000..aaea91528d7 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType2.json @@ -0,0 +1,21 @@ +{ + "kind": "JSDocTupleType", + "pos": 1, + "end": 16, + "types": { + "0": { + "kind": "NumberKeyword", + "pos": 2, + "end": 8 + }, + "1": { + "kind": "StringKeyword", + "pos": 9, + "end": 15 + }, + "length": 2, + "pos": 2, + "end": 15, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType3.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType3.json new file mode 100644 index 00000000000..a685de86622 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType3.json @@ -0,0 +1,26 @@ +{ + "kind": "JSDocTupleType", + "pos": 1, + "end": 24, + "types": { + "0": { + "kind": "NumberKeyword", + "pos": 2, + "end": 8 + }, + "1": { + "kind": "StringKeyword", + "pos": 9, + "end": 15 + }, + "2": { + "kind": "BooleanKeyword", + "pos": 16, + "end": 23 + }, + "length": 3, + "pos": 2, + "end": 23, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference1.json new file mode 100644 index 00000000000..970c6fe1b13 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference1.json @@ -0,0 +1,22 @@ +{ + "kind": "JSDocTypeReference", + "pos": 1, + "end": 11, + "name": { + "kind": "Identifier", + "pos": 1, + "end": 2, + "text": "a" + }, + "typeArguments": { + "0": { + "kind": "NumberKeyword", + "pos": 4, + "end": 10 + }, + "length": 1, + "pos": 4, + "end": 10, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference2.json new file mode 100644 index 00000000000..913ba27897d --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference2.json @@ -0,0 +1,27 @@ +{ + "kind": "JSDocTypeReference", + "pos": 1, + "end": 18, + "name": { + "kind": "Identifier", + "pos": 1, + "end": 2, + "text": "a" + }, + "typeArguments": { + "0": { + "kind": "NumberKeyword", + "pos": 4, + "end": 10 + }, + "1": { + "kind": "StringKeyword", + "pos": 11, + "end": 17 + }, + "length": 2, + "pos": 4, + "end": 17, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference3.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference3.json new file mode 100644 index 00000000000..683c17e582e --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference3.json @@ -0,0 +1,23 @@ +{ + "kind": "JSDocTypeReference", + "pos": 1, + "end": 11, + "name": { + "kind": "FirstNode", + "pos": 1, + "end": 11, + "left": { + "kind": "Identifier", + "pos": 1, + "end": 2, + "text": "a" + }, + "right": { + "kind": "Identifier", + "pos": 3, + "end": 11, + "originalKeywordKind": "FunctionKeyword", + "text": "function" + } + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.unionType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.unionType.json new file mode 100644 index 00000000000..aae1d6bc169 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.unionType.json @@ -0,0 +1,21 @@ +{ + "kind": "JSDocUnionType", + "pos": 1, + "end": 16, + "types": { + "0": { + "kind": "NumberKeyword", + "pos": 2, + "end": 8 + }, + "1": { + "kind": "StringKeyword", + "pos": 9, + "end": 15 + }, + "length": 2, + "pos": 2, + "end": 15, + "arrayKind": 1 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.unknownType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.unknownType.json new file mode 100644 index 00000000000..0fb7af7ef23 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.unknownType.json @@ -0,0 +1,5 @@ +{ + "kind": "JSDocUnknownType", + "pos": 1, + "end": 2 +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.variadicType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.variadicType.json new file mode 100644 index 00000000000..2cf6079533c --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.variadicType.json @@ -0,0 +1,10 @@ +{ + "kind": "JSDocVariadicType", + "pos": 1, + "end": 10, + "type": { + "kind": "NumberKeyword", + "pos": 4, + "end": 10 + } +} \ No newline at end of file diff --git a/tests/cases/unittests/jsDocParsing.ts b/tests/cases/unittests/jsDocParsing.ts index 9988383b467..b742ef783df 100644 --- a/tests/cases/unittests/jsDocParsing.ts +++ b/tests/cases/unittests/jsDocParsing.ts @@ -6,2213 +6,281 @@ module ts { describe("JSDocParsing", () => { describe("TypeExpressions", () => { - function parsesCorrectly(content: string, expected: string) { - let typeAndDiagnostics = ts.parseJSDocTypeExpressionForTests(content); - assert.isTrue(typeAndDiagnostics && typeAndDiagnostics.diagnostics.length === 0); + function parsesCorrectly(name: string, content: string) { + it(name, () => { + let typeAndDiagnostics = ts.parseJSDocTypeExpressionForTests(content); + assert.isTrue(typeAndDiagnostics && typeAndDiagnostics.diagnostics.length === 0); - let result = Utils.sourceFileToJSON(typeAndDiagnostics.jsDocTypeExpression.type); - assert.equal(result, expected); + Harness.Baseline.runBaseline("parseCorrectly", "JSDocParsing/TypeExpressions.parsesCorrectly." + name + ".json", + () => Utils.sourceFileToJSON(typeAndDiagnostics.jsDocTypeExpression.type)); + }); } - function parsesIncorrectly(content: string) { - let type = ts.parseJSDocTypeExpressionForTests(content); - assert.isTrue(!type || type.diagnostics.length > 0); + function parsesIncorrectly(name: string, content: string) { + it(name, () => { + let type = ts.parseJSDocTypeExpressionForTests(content); + assert.isTrue(!type || type.diagnostics.length > 0); + }); } describe("parseCorrectly", () => { - it("unknownType", () => { - parsesCorrectly("{?}", - `{ - "kind": "JSDocUnknownType", - "pos": 1, - "end": 2 -}`); - }); - - it("allType", () => { - parsesCorrectly("{*}", - `{ - "kind": "JSDocAllType", - "pos": 1, - "end": 2 -}`); - }); - - it("nullableType", () => { - parsesCorrectly("{?number}", - `{ - "kind": "JSDocNullableType", - "pos": 1, - "end": 8, - "type": { - "kind": "NumberKeyword", - "pos": 2, - "end": 8 - } -}`) - }); - - it("nullableType2", () => { - parsesCorrectly("{number?}", - `{ - "kind": "JSDocNullableType", - "pos": 1, - "end": 8, - "type": { - "kind": "NumberKeyword", - "pos": 1, - "end": 7 - } -}`) - }); - - it("nonNullableType", () => { - parsesCorrectly("{!number}", - `{ - "kind": "JSDocNonNullableType", - "pos": 1, - "end": 8, - "type": { - "kind": "NumberKeyword", - "pos": 2, - "end": 8 - } -}`) - }); - - it("nonNullableType2", () => { - parsesCorrectly("{number!}", - `{ - "kind": "JSDocNonNullableType", - "pos": 1, - "end": 8, - "type": { - "kind": "NumberKeyword", - "pos": 1, - "end": 7 - } -}`) - }); - - it("recordType1", () => { - parsesCorrectly("{{}}", - `{ - "kind": "JSDocRecordType", - "pos": 1, - "end": 3, - "members": { - "length": 0, - "pos": 2, - "end": 2 - } -}`) - }); - - it("recordType2", () => { - parsesCorrectly("{{foo}}", - `{ - "kind": "JSDocRecordType", - "pos": 1, - "end": 6, - "members": { - "0": { - "kind": "JSDocRecordMember", - "pos": 2, - "end": 5, - "name": { - "kind": "Identifier", - "pos": 2, - "end": 5, - "text": "foo" - } - }, - "length": 1, - "pos": 2, - "end": 5 - } -}`) - }); - - it("recordType3", () => { - parsesCorrectly("{{foo: number}}", - `{ - "kind": "JSDocRecordType", - "pos": 1, - "end": 14, - "members": { - "0": { - "kind": "JSDocRecordMember", - "pos": 2, - "end": 13, - "name": { - "kind": "Identifier", - "pos": 2, - "end": 5, - "text": "foo" - }, - "type": { - "kind": "NumberKeyword", - "pos": 6, - "end": 13 - } - }, - "length": 1, - "pos": 2, - "end": 13 - } -}`) - }); - - it("recordType4", () => { - parsesCorrectly("{{foo, bar}}", - `{ - "kind": "JSDocRecordType", - "pos": 1, - "end": 11, - "members": { - "0": { - "kind": "JSDocRecordMember", - "pos": 2, - "end": 5, - "name": { - "kind": "Identifier", - "pos": 2, - "end": 5, - "text": "foo" - } - }, - "1": { - "kind": "JSDocRecordMember", - "pos": 6, - "end": 10, - "name": { - "kind": "Identifier", - "pos": 6, - "end": 10, - "text": "bar" - } - }, - "length": 2, - "pos": 2, - "end": 10 - } -}`) - }); - - it("recordType5", () => { - parsesCorrectly("{{foo: number, bar}}", - `{ - "kind": "JSDocRecordType", - "pos": 1, - "end": 19, - "members": { - "0": { - "kind": "JSDocRecordMember", - "pos": 2, - "end": 13, - "name": { - "kind": "Identifier", - "pos": 2, - "end": 5, - "text": "foo" - }, - "type": { - "kind": "NumberKeyword", - "pos": 6, - "end": 13 - } - }, - "1": { - "kind": "JSDocRecordMember", - "pos": 14, - "end": 18, - "name": { - "kind": "Identifier", - "pos": 14, - "end": 18, - "text": "bar" - } - }, - "length": 2, - "pos": 2, - "end": 18 - } -}`) - }); - - it("recordType6", () => { - parsesCorrectly("{{foo, bar: number}}", - `{ - "kind": "JSDocRecordType", - "pos": 1, - "end": 19, - "members": { - "0": { - "kind": "JSDocRecordMember", - "pos": 2, - "end": 5, - "name": { - "kind": "Identifier", - "pos": 2, - "end": 5, - "text": "foo" - } - }, - "1": { - "kind": "JSDocRecordMember", - "pos": 6, - "end": 18, - "name": { - "kind": "Identifier", - "pos": 6, - "end": 10, - "text": "bar" - }, - "type": { - "kind": "NumberKeyword", - "pos": 11, - "end": 18 - } - }, - "length": 2, - "pos": 2, - "end": 18 - } -}`) - }); - - it("recordType7", () => { - parsesCorrectly("{{foo: number, bar: number}}", - `{ - "kind": "JSDocRecordType", - "pos": 1, - "end": 27, - "members": { - "0": { - "kind": "JSDocRecordMember", - "pos": 2, - "end": 13, - "name": { - "kind": "Identifier", - "pos": 2, - "end": 5, - "text": "foo" - }, - "type": { - "kind": "NumberKeyword", - "pos": 6, - "end": 13 - } - }, - "1": { - "kind": "JSDocRecordMember", - "pos": 14, - "end": 26, - "name": { - "kind": "Identifier", - "pos": 14, - "end": 18, - "text": "bar" - }, - "type": { - "kind": "NumberKeyword", - "pos": 19, - "end": 26 - } - }, - "length": 2, - "pos": 2, - "end": 26 - } -}`) - }); - - it("recordType8", () => { - parsesCorrectly("{{function}}", - `{ - "kind": "JSDocRecordType", - "pos": 1, - "end": 11, - "members": { - "0": { - "kind": "JSDocRecordMember", - "pos": 2, - "end": 10, - "name": { - "kind": "Identifier", - "pos": 2, - "end": 10, - "originalKeywordKind": "FunctionKeyword", - "text": "function" - } - }, - "length": 1, - "pos": 2, - "end": 10 - } -}`) - }); - - it("unionType", () => { - parsesCorrectly("{(number|string)}", - `{ - "kind": "JSDocUnionType", - "pos": 1, - "end": 16, - "types": { - "0": { - "kind": "NumberKeyword", - "pos": 2, - "end": 8 - }, - "1": { - "kind": "StringKeyword", - "pos": 9, - "end": 15 - }, - "length": 2, - "pos": 2, - "end": 15 - } -}`); - }); - - it("topLevelNoParenUnionType", () => { - parsesCorrectly("{number|string}", - `{ - "kind": "JSDocUnionType", - "pos": 1, - "end": 14, - "types": { - "0": { - "kind": "NumberKeyword", - "pos": 1, - "end": 7 - }, - "1": { - "kind": "StringKeyword", - "pos": 8, - "end": 14 - }, - "length": 2, - "pos": 1, - "end": 14 - } -}`); - }); - - it("functionType1", () => { - parsesCorrectly("{function()}", - `{ - "kind": "JSDocFunctionType", - "pos": 1, - "end": 11, - "parameters": { - "length": 0, - "pos": 10, - "end": 10 - } -}`); - }); - - it("functionType2", () => { - parsesCorrectly("{function(string, boolean)}", - `{ - "kind": "JSDocFunctionType", - "pos": 1, - "end": 26, - "parameters": { - "0": { - "kind": "Parameter", - "pos": 10, - "end": 16, - "type": { - "kind": "StringKeyword", - "pos": 10, - "end": 16 - } - }, - "1": { - "kind": "Parameter", - "pos": 17, - "end": 25, - "type": { - "kind": "BooleanKeyword", - "pos": 17, - "end": 25 - } - }, - "length": 2, - "pos": 10, - "end": 25 - } -}`); - }); - - it("functionReturnType1", () => { - parsesCorrectly("{function(string, boolean)}", - `{ - "kind": "JSDocFunctionType", - "pos": 1, - "end": 26, - "parameters": { - "0": { - "kind": "Parameter", - "pos": 10, - "end": 16, - "type": { - "kind": "StringKeyword", - "pos": 10, - "end": 16 - } - }, - "1": { - "kind": "Parameter", - "pos": 17, - "end": 25, - "type": { - "kind": "BooleanKeyword", - "pos": 17, - "end": 25 - } - }, - "length": 2, - "pos": 10, - "end": 25 - } -}`); - }); - - it("thisType1", () => { - parsesCorrectly("{this:a.b}", - `{ - "kind": "JSDocThisType", - "pos": 1, - "end": 9, - "type": { - "kind": "JSDocTypeReference", - "pos": 6, - "end": 9, - "name": { - "kind": "FirstNode", - "pos": 6, - "end": 9, - "left": { - "kind": "Identifier", - "pos": 6, - "end": 7, - "text": "a" - }, - "right": { - "kind": "Identifier", - "pos": 8, - "end": 9, - "text": "b" - } - } - } -}`); - }); - - it("newType1", () => { - parsesCorrectly("{new:a.b}", - `{ - "kind": "JSDocConstructorType", - "pos": 1, - "end": 8, - "type": { - "kind": "JSDocTypeReference", - "pos": 5, - "end": 8, - "name": { - "kind": "FirstNode", - "pos": 5, - "end": 8, - "left": { - "kind": "Identifier", - "pos": 5, - "end": 6, - "text": "a" - }, - "right": { - "kind": "Identifier", - "pos": 7, - "end": 8, - "text": "b" - } - } - } -}`); - }); - - it("variadicType", () => { - parsesCorrectly("{...number}", - `{ - "kind": "JSDocVariadicType", - "pos": 1, - "end": 10, - "type": { - "kind": "NumberKeyword", - "pos": 4, - "end": 10 - } -}`); - }); - - it("optionalType", () => { - parsesCorrectly("{number=}", - `{ - "kind": "JSDocOptionalType", - "pos": 1, - "end": 8, - "type": { - "kind": "NumberKeyword", - "pos": 1, - "end": 7 - } -}`); - }); - - it("optionalNullable", () => { - parsesCorrectly("{?=}", - `{ - "kind": "JSDocOptionalType", - "pos": 1, - "end": 3, - "type": { - "kind": "JSDocUnknownType", - "pos": 1, - "end": 2 - } -}`); - }); - - it("typeReference1", () => { - parsesCorrectly("{a.}", - `{ - "kind": "JSDocTypeReference", - "pos": 1, - "end": 11, - "name": { - "kind": "Identifier", - "pos": 1, - "end": 2, - "text": "a" - }, - "typeArguments": { - "0": { - "kind": "NumberKeyword", - "pos": 4, - "end": 10 - }, - "length": 1, - "pos": 4, - "end": 10 - } -}`); - }); - - it("typeReference2", () => { - parsesCorrectly("{a.}", - `{ - "kind": "JSDocTypeReference", - "pos": 1, - "end": 18, - "name": { - "kind": "Identifier", - "pos": 1, - "end": 2, - "text": "a" - }, - "typeArguments": { - "0": { - "kind": "NumberKeyword", - "pos": 4, - "end": 10 - }, - "1": { - "kind": "StringKeyword", - "pos": 11, - "end": 17 - }, - "length": 2, - "pos": 4, - "end": 17 - } -}`); - }); - - it("typeReference3", () => { - parsesCorrectly("{a.function}", - `{ - "kind": "JSDocTypeReference", - "pos": 1, - "end": 11, - "name": { - "kind": "FirstNode", - "pos": 1, - "end": 11, - "left": { - "kind": "Identifier", - "pos": 1, - "end": 2, - "text": "a" - }, - "right": { - "kind": "Identifier", - "pos": 3, - "end": 11, - "originalKeywordKind": "FunctionKeyword", - "text": "function" - } - } -}`); - }); - - it("arrayType1", () => { - parsesCorrectly( - "{a[]}", - `{ - "kind": "JSDocArrayType", - "pos": 1, - "end": 4, - "elementType": { - "kind": "JSDocTypeReference", - "pos": 1, - "end": 2, - "name": { - "kind": "Identifier", - "pos": 1, - "end": 2, - "text": "a" - } - } -}`); - }); - - it("arrayType2", () => { - parsesCorrectly( - "{a[][]}", - `{ - "kind": "JSDocArrayType", - "pos": 1, - "end": 6, - "elementType": { - "kind": "JSDocArrayType", - "pos": 1, - "end": 4, - "elementType": { - "kind": "JSDocTypeReference", - "pos": 1, - "end": 2, - "name": { - "kind": "Identifier", - "pos": 1, - "end": 2, - "text": "a" - } - } - } -}`); - }); - - it("arrayType3", () => { - parsesCorrectly( - "{a[][]=}", - `{ - "kind": "JSDocOptionalType", - "pos": 1, - "end": 7, - "type": { - "kind": "JSDocArrayType", - "pos": 1, - "end": 6, - "elementType": { - "kind": "JSDocArrayType", - "pos": 1, - "end": 4, - "elementType": { - "kind": "JSDocTypeReference", - "pos": 1, - "end": 2, - "name": { - "kind": "Identifier", - "pos": 1, - "end": 2, - "text": "a" - } - } - } - } -}`); - }); - - it("keyword1", () => { - parsesCorrectly( - "{var}", - `{ - "kind": "JSDocTypeReference", - "pos": 1, - "end": 4, - "name": { - "kind": "Identifier", - "pos": 1, - "end": 4, - "originalKeywordKind": "VarKeyword", - "text": "var" - } -}`); - }); - - it("keyword2", () => { - parsesCorrectly( - "{null}", - `{ - "kind": "JSDocTypeReference", - "pos": 1, - "end": 5, - "name": { - "kind": "Identifier", - "pos": 1, - "end": 5, - "originalKeywordKind": "NullKeyword", - "text": "null" - } -}`); - }); - - it("keyword3", () => { - parsesCorrectly( - "{undefined}", - `{ - "kind": "JSDocTypeReference", - "pos": 1, - "end": 10, - "name": { - "kind": "Identifier", - "pos": 1, - "end": 10, - "text": "undefined" - } -}`); - }); - - it("tupleType0", () => { - parsesCorrectly( - "{[]}", - `{ - "kind": "JSDocTupleType", - "pos": 1, - "end": 3, - "types": { - "length": 0, - "pos": 2, - "end": 2 - } -}`); - }); - - it("tupleType1", () => { - parsesCorrectly( - "{[number]}", - `{ - "kind": "JSDocTupleType", - "pos": 1, - "end": 9, - "types": { - "0": { - "kind": "NumberKeyword", - "pos": 2, - "end": 8 - }, - "length": 1, - "pos": 2, - "end": 8 - } -}`); - }); - - it("tupleType2", () => { - parsesCorrectly( - "{[number,string]}", - `{ - "kind": "JSDocTupleType", - "pos": 1, - "end": 16, - "types": { - "0": { - "kind": "NumberKeyword", - "pos": 2, - "end": 8 - }, - "1": { - "kind": "StringKeyword", - "pos": 9, - "end": 15 - }, - "length": 2, - "pos": 2, - "end": 15 - } -}`); - }); - - it("tupleType3", () => { - parsesCorrectly( - "{[number,string,boolean]}", - `{ - "kind": "JSDocTupleType", - "pos": 1, - "end": 24, - "types": { - "0": { - "kind": "NumberKeyword", - "pos": 2, - "end": 8 - }, - "1": { - "kind": "StringKeyword", - "pos": 9, - "end": 15 - }, - "2": { - "kind": "BooleanKeyword", - "pos": 16, - "end": 23 - }, - "length": 3, - "pos": 2, - "end": 23 - } -}`); - }); + parsesCorrectly("unknownType", "{?}"); + parsesCorrectly("allType", "{*}"); + parsesCorrectly("nullableType", "{?number}"); + parsesCorrectly("nullableType2", "{number?}"); + parsesCorrectly("nonNullableType", "{!number}"); + parsesCorrectly("nonNullableType2", "{number!}"); + parsesCorrectly("recordType1", "{{}}"); + parsesCorrectly("recordType2", "{{foo}}"); + parsesCorrectly("recordType3", "{{foo: number}}"); + parsesCorrectly("recordType4", "{{foo, bar}}"); + parsesCorrectly("recordType5", "{{foo: number, bar}}"); + parsesCorrectly("recordType6", "{{foo, bar: number}}"); + parsesCorrectly("recordType7", "{{foo: number, bar: number}}"); + parsesCorrectly("recordType8", "{{function}}"); + parsesCorrectly("unionType", "{(number|string)}"); + parsesCorrectly("topLevelNoParenUnionType", "{number|string}"); + parsesCorrectly("functionType1", "{function()}"); + parsesCorrectly("functionType2", "{function(string, boolean)}"); + parsesCorrectly("functionReturnType1", "{function(string, boolean)}"); + parsesCorrectly("thisType1", "{this:a.b}"); + parsesCorrectly("newType1", "{new:a.b}"); + parsesCorrectly("variadicType", "{...number}"); + parsesCorrectly("optionalType", "{number=}"); + parsesCorrectly("optionalNullable", "{?=}"); + parsesCorrectly("typeReference1", "{a.}"); + parsesCorrectly("typeReference2", "{a.}"); + parsesCorrectly("typeReference3", "{a.function}"); + parsesCorrectly("arrayType1", "{a[]}"); + parsesCorrectly("arrayType2", "{a[][]}"); + parsesCorrectly("arrayType3", "{a[][]=}"); + parsesCorrectly("keyword1", "{var}"); + parsesCorrectly("keyword2", "{null}"); + parsesCorrectly("keyword3", "{undefined}"); + parsesCorrectly("tupleType0", "{[]}"); + parsesCorrectly("tupleType1", "{[number]}"); + parsesCorrectly("tupleType2", "{[number,string]}"); + parsesCorrectly("tupleType3", "{[number,string,boolean]}"); }); describe("parsesIncorrectly", () => { - it("emptyType", () => { - parsesIncorrectly("{}"); - }); - - it("trailingCommaInRecordType", () => { - parsesIncorrectly("{{a,}}"); - }); - - it("unionTypeWithTrailingBar", () => { - parsesIncorrectly("{(a|)}"); - }); - - it("unionTypeWithoutTypes", () => { - parsesIncorrectly("{()}"); - }); - - it("nullableTypeWithoutType", () => { - parsesIncorrectly("{!}"); - }); - - it("functionTypeWithTrailingComma", () => { - parsesIncorrectly("{function(a,)}"); - }); - - it("thisWithoutType", () => { - parsesIncorrectly("{this:}"); - }); - - it("newWithoutType", () => { - parsesIncorrectly("{new:}"); - }); - - it("variadicWithoutType", () => { - parsesIncorrectly("{...}"); - }); - - it("optionalWithoutType", () => { - parsesIncorrectly("{=}"); - }); - - it("allWithType", () => { - parsesIncorrectly("{*foo}"); - }); - - it("typeArgumentsNotFollowingDot", () => { - parsesIncorrectly("{a<>}"); - }); - - it("emptyTypeArguments", () => { - parsesIncorrectly("{a.<>}"); - }); - - it("typeArgumentsWithTrailingComma", () => { - parsesIncorrectly("{a.}"); - }); - - it("tsFunctionType", () => { - parsesIncorrectly("{() => string}"); - }); - - it("tsConstructoType", () => { - parsesIncorrectly("{new () => string}"); - }); - - it("typeOfType", () => { - parsesIncorrectly("{typeof M}"); - }); - - it("namedParameter", () => { - parsesIncorrectly("{function(a: number)}"); - }); - - it("callSignatureInRecordType", () => { - parsesIncorrectly("{{(): number}}"); - }); - - it("methodInRecordType", () => { - parsesIncorrectly("{{foo(): number}}"); - }); - - it("tupleTypeWithComma", () => { - parsesIncorrectly( "{[,]}"); - }); - - it("tupleTypeWithTrailingComma", () => { - parsesIncorrectly("{[number,]}"); - }); - - it("tupleTypeWithLeadingComma", () => { - parsesIncorrectly("{[,number]}"); - }); + parsesIncorrectly("emptyType", "{}"); + parsesIncorrectly("trailingCommaInRecordType", "{{a,}}"); + parsesIncorrectly("unionTypeWithTrailingBar", "{(a|)}"); + parsesIncorrectly("unionTypeWithoutTypes", "{()}"); + parsesIncorrectly("nullableTypeWithoutType", "{!}"); + parsesIncorrectly("functionTypeWithTrailingComma", "{function(a,)}"); + parsesIncorrectly("thisWithoutType", "{this:}"); + parsesIncorrectly("newWithoutType", "{new:}"); + parsesIncorrectly("variadicWithoutType", "{...}"); + parsesIncorrectly("optionalWithoutType", "{=}"); + parsesIncorrectly("allWithType", "{*foo}"); + parsesIncorrectly("typeArgumentsNotFollowingDot", "{a<>}"); + parsesIncorrectly("emptyTypeArguments", "{a.<>}"); + parsesIncorrectly("typeArgumentsWithTrailingComma", "{a.}"); + parsesIncorrectly("tsFunctionType", "{() => string}"); + parsesIncorrectly("tsConstructoType", "{new () => string}"); + parsesIncorrectly("typeOfType", "{typeof M}"); + parsesIncorrectly("namedParameter", "{function(a: number)}"); + parsesIncorrectly("callSignatureInRecordType", "{{(): number}}"); + parsesIncorrectly("methodInRecordType", "{{foo(): number}}"); + parsesIncorrectly("tupleTypeWithComma", "{[,]}"); + parsesIncorrectly("tupleTypeWithTrailingComma", "{[number,]}"); + parsesIncorrectly("tupleTypeWithLeadingComma", "{[,number]}"); }); }); describe("DocComments", () => { - function parsesCorrectly(content: string, expected: string) { - let comment = parseIsolatedJSDocComment(content); - if (!comment) { - Debug.fail('Comment failed to parse entirely'); - } - if (comment.diagnostics.length > 0) { - Debug.fail('Comment has at least one diagnostic: ' + comment.diagnostics[0].messageText); - } + function parsesCorrectly(name: string, content: string) { + it(name, () => { + let comment = parseIsolatedJSDocComment(content); + if (!comment) { + Debug.fail('Comment failed to parse entirely'); + } + if (comment.diagnostics.length > 0) { + Debug.fail('Comment has at least one diagnostic: ' + comment.diagnostics[0].messageText); + } - let result = JSON.stringify(comment.jsDocComment, (k, v) => { - return v && v.pos !== undefined - ? JSON.parse(Utils.sourceFileToJSON(v)) - : v; - }, 4); - - if (result !== expected) { - // Turn on a human-readable diff - if (typeof require !== 'undefined') { - require('chai').config.showDiff = true; - chai.expect(JSON.parse(result)).equal(JSON.parse(expected)); - } - else { - assert.equal(result, expected); - } - } + Harness.Baseline.runBaseline("parseCorrectly", "JSDocParsing/DocComments.parsesCorrectly." + name + ".json", + () => JSON.stringify(comment.jsDocComment, + (k, v) => v && v.pos !== undefined ? JSON.parse(Utils.sourceFileToJSON(v)) : v, 4)); + }); } - function parsesIncorrectly(content: string) { - let type = parseIsolatedJSDocComment(content); - assert.isTrue(!type || type.diagnostics.length > 0); + function parsesIncorrectly(name: string, content: string) { + it(name, () => { + let type = parseIsolatedJSDocComment(content); + assert.isTrue(!type || type.diagnostics.length > 0); + }); } describe("parsesIncorrectly", () => { - it("emptyComment", () => { - parsesIncorrectly("/***/"); - }); - - it("threeAsterisks", () => { - parsesIncorrectly("/*** */"); - }); - - it("asteriskAfterPreamble", () => { - parsesIncorrectly("/** * @type {number} */"); - }); - - it("multipleTypes", () => { - parsesIncorrectly( -`/** - * @type {number} + parsesIncorrectly("emptyComment", "/***/"); + parsesIncorrectly("threeAsterisks", "/*** */"); + parsesIncorrectly("asteriskAfterPreamble", "/** * @type {number} */"); + parsesIncorrectly("multipleTypes", + `/** + * @type {number} * @type {string} */`); - }); - - it("multipleReturnTypes", () => { - parsesIncorrectly( -`/** + parsesIncorrectly("multipleReturnTypes", + `/** * @return {number} * @return {string} */`); - }); - - it("noTypeParameters", () => { - parsesIncorrectly( -`/** + parsesIncorrectly("noTypeParameters", + `/** * @template */`); - }); - - it("trailingTypeParameterComma", () => { - parsesIncorrectly( -`/** + parsesIncorrectly("trailingTypeParameterComma", + `/** * @template T, */`); - }); - - it("paramWithoutName", () => { - parsesIncorrectly( -`/** + parsesIncorrectly("paramWithoutName", + `/** * @param {number} */`); - }); - - it("paramWithoutTypeOrName", () => { - parsesIncorrectly( -`/** - * @param + parsesIncorrectly("paramWithoutTypeOrName", + `/** + * @param */`); - }); }); describe("parsesCorrectly", () => { - it("noLeadingAsterisk", () => { - parsesCorrectly( + parsesCorrectly("noLeadingAsterisk", `/** @type {number} - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 27, - "tags": { - "0": { - "kind": "JSDocTypeTag", - "pos": 8, - "end": 22, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 13, - "text": "type" - }, - "typeExpression": { - "kind": "JSDocTypeExpression", - "pos": 14, - "end": 22, - "type": { - "kind": "NumberKeyword", - "pos": 15, - "end": 21 - } - } - }, - "length": 1, - "pos": 8, - "end": 22 - } -}`); - }); + */`); - it("noType", () => { - parsesCorrectly( - `/** + + parsesCorrectly("noType", +`/** * @type - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 18, - "tags": { - "0": { - "kind": "JSDocTypeTag", - "pos": 8, - "end": 13, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 13, - "text": "type" - } - }, - "length": 1, - "pos": 8, - "end": 13 - } -}`); - }); + */`); - it("noReturnType", () => { - parsesCorrectly( - `/** + + parsesCorrectly("noReturnType", +`/** * @return - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 20, - "tags": { - "0": { - "kind": "JSDocReturnTag", - "pos": 8, - "end": 15, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 15, - "text": "return" - } - }, - "length": 1, - "pos": 8, - "end": 15 - } -}`); - }); + */`); - it("leadingAsterisk", () => { - parsesCorrectly( + parsesCorrectly("leadingAsterisk", `/** * @type {number} - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 27, - "tags": { - "0": { - "kind": "JSDocTypeTag", - "pos": 8, - "end": 22, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 13, - "text": "type" - }, - "typeExpression": { - "kind": "JSDocTypeExpression", - "pos": 14, - "end": 22, - "type": { - "kind": "NumberKeyword", - "pos": 15, - "end": 21 - } - } - }, - "length": 1, - "pos": 8, - "end": 22 - } -}`); - }); + */`); - it("typeTag", () => { - parsesCorrectly( + + parsesCorrectly("typeTag", `/** * @type {number} - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 27, - "tags": { - "0": { - "kind": "JSDocTypeTag", - "pos": 8, - "end": 22, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 13, - "text": "type" - }, - "typeExpression": { - "kind": "JSDocTypeExpression", - "pos": 14, - "end": 22, - "type": { - "kind": "NumberKeyword", - "pos": 15, - "end": 21 - } - } - }, - "length": 1, - "pos": 8, - "end": 22 - } -}`); - }); + */`); - it("returnTag1", () => { - parsesCorrectly( + + parsesCorrectly("returnTag1", `/** * @return {number} - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 29, - "tags": { - "0": { - "kind": "JSDocReturnTag", - "pos": 8, - "end": 24, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 15, - "text": "return" - }, - "typeExpression": { - "kind": "JSDocTypeExpression", - "pos": 16, - "end": 24, - "type": { - "kind": "NumberKeyword", - "pos": 17, - "end": 23 - } - } - }, - "length": 1, - "pos": 8, - "end": 24 - } -}`); - }); + */`); - it("returnTag2", () => { - parsesCorrectly( - `/** + + parsesCorrectly("returnTag2", +`/** * @return {number} Description text follows - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 54, - "tags": { - "0": { - "kind": "JSDocReturnTag", - "pos": 8, - "end": 24, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 15, - "text": "return" - }, - "typeExpression": { - "kind": "JSDocTypeExpression", - "pos": 16, - "end": 24, - "type": { - "kind": "NumberKeyword", - "pos": 17, - "end": 23 - } - } - }, - "length": 1, - "pos": 8, - "end": 24 - } -}`); - }); + */`); - it("returnsTag1", () => { - parsesCorrectly( - `/** + + parsesCorrectly("returnsTag1", +`/** * @returns {number} - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 30, - "tags": { - "0": { - "kind": "JSDocReturnTag", - "pos": 8, - "end": 25, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 16, - "text": "returns" - }, - "typeExpression": { - "kind": "JSDocTypeExpression", - "pos": 17, - "end": 25, - "type": { - "kind": "NumberKeyword", - "pos": 18, - "end": 24 - } - } - }, - "length": 1, - "pos": 8, - "end": 25 - } -}`); - }); + */`); - it("oneParamTag", () => { - parsesCorrectly( + + parsesCorrectly("oneParamTag", `/** * @param {number} name1 - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 34, - "tags": { - "0": { - "kind": "JSDocParameterTag", - "pos": 8, - "end": 29, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 14, - "text": "param" - }, - "typeExpression": { - "kind": "JSDocTypeExpression", - "pos": 15, - "end": 23, - "type": { - "kind": "NumberKeyword", - "pos": 16, - "end": 22 - } - }, - "postParameterName": { - "kind": "Identifier", - "pos": 24, - "end": 29, - "text": "name1" - } - }, - "length": 1, - "pos": 8, - "end": 29 - } -}`); - }); + */`); - it("twoParamTag2", () => { - parsesCorrectly( + + parsesCorrectly("twoParamTag2", `/** * @param {number} name1 * @param {number} name2 - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 60, - "tags": { - "0": { - "kind": "JSDocParameterTag", - "pos": 8, - "end": 29, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 14, - "text": "param" - }, - "typeExpression": { - "kind": "JSDocTypeExpression", - "pos": 15, - "end": 23, - "type": { - "kind": "NumberKeyword", - "pos": 16, - "end": 22 - } - }, - "postParameterName": { - "kind": "Identifier", - "pos": 24, - "end": 29, - "text": "name1" - } - }, - "1": { - "kind": "JSDocParameterTag", - "pos": 34, - "end": 55, - "atToken": { - "kind": "AtToken", - "pos": 34, - "end": 35 - }, - "tagName": { - "kind": "Identifier", - "pos": 35, - "end": 40, - "text": "param" - }, - "typeExpression": { - "kind": "JSDocTypeExpression", - "pos": 41, - "end": 49, - "type": { - "kind": "NumberKeyword", - "pos": 42, - "end": 48 - } - }, - "postParameterName": { - "kind": "Identifier", - "pos": 50, - "end": 55, - "text": "name2" - } - }, - "length": 2, - "pos": 8, - "end": 55 - } -}`); - }); + */`); - it("paramTag1", () => { - parsesCorrectly( - `/** + + parsesCorrectly("paramTag1", +`/** * @param {number} name1 Description text follows - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 59, - "tags": { - "0": { - "kind": "JSDocParameterTag", - "pos": 8, - "end": 29, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 14, - "text": "param" - }, - "typeExpression": { - "kind": "JSDocTypeExpression", - "pos": 15, - "end": 23, - "type": { - "kind": "NumberKeyword", - "pos": 16, - "end": 22 - } - }, - "postParameterName": { - "kind": "Identifier", - "pos": 24, - "end": 29, - "text": "name1" - } - }, - "length": 1, - "pos": 8, - "end": 29 - } -}`); - }); + */`); - it("paramTagBracketedName1", () => { - parsesCorrectly( - `/** + + parsesCorrectly("paramTagBracketedName1", +`/** * @param {number} [name1] Description text follows - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 61, - "tags": { - "0": { - "kind": "JSDocParameterTag", - "pos": 8, - "end": 31, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 14, - "text": "param" - }, - "typeExpression": { - "kind": "JSDocTypeExpression", - "pos": 15, - "end": 23, - "type": { - "kind": "NumberKeyword", - "pos": 16, - "end": 22 - } - }, - "postParameterName": { - "kind": "Identifier", - "pos": 25, - "end": 30, - "text": "name1" - }, - "isBracketed": true - }, - "length": 1, - "pos": 8, - "end": 31 - } -}`); - }); + */`); - it("paramTagBracketedName2", () => { - parsesCorrectly( - `/** + + parsesCorrectly("paramTagBracketedName2", +`/** * @param {number} [ name1 = 1] Description text follows - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 66, - "tags": { - "0": { - "kind": "JSDocParameterTag", - "pos": 8, - "end": 36, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 14, - "text": "param" - }, - "typeExpression": { - "kind": "JSDocTypeExpression", - "pos": 15, - "end": 23, - "type": { - "kind": "NumberKeyword", - "pos": 16, - "end": 22 - } - }, - "postParameterName": { - "kind": "Identifier", - "pos": 26, - "end": 31, - "text": "name1" - }, - "isBracketed": true - }, - "length": 1, - "pos": 8, - "end": 36 - } -}`); - }); + */`); - it("twoParamTagOnSameLine", () => { - parsesCorrectly( + + parsesCorrectly("twoParamTagOnSameLine", `/** * @param {number} name1 @param {number} name2 - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 56, - "tags": { - "0": { - "kind": "JSDocParameterTag", - "pos": 8, - "end": 29, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 14, - "text": "param" - }, - "typeExpression": { - "kind": "JSDocTypeExpression", - "pos": 15, - "end": 23, - "type": { - "kind": "NumberKeyword", - "pos": 16, - "end": 22 - } - }, - "postParameterName": { - "kind": "Identifier", - "pos": 24, - "end": 29, - "text": "name1" - } - }, - "length": 1, - "pos": 8, - "end": 29 - } -}`); - }); + */`); - it("paramTagNameThenType1", () => { - parsesCorrectly( - `/** + + parsesCorrectly("paramTagNameThenType1", +`/** * @param name1 {number} - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 34, - "tags": { - "0": { - "kind": "JSDocParameterTag", - "pos": 8, - "end": 29, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 14, - "text": "param" - }, - "preParameterName": { - "kind": "Identifier", - "pos": 15, - "end": 20, - "text": "name1" - }, - "typeExpression": { - "kind": "JSDocTypeExpression", - "pos": 21, - "end": 29, - "type": { - "kind": "NumberKeyword", - "pos": 22, - "end": 28 - } - } - }, - "length": 1, - "pos": 8, - "end": 29 - } -}`); - }); + */`); - it("paramTagNameThenType2", () => { - parsesCorrectly( - `/** + + parsesCorrectly("paramTagNameThenType2", +`/** * @param name1 {number} Description - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 46, - "tags": { - "0": { - "kind": "JSDocParameterTag", - "pos": 8, - "end": 29, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 14, - "text": "param" - }, - "preParameterName": { - "kind": "Identifier", - "pos": 15, - "end": 20, - "text": "name1" - }, - "typeExpression": { - "kind": "JSDocTypeExpression", - "pos": 21, - "end": 29, - "type": { - "kind": "NumberKeyword", - "pos": 22, - "end": 28 - } - } - }, - "length": 1, - "pos": 8, - "end": 29 - } -}`); - }); + */`); - it("templateTag", () => { - parsesCorrectly( + + parsesCorrectly("templateTag", `/** * @template T - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 24, - "tags": { - "0": { - "kind": "JSDocTemplateTag", - "pos": 8, - "end": 19, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 17, - "text": "template" - }, - "typeParameters": { - "0": { - "kind": "TypeParameter", - "pos": 18, - "end": 19, - "name": { - "kind": "Identifier", - "pos": 18, - "end": 19, - "text": "T" - } - }, - "length": 1, - "pos": 17, - "end": 19 - } - }, - "length": 1, - "pos": 8, - "end": 19 - } -}`); - }); + */`); - it("templateTag2", () => { - parsesCorrectly( - `/** + + parsesCorrectly("templateTag2", +`/** * @template K,V - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 26, - "tags": { - "0": { - "kind": "JSDocTemplateTag", - "pos": 8, - "end": 21, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 17, - "text": "template" - }, - "typeParameters": { - "0": { - "kind": "TypeParameter", - "pos": 18, - "end": 19, - "name": { - "kind": "Identifier", - "pos": 18, - "end": 19, - "text": "K" - } - }, - "1": { - "kind": "TypeParameter", - "pos": 20, - "end": 21, - "name": { - "kind": "Identifier", - "pos": 20, - "end": 21, - "text": "V" - } - }, - "length": 2, - "pos": 17, - "end": 21 - } - }, - "length": 1, - "pos": 8, - "end": 21 - } -}`); - }); + */`); - it("templateTag3", () => { - parsesCorrectly( - `/** + + parsesCorrectly("templateTag3", +`/** * @template K ,V - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 27, - "tags": { - "0": { - "kind": "JSDocTemplateTag", - "pos": 8, - "end": 22, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 17, - "text": "template" - }, - "typeParameters": { - "0": { - "kind": "TypeParameter", - "pos": 18, - "end": 19, - "name": { - "kind": "Identifier", - "pos": 18, - "end": 19, - "text": "K" - } - }, - "1": { - "kind": "TypeParameter", - "pos": 21, - "end": 22, - "name": { - "kind": "Identifier", - "pos": 21, - "end": 22, - "text": "V" - } - }, - "length": 2, - "pos": 17, - "end": 22 - } - }, - "length": 1, - "pos": 8, - "end": 22 - } -}`); - }); + */`); - it("templateTag4", () => { - parsesCorrectly( - `/** + + parsesCorrectly("templateTag4", +`/** * @template K, V - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 27, - "tags": { - "0": { - "kind": "JSDocTemplateTag", - "pos": 8, - "end": 22, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 17, - "text": "template" - }, - "typeParameters": { - "0": { - "kind": "TypeParameter", - "pos": 18, - "end": 19, - "name": { - "kind": "Identifier", - "pos": 18, - "end": 19, - "text": "K" - } - }, - "1": { - "kind": "TypeParameter", - "pos": 21, - "end": 22, - "name": { - "kind": "Identifier", - "pos": 21, - "end": 22, - "text": "V" - } - }, - "length": 2, - "pos": 17, - "end": 22 - } - }, - "length": 1, - "pos": 8, - "end": 22 - } -}`); - }); + */`); - it("templateTag5", () => { - parsesCorrectly( - `/** + + parsesCorrectly("templateTag5", +`/** * @template K , V - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 28, - "tags": { - "0": { - "kind": "JSDocTemplateTag", - "pos": 8, - "end": 23, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 17, - "text": "template" - }, - "typeParameters": { - "0": { - "kind": "TypeParameter", - "pos": 18, - "end": 19, - "name": { - "kind": "Identifier", - "pos": 18, - "end": 19, - "text": "K" - } - }, - "1": { - "kind": "TypeParameter", - "pos": 22, - "end": 23, - "name": { - "kind": "Identifier", - "pos": 22, - "end": 23, - "text": "V" - } - }, - "length": 2, - "pos": 17, - "end": 23 - } - }, - "length": 1, - "pos": 8, - "end": 23 - } -}`); - }); + */`); - it("templateTag6", () => { - parsesCorrectly( - `/** + parsesCorrectly("templateTag6", +`/** * @template K , V Description of type parameters. - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 60, - "tags": { - "0": { - "kind": "JSDocTemplateTag", - "pos": 8, - "end": 23, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 17, - "text": "template" - }, - "typeParameters": { - "0": { - "kind": "TypeParameter", - "pos": 18, - "end": 19, - "name": { - "kind": "Identifier", - "pos": 18, - "end": 19, - "text": "K" - } - }, - "1": { - "kind": "TypeParameter", - "pos": 22, - "end": 23, - "name": { - "kind": "Identifier", - "pos": 22, - "end": 23, - "text": "V" - } - }, - "length": 2, - "pos": 17, - "end": 23 - } - }, - "length": 1, - "pos": 8, - "end": 23 - } -}`); - }); + */`); - it("paramWithoutType", () => { - parsesCorrectly( - `/** + parsesCorrectly("paramWithoutType", +`/** * @param foo - */`, - `{ - "kind": "JSDocComment", - "pos": 0, - "end": 23, - "tags": { - "0": { - "kind": "JSDocParameterTag", - "pos": 8, - "end": 18, - "atToken": { - "kind": "AtToken", - "pos": 8, - "end": 9 - }, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 14, - "text": "param" - }, - "preParameterName": { - "kind": "Identifier", - "pos": 15, - "end": 18, - "text": "foo" - } - }, - "length": 1, - "pos": 8, - "end": 18 - } -}`); - }); + */`); }); }); });