Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.

Commit 16a0f69

Browse files
committed
emit full jsdoc for function types
Rather than emitting a type per parameter, emit a jsdoc before the function declaration. This allows us to mark optional arguments properly with the = suffix. Note the changed "optional.ts" test; it now verifies that Closure accepts a missing argument when that argument was missing before. Fixes #43.
1 parent 5c21aad commit 16a0f69

16 files changed

+125
-35
lines changed

src/sickle.ts

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class Annotator {
7373
this.indent++;
7474
switch (node.kind) {
7575
case ts.SyntaxKind.VariableDeclaration:
76-
this.maybeVisitType((<ts.VariableDeclaration>node).type);
76+
this.maybeEmitJSDocType((<ts.VariableDeclaration>node).type);
7777
this.writeNode(node);
7878
break;
7979
case ts.SyntaxKind.ClassDeclaration: {
@@ -124,25 +124,33 @@ class Annotator {
124124
case ts.SyntaxKind.FunctionDeclaration:
125125
case ts.SyntaxKind.ArrowFunction:
126126
let fnDecl = <ts.FunctionLikeDeclaration>node;
127-
this.maybeVisitType(fnDecl.type, '@return');
128127
let writeOffset = fnDecl.getFullStart();
128+
writeOffset = this.writeRange(writeOffset, fnDecl.getStart());
129+
// The first \n makes the output sometimes uglier than necessary,
130+
// but it's needed to work around
131+
// https://github.com/Microsoft/TypeScript/issues/6982
132+
this.emit('\n/**\n');
129133
// Parameters.
130134
if (fnDecl.parameters.length) {
131135
for (let param of fnDecl.parameters) {
132-
this.writeTextFromOffset(writeOffset, param);
133-
writeOffset = param.getEnd();
134-
let optional = param.initializer != null || param.questionToken != null;
135-
this.maybeVisitType(param.type, null, optional);
136-
this.visit(param);
136+
if (param.type) {
137+
let optional = param.initializer != null || param.questionToken != null;
138+
this.emit(' * @param {');
139+
this.emitType(param.type, optional);
140+
this.emit('} ');
141+
this.writeNode(param.name);
142+
this.emit('\n');
143+
}
137144
}
138145
}
139146
// Return type.
140147
if (fnDecl.type) {
141-
this.writeTextFromOffset(writeOffset, fnDecl.type);
142-
this.visit(fnDecl.type);
143-
writeOffset = fnDecl.type.getEnd();
148+
this.emit(' * @return {');
149+
this.emitType(fnDecl.type);
150+
this.emit('}\n');
144151
}
145-
// Body.
152+
this.emit(' */\n');
153+
146154
this.writeTextFromOffset(writeOffset, fnDecl.body);
147155
this.visit(fnDecl.body);
148156
break;
@@ -203,7 +211,7 @@ class Annotator {
203211
if (existingAnnotation) {
204212
existingAnnotation += '\n';
205213
}
206-
this.maybeVisitType(p.type, existingAnnotation + '@type');
214+
this.maybeEmitJSDocType(p.type, existingAnnotation + '@type');
207215
this.emit('\nthis.');
208216
this.emit(p.name.getText());
209217
this.emit(';');
@@ -233,14 +241,22 @@ class Annotator {
233241
return '';
234242
}
235243

236-
private maybeVisitType(type: ts.TypeNode, jsDocTag?: string, optional?: boolean) {
244+
private maybeEmitJSDocType(type: ts.TypeNode, jsDocTag?: string) {
237245
if (!type && !this.options.untyped) return;
238246
this.emit(' /**');
239247
if (jsDocTag) {
240248
this.emit(' ');
241249
this.emit(jsDocTag);
242250
this.emit(' {');
243251
}
252+
this.emitType(type);
253+
if (jsDocTag) {
254+
this.emit('}');
255+
}
256+
this.emit(' */');
257+
}
258+
259+
private emitType(type: ts.TypeNode, optional?: boolean) {
244260
if (this.options.untyped) {
245261
this.emit(' ?');
246262
} else {
@@ -249,10 +265,6 @@ class Annotator {
249265
if (optional) {
250266
this.emit('=');
251267
}
252-
if (jsDocTag) {
253-
this.emit('}');
254-
}
255-
this.emit(' */');
256268
}
257269

258270
private visitTypeAlias(node: ts.TypeAliasDeclaration) {

test_files/es6/arrow_fn.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,10 @@
1-
var fn3 = (/** number */ a) => 12;
1+
var fn3 =
2+
/**
3+
* @param { number} a
4+
* @return { number}
5+
*/
6+
/**
7+
* @param { number} a
8+
* @return { number}
9+
*/
10+
(a) => 12;

test_files/es6/basic.untyped.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
/** @return { ?} */ // This test is just a random collection of typed code, to
1+
// This test is just a random collection of typed code, to
22
// ensure the output is all with {?} annotations.
3-
function func(/** ? */ arg1) {
3+
/**
4+
* @param { ?} arg1
5+
* @return { ?}
6+
*/
7+
function func(arg1) {
48
return [3];
59
}
610
class Foo {

test_files/es6/decorator.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
77
var __metadata = (this && this.__metadata) || function (k, v) {
88
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
99
};
10-
function decorator(/** Object */ a, /** string */ b) { }
10+
/**
11+
* @param { Object} a
12+
* @param { string} b
13+
*/
14+
function decorator(a, b) { }
1115
class DecoratorTest {
1216
// Sickle: begin synthetic ctor.
1317
constructor() {

test_files/es6/default.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
1-
function DefaultArgument(/** number */ x, /** string= */ y = 'hi') {
1+
/**
2+
* @param { number} x
3+
* @param { string=} y
4+
*/
5+
function DefaultArgument(x, y = 'hi') {
26
}

test_files/es6/file_comment.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
/** @return { string} */ // This test verifies that initial comments don't confuse offsets.
1+
// This test verifies that initial comments don't confuse offsets.
2+
/**
3+
* @return { string}
4+
*/
25
function foo() {
36
return 'foo';
47
}

test_files/es6/functions.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
/** @return { string} */ function fn1(/** number */ a) {
1+
/**
2+
* @param { number} a
3+
* @return { string}
4+
*/
5+
function fn1(a) {
26
return "a";
37
}
4-
function fn2(/** number */ a, /** number */ b) { }
8+
/**
9+
* @param { number} a
10+
* @param { number} b
11+
*/
12+
function fn2(a, b) { }

test_files/es6/optional.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
1-
function optionalArgument(/** number */ x, /** string= */ y) {
1+
/**
2+
* @param { number} x
3+
* @param { string=} y
4+
*/
5+
function optionalArgument(x, y) {
26
}
7+
optionalArgument(1);

test_files/optional.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
function optionalArgument(x: number, y?: string) {
22
}
3+
optionalArgument(1);

test_files/sickle/arrow_fn.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
var fn3 = /** @return { number} */ ( /** number */a: number): number => 12;
1+
var fn3 =
2+
/**
3+
* @param { number} a
4+
* @return { number}
5+
*/
6+
(a: number): number => 12;

test_files/sickle/basic.untyped.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
/** @return { ?} */// This test is just a random collection of typed code, to
1+
// This test is just a random collection of typed code, to
22
// ensure the output is all with {?} annotations.
3-
function func( /** ? */arg1: string): number[] {
3+
4+
/**
5+
* @param { ?} arg1
6+
* @return { ?}
7+
*/
8+
function func(arg1: string): number[] {
49
return [3];
510
}
611

test_files/sickle/decorator.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
function decorator( /** Object */a: Object, /** string */ b: string) {}
1+
2+
/**
3+
* @param { Object} a
4+
* @param { string} b
5+
*/
6+
function decorator(a: Object, b: string) {}
27

38
class DecoratorTest {
49
@decorator

test_files/sickle/default.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
1-
function DefaultArgument( /** number */x: number, /** string= */ y: string = 'hi') {
1+
2+
/**
3+
* @param { number} x
4+
* @param { string=} y
5+
*/
6+
function DefaultArgument(x: number, y: string = 'hi') {
27
}

test_files/sickle/file_comment.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
/** @return { string} */// This test verifies that initial comments don't confuse offsets.
1+
// This test verifies that initial comments don't confuse offsets.
2+
3+
/**
4+
* @return { string}
5+
*/
26
function foo(): string {
37
return 'foo';
48
}

test_files/sickle/functions.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
/** @return { string} */function fn1( /** number */a: number): string {
1+
2+
/**
3+
* @param { number} a
4+
* @return { string}
5+
*/
6+
function fn1(a: number): string {
27
return "a";
38
}
4-
function fn2( /** number */a: number, /** number */ b: number) {}
9+
10+
/**
11+
* @param { number} a
12+
* @param { number} b
13+
*/
14+
function fn2(a: number, b: number) {}

test_files/sickle/optional.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
1-
function optionalArgument( /** number */x: number, /** string= */ y?: string) {
1+
2+
/**
3+
* @param { number} x
4+
* @param { string=} y
5+
*/
6+
function optionalArgument(x: number, y?: string) {
27
}
8+
optionalArgument(1);

0 commit comments

Comments
 (0)