mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' of https://github.com/Microsoft/TypeScript into feature/eslint
This commit is contained in:
+47
-24
@@ -2377,7 +2377,7 @@ namespace ts {
|
||||
return links.target;
|
||||
}
|
||||
|
||||
function markExportAsReferenced(node: ImportEqualsDeclaration | ExportAssignment | ExportSpecifier) {
|
||||
function markExportAsReferenced(node: ImportEqualsDeclaration | ExportSpecifier) {
|
||||
const symbol = getSymbolOfNode(node);
|
||||
const target = resolveAlias(symbol);
|
||||
if (target) {
|
||||
@@ -2399,15 +2399,10 @@ namespace ts {
|
||||
links.referenced = true;
|
||||
const node = getDeclarationOfAliasSymbol(symbol);
|
||||
if (!node) return Debug.fail();
|
||||
if (node.kind === SyntaxKind.ExportAssignment) {
|
||||
// export default <symbol>
|
||||
checkExpressionCached((<ExportAssignment>node).expression);
|
||||
}
|
||||
else if (node.kind === SyntaxKind.ExportSpecifier) {
|
||||
// export { <symbol> } or export { <symbol> as foo }
|
||||
checkExpressionCached((<ExportSpecifier>node).propertyName || (<ExportSpecifier>node).name);
|
||||
}
|
||||
else if (isInternalModuleImportEqualsDeclaration(node)) {
|
||||
// We defer checking of the reference of an `import =` until the import itself is referenced,
|
||||
// This way a chain of imports can be elided if ultimately the final input is only used in a type
|
||||
// position.
|
||||
if (isInternalModuleImportEqualsDeclaration(node)) {
|
||||
// import foo = <symbol>
|
||||
checkExpressionCached(<Expression>node.moduleReference);
|
||||
}
|
||||
@@ -17829,8 +17824,12 @@ namespace ts {
|
||||
return type;
|
||||
}
|
||||
|
||||
function isExportOrExportExpression(location: Node) {
|
||||
return !!findAncestor(location, e => e.parent && isExportAssignment(e.parent) && e.parent.expression === e && isEntityNameExpression(e));
|
||||
}
|
||||
|
||||
function markAliasReferenced(symbol: Symbol, location: Node) {
|
||||
if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(location) && !isConstEnumOrConstEnumOnlyModule(resolveAlias(symbol))) {
|
||||
if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(location) && ((compilerOptions.preserveConstEnums && isExportOrExportExpression(location)) || !isConstEnumOrConstEnumOnlyModule(resolveAlias(symbol)))) {
|
||||
markAliasSymbolAsReferenced(symbol);
|
||||
}
|
||||
}
|
||||
@@ -18812,6 +18811,17 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function getContextualIterationType(kind: IterationTypeKind, functionDecl: SignatureDeclaration): Type | undefined {
|
||||
const isAsync = !!(getFunctionFlags(functionDecl) & FunctionFlags.Async);
|
||||
const contextualReturnType = getContextualReturnType(functionDecl);
|
||||
if (contextualReturnType) {
|
||||
return getIterationTypeOfGeneratorFunctionReturnType(kind, contextualReturnType, isAsync)
|
||||
|| undefined;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getContextualReturnType(functionDecl: SignatureDeclaration): Type | undefined {
|
||||
// If the containing function has a return type annotation, is a constructor, or is a get accessor whose
|
||||
// corresponding set accessor has a type annotation, return statements in the function are contextually typed
|
||||
@@ -20341,8 +20351,8 @@ namespace ts {
|
||||
// if jsx emit was not react as there wont be error being emitted
|
||||
reactSym.isReferenced = SymbolFlags.All;
|
||||
|
||||
// If react symbol is alias, mark it as referenced
|
||||
if (reactSym.flags & SymbolFlags.Alias && !isConstEnumOrConstEnumOnlyModule(resolveAlias(reactSym))) {
|
||||
// If react symbol is alias, mark it as refereced
|
||||
if (reactSym.flags & SymbolFlags.Alias) {
|
||||
markAliasSymbolAsReferenced(reactSym);
|
||||
}
|
||||
}
|
||||
@@ -23477,7 +23487,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (isGenerator) {
|
||||
return createGeneratorReturnType(yieldType || neverType, returnType || fallbackReturnType, nextType || unknownType, isAsync);
|
||||
return createGeneratorReturnType(
|
||||
yieldType || neverType,
|
||||
returnType || fallbackReturnType,
|
||||
nextType || getContextualIterationType(IterationTypeKind.Next, func) || unknownType,
|
||||
isAsync);
|
||||
}
|
||||
else {
|
||||
// From within an async function you can return either a non-promise value or a promise. Any
|
||||
@@ -24839,13 +24853,7 @@ namespace ts {
|
||||
|| anyType;
|
||||
}
|
||||
|
||||
const contextualReturnType = getContextualReturnType(func);
|
||||
if (contextualReturnType) {
|
||||
return getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Next, contextualReturnType, isAsync)
|
||||
|| anyType;
|
||||
}
|
||||
|
||||
return anyType;
|
||||
return getContextualIterationType(IterationTypeKind.Next, func) || anyType;
|
||||
}
|
||||
|
||||
function checkConditionalExpression(node: ConditionalExpression, checkMode?: CheckMode): Type {
|
||||
@@ -24894,7 +24902,7 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function checkExpressionCached(node: Expression, checkMode?: CheckMode): Type {
|
||||
function checkExpressionCached(node: Expression | QualifiedName, checkMode?: CheckMode): Type {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
if (checkMode && checkMode !== CheckMode.Normal) {
|
||||
@@ -25222,7 +25230,8 @@ namespace ts {
|
||||
(node.parent.kind === SyntaxKind.PropertyAccessExpression && (<PropertyAccessExpression>node.parent).expression === node) ||
|
||||
(node.parent.kind === SyntaxKind.ElementAccessExpression && (<ElementAccessExpression>node.parent).expression === node) ||
|
||||
((node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) && isInRightSideOfImportOrExportAssignment(<Identifier>node) ||
|
||||
(node.parent.kind === SyntaxKind.TypeQuery && (<TypeQueryNode>node.parent).exprName === node));
|
||||
(node.parent.kind === SyntaxKind.TypeQuery && (<TypeQueryNode>node.parent).exprName === node)) ||
|
||||
(node.parent.kind === SyntaxKind.ExportSpecifier && (compilerOptions.preserveConstEnums || node.flags & NodeFlags.Ambient)); // We allow reexporting const enums
|
||||
|
||||
if (!ok) {
|
||||
error(node, Diagnostics.const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment_or_type_query);
|
||||
@@ -30152,6 +30161,10 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
markExportAsReferenced(node);
|
||||
const target = symbol && (symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol);
|
||||
if (!target || target === unknownSymbol || target.flags & SymbolFlags.Value) {
|
||||
checkExpressionCached(node.propertyName || node.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30178,7 +30191,17 @@ namespace ts {
|
||||
grammarErrorOnFirstToken(node, Diagnostics.An_export_assignment_cannot_have_modifiers);
|
||||
}
|
||||
if (node.expression.kind === SyntaxKind.Identifier) {
|
||||
markExportAsReferenced(node);
|
||||
const id = node.expression as Identifier;
|
||||
const sym = resolveEntityName(id, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, node);
|
||||
if (sym) {
|
||||
markAliasReferenced(sym, id);
|
||||
// If not a value, we're interpreting the identifier as a type export, along the lines of (`export { Id as default }`)
|
||||
const target = sym.flags & SymbolFlags.Alias ? resolveAlias(sym) : sym;
|
||||
if (target === unknownSymbol || target.flags & SymbolFlags.Value) {
|
||||
// However if it is a value, we need to check it's being used correctly
|
||||
checkExpressionCached(node.expression);
|
||||
}
|
||||
}
|
||||
|
||||
if (getEmitDeclarations(compilerOptions)) {
|
||||
collectLinkedAliases(node.expression as Identifier, /*setVisibility*/ true);
|
||||
|
||||
@@ -1743,6 +1743,16 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface TSConfig {
|
||||
compilerOptions: CompilerOptions;
|
||||
compileOnSave: boolean | undefined;
|
||||
exclude?: ReadonlyArray<string>;
|
||||
files: ReadonlyArray<string> | undefined;
|
||||
include?: ReadonlyArray<string>;
|
||||
references: ReadonlyArray<ProjectReference> | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an uncommented, complete tsconfig for use with "--showConfig"
|
||||
* @param configParseResult options to be generated into tsconfig.json
|
||||
@@ -1750,7 +1760,7 @@ namespace ts {
|
||||
* @param host provides current directory and case sensitivity services
|
||||
*/
|
||||
/** @internal */
|
||||
export function convertToTSConfig(configParseResult: ParsedCommandLine, configFileName: string, host: { getCurrentDirectory(): string, useCaseSensitiveFileNames: boolean }): object {
|
||||
export function convertToTSConfig(configParseResult: ParsedCommandLine, configFileName: string, host: { getCurrentDirectory(): string, useCaseSensitiveFileNames: boolean }): TSConfig {
|
||||
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
|
||||
const files = map(
|
||||
filter(
|
||||
@@ -1778,13 +1788,13 @@ namespace ts {
|
||||
build: undefined,
|
||||
version: undefined,
|
||||
},
|
||||
references: map(configParseResult.projectReferences, r => ({ ...r, path: r.originalPath, originalPath: undefined })),
|
||||
references: map(configParseResult.projectReferences, r => ({ ...r, path: r.originalPath ? r.originalPath : "", originalPath: undefined })),
|
||||
files: length(files) ? files : undefined,
|
||||
...(configParseResult.configFileSpecs ? {
|
||||
include: filterSameAsDefaultInclude(configParseResult.configFileSpecs.validatedIncludeSpecs),
|
||||
exclude: configParseResult.configFileSpecs.validatedExcludeSpecs
|
||||
} : {}),
|
||||
compilerOnSave: !!configParseResult.compileOnSave ? true : undefined
|
||||
compileOnSave: !!configParseResult.compileOnSave ? true : undefined
|
||||
};
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace ts {
|
||||
const previousOnSubstituteNode = context.onSubstituteNode;
|
||||
context.onSubstituteNode = onSubstituteNode;
|
||||
|
||||
let exportedVariableStatement = false;
|
||||
let enabledSubstitutions: ESNextSubstitutionFlags;
|
||||
let enclosingFunctionFlags: FunctionFlags;
|
||||
let enclosingSuperContainerFlags: NodeCheckFlags = 0;
|
||||
@@ -40,6 +41,7 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
exportedVariableStatement = false;
|
||||
const visited = visitEachChild(node, visitor, context);
|
||||
addEmitHelpers(visited, context.readEmitHelpers());
|
||||
return visited;
|
||||
@@ -79,6 +81,8 @@ namespace ts {
|
||||
return visitBinaryExpression(node as BinaryExpression, noDestructuringValue);
|
||||
case SyntaxKind.CatchClause:
|
||||
return visitCatchClause(node as CatchClause);
|
||||
case SyntaxKind.VariableStatement:
|
||||
return visitVariableStatement(node as VariableStatement);
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return visitVariableDeclaration(node as VariableDeclaration);
|
||||
case SyntaxKind.ForOfStatement:
|
||||
@@ -321,19 +325,43 @@ namespace ts {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitVariableStatement(node: VariableStatement): VisitResult<VariableStatement> {
|
||||
if (hasModifier(node, ModifierFlags.Export)) {
|
||||
const savedExportedVariableStatement = exportedVariableStatement;
|
||||
exportedVariableStatement = true;
|
||||
const visited = visitEachChild(node, visitor, context);
|
||||
exportedVariableStatement = savedExportedVariableStatement;
|
||||
return visited;
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a VariableDeclaration node with a binding pattern.
|
||||
*
|
||||
* @param node A VariableDeclaration node.
|
||||
*/
|
||||
function visitVariableDeclaration(node: VariableDeclaration): VisitResult<VariableDeclaration> {
|
||||
if (exportedVariableStatement) {
|
||||
const savedExportedVariableStatement = exportedVariableStatement;
|
||||
exportedVariableStatement = false;
|
||||
const visited = visitVariableDeclarationWorker(node, /*exportedVariableStatement*/ true);
|
||||
exportedVariableStatement = savedExportedVariableStatement;
|
||||
return visited;
|
||||
}
|
||||
return visitVariableDeclarationWorker(node, /*exportedVariableStatement*/ false);
|
||||
}
|
||||
|
||||
function visitVariableDeclarationWorker(node: VariableDeclaration, exportedVariableStatement: boolean): VisitResult<VariableDeclaration> {
|
||||
// If we are here it is because the name contains a binding pattern with a rest somewhere in it.
|
||||
if (isBindingPattern(node.name) && node.name.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
|
||||
return flattenDestructuringBinding(
|
||||
node,
|
||||
visitor,
|
||||
context,
|
||||
FlattenLevel.ObjectRest
|
||||
FlattenLevel.ObjectRest,
|
||||
/*rval*/ undefined,
|
||||
exportedVariableStatement
|
||||
);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
|
||||
@@ -567,6 +567,8 @@ namespace ts {
|
||||
return emitNode && emitNode.flags || 0;
|
||||
}
|
||||
|
||||
const escapeNoSubstitutionTemplateLiteralText = compose(escapeString, escapeTemplateSubstitution);
|
||||
const escapeNonAsciiNoSubstitutionTemplateLiteralText = compose(escapeNonAsciiString, escapeTemplateSubstitution);
|
||||
export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile, neverAsciiEscape: boolean | undefined) {
|
||||
// If we don't need to downlevel and we can reach the original source text using
|
||||
// the node's parent reference, then simply get the text as it was originally written.
|
||||
@@ -577,7 +579,11 @@ namespace ts {
|
||||
return getSourceTextOfNodeFromSourceFile(sourceFile, node);
|
||||
}
|
||||
|
||||
const escapeText = neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ? escapeString : escapeNonAsciiString;
|
||||
// If a NoSubstitutionTemplateLiteral appears to have a substitution in it, the original text
|
||||
// had to include a backslash: `not \${a} substitution`.
|
||||
const escapeText = neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ?
|
||||
node.kind === SyntaxKind.NoSubstitutionTemplateLiteral ? escapeNoSubstitutionTemplateLiteralText : escapeString :
|
||||
node.kind === SyntaxKind.NoSubstitutionTemplateLiteral ? escapeNonAsciiNoSubstitutionTemplateLiteralText : escapeNonAsciiString;
|
||||
|
||||
// If we can't reach the original source text, use the canonical form if it's a number,
|
||||
// or a (possibly escaped) quoted form of the original text if it's string-like.
|
||||
@@ -3118,6 +3124,11 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
const templateSubstitutionRegExp = /\$\{/g;
|
||||
function escapeTemplateSubstitution(str: string): string {
|
||||
return str.replace(templateSubstitutionRegExp, "\\${");
|
||||
}
|
||||
|
||||
// This consists of the first 19 unprintable ASCII characters, canonical escapes, lineSeparator,
|
||||
// paragraphSeparator, and nextLine. The latter three are just desirable to suppress new lines in
|
||||
// the language service. These characters should be escaped when printing, and if any characters are added,
|
||||
|
||||
@@ -730,6 +730,7 @@ namespace Harness {
|
||||
includeBuiltFile?: string;
|
||||
baselineFile?: string;
|
||||
libFiles?: string;
|
||||
noTypesAndSymbols?: boolean;
|
||||
}
|
||||
|
||||
// Additional options not already in ts.optionDeclarations
|
||||
@@ -746,6 +747,7 @@ namespace Harness {
|
||||
{ name: "currentDirectory", type: "string" },
|
||||
{ name: "symlink", type: "string" },
|
||||
{ name: "link", type: "string" },
|
||||
{ name: "noTypesAndSymbols", type: "boolean" },
|
||||
// Emitted js baseline will print full paths for every output file
|
||||
{ name: "fullEmitPaths", type: "boolean" }
|
||||
];
|
||||
|
||||
@@ -577,10 +577,10 @@ namespace ts.FindAllReferences {
|
||||
// If a reference is a class expression, the exported node would be its parent.
|
||||
// If a reference is a variable declaration, the exported node would be the variable statement.
|
||||
function getExportNode(parent: Node, node: Node): Node | undefined {
|
||||
if (parent.kind === SyntaxKind.VariableDeclaration) {
|
||||
const p = parent as VariableDeclaration;
|
||||
return p.name !== node ? undefined :
|
||||
p.parent.kind === SyntaxKind.CatchClause ? undefined : p.parent.parent.kind === SyntaxKind.VariableStatement ? p.parent.parent : undefined;
|
||||
const declaration = isVariableDeclaration(parent) ? parent : isBindingElement(parent) ? walkUpBindingElementsAndPatterns(parent) : undefined;
|
||||
if (declaration) {
|
||||
return (parent as VariableDeclaration | BindingElement).name !== node ? undefined :
|
||||
isCatchClause(declaration.parent) ? undefined : isVariableStatement(declaration.parent.parent) ? declaration.parent.parent : undefined;
|
||||
}
|
||||
else {
|
||||
return parent;
|
||||
|
||||
@@ -58,16 +58,18 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
}
|
||||
|
||||
public checkTestCodeOutput(fileName: string, test?: CompilerFileBasedTest) {
|
||||
if (test && test.configurations) {
|
||||
if (test && ts.some(test.configurations)) {
|
||||
test.configurations.forEach(configuration => {
|
||||
describe(`${this.testSuiteName} tests for ${fileName}${configuration ? ` (${Harness.getFileBasedTestConfigurationDescription(configuration)})` : ``}`, () => {
|
||||
this.runSuite(fileName, test, configuration);
|
||||
});
|
||||
});
|
||||
}
|
||||
describe(`${this.testSuiteName} tests for ${fileName}`, () => {
|
||||
this.runSuite(fileName, test);
|
||||
});
|
||||
else {
|
||||
describe(`${this.testSuiteName} tests for ${fileName}`, () => {
|
||||
this.runSuite(fileName, test);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private runSuite(fileName: string, test?: CompilerFileBasedTest, configuration?: Harness.FileBasedTestConfiguration) {
|
||||
@@ -112,6 +114,7 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
class CompilerTest {
|
||||
private fileName: string;
|
||||
private justName: string;
|
||||
private configuredName: string;
|
||||
private lastUnit: Harness.TestCaseParser.TestUnitData;
|
||||
private harnessSettings: Harness.TestCaseParser.CompilerSettings;
|
||||
private hasNonDtsFiles: boolean;
|
||||
@@ -126,6 +129,25 @@ class CompilerTest {
|
||||
constructor(fileName: string, testCaseContent?: Harness.TestCaseParser.TestCaseContent, configurationOverrides?: Harness.TestCaseParser.CompilerSettings) {
|
||||
this.fileName = fileName;
|
||||
this.justName = vpath.basename(fileName);
|
||||
this.configuredName = this.justName;
|
||||
if (configurationOverrides) {
|
||||
let configuredName = "";
|
||||
const keys = Object
|
||||
.keys(configurationOverrides)
|
||||
.map(k => k.toLowerCase())
|
||||
.sort();
|
||||
for (const key of keys) {
|
||||
if (configuredName) {
|
||||
configuredName += ",";
|
||||
}
|
||||
configuredName += `${key}=${configurationOverrides[key].toLowerCase()}`;
|
||||
}
|
||||
if (configuredName) {
|
||||
const extname = vpath.extname(this.justName);
|
||||
const basename = vpath.basename(this.justName, extname, /*ignoreCase*/ true);
|
||||
this.configuredName = `${basename}(${configuredName})${extname}`;
|
||||
}
|
||||
}
|
||||
|
||||
const rootDir = fileName.indexOf("conformance") === -1 ? "tests/cases/compiler/" : ts.getDirectoryPath(fileName) + "/";
|
||||
|
||||
@@ -205,7 +227,7 @@ class CompilerTest {
|
||||
public verifyDiagnostics() {
|
||||
// check errors
|
||||
Harness.Compiler.doErrorBaseline(
|
||||
this.justName,
|
||||
this.configuredName,
|
||||
this.tsConfigFiles.concat(this.toBeCompiled, this.otherFiles),
|
||||
this.result.diagnostics,
|
||||
!!this.options.pretty);
|
||||
@@ -213,7 +235,7 @@ class CompilerTest {
|
||||
|
||||
public verifyModuleResolution() {
|
||||
if (this.options.traceResolution) {
|
||||
Harness.Baseline.runBaseline(this.justName.replace(/\.tsx?$/, ".trace.json"),
|
||||
Harness.Baseline.runBaseline(this.configuredName.replace(/\.tsx?$/, ".trace.json"),
|
||||
JSON.stringify(this.result.traces.map(utils.sanitizeTraceResolutionLogEntry), undefined, 4));
|
||||
}
|
||||
}
|
||||
@@ -225,14 +247,14 @@ class CompilerTest {
|
||||
// Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required.
|
||||
? null // eslint-disable-line no-null/no-null
|
||||
: record;
|
||||
Harness.Baseline.runBaseline(this.justName.replace(/\.tsx?$/, ".sourcemap.txt"), baseline);
|
||||
Harness.Baseline.runBaseline(this.configuredName.replace(/\.tsx?$/, ".sourcemap.txt"), baseline);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyJavaScriptOutput() {
|
||||
if (this.hasNonDtsFiles) {
|
||||
Harness.Compiler.doJsEmitBaseline(
|
||||
this.justName,
|
||||
this.configuredName,
|
||||
this.fileName,
|
||||
this.options,
|
||||
this.result,
|
||||
@@ -245,7 +267,7 @@ class CompilerTest {
|
||||
|
||||
public verifySourceMapOutput() {
|
||||
Harness.Compiler.doSourcemapBaseline(
|
||||
this.justName,
|
||||
this.configuredName,
|
||||
this.options,
|
||||
this.result,
|
||||
this.harnessSettings);
|
||||
@@ -256,8 +278,15 @@ class CompilerTest {
|
||||
return;
|
||||
}
|
||||
|
||||
const noTypesAndSymbols =
|
||||
this.harnessSettings.noTypesAndSymbols &&
|
||||
this.harnessSettings.noTypesAndSymbols.toLowerCase() === "true";
|
||||
if (noTypesAndSymbols) {
|
||||
return;
|
||||
}
|
||||
|
||||
Harness.Compiler.doTypeAndSymbolBaseline(
|
||||
this.justName,
|
||||
this.configuredName,
|
||||
this.result.program!,
|
||||
this.toBeCompiled.concat(this.otherFiles).filter(file => !!this.result.program!.getSourceFile(file.unitName)),
|
||||
/*opts*/ undefined,
|
||||
|
||||
@@ -131,6 +131,7 @@
|
||||
"unittests/tsserver/formatSettings.ts",
|
||||
"unittests/tsserver/getApplicableRefactors.ts",
|
||||
"unittests/tsserver/getEditsForFileRename.ts",
|
||||
"unittests/tsserver/getExportReferences.ts",
|
||||
"unittests/tsserver/importHelpers.ts",
|
||||
"unittests/tsserver/inferredProjects.ts",
|
||||
"unittests/tsserver/languageService.ts",
|
||||
|
||||
@@ -53,6 +53,26 @@ namespace ts {
|
||||
|
||||
showTSConfigCorrectly("Show TSConfig with advanced options", ["--showConfig", "--declaration", "--declarationDir", "lib", "--skipLibCheck", "--noErrorTruncation"]);
|
||||
|
||||
showTSConfigCorrectly("Show TSConfig with compileOnSave and more", ["-p", "tsconfig.json"], {
|
||||
compilerOptions: {
|
||||
esModuleInterop: true,
|
||||
target: "es5",
|
||||
module: "commonjs",
|
||||
strict: true,
|
||||
},
|
||||
compileOnSave: true,
|
||||
exclude: [
|
||||
"dist"
|
||||
],
|
||||
files: [],
|
||||
include: [
|
||||
"src/*"
|
||||
],
|
||||
references: [
|
||||
{ path: "./test" }
|
||||
],
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/Microsoft/TypeScript/issues/28836
|
||||
showTSConfigCorrectly("Show TSConfig with paths and more", ["-p", "tsconfig.json"], {
|
||||
compilerOptions: {
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
namespace ts.projectSystem {
|
||||
interface DocumentSpanFromSubstring {
|
||||
file: File;
|
||||
text: string;
|
||||
options?: SpanFromSubstringOptions;
|
||||
contextText?: string;
|
||||
contextOptions?: SpanFromSubstringOptions;
|
||||
}
|
||||
function documentSpanFromSubstring({ file, text, contextText, options, contextOptions }: DocumentSpanFromSubstring): DocumentSpan {
|
||||
const contextSpan = contextText !== undefined ? documentSpanFromSubstring({ file, text: contextText, options: contextOptions }) : undefined;
|
||||
return {
|
||||
@@ -19,19 +12,6 @@ namespace ts.projectSystem {
|
||||
return documentSpanFromSubstring(input);
|
||||
}
|
||||
|
||||
interface MakeReferenceItem extends DocumentSpanFromSubstring {
|
||||
isDefinition: boolean;
|
||||
lineText: string;
|
||||
}
|
||||
function makeReferenceItem({ isDefinition, lineText, ...rest }: MakeReferenceItem): protocol.ReferencesResponseItem {
|
||||
return {
|
||||
...protocolFileSpanWithContextFromSubstring(rest),
|
||||
isDefinition,
|
||||
isWriteAccess: isDefinition,
|
||||
lineText,
|
||||
};
|
||||
}
|
||||
|
||||
interface MakeReferenceEntry extends DocumentSpanFromSubstring {
|
||||
isDefinition: boolean;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
namespace ts.projectSystem {
|
||||
describe("unittests:: tsserver:: getExportReferences", () => {
|
||||
const exportVariable = "export const value = 0;";
|
||||
const exportArrayDestructured = "export const [valueA, valueB] = [0, 1];";
|
||||
const exportObjectDestructured = "export const { valueC, valueD: renamedD } = { valueC: 0, valueD: 1 };";
|
||||
const exportNestedObject = "export const { nest: [valueE, { valueF }] } = { nest: [0, { valueF: 1 }] };";
|
||||
|
||||
const mainTs: File = {
|
||||
path: "/main.ts",
|
||||
content: 'import { value, valueA, valueB, valueC, renamedD, valueE, valueF } from "./mod";',
|
||||
};
|
||||
const modTs: File = {
|
||||
path: "/mod.ts",
|
||||
content: `${exportVariable}
|
||||
${exportArrayDestructured}
|
||||
${exportObjectDestructured}
|
||||
${exportNestedObject}
|
||||
`,
|
||||
};
|
||||
const tsconfig: File = {
|
||||
path: "/tsconfig.json",
|
||||
content: "{}",
|
||||
};
|
||||
|
||||
function makeSampleSession() {
|
||||
const host = createServerHost([mainTs, modTs, tsconfig]);
|
||||
const session = createSession(host);
|
||||
openFilesForSession([mainTs, modTs], session);
|
||||
return session;
|
||||
}
|
||||
|
||||
const referenceMainTs = (mainTs: File, text: string): protocol.ReferencesResponseItem =>
|
||||
makeReferenceItem({
|
||||
file: mainTs,
|
||||
isDefinition: true,
|
||||
lineText: mainTs.content,
|
||||
contextText: mainTs.content,
|
||||
text,
|
||||
});
|
||||
|
||||
const referenceModTs = (
|
||||
texts: { text: string; lineText: string; contextText?: string },
|
||||
override: Partial<MakeReferenceItem> = {},
|
||||
): protocol.ReferencesResponseItem =>
|
||||
makeReferenceItem({
|
||||
file: modTs,
|
||||
isDefinition: true,
|
||||
...texts,
|
||||
...override,
|
||||
});
|
||||
|
||||
it("should get const variable declaration references", () => {
|
||||
const session = makeSampleSession();
|
||||
|
||||
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(
|
||||
session,
|
||||
protocol.CommandTypes.References,
|
||||
protocolFileLocationFromSubstring(modTs, "value"),
|
||||
);
|
||||
|
||||
const expectResponse = {
|
||||
refs: [
|
||||
referenceModTs({ text: "value", lineText: exportVariable, contextText: exportVariable }),
|
||||
referenceMainTs(mainTs, "value"),
|
||||
],
|
||||
symbolDisplayString: "const value: 0",
|
||||
symbolName: "value",
|
||||
symbolStartOffset: protocolLocationFromSubstring(modTs.content, "value").offset,
|
||||
};
|
||||
|
||||
assert.deepEqual(response, expectResponse);
|
||||
});
|
||||
|
||||
it("should get array destructuring declaration references", () => {
|
||||
const session = makeSampleSession();
|
||||
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(
|
||||
session,
|
||||
protocol.CommandTypes.References,
|
||||
protocolFileLocationFromSubstring(modTs, "valueA"),
|
||||
);
|
||||
|
||||
const expectResponse = {
|
||||
refs: [
|
||||
referenceModTs({
|
||||
text: "valueA",
|
||||
lineText: exportArrayDestructured,
|
||||
contextText: exportArrayDestructured,
|
||||
}),
|
||||
referenceMainTs(mainTs, "valueA"),
|
||||
],
|
||||
symbolDisplayString: "const valueA: number",
|
||||
symbolName: "valueA",
|
||||
symbolStartOffset: protocolLocationFromSubstring(modTs.content, "valueA").offset,
|
||||
};
|
||||
|
||||
assert.deepEqual(response, expectResponse);
|
||||
});
|
||||
|
||||
it("should get object destructuring declaration references", () => {
|
||||
const session = makeSampleSession();
|
||||
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(
|
||||
session,
|
||||
protocol.CommandTypes.References,
|
||||
protocolFileLocationFromSubstring(modTs, "valueC"),
|
||||
);
|
||||
const expectResponse = {
|
||||
refs: [
|
||||
referenceModTs({
|
||||
text: "valueC",
|
||||
lineText: exportObjectDestructured,
|
||||
contextText: exportObjectDestructured,
|
||||
}),
|
||||
referenceMainTs(mainTs, "valueC"),
|
||||
referenceModTs(
|
||||
{ text: "valueC", lineText: exportObjectDestructured, contextText: "valueC: 0" },
|
||||
{ options: { index: 1 } },
|
||||
),
|
||||
],
|
||||
symbolDisplayString: "const valueC: number",
|
||||
symbolName: "valueC",
|
||||
symbolStartOffset: protocolLocationFromSubstring(modTs.content, "valueC").offset,
|
||||
};
|
||||
|
||||
assert.deepEqual(response, expectResponse);
|
||||
});
|
||||
|
||||
it("should get object declaration references that renames destructured property", () => {
|
||||
const session = makeSampleSession();
|
||||
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(
|
||||
session,
|
||||
protocol.CommandTypes.References,
|
||||
protocolFileLocationFromSubstring(modTs, "renamedD"),
|
||||
);
|
||||
|
||||
const expectResponse = {
|
||||
refs: [
|
||||
referenceModTs({
|
||||
text: "renamedD",
|
||||
lineText: exportObjectDestructured,
|
||||
contextText: exportObjectDestructured,
|
||||
}),
|
||||
referenceMainTs(mainTs, "renamedD"),
|
||||
],
|
||||
symbolDisplayString: "const renamedD: number",
|
||||
symbolName: "renamedD",
|
||||
symbolStartOffset: protocolLocationFromSubstring(modTs.content, "renamedD").offset,
|
||||
};
|
||||
|
||||
assert.deepEqual(response, expectResponse);
|
||||
});
|
||||
|
||||
it("should get nested object declaration references", () => {
|
||||
const session = makeSampleSession();
|
||||
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(
|
||||
session,
|
||||
protocol.CommandTypes.References,
|
||||
protocolFileLocationFromSubstring(modTs, "valueF"),
|
||||
);
|
||||
|
||||
const expectResponse = {
|
||||
refs: [
|
||||
referenceModTs({
|
||||
text: "valueF",
|
||||
lineText: exportNestedObject,
|
||||
contextText: exportNestedObject,
|
||||
}),
|
||||
referenceMainTs(mainTs, "valueF"),
|
||||
referenceModTs(
|
||||
{
|
||||
text: "valueF",
|
||||
lineText: exportNestedObject,
|
||||
contextText: "valueF: 1",
|
||||
},
|
||||
{ options: { index: 1 } },
|
||||
),
|
||||
],
|
||||
symbolDisplayString: "const valueF: number",
|
||||
symbolName: "valueF",
|
||||
symbolStartOffset: protocolLocationFromSubstring(modTs.content, "valueF").offset,
|
||||
};
|
||||
|
||||
assert.deepEqual(response, expectResponse);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -519,6 +519,8 @@ namespace ts.projectSystem {
|
||||
file: File;
|
||||
text: string;
|
||||
options?: SpanFromSubstringOptions;
|
||||
contextText?: string;
|
||||
contextOptions?: SpanFromSubstringOptions;
|
||||
}
|
||||
export function protocolFileSpanFromSubstring({ file, text, options }: DocumentSpanFromSubstring): protocol.FileSpan {
|
||||
return { file: file.path, ...protocolTextSpanFromSubstring(file.content, text, options) };
|
||||
@@ -727,4 +729,18 @@ namespace ts.projectSystem {
|
||||
assert.strictEqual(outputs.length, index + 1, JSON.stringify(outputs));
|
||||
}
|
||||
}
|
||||
|
||||
export interface MakeReferenceItem extends DocumentSpanFromSubstring {
|
||||
isDefinition: boolean;
|
||||
lineText: string;
|
||||
}
|
||||
|
||||
export function makeReferenceItem({ isDefinition, lineText, ...rest }: MakeReferenceItem): protocol.ReferencesResponseItem {
|
||||
return {
|
||||
...protocolFileSpanWithContextFromSubstring(rest),
|
||||
isDefinition,
|
||||
isWriteAccess: isDefinition,
|
||||
lineText,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user