Skip to content

Commit cb1e433

Browse files
committed
preserve comments on signatures and declarations where possible
1 parent 01e2819 commit cb1e433

23 files changed

+526
-12
lines changed

src/compiler/checker.ts

+23-12
Original file line numberDiff line numberDiff line change
@@ -4959,6 +4959,7 @@ namespace ts {
49594959
createNamedExports(flatMap(exports, e => e.exportClause!.elements)),
49604960
/*moduleSpecifier*/ undefined
49614961
)];
4962+
// TODO combine multiple `export {a} from "..."` into a single statement
49624963
}
49634964
// Pass 3: Move all `export {}`'s to `export` modifiers where possible
49644965
const exportDecl = find(statements, d => isExportDeclaration(d) && !d.moduleSpecifier && !!d.exportClause) as ExportDeclaration | undefined;
@@ -5091,7 +5092,7 @@ namespace ts {
50915092
// Each overload becomes a seperate function declaration, in order
50925093
const decl = signatureToSignatureDeclarationHelper(sig, SyntaxKind.FunctionDeclaration, context) as FunctionDeclaration;
50935094
decl.name = createIdentifier(localName);
5094-
addResult(decl, modifierFlags);
5095+
addResult(setTextRange(decl, sig.declaration), modifierFlags);
50955096
}
50965097
const props = getPropertiesOfType(type);
50975098
if (length(props)) {
@@ -5142,14 +5143,14 @@ namespace ts {
51425143
c.typeParameters = undefined;
51435144
}
51445145
const indexSignatures = serializeIndexSignatures(classType, baseTypes[0]);
5145-
addResult(createClassDeclaration(
5146+
addResult(setTextRange(createClassDeclaration(
51465147
/*decorators*/ undefined,
51475148
/*modifiers*/ undefined,
51485149
localName,
51495150
typeParamDecls,
51505151
heritageClauses,
51515152
[...indexSignatures, ...staticMembers, ...constructors, ...members]
5152-
), modifierFlags);
5153+
), filter(symbol.declarations, d => isClassDeclaration(d) || isClassExpression(d))[0]), modifierFlags);
51535154
}
51545155

