mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-10 18:04:18 -05:00
Always export typedefs (#23723)
* Always export typedefs This actually just required deleting a check in declareModuleMembers and checking for external AND commonjs modules in a couple of places. However, while experimenting with this feature, I discovered that even previously-exported typedefs would only be exported if they came after a commonjs export node. So I added a commonjs check to the pass in the parser. It will not catch nested module.exports, but it will catch top-level assignments. The new test tests both changes. * Post-bind typedef instead of pre-checking for commonjs * Duplicate identifier errors * Fix class type reference resolution+update baselines * Move to a type-based check for duplicate identifiers
This commit is contained in:
committed by
GitHub
parent
0bbf4d5c48
commit
7cda045d52
@@ -118,6 +118,7 @@ namespace ts {
|
||||
let thisParentContainer: Node; // Container one level up
|
||||
let blockScopeContainer: Node;
|
||||
let lastContainer: Node;
|
||||
let delayedTypedefs: { typedef: JSDocTypedefTag, container: Node, lastContainer: Node, blockScopeContainer: Node, parent: Node }[];
|
||||
let seenThisKeyword: boolean;
|
||||
|
||||
// state used by control flow analysis
|
||||
@@ -176,6 +177,7 @@ namespace ts {
|
||||
bind(file);
|
||||
file.symbolCount = symbolCount;
|
||||
file.classifiableNames = classifiableNames;
|
||||
delayedBindJSDocTypedefTag();
|
||||
}
|
||||
|
||||
file = undefined;
|
||||
@@ -186,6 +188,7 @@ namespace ts {
|
||||
thisParentContainer = undefined;
|
||||
blockScopeContainer = undefined;
|
||||
lastContainer = undefined;
|
||||
delayedTypedefs = undefined;
|
||||
seenThisKeyword = false;
|
||||
currentFlow = undefined;
|
||||
currentBreakTarget = undefined;
|
||||
@@ -450,8 +453,7 @@ namespace ts {
|
||||
// and this case is specially handled. Module augmentations should only be merged with original module definition
|
||||
// and should never be merged directly with other augmentation, and the latter case would be possible if automatic merge is allowed.
|
||||
if (node.kind === SyntaxKind.JSDocTypedefTag) Debug.assert(isInJavaScriptFile(node)); // We shouldn't add symbols for JSDoc nodes if not in a JS file.
|
||||
const isJSDocTypedefInJSDocNamespace = isJSDocTypedefTag(node) && node.name && node.name.kind === SyntaxKind.Identifier && node.name.isInJSDocNamespace;
|
||||
if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypedefInJSDocNamespace) {
|
||||
if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypedefTag(node)) {
|
||||
if (hasModifier(node, ModifierFlags.Default) && !getDeclarationName(node)) {
|
||||
return declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes); // No local symbol for an unnamed default!
|
||||
}
|
||||
@@ -1727,7 +1729,7 @@ namespace ts {
|
||||
declareModuleMember(node, symbolFlags, symbolExcludes);
|
||||
break;
|
||||
case SyntaxKind.SourceFile:
|
||||
if (isExternalModule(<SourceFile>container)) {
|
||||
if (isExternalOrCommonJsModule(<SourceFile>container)) {
|
||||
declareModuleMember(node, symbolFlags, symbolExcludes);
|
||||
break;
|
||||
}
|
||||
@@ -1745,6 +1747,24 @@ namespace ts {
|
||||
bindBlockScopedDeclaration(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes);
|
||||
}
|
||||
|
||||
function delayedBindJSDocTypedefTag() {
|
||||
if (!delayedTypedefs) {
|
||||
return;
|
||||
}
|
||||
const saveContainer = container;
|
||||
const saveLastContainer = lastContainer;
|
||||
const saveBlockScopeContainer = blockScopeContainer;
|
||||
const saveParent = parent;
|
||||
for (const delay of delayedTypedefs) {
|
||||
({ container, lastContainer, blockScopeContainer, parent } = delay);
|
||||
bindBlockScopedDeclaration(delay.typedef, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
|
||||
}
|
||||
container = saveContainer;
|
||||
lastContainer = saveLastContainer;
|
||||
blockScopeContainer = saveBlockScopeContainer;
|
||||
parent = saveParent;
|
||||
}
|
||||
|
||||
// The binder visits every node in the syntax tree so it is a convenient place to perform a single localized
|
||||
// check for reserved words used as identifiers in strict mode code.
|
||||
function checkStrictModeIdentifier(node: Identifier) {
|
||||
@@ -2194,7 +2214,7 @@ namespace ts {
|
||||
case SyntaxKind.JSDocTypedefTag: {
|
||||
const { fullName } = node as JSDocTypedefTag;
|
||||
if (!fullName || fullName.kind === SyntaxKind.Identifier) {
|
||||
return bindBlockScopedDeclaration(<Declaration>node, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
|
||||
(delayedTypedefs || (delayedTypedefs = [])).push({ typedef: node as JSDocTypedefTag, container, lastContainer, blockScopeContainer, parent });
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2304,7 +2324,10 @@ namespace ts {
|
||||
return s;
|
||||
});
|
||||
if (symbol) {
|
||||
declareSymbol(symbol.exports, symbol, lhs, SymbolFlags.Property | SymbolFlags.ExportValue, SymbolFlags.None);
|
||||
const flags = isClassExpression(node.right) ?
|
||||
SymbolFlags.Property | SymbolFlags.ExportValue | SymbolFlags.Class :
|
||||
SymbolFlags.Property | SymbolFlags.ExportValue;
|
||||
declareSymbol(symbol.exports, symbol, lhs, flags, SymbolFlags.None);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7626,23 +7626,38 @@ namespace ts {
|
||||
return unknownType;
|
||||
}
|
||||
|
||||
// A jsdoc TypeReference may have resolved to a value (as opposed to a type). If
|
||||
// the symbol is a constructor function, return the inferred class type; otherwise,
|
||||
// the type of this reference is just the type of the value we resolved to.
|
||||
const assignedType = getAssignedClassType(symbol);
|
||||
const valueType = getTypeOfSymbol(symbol);
|
||||
const referenceType = valueType.symbol && !isInferredClassType(valueType) && getTypeReferenceTypeWorker(node, valueType.symbol, typeArguments);
|
||||
if (referenceType || assignedType) {
|
||||
return referenceType && assignedType ? getIntersectionType([assignedType, referenceType]) : referenceType || assignedType;
|
||||
const jsdocType = getJSDocTypeReference(node, symbol, typeArguments);
|
||||
if (jsdocType) {
|
||||
return jsdocType;
|
||||
}
|
||||
|
||||
// Resolve the type reference as a Type for the purpose of reporting errors.
|
||||
resolveTypeReferenceName(getTypeReferenceName(node), SymbolFlags.Type);
|
||||
return valueType;
|
||||
return getTypeOfSymbol(symbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* A jsdoc TypeReference may have resolved to a value (as opposed to a type). If
|
||||
* the symbol is a constructor function, return the inferred class type; otherwise,
|
||||
* the type of this reference is just the type of the value we resolved to.
|
||||
*/
|
||||
function getJSDocTypeReference(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[]): Type | undefined {
|
||||
const assignedType = getAssignedClassType(symbol);
|
||||
const valueType = getTypeOfSymbol(symbol);
|
||||
const referenceType = valueType.symbol && valueType.symbol !== symbol && !isInferredClassType(valueType) && getTypeReferenceTypeWorker(node, valueType.symbol, typeArguments);
|
||||
if (referenceType || assignedType) {
|
||||
return referenceType && assignedType ? getIntersectionType([assignedType, referenceType]) : referenceType || assignedType;
|
||||
}
|
||||
}
|
||||
|
||||
function getTypeReferenceTypeWorker(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[]): Type | undefined {
|
||||
if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
|
||||
if (symbol.valueDeclaration && isBinaryExpression(symbol.valueDeclaration.parent)) {
|
||||
const jsdocType = getJSDocTypeReference(node, symbol, typeArguments);
|
||||
if (jsdocType) {
|
||||
return jsdocType;
|
||||
}
|
||||
}
|
||||
return getTypeFromClassOrInterfaceReference(node, symbol, typeArguments);
|
||||
}
|
||||
|
||||
@@ -20031,6 +20046,7 @@ namespace ts {
|
||||
getUnionType([removeDefinitelyFalsyTypes(leftType), rightType], UnionReduction.Subtype) :
|
||||
leftType;
|
||||
case SyntaxKind.EqualsToken:
|
||||
checkSpecialAssignment(left, right);
|
||||
checkAssignmentOperator(rightType);
|
||||
return getRegularTypeOfObjectLiteral(rightType);
|
||||
case SyntaxKind.CommaToken:
|
||||
@@ -20040,6 +20056,24 @@ namespace ts {
|
||||
return rightType;
|
||||
}
|
||||
|
||||
function checkSpecialAssignment(left: Node, right: Expression) {
|
||||
const special = getSpecialPropertyAssignmentKind(left.parent as BinaryExpression);
|
||||
if (special === SpecialPropertyAssignmentKind.ModuleExports) {
|
||||
const rightType = checkExpression(right, checkMode);
|
||||
for (const prop of getPropertiesOfObjectType(rightType)) {
|
||||
const propType = getTypeOfSymbol(prop);
|
||||
if (propType.symbol && propType.symbol.flags & SymbolFlags.Class) {
|
||||
const name = prop.escapedName;
|
||||
const symbol = resolveName(prop.valueDeclaration, name, SymbolFlags.Type, undefined, name, /*isUse*/ false);
|
||||
if (symbol) {
|
||||
grammarErrorOnNode(symbol.declarations[0], Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(name));
|
||||
return grammarErrorOnNode(prop.valueDeclaration, Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isEvalNode(node: Expression) {
|
||||
return node.kind === SyntaxKind.Identifier && (node as Identifier).escapedText === "eval";
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ namespace Utils {
|
||||
for (const childName in node) {
|
||||
if (childName === "parent" || childName === "nextContainer" || childName === "modifiers" || childName === "externalModuleIndicator" ||
|
||||
// for now ignore jsdoc comments
|
||||
childName === "jsDocComment" || childName === "checkJsDirective") {
|
||||
childName === "jsDocComment" || childName === "checkJsDirective" || childName === "commonJsModuleIndicator") {
|
||||
continue;
|
||||
}
|
||||
const child = (<any>node)[childName];
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
* }}
|
||||
*/
|
||||
export const foo = 5;
|
||||
>foo : Symbol(foo, Decl(export.js, 4, 12))
|
||||
>foo : Symbol(foo, Decl(export.js, 4, 12), Decl(export.js, 1, 3))
|
||||
|
||||
|
||||
70
tests/baselines/reference/typedefCrossModule.symbols
Normal file
70
tests/baselines/reference/typedefCrossModule.symbols
Normal file
@@ -0,0 +1,70 @@
|
||||
=== tests/cases/conformance/jsdoc/commonjs.d.ts ===
|
||||
declare var module: { exports: any};
|
||||
>module : Symbol(module, Decl(commonjs.d.ts, 0, 11))
|
||||
>exports : Symbol(exports, Decl(commonjs.d.ts, 0, 21))
|
||||
|
||||
=== tests/cases/conformance/jsdoc/mod1.js ===
|
||||
/// <reference path="./commonjs.d.ts"/>
|
||||
/** @typedef {{ type: "a", x: 1 }} A */
|
||||
/** @typedef {{ type: "b", y: 1 }} B */
|
||||
/** @typedef {A | B} Both */
|
||||
module.exports = C
|
||||
>module.exports : Symbol(exports, Decl(commonjs.d.ts, 0, 21))
|
||||
>module : Symbol(export=, Decl(mod1.js, 0, 0))
|
||||
>exports : Symbol(export=, Decl(mod1.js, 0, 0))
|
||||
>C : Symbol(C, Decl(mod1.js, 4, 18))
|
||||
|
||||
function C() {
|
||||
>C : Symbol(C, Decl(mod1.js, 4, 18))
|
||||
|
||||
this.p = 1
|
||||
>p : Symbol(C.p, Decl(mod1.js, 5, 14))
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/jsdoc/mod2.js ===
|
||||
/// <reference path="./commonjs.d.ts"/>
|
||||
/** @typedef {{ type: "a", x: 1 }} A */
|
||||
/** @typedef {{ type: "b", y: 1 }} B */
|
||||
/** @typedef {A | B} Both */
|
||||
|
||||
export function C() {
|
||||
>C : Symbol(C, Decl(mod2.js, 0, 0))
|
||||
|
||||
this.p = 1
|
||||
>p : Symbol(C.p, Decl(mod2.js, 5, 21))
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/jsdoc/mod3.js ===
|
||||
/// <reference path="./commonjs.d.ts"/>
|
||||
/** @typedef {{ type: "a", x: 1 }} A */
|
||||
/** @typedef {{ type: "b", y: 1 }} B */
|
||||
/** @typedef {A | B} Both */
|
||||
|
||||
exports.C = function() {
|
||||
>exports.C : Symbol(C, Decl(mod3.js, 0, 0))
|
||||
>exports : Symbol(C, Decl(mod3.js, 0, 0))
|
||||
>C : Symbol(C, Decl(mod3.js, 0, 0))
|
||||
|
||||
this.p = 1
|
||||
>p : Symbol(C.p, Decl(mod3.js, 5, 24))
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/jsdoc/use.js ===
|
||||
/** @type {import('./mod1').Both} */
|
||||
var both1 = { type: 'a', x: 1 };
|
||||
>both1 : Symbol(both1, Decl(use.js, 1, 3))
|
||||
>type : Symbol(type, Decl(use.js, 1, 13))
|
||||
>x : Symbol(x, Decl(use.js, 1, 24))
|
||||
|
||||
/** @type {import('./mod2').Both} */
|
||||
var both2 = both1;
|
||||
>both2 : Symbol(both2, Decl(use.js, 3, 3))
|
||||
>both1 : Symbol(both1, Decl(use.js, 1, 3))
|
||||
|
||||
/** @type {import('./mod3').Both} */
|
||||
var both3 = both2;
|
||||
>both3 : Symbol(both3, Decl(use.js, 5, 3))
|
||||
>both2 : Symbol(both2, Decl(use.js, 3, 3))
|
||||
|
||||
|
||||
|
||||
88
tests/baselines/reference/typedefCrossModule.types
Normal file
88
tests/baselines/reference/typedefCrossModule.types
Normal file
@@ -0,0 +1,88 @@
|
||||
=== tests/cases/conformance/jsdoc/commonjs.d.ts ===
|
||||
declare var module: { exports: any};
|
||||
>module : { exports: any; }
|
||||
>exports : any
|
||||
|
||||
=== tests/cases/conformance/jsdoc/mod1.js ===
|
||||
/// <reference path="./commonjs.d.ts"/>
|
||||
/** @typedef {{ type: "a", x: 1 }} A */
|
||||
/** @typedef {{ type: "b", y: 1 }} B */
|
||||
/** @typedef {A | B} Both */
|
||||
module.exports = C
|
||||
>module.exports = C : typeof C
|
||||
>module.exports : any
|
||||
>module : { exports: any; }
|
||||
>exports : any
|
||||
>C : typeof C
|
||||
|
||||
function C() {
|
||||
>C : typeof C
|
||||
|
||||
this.p = 1
|
||||
>this.p = 1 : 1
|
||||
>this.p : any
|
||||
>this : any
|
||||
>p : any
|
||||
>1 : 1
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/jsdoc/mod2.js ===
|
||||
/// <reference path="./commonjs.d.ts"/>
|
||||
/** @typedef {{ type: "a", x: 1 }} A */
|
||||
/** @typedef {{ type: "b", y: 1 }} B */
|
||||
/** @typedef {A | B} Both */
|
||||
|
||||
export function C() {
|
||||
>C : typeof C
|
||||
|
||||
this.p = 1
|
||||
>this.p = 1 : 1
|
||||
>this.p : any
|
||||
>this : any
|
||||
>p : any
|
||||
>1 : 1
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/jsdoc/mod3.js ===
|
||||
/// <reference path="./commonjs.d.ts"/>
|
||||
/** @typedef {{ type: "a", x: 1 }} A */
|
||||
/** @typedef {{ type: "b", y: 1 }} B */
|
||||
/** @typedef {A | B} Both */
|
||||
|
||||
exports.C = function() {
|
||||
>exports.C = function() { this.p = 1} : typeof C
|
||||
>exports.C : typeof C
|
||||
>exports : typeof import("tests/cases/conformance/jsdoc/mod3")
|
||||
>C : typeof C
|
||||
>function() { this.p = 1} : typeof C
|
||||
|
||||
this.p = 1
|
||||
>this.p = 1 : 1
|
||||
>this.p : any
|
||||
>this : any
|
||||
>p : any
|
||||
>1 : 1
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/jsdoc/use.js ===
|
||||
/** @type {import('./mod1').Both} */
|
||||
var both1 = { type: 'a', x: 1 };
|
||||
>both1 : { type: "a"; x: 1; } | { type: "b"; y: 1; }
|
||||
>{ type: 'a', x: 1 } : { type: "a"; x: 1; }
|
||||
>type : "a"
|
||||
>'a' : "a"
|
||||
>x : 1
|
||||
>1 : 1
|
||||
|
||||
/** @type {import('./mod2').Both} */
|
||||
var both2 = both1;
|
||||
>both2 : { type: "a"; x: 1; } | { type: "b"; y: 1; }
|
||||
>both1 : { type: "a"; x: 1; }
|
||||
|
||||
/** @type {import('./mod3').Both} */
|
||||
var both3 = both2;
|
||||
>both3 : { type: "a"; x: 1; } | { type: "b"; y: 1; }
|
||||
>both2 : { type: "a"; x: 1; }
|
||||
|
||||
|
||||
|
||||
64
tests/baselines/reference/typedefCrossModule2.errors.txt
Normal file
64
tests/baselines/reference/typedefCrossModule2.errors.txt
Normal file
@@ -0,0 +1,64 @@
|
||||
tests/cases/conformance/jsdoc/mod1.js(3,23): error TS2300: Duplicate identifier 'Foo'.
|
||||
tests/cases/conformance/jsdoc/mod1.js(4,7): error TS2300: Duplicate identifier 'Foo'.
|
||||
tests/cases/conformance/jsdoc/mod1.js(6,23): error TS2300: Duplicate identifier 'Bar'.
|
||||
tests/cases/conformance/jsdoc/mod1.js(7,9): error TS2300: Duplicate identifier 'Bar'.
|
||||
tests/cases/conformance/jsdoc/mod1.js(9,5): error TS2300: Duplicate identifier 'Baz'.
|
||||
tests/cases/conformance/jsdoc/mod1.js(10,1): error TS2304: Cannot find name 'module'.
|
||||
tests/cases/conformance/jsdoc/mod1.js(11,5): error TS2300: Duplicate identifier 'Baz'.
|
||||
tests/cases/conformance/jsdoc/mod1.js(23,1): error TS2304: Cannot find name 'module'.
|
||||
tests/cases/conformance/jsdoc/use.js(1,11): error TS2304: Cannot find name 'require'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/use.js (1 errors) ====
|
||||
var mod = require('./mod1.js');
|
||||
~~~~~~~
|
||||
!!! error TS2304: Cannot find name 'require'.
|
||||
/** @type {import("./mod1.js").Baz} */
|
||||
var b;
|
||||
/** @type {mod.Baz} */
|
||||
var bb;
|
||||
var bbb = new mod.Baz();
|
||||
|
||||
==== tests/cases/conformance/jsdoc/mod1.js (8 errors) ====
|
||||
// error
|
||||
|
||||
/** @typedef {number} Foo */
|
||||
~~~
|
||||
!!! error TS2300: Duplicate identifier 'Foo'.
|
||||
class Foo { } // should error
|
||||
~~~
|
||||
!!! error TS2300: Duplicate identifier 'Foo'.
|
||||
|
||||
/** @typedef {number} Bar */
|
||||
~~~
|
||||
!!! error TS2300: Duplicate identifier 'Bar'.
|
||||
exports.Bar = class { }
|
||||
~~~
|
||||
!!! error TS2300: Duplicate identifier 'Bar'.
|
||||
|
||||
/** @typedef {number} Baz */
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2300: Duplicate identifier 'Baz'.
|
||||
module.exports = {
|
||||
~~~~~~
|
||||
!!! error TS2304: Cannot find name 'module'.
|
||||
Baz: class { }
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS2300: Duplicate identifier 'Baz'.
|
||||
}
|
||||
|
||||
// ok
|
||||
|
||||
/** @typedef {number} Qux */
|
||||
var Qux = 2;
|
||||
|
||||
/** @typedef {number} Quid */
|
||||
exports.Quid = 2;
|
||||
|
||||
/** @typedef {number} Quack */
|
||||
module.exports = {
|
||||
~~~~~~
|
||||
!!! error TS2304: Cannot find name 'module'.
|
||||
Quack: 2
|
||||
}
|
||||
|
||||
60
tests/baselines/reference/typedefCrossModule2.symbols
Normal file
60
tests/baselines/reference/typedefCrossModule2.symbols
Normal file
@@ -0,0 +1,60 @@
|
||||
=== tests/cases/conformance/jsdoc/use.js ===
|
||||
var mod = require('./mod1.js');
|
||||
>mod : Symbol(mod, Decl(use.js, 0, 3))
|
||||
>'./mod1.js' : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0))
|
||||
|
||||
/** @type {import("./mod1.js").Baz} */
|
||||
var b;
|
||||
>b : Symbol(b, Decl(use.js, 2, 3))
|
||||
|
||||
/** @type {mod.Baz} */
|
||||
var bb;
|
||||
>bb : Symbol(bb, Decl(use.js, 4, 3))
|
||||
|
||||
var bbb = new mod.Baz();
|
||||
>bbb : Symbol(bbb, Decl(use.js, 5, 3))
|
||||
>mod : Symbol(mod, Decl(use.js, 0, 3))
|
||||
|
||||
=== tests/cases/conformance/jsdoc/mod1.js ===
|
||||
// error
|
||||
|
||||
/** @typedef {number} Foo */
|
||||
class Foo { } // should error
|
||||
>Foo : Symbol(Foo, Decl(mod1.js, 0, 0))
|
||||
|
||||
/** @typedef {number} Bar */
|
||||
exports.Bar = class { }
|
||||
>exports.Bar : Symbol(Bar, Decl(mod1.js, 3, 13))
|
||||
>exports : Symbol(Bar, Decl(mod1.js, 3, 13))
|
||||
>Bar : Symbol(Bar, Decl(mod1.js, 3, 13))
|
||||
|
||||
/** @typedef {number} Baz */
|
||||
module.exports = {
|
||||
>module : Symbol(export=, Decl(mod1.js, 6, 23), Decl(mod1.js, 19, 17))
|
||||
>exports : Symbol(export=, Decl(mod1.js, 6, 23), Decl(mod1.js, 19, 17))
|
||||
|
||||
Baz: class { }
|
||||
>Baz : Symbol(Baz, Decl(mod1.js, 9, 18))
|
||||
}
|
||||
|
||||
// ok
|
||||
|
||||
/** @typedef {number} Qux */
|
||||
var Qux = 2;
|
||||
>Qux : Symbol(Qux, Decl(mod1.js, 16, 3), Decl(mod1.js, 15, 4))
|
||||
|
||||
/** @typedef {number} Quid */
|
||||
exports.Quid = 2;
|
||||
>exports.Quid : Symbol(Quid, Decl(mod1.js, 16, 12), Decl(mod1.js, 18, 4))
|
||||
>exports : Symbol(Quid, Decl(mod1.js, 16, 12), Decl(mod1.js, 18, 4))
|
||||
>Quid : Symbol(Quid, Decl(mod1.js, 16, 12), Decl(mod1.js, 18, 4))
|
||||
|
||||
/** @typedef {number} Quack */
|
||||
module.exports = {
|
||||
>module : Symbol(export=, Decl(mod1.js, 6, 23), Decl(mod1.js, 19, 17))
|
||||
>exports : Symbol(export=, Decl(mod1.js, 6, 23), Decl(mod1.js, 19, 17))
|
||||
|
||||
Quack: 2
|
||||
>Quack : Symbol(Quack, Decl(mod1.js, 22, 18))
|
||||
}
|
||||
|
||||
78
tests/baselines/reference/typedefCrossModule2.types
Normal file
78
tests/baselines/reference/typedefCrossModule2.types
Normal file
@@ -0,0 +1,78 @@
|
||||
=== tests/cases/conformance/jsdoc/use.js ===
|
||||
var mod = require('./mod1.js');
|
||||
>mod : { [x: string]: any; Baz: any; Bar: typeof Bar; Quid: any; } | { [x: string]: any; Quack: any; Bar: typeof Bar; Quid: any; }
|
||||
>require('./mod1.js') : { [x: string]: any; Baz: any; Bar: typeof Bar; Quid: any; } | { [x: string]: any; Quack: any; Bar: typeof Bar; Quid: any; }
|
||||
>require : any
|
||||
>'./mod1.js' : "./mod1.js"
|
||||
|
||||
/** @type {import("./mod1.js").Baz} */
|
||||
var b;
|
||||
>b : number
|
||||
|
||||
/** @type {mod.Baz} */
|
||||
var bb;
|
||||
>bb : number
|
||||
|
||||
var bbb = new mod.Baz();
|
||||
>bbb : any
|
||||
>new mod.Baz() : any
|
||||
>mod.Baz : any
|
||||
>mod : { [x: string]: any; Baz: any; Bar: typeof Bar; Quid: any; } | { [x: string]: any; Quack: any; Bar: typeof Bar; Quid: any; }
|
||||
>Baz : any
|
||||
|
||||
=== tests/cases/conformance/jsdoc/mod1.js ===
|
||||
// error
|
||||
|
||||
/** @typedef {number} Foo */
|
||||
class Foo { } // should error
|
||||
>Foo : Foo
|
||||
|
||||
/** @typedef {number} Bar */
|
||||
exports.Bar = class { }
|
||||
>exports.Bar = class { } : typeof Bar
|
||||
>exports.Bar : typeof Bar
|
||||
>exports : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>Bar : typeof Bar
|
||||
>class { } : typeof Bar
|
||||
|
||||
/** @typedef {number} Baz */
|
||||
module.exports = {
|
||||
>module.exports = { Baz: class { }} : { [x: string]: any; Baz: typeof Baz; }
|
||||
>module.exports : any
|
||||
>module : any
|
||||
>exports : any
|
||||
>{ Baz: class { }} : { [x: string]: any; Baz: typeof Baz; }
|
||||
|
||||
Baz: class { }
|
||||
>Baz : typeof Baz
|
||||
>class { } : typeof Baz
|
||||
}
|
||||
|
||||
// ok
|
||||
|
||||
/** @typedef {number} Qux */
|
||||
var Qux = 2;
|
||||
>Qux : number
|
||||
>2 : 2
|
||||
|
||||
/** @typedef {number} Quid */
|
||||
exports.Quid = 2;
|
||||
>exports.Quid = 2 : 2
|
||||
>exports.Quid : any
|
||||
>exports : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>Quid : any
|
||||
>2 : 2
|
||||
|
||||
/** @typedef {number} Quack */
|
||||
module.exports = {
|
||||
>module.exports = { Quack: 2} : { [x: string]: any; Quack: number; }
|
||||
>module.exports : any
|
||||
>module : any
|
||||
>exports : any
|
||||
>{ Quack: 2} : { [x: string]: any; Quack: number; }
|
||||
|
||||
Quack: 2
|
||||
>Quack : number
|
||||
>2 : 2
|
||||
}
|
||||
|
||||
18
tests/baselines/reference/typedefCrossModule3.errors.txt
Normal file
18
tests/baselines/reference/typedefCrossModule3.errors.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
tests/cases/conformance/jsdoc/mod2.js(1,5): error TS2300: Duplicate identifier 'Foo'.
|
||||
tests/cases/conformance/jsdoc/mod2.js(3,1): error TS2300: Duplicate identifier 'Foo'.
|
||||
tests/cases/conformance/jsdoc/mod2.js(4,1): error TS2304: Cannot find name 'module'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/mod2.js (3 errors) ====
|
||||
/** @typedef {number} Foo */
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2300: Duplicate identifier 'Foo'.
|
||||
const ns = {};
|
||||
ns.Foo = class {}
|
||||
~~~~~~
|
||||
!!! error TS2300: Duplicate identifier 'Foo'.
|
||||
module.exports = ns;
|
||||
~~~~~~
|
||||
!!! error TS2304: Cannot find name 'module'.
|
||||
|
||||
|
||||
16
tests/baselines/reference/typedefCrossModule3.symbols
Normal file
16
tests/baselines/reference/typedefCrossModule3.symbols
Normal file
@@ -0,0 +1,16 @@
|
||||
=== tests/cases/conformance/jsdoc/mod2.js ===
|
||||
/** @typedef {number} Foo */
|
||||
const ns = {};
|
||||
>ns : Symbol(ns, Decl(mod2.js, 1, 5), Decl(mod2.js, 1, 14))
|
||||
|
||||
ns.Foo = class {}
|
||||
>ns.Foo : Symbol(Foo, Decl(mod2.js, 1, 14))
|
||||
>ns : Symbol(ns, Decl(mod2.js, 1, 5), Decl(mod2.js, 1, 14))
|
||||
>Foo : Symbol(Foo, Decl(mod2.js, 1, 14))
|
||||
|
||||
module.exports = ns;
|
||||
>module : Symbol(export=, Decl(mod2.js, 2, 17))
|
||||
>exports : Symbol(export=, Decl(mod2.js, 2, 17))
|
||||
>ns : Symbol(ns, Decl(mod2.js, 1, 5), Decl(mod2.js, 1, 14))
|
||||
|
||||
|
||||
21
tests/baselines/reference/typedefCrossModule3.types
Normal file
21
tests/baselines/reference/typedefCrossModule3.types
Normal file
@@ -0,0 +1,21 @@
|
||||
=== tests/cases/conformance/jsdoc/mod2.js ===
|
||||
/** @typedef {number} Foo */
|
||||
const ns = {};
|
||||
>ns : { [x: string]: any; Foo: typeof Foo; }
|
||||
>{} : { [x: string]: any; Foo: typeof Foo; }
|
||||
|
||||
ns.Foo = class {}
|
||||
>ns.Foo = class {} : typeof Foo
|
||||
>ns.Foo : typeof Foo
|
||||
>ns : { [x: string]: any; Foo: typeof Foo; }
|
||||
>Foo : typeof Foo
|
||||
>class {} : typeof Foo
|
||||
|
||||
module.exports = ns;
|
||||
>module.exports = ns : { [x: string]: any; Foo: typeof Foo; }
|
||||
>module.exports : any
|
||||
>module : any
|
||||
>exports : any
|
||||
>ns : { [x: string]: any; Foo: typeof Foo; }
|
||||
|
||||
|
||||
17
tests/baselines/reference/typedefCrossModule4.errors.txt
Normal file
17
tests/baselines/reference/typedefCrossModule4.errors.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
tests/cases/conformance/jsdoc/mod3.js(1,5): error TS2300: Duplicate identifier 'Foo'.
|
||||
tests/cases/conformance/jsdoc/mod3.js(3,1): error TS2304: Cannot find name 'module'.
|
||||
tests/cases/conformance/jsdoc/mod3.js(3,20): error TS2300: Duplicate identifier 'Foo'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/mod3.js (3 errors) ====
|
||||
/** @typedef {number} Foo */
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2300: Duplicate identifier 'Foo'.
|
||||
class Bar { }
|
||||
module.exports = { Foo: Bar };
|
||||
~~~~~~
|
||||
!!! error TS2304: Cannot find name 'module'.
|
||||
~~~~~~~~
|
||||
!!! error TS2300: Duplicate identifier 'Foo'.
|
||||
|
||||
|
||||
12
tests/baselines/reference/typedefCrossModule4.symbols
Normal file
12
tests/baselines/reference/typedefCrossModule4.symbols
Normal file
@@ -0,0 +1,12 @@
|
||||
=== tests/cases/conformance/jsdoc/mod3.js ===
|
||||
/** @typedef {number} Foo */
|
||||
class Bar { }
|
||||
>Bar : Symbol(Bar, Decl(mod3.js, 0, 0))
|
||||
|
||||
module.exports = { Foo: Bar };
|
||||
>module : Symbol(export=, Decl(mod3.js, 1, 13))
|
||||
>exports : Symbol(export=, Decl(mod3.js, 1, 13))
|
||||
>Foo : Symbol(Foo, Decl(mod3.js, 2, 18))
|
||||
>Bar : Symbol(Bar, Decl(mod3.js, 0, 0))
|
||||
|
||||
|
||||
15
tests/baselines/reference/typedefCrossModule4.types
Normal file
15
tests/baselines/reference/typedefCrossModule4.types
Normal file
@@ -0,0 +1,15 @@
|
||||
=== tests/cases/conformance/jsdoc/mod3.js ===
|
||||
/** @typedef {number} Foo */
|
||||
class Bar { }
|
||||
>Bar : Bar
|
||||
|
||||
module.exports = { Foo: Bar };
|
||||
>module.exports = { Foo: Bar } : { [x: string]: any; Foo: typeof Bar; }
|
||||
>module.exports : any
|
||||
>module : any
|
||||
>exports : any
|
||||
>{ Foo: Bar } : { [x: string]: any; Foo: typeof Bar; }
|
||||
>Foo : typeof Bar
|
||||
>Bar : typeof Bar
|
||||
|
||||
|
||||
44
tests/cases/conformance/jsdoc/typedefCrossModule.ts
Normal file
44
tests/cases/conformance/jsdoc/typedefCrossModule.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
// @noEmit: true
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @Filename: commonjs.d.ts
|
||||
declare var module: { exports: any};
|
||||
// @Filename: mod1.js
|
||||
/// <reference path="./commonjs.d.ts"/>
|
||||
/** @typedef {{ type: "a", x: 1 }} A */
|
||||
/** @typedef {{ type: "b", y: 1 }} B */
|
||||
/** @typedef {A | B} Both */
|
||||
module.exports = C
|
||||
function C() {
|
||||
this.p = 1
|
||||
}
|
||||
|
||||
// @Filename: mod2.js
|
||||
/// <reference path="./commonjs.d.ts"/>
|
||||
/** @typedef {{ type: "a", x: 1 }} A */
|
||||
/** @typedef {{ type: "b", y: 1 }} B */
|
||||
/** @typedef {A | B} Both */
|
||||
|
||||
export function C() {
|
||||
this.p = 1
|
||||
}
|
||||
|
||||
// @Filename: mod3.js
|
||||
/// <reference path="./commonjs.d.ts"/>
|
||||
/** @typedef {{ type: "a", x: 1 }} A */
|
||||
/** @typedef {{ type: "b", y: 1 }} B */
|
||||
/** @typedef {A | B} Both */
|
||||
|
||||
exports.C = function() {
|
||||
this.p = 1
|
||||
}
|
||||
|
||||
// @Filename: use.js
|
||||
/** @type {import('./mod1').Both} */
|
||||
var both1 = { type: 'a', x: 1 };
|
||||
/** @type {import('./mod2').Both} */
|
||||
var both2 = both1;
|
||||
/** @type {import('./mod3').Both} */
|
||||
var both3 = both2;
|
||||
|
||||
|
||||
39
tests/cases/conformance/jsdoc/typedefCrossModule2.ts
Normal file
39
tests/cases/conformance/jsdoc/typedefCrossModule2.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
// @noEmit: true
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @Filename: mod1.js
|
||||
|
||||
// error
|
||||
|
||||
/** @typedef {number} Foo */
|
||||
class Foo { } // should error
|
||||
|
||||
/** @typedef {number} Bar */
|
||||
exports.Bar = class { }
|
||||
|
||||
/** @typedef {number} Baz */
|
||||
module.exports = {
|
||||
Baz: class { }
|
||||
}
|
||||
|
||||
// ok
|
||||
|
||||
/** @typedef {number} Qux */
|
||||
var Qux = 2;
|
||||
|
||||
/** @typedef {number} Quid */
|
||||
exports.Quid = 2;
|
||||
|
||||
/** @typedef {number} Quack */
|
||||
module.exports = {
|
||||
Quack: 2
|
||||
}
|
||||
|
||||
// @Filename: use.js
|
||||
|
||||
var mod = require('./mod1.js');
|
||||
/** @type {import("./mod1.js").Baz} */
|
||||
var b;
|
||||
/** @type {mod.Baz} */
|
||||
var bb;
|
||||
var bbb = new mod.Baz();
|
||||
10
tests/cases/conformance/jsdoc/typedefCrossModule3.ts
Normal file
10
tests/cases/conformance/jsdoc/typedefCrossModule3.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
// @noEmit: true
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @Filename: mod2.js
|
||||
|
||||
/** @typedef {number} Foo */
|
||||
const ns = {};
|
||||
ns.Foo = class {}
|
||||
module.exports = ns;
|
||||
|
||||
9
tests/cases/conformance/jsdoc/typedefCrossModule4.ts
Normal file
9
tests/cases/conformance/jsdoc/typedefCrossModule4.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
// @noEmit: true
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @Filename: mod3.js
|
||||
|
||||
/** @typedef {number} Foo */
|
||||
class Bar { }
|
||||
module.exports = { Foo: Bar };
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
////[|A|];
|
||||
|
||||
const [r0, r1, r2] = test.ranges();
|
||||
const defs = { definition: "(property) A: typeof A", ranges: [r0] };
|
||||
const imports = { definition: "(alias) (property) A: typeof A\nimport A", ranges: [r1, r2] };
|
||||
const defs = { definition: "class A\n(property) A: typeof A", ranges: [r0] };
|
||||
const imports = { definition: "(alias) class A\n(alias) (property) A: typeof A\nimport A", ranges: [r1, r2] };
|
||||
verify.referenceGroups([r0], [defs, imports]);
|
||||
verify.referenceGroups([r1, r2], [imports, defs]);
|
||||
|
||||
@@ -21,7 +21,9 @@ verify.codeFix({
|
||||
description: "Convert to ES6 module",
|
||||
newFileContent:
|
||||
`export function f() {}
|
||||
export class C {}
|
||||
const _C = class {
|
||||
};
|
||||
export { _C as C };
|
||||
export const x = 0;
|
||||
export function a1() {}
|
||||
export function a2() { return 0; }
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
verify.codeFix({
|
||||
description: "Convert to ES6 module",
|
||||
newFileContent:
|
||||
`export const C = class E { static instance = new E(); }
|
||||
export class D { static instance = new D(); }`,
|
||||
`const _C = class E {
|
||||
static instance = new E();
|
||||
};
|
||||
export { _C as C };
|
||||
const _D = class D {
|
||||
static instance = new D();
|
||||
};
|
||||
export { _D as D };`,
|
||||
});
|
||||
|
||||
@@ -11,5 +11,8 @@ verify.codeFix({
|
||||
description: "Convert to ES6 module",
|
||||
newFileContent:
|
||||
`export async function* f(p) { p; }
|
||||
export class C extends D { m() {} }`,
|
||||
const _C = class C extends D {
|
||||
m() { }
|
||||
};
|
||||
export { _C as C };`,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user