mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-21 04:17:02 -06:00
Transform jsdoc types in the refactor, not emitter
The emitter now understands JSDoc types but emits them in the original format.
This commit is contained in:
parent
96b8093890
commit
fc933d7c33
@ -545,8 +545,9 @@ namespace ts {
|
||||
case SyntaxKind.TypeReference:
|
||||
return emitTypeReference(<TypeReferenceNode>node);
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
return emitFunctionType(<FunctionTypeNode>node);
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
return emitJSDocFunctionType(node as JSDocFunctionType);
|
||||
case SyntaxKind.ConstructorType:
|
||||
return emitConstructorType(<ConstructorTypeNode>node);
|
||||
case SyntaxKind.TypeQuery:
|
||||
@ -576,8 +577,10 @@ namespace ts {
|
||||
case SyntaxKind.LiteralType:
|
||||
return emitLiteralType(<LiteralTypeNode>node);
|
||||
case SyntaxKind.JSDocAllType:
|
||||
write("*");
|
||||
break;
|
||||
case SyntaxKind.JSDocUnknownType:
|
||||
write("any");
|
||||
write("?");
|
||||
break;
|
||||
case SyntaxKind.JSDocNullableType:
|
||||
return emitJSDocNullableType(node as JSDocNullableType);
|
||||
@ -930,14 +933,13 @@ namespace ts {
|
||||
if (node.name) {
|
||||
emit(node.name);
|
||||
}
|
||||
else if (node.parent.kind === SyntaxKind.JSDocFunctionType) {
|
||||
const i = (node.parent as JSDocFunctionType).parameters.indexOf(node);
|
||||
if (i > -1) {
|
||||
write("arg" + i);
|
||||
}
|
||||
}
|
||||
emitIfPresent(node.questionToken);
|
||||
emitWithPrefix(": ", node.type);
|
||||
if (node.parent && node.parent.kind === SyntaxKind.JSDocFunctionType && !node.name) {
|
||||
emit(node.type);
|
||||
}
|
||||
else {
|
||||
emitWithPrefix(": ", node.type);
|
||||
}
|
||||
emitExpressionWithPrefix(" = ", node.initializer);
|
||||
}
|
||||
|
||||
@ -1056,18 +1058,27 @@ namespace ts {
|
||||
emit(node.type);
|
||||
}
|
||||
|
||||
function emitJSDocNullableType(node: JSDocNullableType) {
|
||||
function emitJSDocFunctionType(node: JSDocFunctionType) {
|
||||
write("function");
|
||||
emitParameters(node, node.parameters);
|
||||
write(":");
|
||||
emit(node.type);
|
||||
}
|
||||
|
||||
|
||||
function emitJSDocNullableType(node: JSDocNullableType) {
|
||||
write("?");
|
||||
emit(node.type);
|
||||
write(" | null");
|
||||
}
|
||||
|
||||
function emitJSDocNonNullableType(node: JSDocNonNullableType) {
|
||||
write("!");
|
||||
emit(node.type);
|
||||
}
|
||||
|
||||
function emitJSDocOptionalType(node: JSDocOptionalType) {
|
||||
emit(node.type);
|
||||
write(" | undefined");
|
||||
write("=");
|
||||
}
|
||||
|
||||
function emitConstructorType(node: ConstructorTypeNode) {
|
||||
@ -1096,8 +1107,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function emitJSDocVariadicType(node: JSDocVariadicType) {
|
||||
write("...");
|
||||
emit(node.type);
|
||||
write("[]");
|
||||
}
|
||||
|
||||
function emitTupleType(node: TupleTypeNode) {
|
||||
@ -2397,7 +2408,7 @@ namespace ts {
|
||||
emitList(parentNode, parameters, ListFormat.Parameters);
|
||||
}
|
||||
|
||||
function canEmitSimpleArrowHead(parentNode: FunctionTypeNode | ArrowFunction | JSDocFunctionType, parameters: NodeArray<ParameterDeclaration>) {
|
||||
function canEmitSimpleArrowHead(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray<ParameterDeclaration>) {
|
||||
const parameter = singleOrUndefined(parameters);
|
||||
return parameter
|
||||
&& parameter.pos === parentNode.pos // may not have parsed tokens between parent and parameter
|
||||
@ -2414,7 +2425,7 @@ namespace ts {
|
||||
&& isIdentifier(parameter.name); // parameter name must be identifier
|
||||
}
|
||||
|
||||
function emitParametersForArrow(parentNode: FunctionTypeNode | ArrowFunction | JSDocFunctionType, parameters: NodeArray<ParameterDeclaration>) {
|
||||
function emitParametersForArrow(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray<ParameterDeclaration>) {
|
||||
if (canEmitSimpleArrowHead(parentNode, parameters)) {
|
||||
emitList(parentNode, parameters, ListFormat.Parameters & ~ListFormat.Parenthesis);
|
||||
}
|
||||
|
||||
@ -35,16 +35,16 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
|
||||
if (decl && !decl.type) {
|
||||
const annotate = getJSDocType(decl) ? annotateTypeFromJSDoc :
|
||||
getJSDocReturnType(decl) ? annotateReturnTypeFromJSDoc :
|
||||
undefined;
|
||||
undefined;
|
||||
if (annotate) {
|
||||
return [{
|
||||
name: annotate.name,
|
||||
description: annotate.description,
|
||||
actions: [
|
||||
{
|
||||
description: annotate.description,
|
||||
name: actionName
|
||||
}
|
||||
description: annotate.description,
|
||||
name: actionName
|
||||
}
|
||||
]
|
||||
}];
|
||||
}
|
||||
@ -62,10 +62,9 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
|
||||
const sourceFile = context.file;
|
||||
const token = getTokenAtPosition(sourceFile, start, /*includeJsDocComment*/ false);
|
||||
const decl = findAncestor(token, isTypedNode);
|
||||
const jsdocType = getJSDocType(decl);
|
||||
const jsdocReturn = getJSDocReturnType(decl);
|
||||
if (!decl || !jsdocType && !jsdocReturn || decl.type) {
|
||||
Debug.fail(`!decl || !jsdocType && !jsdocReturn || decl.type: !${decl} || !${jsdocType} && !{jsdocReturn} || ${decl.type}`);
|
||||
const jsdocType = getJSDocReturnType(decl) || getJSDocType(decl);
|
||||
if (!decl || !jsdocType || decl.type) {
|
||||
Debug.fail(`!decl || !jsdocType || decl.type: !${decl} || !${jsdocType} || ${decl.type}`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -76,12 +75,12 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
|
||||
// other syntax changes
|
||||
const arrow = decl.parent as ArrowFunction;
|
||||
const param = decl as ParameterDeclaration;
|
||||
const replacementParam = createParameter(param.decorators, param.modifiers, param.dotDotDotToken, param.name, param.questionToken, jsdocType, param.initializer);
|
||||
const replacementParam = createParameter(param.decorators, param.modifiers, param.dotDotDotToken, param.name, param.questionToken, transformJSDocType(jsdocType) as TypeNode, param.initializer);
|
||||
const replacement = createArrowFunction(arrow.modifiers, arrow.typeParameters, [replacementParam], arrow.type, arrow.equalsGreaterThanToken, arrow.body);
|
||||
changeTracker.replaceRange(sourceFile, { pos: arrow.getStart(), end: arrow.end }, replacement);
|
||||
}
|
||||
else {
|
||||
changeTracker.replaceRange(sourceFile, { pos: decl.getStart(), end: decl.end }, replaceType(decl, jsdocType, jsdocReturn));
|
||||
changeTracker.replaceRange(sourceFile, { pos: decl.getStart(), end: decl.end }, replaceType(decl, transformJSDocType(jsdocType) as TypeNode));
|
||||
}
|
||||
return {
|
||||
edits: changeTracker.getChanges(),
|
||||
@ -98,7 +97,7 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
|
||||
node.kind === SyntaxKind.PropertyDeclaration;
|
||||
}
|
||||
|
||||
function replaceType(decl: DeclarationWithType, jsdocType: TypeNode, jsdocReturn: TypeNode) {
|
||||
function replaceType(decl: DeclarationWithType, jsdocType: TypeNode) {
|
||||
switch (decl.kind) {
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return createVariableDeclaration(decl.name, jsdocType, decl.initializer);
|
||||
@ -109,15 +108,15 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
return createProperty(decl.decorators, decl.modifiers, decl.name, decl.questionToken, jsdocType, decl.initializer);
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
return createFunctionDeclaration(decl.decorators, decl.modifiers, decl.asteriskToken, decl.name, decl.typeParameters, decl.parameters, jsdocReturn, decl.body);
|
||||
return createFunctionDeclaration(decl.decorators, decl.modifiers, decl.asteriskToken, decl.name, decl.typeParameters, decl.parameters, jsdocType, decl.body);
|
||||
case SyntaxKind.FunctionExpression:
|
||||
return createFunctionExpression(decl.modifiers, decl.asteriskToken, decl.name, decl.typeParameters, decl.parameters, jsdocReturn, decl.body);
|
||||
return createFunctionExpression(decl.modifiers, decl.asteriskToken, decl.name, decl.typeParameters, decl.parameters, jsdocType, decl.body);
|
||||
case SyntaxKind.ArrowFunction:
|
||||
return createArrowFunction(decl.modifiers, decl.typeParameters, decl.parameters, jsdocReturn, decl.equalsGreaterThanToken, decl.body);
|
||||
return createArrowFunction(decl.modifiers, decl.typeParameters, decl.parameters, jsdocType, decl.equalsGreaterThanToken, decl.body);
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
return createMethod(decl.decorators, decl.modifiers, decl.asteriskToken, decl.name, decl.questionToken, decl.typeParameters, decl.parameters, jsdocReturn, decl.body);
|
||||
return createMethod(decl.decorators, decl.modifiers, decl.asteriskToken, decl.name, decl.questionToken, decl.typeParameters, decl.parameters, jsdocType, decl.body);
|
||||
case SyntaxKind.GetAccessor:
|
||||
return createGetAccessor(decl.decorators, decl.modifiers, decl.name, decl.parameters, jsdocReturn, decl.body);
|
||||
return createGetAccessor(decl.decorators, decl.modifiers, decl.name, decl.parameters, jsdocType, decl.body);
|
||||
default:
|
||||
Debug.fail(`Unexpected SyntaxKind: ${decl.kind}`);
|
||||
return undefined;
|
||||
@ -144,4 +143,82 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
|
||||
&& !parameter.initializer // parameter may not have an initializer
|
||||
&& isIdentifier(parameter.name); // parameter name must be identifier
|
||||
}
|
||||
|
||||
function transformJSDocType(node: Node): Node | undefined {
|
||||
if (node === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.JSDocAllType:
|
||||
case SyntaxKind.JSDocUnknownType:
|
||||
return createTypeReferenceNode("any", emptyArray);
|
||||
case SyntaxKind.JSDocOptionalType:
|
||||
return visitJSDocOptionalType(node as JSDocOptionalType);
|
||||
case SyntaxKind.JSDocNonNullableType:
|
||||
return transformJSDocType((node as JSDocNonNullableType).type);
|
||||
case SyntaxKind.JSDocNullableType:
|
||||
return visitJSDocNullableType(node as JSDocNullableType);
|
||||
case SyntaxKind.JSDocVariadicType:
|
||||
return visitJSDocVariadicType(node as JSDocVariadicType);
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
return visitJSDocFunctionType(node as JSDocFunctionType);
|
||||
case SyntaxKind.Parameter:
|
||||
return visitJSDocParameter(node as ParameterDeclaration);
|
||||
case SyntaxKind.TypeReference:
|
||||
return visitJSDocTypeReference(node as TypeReferenceNode);
|
||||
default:
|
||||
return visitEachChild(node, transformJSDocType, /*context*/ undefined) as TypeNode;
|
||||
}
|
||||
}
|
||||
|
||||
function visitJSDocOptionalType(node: JSDocOptionalType) {
|
||||
return createUnionTypeNode([visitNode(node.type, transformJSDocType), createTypeReferenceNode("undefined", emptyArray)]);
|
||||
}
|
||||
|
||||
function visitJSDocNullableType(node: JSDocNullableType) {
|
||||
return createUnionTypeNode([visitNode(node.type, transformJSDocType), createTypeReferenceNode("null", emptyArray)]);
|
||||
}
|
||||
|
||||
function visitJSDocVariadicType(node: JSDocVariadicType) {
|
||||
return createArrayTypeNode(visitNode(node.type, transformJSDocType));
|
||||
}
|
||||
|
||||
function visitJSDocFunctionType(node: JSDocFunctionType) {
|
||||
const parameters = node.parameters && node.parameters.map(transformJSDocType);
|
||||
return createFunctionTypeNode(emptyArray, parameters as ParameterDeclaration[], node.type);
|
||||
}
|
||||
|
||||
function visitJSDocParameter(node: ParameterDeclaration) {
|
||||
const name = node.name || "arg" + node.parent.parameters.indexOf(node);
|
||||
return createParameter(node.decorators, node.modifiers, node.dotDotDotToken, name, node.questionToken, node.type, node.initializer);
|
||||
}
|
||||
|
||||
function visitJSDocTypeReference(node: TypeReferenceNode) {
|
||||
let name = node.typeName;
|
||||
let args = node.typeArguments;
|
||||
if (isIdentifier(node.typeName)) {
|
||||
let text = node.typeName.text;
|
||||
switch (node.typeName.text) {
|
||||
case "String":
|
||||
case "Boolean":
|
||||
case "Object":
|
||||
case "Number":
|
||||
text = text.toLowerCase();
|
||||
break;
|
||||
case "array":
|
||||
case "date":
|
||||
case "promise":
|
||||
text = text[0].toUpperCase() + text.slice(1);
|
||||
break;
|
||||
}
|
||||
name = createIdentifier(text);
|
||||
if ((text === "Array" || text === "Promise") && !node.typeArguments) {
|
||||
args = createNodeArray([createTypeReferenceNode("any", emptyArray)]);
|
||||
}
|
||||
else {
|
||||
args = visitNodes(node.typeArguments, transformJSDocType);
|
||||
}
|
||||
}
|
||||
return createTypeReferenceNode(name, args);
|
||||
}
|
||||
}
|
||||
|
||||
158
tests/cases/fourslash/annotateWithTypeFromJSDoc15.ts
Normal file
158
tests/cases/fourslash/annotateWithTypeFromJSDoc15.ts
Normal file
@ -0,0 +1,158 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
// @strict: true
|
||||
/////**
|
||||
//// * @param {Boolean} x
|
||||
//// * @param {String} y
|
||||
//// * @param {Number} z
|
||||
//// * @param {Object} alpha
|
||||
//// * @param {date} beta
|
||||
//// * @param {promise} gamma
|
||||
//// * @param {array} delta
|
||||
//// * @param {Array<number>} epsilon
|
||||
//// * @param {promise<String>} zeta
|
||||
//// */
|
||||
////function f(/*1*/x, /*2*/y, /*3*/z, /*4*/alpha, /*5*/beta, /*6*/gamma, /*7*/delta, /*8*/epsilon, /*9*/zeta) {
|
||||
////}
|
||||
verify.applicableRefactorAvailableAtMarker('1');
|
||||
verify.fileAfterApplyingRefactorAtMarker('1',
|
||||
`/**
|
||||
* @param {Boolean} x
|
||||
* @param {String} y
|
||||
* @param {Number} z
|
||||
* @param {Object} alpha
|
||||
* @param {date} beta
|
||||
* @param {promise} gamma
|
||||
* @param {array} delta
|
||||
* @param {Array<number>} epsilon
|
||||
* @param {promise<String>} zeta
|
||||
*/
|
||||
function f(x: boolean, y, z, alpha, beta, gamma, delta, epsilon, zeta) {
|
||||
}`, 'Annotate with type from JSDoc', 'annotate');
|
||||
|
||||
verify.applicableRefactorAvailableAtMarker('2');
|
||||
verify.fileAfterApplyingRefactorAtMarker('2',
|
||||
`/**
|
||||
* @param {Boolean} x
|
||||
* @param {String} y
|
||||
* @param {Number} z
|
||||
* @param {Object} alpha
|
||||
* @param {date} beta
|
||||
* @param {promise} gamma
|
||||
* @param {array} delta
|
||||
* @param {Array<number>} epsilon
|
||||
* @param {promise<String>} zeta
|
||||
*/
|
||||
function f(x: boolean, y: string, z, alpha, beta, gamma, delta, epsilon, zeta) {
|
||||
}`, 'Annotate with type from JSDoc', 'annotate');
|
||||
|
||||
verify.applicableRefactorAvailableAtMarker('3');
|
||||
verify.fileAfterApplyingRefactorAtMarker('3',
|
||||
`/**
|
||||
* @param {Boolean} x
|
||||
* @param {String} y
|
||||
* @param {Number} z
|
||||
* @param {Object} alpha
|
||||
* @param {date} beta
|
||||
* @param {promise} gamma
|
||||
* @param {array} delta
|
||||
* @param {Array<number>} epsilon
|
||||
* @param {promise<String>} zeta
|
||||
*/
|
||||
function f(x: boolean, y: string, z: number, alpha, beta, gamma, delta, epsilon, zeta) {
|
||||
}`, 'Annotate with type from JSDoc', 'annotate');
|
||||
|
||||
verify.applicableRefactorAvailableAtMarker('4');
|
||||
verify.fileAfterApplyingRefactorAtMarker('4',
|
||||
`/**
|
||||
* @param {Boolean} x
|
||||
* @param {String} y
|
||||
* @param {Number} z
|
||||
* @param {Object} alpha
|
||||
* @param {date} beta
|
||||
* @param {promise} gamma
|
||||
* @param {array} delta
|
||||
* @param {Array<number>} epsilon
|
||||
* @param {promise<String>} zeta
|
||||
*/
|
||||
function f(x: boolean, y: string, z: number, alpha: object, beta, gamma, delta, epsilon, zeta) {
|
||||
}`, 'Annotate with type from JSDoc', 'annotate');
|
||||
|
||||
verify.applicableRefactorAvailableAtMarker('5');
|
||||
verify.fileAfterApplyingRefactorAtMarker('5',
|
||||
`/**
|
||||
* @param {Boolean} x
|
||||
* @param {String} y
|
||||
* @param {Number} z
|
||||
* @param {Object} alpha
|
||||
* @param {date} beta
|
||||
* @param {promise} gamma
|
||||
* @param {array} delta
|
||||
* @param {Array<number>} epsilon
|
||||
* @param {promise<String>} zeta
|
||||
*/
|
||||
function f(x: boolean, y: string, z: number, alpha: object, beta: Date, gamma, delta, epsilon, zeta) {
|
||||
}`, 'Annotate with type from JSDoc', 'annotate');
|
||||
|
||||
verify.applicableRefactorAvailableAtMarker('6');
|
||||
verify.fileAfterApplyingRefactorAtMarker('6',
|
||||
`/**
|
||||
* @param {Boolean} x
|
||||
* @param {String} y
|
||||
* @param {Number} z
|
||||
* @param {Object} alpha
|
||||
* @param {date} beta
|
||||
* @param {promise} gamma
|
||||
* @param {array} delta
|
||||
* @param {Array<number>} epsilon
|
||||
* @param {promise<String>} zeta
|
||||
*/
|
||||
function f(x: boolean, y: string, z: number, alpha: object, beta: Date, gamma: Promise<any>, delta, epsilon, zeta) {
|
||||
}`, 'Annotate with type from JSDoc', 'annotate');
|
||||
|
||||
verify.applicableRefactorAvailableAtMarker('7');
|
||||
verify.fileAfterApplyingRefactorAtMarker('7',
|
||||
`/**
|
||||
* @param {Boolean} x
|
||||
* @param {String} y
|
||||
* @param {Number} z
|
||||
* @param {Object} alpha
|
||||
* @param {date} beta
|
||||
* @param {promise} gamma
|
||||
* @param {array} delta
|
||||
* @param {Array<number>} epsilon
|
||||
* @param {promise<String>} zeta
|
||||
*/
|
||||
function f(x: boolean, y: string, z: number, alpha: object, beta: Date, gamma: Promise<any>, delta: Array<any>, epsilon, zeta) {
|
||||
}`, 'Annotate with type from JSDoc', 'annotate');
|
||||
|
||||
verify.applicableRefactorAvailableAtMarker('8');
|
||||
verify.fileAfterApplyingRefactorAtMarker('8',
|
||||
`/**
|
||||
* @param {Boolean} x
|
||||
* @param {String} y
|
||||
* @param {Number} z
|
||||
* @param {Object} alpha
|
||||
* @param {date} beta
|
||||
* @param {promise} gamma
|
||||
* @param {array} delta
|
||||
* @param {Array<number>} epsilon
|
||||
* @param {promise<String>} zeta
|
||||
*/
|
||||
function f(x: boolean, y: string, z: number, alpha: object, beta: Date, gamma: Promise<any>, delta: Array<any>, epsilon: Array<number>, zeta) {
|
||||
}`, 'Annotate with type from JSDoc', 'annotate');
|
||||
|
||||
verify.applicableRefactorAvailableAtMarker('9');
|
||||
verify.fileAfterApplyingRefactorAtMarker('9',
|
||||
`/**
|
||||
* @param {Boolean} x
|
||||
* @param {String} y
|
||||
* @param {Number} z
|
||||
* @param {Object} alpha
|
||||
* @param {date} beta
|
||||
* @param {promise} gamma
|
||||
* @param {array} delta
|
||||
* @param {Array<number>} epsilon
|
||||
* @param {promise<String>} zeta
|
||||
*/
|
||||
function f(x: boolean, y: string, z: number, alpha: object, beta: Date, gamma: Promise<any>, delta: Array<any>, epsilon: Array<number>, zeta: Promise<string>) {
|
||||
}`, 'Annotate with type from JSDoc', 'annotate');
|
||||
Loading…
x
Reference in New Issue
Block a user