51555156
// Synthesize declarations for a symbol - might be an Interface, a Class, a Namespace, a Type, a Variable (const, let, or var), an Alias
@@ -5200,9 +5201,13 @@ namespace ts {
52005201
// `var` is `FunctionScopedVariable`, `const` and `let` are `BlockScopedVariable`, and `module.exports.thing =` is `Property`
52015202
const flags = !(symbol.flags & SymbolFlags.BlockScopedVariable) ? undefined : isConstVariable(symbol) ? NodeFlags.Const : NodeFlags.Let;
52025203
const name = (needsPostExportDefault || !(symbol.flags & SymbolFlags.Property)) ? localName : getUnusedName(localName, symbol);
5203-
const statement = createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([
5204+
let textRange: Node | undefined = filter(symbol.declarations, d => isVariableDeclaration(d))[0];
5205+
if (textRange && isVariableDeclarationList(textRange.parent) && textRange.parent.declarations.length === 1) {
5206+
textRange = textRange.parent.parent;
5207+
}
5208+
const statement = setTextRange(createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([
52045209
createVariableDeclaration(name, serializeTypeForDeclaration(getTypeOfSymbol(symbol), symbol))
5205-
], flags));
5210+
], flags)), textRange);
52065211
addResult(statement, name !== localName ? modifierFlags & ~ModifierFlags.Export : modifierFlags);
52075212
if (name !== localName && !isPrivate) {
52085213
// We rename the variable declaration we generate for Property symbols since they may have a name which conflicts with a local declaration. Eg,
@@ -5338,7 +5343,8 @@ namespace ts {
53385343
break;
53395344
case SyntaxKind.ExportSpecifier:
53405345
// does not use localName because the symbol name in this case refers to the name in the exports table, which we must exactly preserve
5341-
serializeExportSpecifier(unescapeLeadingUnderscores(symbol.escapedName), targetName);
5346+
const specifier = (node.parent.parent as ExportDeclaration).moduleSpecifier;
5347+
serializeExportSpecifier(unescapeLeadingUnderscores(symbol.escapedName), targetName, specifier && isStringLiteralLike(specifier) ? createLiteral(specifier.text) : undefined);
53425348
break;
53435349
case SyntaxKind.ExportAssignment:
53445350
serializeMaybeAliasAssignment(symbol);
@@ -5362,8 +5368,13 @@ namespace ts {
53625368
}
53635369
}
53645370

5365-
function serializeExportSpecifier(localName: string, targetName: string) {
5366-
addResult(createExportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createNamedExports([createExportSpecifier(localName !== targetName ? targetName : undefined, localName)])), ModifierFlags.None);
5371+
function serializeExportSpecifier(localName: string, targetName: string, specifier?: Expression) {
5372+
addResult(createExportDeclaration(
5373+
/*decorators*/ undefined,
5374+
/*modifiers*/ undefined,
5375+
createNamedExports([createExportSpecifier(localName !== targetName ? targetName : undefined, localName)]),
5376+
specifier
5377+
), ModifierFlags.None);
53675378
}
53685379

53695380
function serializeMaybeAliasAssignment(symbol: Symbol) {
@@ -5485,14 +5496,14 @@ namespace ts {
54855496
const rawName = unescapeLeadingUnderscores(p.escapedName);
54865497
const name = getPropertyNameNodeForSymbolFromNameType(p, context) || createIdentifier(rawName);
54875498
if (p.flags & (SymbolFlags.Property | SymbolFlags.Accessor | SymbolFlags.Variable)) {
5488-
return createProperty(
5499+
return setTextRange(createProperty(
54895500
/*decorators*/ undefined,
54905501
createModifiersFromModifierFlags((isReadonlySymbol(p) ? ModifierFlags.Readonly : 0) | staticFlag),
54915502
name,
54925503
p.flags & SymbolFlags.Optional ? createToken(SyntaxKind.QuestionToken) : undefined,
54935504
serializeTypeForDeclaration(getTypeOfSymbol(p), p),
54945505
/*initializer*/ undefined // interface members can't have initializers, however class members _can_
5495-
);
5506+
), filter(p.declarations, d => isPropertyDeclaration(d) || isAccessor(d) || isVariableDeclaration(d) || isPropertySignature(d) || isBinaryExpression(d) || isPropertyAccessExpression(d))[0]);
54965507
}
54975508
if (p.flags & (SymbolFlags.Method | SymbolFlags.Function)) {
54985509
const type = getTypeOfSymbol(p);
@@ -5508,7 +5519,7 @@ namespace ts {
55085519
if (p.flags & SymbolFlags.Optional) {
55095520
decl.questionToken = createToken(SyntaxKind.QuestionToken);
55105521
}
5511-
results.push(decl);
5522+
results.push(setTextRange(decl, sig.declaration));
55125523
}
55135524
return results as unknown as T[];
55145525
}
@@ -5695,7 +5706,7 @@ namespace ts {
56955706
for (const sig of signatures) {
56965707
// Each overload becomes a seperate constructor declaration, in order
56975708
const decl = signatureToSignatureDeclarationHelper(sig, outputKind, context);
5698-
results.push(decl);
5709+
results.push(setTextRange(decl, sig.declaration));
56995710
}
57005711
return results;
57015712
}

tests/baselines/reference/jsDeclarationsClasses.js

+71
Original file line numberDiff line numberDiff line change
@@ -459,26 +459,84 @@ export class C {
459459
};
460460
}
461461
export class D {
462+
/**
463+
* @param {number} a
464+
* @param {number} b
465+
*/
462466
constructor(a: number, b: number);
463467
}
468+
/**
469+
* @template T,U
470+
*/
464471
export class E<T, U> {
472+
/**
473+
* @type {string}
474+
*/
465475
static staticField: string;
476+
/**
477+
* @type {string}
478+
* @readonly
479+
*/
466480
static staticReadonlyField: string;
467481
static staticInitializedField: number;
482+
/**
483+
* @return {string}
484+
*/
468485
static s1: string;
486+
/**
487+
* @return {string}
488+
*/
469489
static readonly s2: string;
490+
/**
491+
* @param {string} _p
492+
*/
470493
static s3: string;
494+
/**
495+
* @param {T} a
496+
* @param {U} b
497+
*/
471498
constructor(a: T, b: U);
499+
/**
500+
* @type {T & U}
501+
*/
472502
field: T & U;
503+
/**
504+
* @type {T & U}
505+
* @readonly
506+
*/
473507
readonlyField: T & U;
474508
initializedField: number;
509+
/**
510+
* @return {U}
511+
*/
475512
f1: U;
513+
/**
514+
* @return {U}
515+
*/
476516
readonly f2: U;
517+
/**
518+
* @param {U} _p
519+
*/
477520
f3: U;
478521
}
522+
/**
523+
* @template T,U
524+
*/
479525
export class F<T, U> {
526+
/**
527+
* @template A,B
528+
* @param {A} a
529+
* @param {B} b
530+
*/
480531
static create<A_1, B_1>(a: A_1, b: B_1): F<A_1, B_1>;
532+
/**
533+
* @param {T} a
534+
* @param {U} b
535+
*/
481536
constructor(a: T, b: U);
537+
/**
538+
* @type {T & U}
539+
*/
482540
field: T & U;
483541
}
484542
export class I {
@@ -495,11 +553,24 @@ export class L extends K {
495553
export class M {
496554
prop: number;
497555
}
556+
/**
557+
* @template T
558+
*/
498559
export class N<T> extends L {
560+
/**
561+
* @param {T} param
562+
*/
499563
constructor(param: T);
500564
another: T;
501565
}
566+
/**
567+
* @template U
568+
* @extends {N<U>}
569+
*/
502570
export class O<U> extends N<U> {
571+
/**
572+
* @param {U} param
573+
*/
503574
constructor(param: U);
504575
another2: U;
505576
}

tests/baselines/reference/jsDeclarationsComputedNames.js

+3
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ declare const InnerSym: unique symbol;
8181
//// [index2.d.ts]
8282
export class MyClass {
8383
static [TopLevelSym]: number;
84+
/**
85+
* @param {typeof TopLevelSym | typeof InnerSym} _p
86+
*/
8487
constructor(_p?: typeof TopLevelSym | typeof InnerSym);
8588
[InnerSym]: string;
8689
}

tests/baselines/reference/jsDeclarationsEnumTag.js

+9
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,16 @@ exports.ff = ff;
102102

103103

104104
//// [index.d.ts]
105+
/**
106+
* @param {Target} t
107+
* @param {Second} s
108+
* @param {Fs} f
109+
*/
105110
export function consume(t: string, s: number, f: (arg0: number) => number): void;
111+
/** @param {string} s */
106112
export function ff(s: string): any;
107113
export type Target = string;
114+
/** @enum {string} */
108115
export const Target: {
109116
START: string;
110117
MIDDLE: string;
@@ -113,12 +120,14 @@ export const Target: {
113120
OK_I_GUESS: number;
114121
};
115122
export type Second = number;
123+
/** @enum number */
116124
export const Second: {
117125
OK: number;
118126
/** @type {number} */
119127
FINE: number;
120128
};
121129
export type Fs = (arg0: number) => number;
130+
/** @enum {function(number): number} */
122131
export const Fs: {
123132
ADD1: (n: any) => any;
124133
ID: (n: any) => any;

tests/baselines/reference/jsDeclarationsExportAssignedClassExpression.js

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ module.exports = /** @class */ (function () {
2323
//// [index.d.ts]
2424
export = Thing;
2525
declare class Thing {
26+
/**
27+
* @param {number} p
28+
*/
2629
constructor(p: number);
2730
t: number;
2831
}

tests/baselines/reference/jsDeclarationsExportAssignedClassExpressionAnonymous.js

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ module.exports = /** @class */ (function () {
2323
//// [index.d.ts]
2424
export = exports;
2525
declare class exports {
26+
/**
27+
* @param {number} p
28+
*/
2629
constructor(p: number);
2730
t: number;
2831
}

tests/baselines/reference/jsDeclarationsExportAssignedClassExpressionAnonymousWithSub.js

+3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ module.exports.Sub = /** @class */ (function () {
3535
//// [index.d.ts]
3636
export = exports;
3737
declare class exports {
38+
/**
39+
* @param {number} p
40+
*/
3841
constructor(p: number);
3942
t: number;
4043
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//// [tests/cases/conformance/jsdoc/declarations/jsDeclarationsExportSpecifierNonlocal.ts] ////
2+
3+
//// [source.js]
4+
export class Thing {}
5+
export class OtherThing {}
6+
//// [index.js]
7+
export { Thing, OtherThing as default } from "./source";
8+
9+
10+
//// [source.js]
11+
"use strict";
12+
Object.defineProperty(exports, "__esModule", { value: true });
13+
var Thing = /** @class */ (function () {
14+
function Thing() {
15+
}
16+
return Thing;
17+
}());
18+
exports.Thing = Thing;
19+
var OtherThing = /** @class */ (function () {
20+
function OtherThing() {
21+
}
22+
return OtherThing;
23+
}());
24+
exports.OtherThing = OtherThing;
25+
//// [index.js]
26+
"use strict";
27+
Object.defineProperty(exports, "__esModule", { value: true });
28+
var source_1 = require("./source");
29+
exports.Thing = source_1.Thing;
30+
exports.default = source_1.OtherThing;
31+
32+
33+
//// [source.d.ts]
34+
export class Thing {
35+
}
36+
export class OtherThing {
37+
}
38+
//// [index.d.ts]
39+
export { Thing } from "./source";
40+
export { OtherThing as default } from "./source";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
=== tests/cases/conformance/jsdoc/declarations/source.js ===
2+
export class Thing {}
3+
>Thing : Symbol(Thing, Decl(source.js, 0, 0))
4+
5+
export class OtherThing {}
6+
>OtherThing : Symbol(OtherThing, Decl(source.js, 0, 21))
7+
8+
=== tests/cases/conformance/jsdoc/declarations/index.js ===
9+
export { Thing, OtherThing as default } from "./source";
10+
>Thing : Symbol(Thing, Decl(index.js, 0, 8))
11+
>OtherThing : Symbol(OtherThing, Decl(source.js, 0, 21))
12+
>default : Symbol(default, Decl(index.js, 0, 15))
13+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
=== tests/cases/conformance/jsdoc/declarations/source.js ===
2+
export class Thing {}
3+
>Thing : Thing
4+
5+
export class OtherThing {}
6+
>OtherThing : OtherThing
7+
8+
=== tests/cases/conformance/jsdoc/declarations/index.js ===
9+
export { Thing, OtherThing as default } from "./source";
10+
>Thing : typeof import("tests/cases/conformance/jsdoc/declarations/source").Thing
11+
>OtherThing : typeof import("tests/cases/conformance/jsdoc/declarations/source").OtherThing
12+
>default : typeof import("tests/cases/conformance/jsdoc/declarations/source").OtherThing
13+

0 commit comments

Comments
 (0)