mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into tsbuild
This commit is contained in:
@@ -86,8 +86,8 @@ namespace ts {
|
||||
return createCombinedCodeActions(changes, commands.length === 0 ? undefined : commands);
|
||||
}
|
||||
|
||||
function eachDiagnostic({ program, sourceFile }: CodeFixAllContext, errorCodes: number[], cb: (diag: DiagnosticWithLocation) => void): void {
|
||||
for (const diag of program.getSemanticDiagnostics(sourceFile).concat(computeSuggestionDiagnostics(sourceFile, program))) {
|
||||
function eachDiagnostic({ program, sourceFile, cancellationToken }: CodeFixAllContext, errorCodes: number[], cb: (diag: DiagnosticWithLocation) => void): void {
|
||||
for (const diag of program.getSemanticDiagnostics(sourceFile, cancellationToken).concat(computeSuggestionDiagnostics(sourceFile, program, cancellationToken))) {
|
||||
if (contains(errorCodes, diag.code)) {
|
||||
cb(diag as DiagnosticWithLocation);
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ namespace ts.codefix {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const memberElements = createClassElementsFromSymbol(initializer.symbol);
|
||||
const memberElements = createClassElementsFromSymbol(node.symbol);
|
||||
if (initializer.body) {
|
||||
memberElements.unshift(createConstructor(/*decorators*/ undefined, /*modifiers*/ undefined, initializer.parameters, initializer.body));
|
||||
}
|
||||
|
||||
@@ -1,321 +0,0 @@
|
||||
// Used by importFixes to synthesize import module specifiers.
|
||||
/* @internal */
|
||||
namespace ts.moduleSpecifiers {
|
||||
// For each symlink/original for a module, returns a list of ways to import that file.
|
||||
export function getModuleSpecifiers(
|
||||
moduleSymbol: Symbol,
|
||||
program: Program,
|
||||
importingSourceFile: SourceFile,
|
||||
host: LanguageServiceHost,
|
||||
preferences: UserPreferences,
|
||||
): ReadonlyArray<ReadonlyArray<string>> {
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
const { baseUrl, paths, rootDirs } = compilerOptions;
|
||||
const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions);
|
||||
const addJsExtension = usesJsExtensionOnImports(importingSourceFile);
|
||||
const getCanonicalFileName = hostGetCanonicalFileName(host);
|
||||
const sourceDirectory = getDirectoryPath(importingSourceFile.fileName);
|
||||
|
||||
const ambient = tryGetModuleNameFromAmbientModule(moduleSymbol);
|
||||
if (ambient) return [[ambient]];
|
||||
|
||||
const modulePaths = getAllModulePaths(program, moduleSymbol.valueDeclaration.getSourceFile());
|
||||
|
||||
const global = mapDefined(modulePaths, moduleFileName =>
|
||||
tryGetModuleNameFromTypeRoots(compilerOptions, host, getCanonicalFileName, moduleFileName, addJsExtension) ||
|
||||
tryGetModuleNameAsNodeModule(compilerOptions, moduleFileName, host, getCanonicalFileName, sourceDirectory) ||
|
||||
rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName));
|
||||
if (global.length) return global.map(g => [g]);
|
||||
|
||||
return modulePaths.map(moduleFileName => {
|
||||
const relativePath = removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), moduleResolutionKind, addJsExtension);
|
||||
if (!baseUrl || preferences.importModuleSpecifierPreference === "relative") {
|
||||
return [relativePath];
|
||||
}
|
||||
|
||||
const relativeToBaseUrl = getRelativePathIfInDirectory(moduleFileName, baseUrl, getCanonicalFileName);
|
||||
if (!relativeToBaseUrl) {
|
||||
return [relativePath];
|
||||
}
|
||||
|
||||
const importRelativeToBaseUrl = removeExtensionAndIndexPostFix(relativeToBaseUrl, moduleResolutionKind, addJsExtension);
|
||||
if (paths) {
|
||||
const fromPaths = tryGetModuleNameFromPaths(removeFileExtension(relativeToBaseUrl), importRelativeToBaseUrl, paths);
|
||||
if (fromPaths) {
|
||||
return [fromPaths];
|
||||
}
|
||||
}
|
||||
|
||||
if (preferences.importModuleSpecifierPreference === "non-relative") {
|
||||
return [importRelativeToBaseUrl];
|
||||
}
|
||||
|
||||
if (preferences.importModuleSpecifierPreference !== undefined) Debug.assertNever(preferences.importModuleSpecifierPreference);
|
||||
|
||||
if (isPathRelativeToParent(relativeToBaseUrl)) {
|
||||
return [relativePath];
|
||||
}
|
||||
|
||||
/*
|
||||
Prefer a relative import over a baseUrl import if it doesn't traverse up to baseUrl.
|
||||
|
||||
Suppose we have:
|
||||
baseUrl = /base
|
||||
sourceDirectory = /base/a/b
|
||||
moduleFileName = /base/foo/bar
|
||||
Then:
|
||||
relativePath = ../../foo/bar
|
||||
getRelativePathNParents(relativePath) = 2
|
||||
pathFromSourceToBaseUrl = ../../
|
||||
getRelativePathNParents(pathFromSourceToBaseUrl) = 2
|
||||
2 < 2 = false
|
||||
In this case we should prefer using the baseUrl path "/a/b" instead of the relative path "../../foo/bar".
|
||||
|
||||
Suppose we have:
|
||||
baseUrl = /base
|
||||
sourceDirectory = /base/foo/a
|
||||
moduleFileName = /base/foo/bar
|
||||
Then:
|
||||
relativePath = ../a
|
||||
getRelativePathNParents(relativePath) = 1
|
||||
pathFromSourceToBaseUrl = ../../
|
||||
getRelativePathNParents(pathFromSourceToBaseUrl) = 2
|
||||
1 < 2 = true
|
||||
In this case we should prefer using the relative path "../a" instead of the baseUrl path "foo/a".
|
||||
*/
|
||||
const pathFromSourceToBaseUrl = ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, baseUrl, getCanonicalFileName));
|
||||
const relativeFirst = getRelativePathNParents(relativePath) < getRelativePathNParents(pathFromSourceToBaseUrl);
|
||||
return relativeFirst ? [relativePath, importRelativeToBaseUrl] : [importRelativeToBaseUrl, relativePath];
|
||||
});
|
||||
}
|
||||
|
||||
function usesJsExtensionOnImports({ imports }: SourceFile): boolean {
|
||||
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? fileExtensionIs(text, Extension.Js) : undefined) || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for a existing imports that use symlinks to this module.
|
||||
* Only if no symlink is available, the real path will be used.
|
||||
*/
|
||||
function getAllModulePaths(program: Program, { fileName }: SourceFile): ReadonlyArray<string> {
|
||||
const symlinks = mapDefined(program.getSourceFiles(), sf =>
|
||||
sf.resolvedModules && firstDefinedIterator(sf.resolvedModules.values(), res =>
|
||||
res && res.resolvedFileName === fileName ? res.originalPath : undefined));
|
||||
return symlinks.length === 0 ? [fileName] : symlinks;
|
||||
}
|
||||
|
||||
function getRelativePathNParents(relativePath: string): number {
|
||||
const components = getPathComponents(relativePath);
|
||||
if (components[0] || components.length === 1) return 0;
|
||||
for (let i = 1; i < components.length; i++) {
|
||||
if (components[i] !== "..") return i - 1;
|
||||
}
|
||||
return components.length - 1;
|
||||
}
|
||||
|
||||
function tryGetModuleNameFromAmbientModule(moduleSymbol: Symbol): string | undefined {
|
||||
const decl = moduleSymbol.valueDeclaration;
|
||||
if (isModuleDeclaration(decl) && isStringLiteral(decl.name)) {
|
||||
return decl.name.text;
|
||||
}
|
||||
}
|
||||
|
||||
function tryGetModuleNameFromPaths(relativeToBaseUrlWithIndex: string, relativeToBaseUrl: string, paths: MapLike<ReadonlyArray<string>>): string | undefined {
|
||||
for (const key in paths) {
|
||||
for (const patternText of paths[key]) {
|
||||
const pattern = removeFileExtension(normalizePath(patternText));
|
||||
const indexOfStar = pattern.indexOf("*");
|
||||
if (indexOfStar === 0 && pattern.length === 1) {
|
||||
continue;
|
||||
}
|
||||
else if (indexOfStar !== -1) {
|
||||
const prefix = pattern.substr(0, indexOfStar);
|
||||
const suffix = pattern.substr(indexOfStar + 1);
|
||||
if (relativeToBaseUrl.length >= prefix.length + suffix.length &&
|
||||
startsWith(relativeToBaseUrl, prefix) &&
|
||||
endsWith(relativeToBaseUrl, suffix)) {
|
||||
const matchedStar = relativeToBaseUrl.substr(prefix.length, relativeToBaseUrl.length - suffix.length);
|
||||
return key.replace("*", matchedStar);
|
||||
}
|
||||
}
|
||||
else if (pattern === relativeToBaseUrl || pattern === relativeToBaseUrlWithIndex) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tryGetModuleNameFromRootDirs(rootDirs: ReadonlyArray<string>, moduleFileName: string, sourceDirectory: string, getCanonicalFileName: (file: string) => string): string | undefined {
|
||||
const normalizedTargetPath = getPathRelativeToRootDirs(moduleFileName, rootDirs, getCanonicalFileName);
|
||||
if (normalizedTargetPath === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const normalizedSourcePath = getPathRelativeToRootDirs(sourceDirectory, rootDirs, getCanonicalFileName);
|
||||
const relativePath = normalizedSourcePath !== undefined ? ensurePathIsNonModuleName(getRelativePathFromDirectory(normalizedSourcePath, normalizedTargetPath, getCanonicalFileName)) : normalizedTargetPath;
|
||||
return removeFileExtension(relativePath);
|
||||
}
|
||||
|
||||
function tryGetModuleNameFromTypeRoots(
|
||||
options: CompilerOptions,
|
||||
host: GetEffectiveTypeRootsHost,
|
||||
getCanonicalFileName: (file: string) => string,
|
||||
moduleFileName: string,
|
||||
addJsExtension: boolean,
|
||||
): string | undefined {
|
||||
const roots = getEffectiveTypeRoots(options, host);
|
||||
return firstDefined(roots, unNormalizedTypeRoot => {
|
||||
const typeRoot = toPath(unNormalizedTypeRoot, /*basePath*/ undefined, getCanonicalFileName);
|
||||
if (startsWith(moduleFileName, typeRoot)) {
|
||||
// For a type definition, we can strip `/index` even with classic resolution.
|
||||
return removeExtensionAndIndexPostFix(moduleFileName.substring(typeRoot.length + 1), ModuleResolutionKind.NodeJs, addJsExtension);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function tryGetModuleNameAsNodeModule(
|
||||
options: CompilerOptions,
|
||||
moduleFileName: string,
|
||||
host: LanguageServiceHost,
|
||||
getCanonicalFileName: (file: string) => string,
|
||||
sourceDirectory: string,
|
||||
): string | undefined {
|
||||
if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs) {
|
||||
// nothing to do here
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const parts: NodeModulePathParts = getNodeModulePathParts(moduleFileName)!;
|
||||
|
||||
if (!parts) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Simplify the full file path to something that can be resolved by Node.
|
||||
|
||||
// If the module could be imported by a directory name, use that directory's name
|
||||
const moduleSpecifier = getDirectoryOrExtensionlessFileName(moduleFileName);
|
||||
// Get a path that's relative to node_modules or the importing file's path
|
||||
// if node_modules folder is in this folder or any of its parent folders, no need to keep it.
|
||||
if (!startsWith(sourceDirectory, moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex))) return undefined;
|
||||
// If the module was found in @types, get the actual Node package name
|
||||
return getPackageNameFromAtTypesDirectory(moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1));
|
||||
|
||||
function getDirectoryOrExtensionlessFileName(path: string): string {
|
||||
// If the file is the main module, it can be imported by the package name
|
||||
const packageRootPath = path.substring(0, parts.packageRootIndex);
|
||||
const packageJsonPath = combinePaths(packageRootPath, "package.json");
|
||||
if (host.fileExists!(packageJsonPath)) { // TODO: GH#18217
|
||||
const packageJsonContent = JSON.parse(host.readFile!(packageJsonPath)!);
|
||||
if (packageJsonContent) {
|
||||
const mainFileRelative = packageJsonContent.typings || packageJsonContent.types || packageJsonContent.main;
|
||||
if (mainFileRelative) {
|
||||
const mainExportFile = toPath(mainFileRelative, packageRootPath, getCanonicalFileName);
|
||||
if (mainExportFile === getCanonicalFileName(path)) {
|
||||
return packageRootPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We still have a file name - remove the extension
|
||||
const fullModulePathWithoutExtension = removeFileExtension(path);
|
||||
|
||||
// If the file is /index, it can be imported by its directory name
|
||||
if (getCanonicalFileName(fullModulePathWithoutExtension.substring(parts.fileNameIndex)) === "/index") {
|
||||
return fullModulePathWithoutExtension.substring(0, parts.fileNameIndex);
|
||||
}
|
||||
|
||||
return fullModulePathWithoutExtension;
|
||||
}
|
||||
}
|
||||
|
||||
interface NodeModulePathParts {
|
||||
readonly topLevelNodeModulesIndex: number;
|
||||
readonly topLevelPackageNameIndex: number;
|
||||
readonly packageRootIndex: number;
|
||||
readonly fileNameIndex: number;
|
||||
}
|
||||
function getNodeModulePathParts(fullPath: string): NodeModulePathParts | undefined {
|
||||
// If fullPath can't be valid module file within node_modules, returns undefined.
|
||||
// Example of expected pattern: /base/path/node_modules/[@scope/otherpackage/@otherscope/node_modules/]package/[subdirectory/]file.js
|
||||
// Returns indices: ^ ^ ^ ^
|
||||
|
||||
let topLevelNodeModulesIndex = 0;
|
||||
let topLevelPackageNameIndex = 0;
|
||||
let packageRootIndex = 0;
|
||||
let fileNameIndex = 0;
|
||||
|
||||
const enum States {
|
||||
BeforeNodeModules,
|
||||
NodeModules,
|
||||
Scope,
|
||||
PackageContent
|
||||
}
|
||||
|
||||
let partStart = 0;
|
||||
let partEnd = 0;
|
||||
let state = States.BeforeNodeModules;
|
||||
|
||||
while (partEnd >= 0) {
|
||||
partStart = partEnd;
|
||||
partEnd = fullPath.indexOf("/", partStart + 1);
|
||||
switch (state) {
|
||||
case States.BeforeNodeModules:
|
||||
if (fullPath.indexOf("/node_modules/", partStart) === partStart) {
|
||||
topLevelNodeModulesIndex = partStart;
|
||||
topLevelPackageNameIndex = partEnd;
|
||||
state = States.NodeModules;
|
||||
}
|
||||
break;
|
||||
case States.NodeModules:
|
||||
case States.Scope:
|
||||
if (state === States.NodeModules && fullPath.charAt(partStart + 1) === "@") {
|
||||
state = States.Scope;
|
||||
}
|
||||
else {
|
||||
packageRootIndex = partEnd;
|
||||
state = States.PackageContent;
|
||||
}
|
||||
break;
|
||||
case States.PackageContent:
|
||||
if (fullPath.indexOf("/node_modules/", partStart) === partStart) {
|
||||
state = States.NodeModules;
|
||||
}
|
||||
else {
|
||||
state = States.PackageContent;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fileNameIndex = partStart;
|
||||
|
||||
return state > States.NodeModules ? { topLevelNodeModulesIndex, topLevelPackageNameIndex, packageRootIndex, fileNameIndex } : undefined;
|
||||
}
|
||||
|
||||
function getPathRelativeToRootDirs(path: string, rootDirs: ReadonlyArray<string>, getCanonicalFileName: GetCanonicalFileName): string | undefined {
|
||||
return firstDefined(rootDirs, rootDir => {
|
||||
const relativePath = getRelativePathIfInDirectory(path, rootDir, getCanonicalFileName)!; // TODO: GH#18217
|
||||
return isPathRelativeToParent(relativePath) ? undefined : relativePath;
|
||||
});
|
||||
}
|
||||
|
||||
function removeExtensionAndIndexPostFix(fileName: string, moduleResolutionKind: ModuleResolutionKind, addJsExtension: boolean): string {
|
||||
const noExtension = removeFileExtension(fileName);
|
||||
return addJsExtension
|
||||
? noExtension + ".js"
|
||||
: moduleResolutionKind === ModuleResolutionKind.NodeJs
|
||||
? removeSuffix(noExtension, "/index")
|
||||
: noExtension;
|
||||
}
|
||||
|
||||
function getRelativePathIfInDirectory(path: string, directoryPath: string, getCanonicalFileName: GetCanonicalFileName): string | undefined {
|
||||
const relativePath = getRelativePathToDirectoryOrUrl(directoryPath, path, directoryPath, getCanonicalFileName, /*isAbsolutePathAnUrl*/ false);
|
||||
return isRootedDiskPath(relativePath) ? undefined : relativePath;
|
||||
}
|
||||
|
||||
function isPathRelativeToParent(path: string): boolean {
|
||||
return startsWith(path, "..");
|
||||
}
|
||||
}
|
||||
@@ -633,7 +633,7 @@ namespace ts.Completions {
|
||||
}
|
||||
|
||||
const { moduleSymbol } = symbolOriginInfo;
|
||||
const exportedSymbol = skipAlias(symbol.exportSymbol || symbol, checker);
|
||||
const exportedSymbol = checker.getMergedSymbol(skipAlias(symbol.exportSymbol || symbol, checker));
|
||||
const { moduleSpecifier, codeAction } = codefix.getImportCompletionAction(
|
||||
exportedSymbol,
|
||||
moduleSymbol,
|
||||
@@ -875,7 +875,7 @@ namespace ts.Completions {
|
||||
let isStartingCloseTag = false;
|
||||
let isJsxInitializer: IsJsxInitializer = false;
|
||||
|
||||
let location = getTouchingPropertyName(sourceFile, position, insideJsDocTagTypeExpression); // TODO: GH#15853
|
||||
let location = getTouchingPropertyName(sourceFile, position);
|
||||
if (contextToken) {
|
||||
// Bail out if this is a known invalid completion location
|
||||
if (isCompletionListBlocker(contextToken)) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* @internal */
|
||||
namespace ts.DocumentHighlights {
|
||||
export function getDocumentHighlights(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, position: number, sourceFilesToSearch: ReadonlyArray<SourceFile>): DocumentHighlights[] | undefined {
|
||||
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
const node = getTouchingPropertyName(sourceFile, position);
|
||||
|
||||
if (node.parent && (isJsxOpeningElement(node.parent) && node.parent.tagName === node || isJsxClosingElement(node.parent))) {
|
||||
// For a JSX element, just highlight the matching tag, not all references.
|
||||
@@ -78,6 +78,8 @@ namespace ts.DocumentHighlights {
|
||||
return useParent(node.parent, isAwaitExpression, getAsyncAndAwaitOccurrences);
|
||||
case SyntaxKind.AsyncKeyword:
|
||||
return highlightSpans(getAsyncAndAwaitOccurrences(node));
|
||||
case SyntaxKind.YieldKeyword:
|
||||
return highlightSpans(getYieldOccurrences(node));
|
||||
default:
|
||||
return isModifierKind(node.kind) && (isDeclaration(node.parent) || isVariableStatement(node.parent))
|
||||
? highlightSpans(getModifierOccurrences(node.kind, node.parent))
|
||||
@@ -170,7 +172,7 @@ namespace ts.DocumentHighlights {
|
||||
if (statement.kind === SyntaxKind.ContinueStatement) {
|
||||
return false;
|
||||
}
|
||||
// falls through
|
||||
// falls through
|
||||
case SyntaxKind.ForStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForOfStatement:
|
||||
@@ -237,7 +239,7 @@ namespace ts.DocumentHighlights {
|
||||
}
|
||||
}
|
||||
|
||||
function pushKeywordIf(keywordList: Push<Node>, token: Node, ...expected: SyntaxKind[]): boolean {
|
||||
function pushKeywordIf(keywordList: Push<Node>, token: Node | undefined, ...expected: SyntaxKind[]): boolean {
|
||||
if (token && contains(expected, token.kind)) {
|
||||
keywordList.push(token);
|
||||
return true;
|
||||
@@ -384,18 +386,42 @@ namespace ts.DocumentHighlights {
|
||||
});
|
||||
}
|
||||
|
||||
forEachChild(func, aggregate);
|
||||
forEachChild(func, child => {
|
||||
traverseWithoutCrossingFunction(child, node => {
|
||||
if (isAwaitExpression(node)) {
|
||||
pushKeywordIf(keywords, node.getFirstToken(), SyntaxKind.AwaitKeyword);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
return keywords;
|
||||
}
|
||||
|
||||
function aggregate(node: Node): void {
|
||||
if (isAwaitExpression(node)) {
|
||||
pushKeywordIf(keywords, node.getFirstToken()!, SyntaxKind.AwaitKeyword);
|
||||
}
|
||||
// Do not cross function boundaries.
|
||||
if (!isFunctionLike(node) && !isClassLike(node) && !isInterfaceDeclaration(node) && !isModuleDeclaration(node) && !isTypeAliasDeclaration(node) && !isTypeNode(node)) {
|
||||
forEachChild(node, aggregate);
|
||||
}
|
||||
function getYieldOccurrences(node: Node): Node[] | undefined {
|
||||
const func = getContainingFunction(node) as FunctionDeclaration;
|
||||
if (!func) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const keywords: Node[] = [];
|
||||
|
||||
forEachChild(func, child => {
|
||||
traverseWithoutCrossingFunction(child, node => {
|
||||
if (isYieldExpression(node)) {
|
||||
pushKeywordIf(keywords, node.getFirstToken(), SyntaxKind.YieldKeyword);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return keywords;
|
||||
}
|
||||
|
||||
// Do not cross function/class/interface/module/type boundaries.
|
||||
function traverseWithoutCrossingFunction(node: Node, cb: (node: Node) => void) {
|
||||
cb(node);
|
||||
if (!isFunctionLike(node) && !isClassLike(node) && !isInterfaceDeclaration(node) && !isModuleDeclaration(node) && !isTypeAliasDeclaration(node) && !isTypeNode(node)) {
|
||||
forEachChild(node, child => traverseWithoutCrossingFunction(child, cb));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace ts.FindAllReferences {
|
||||
textSpan: TextSpan;
|
||||
}
|
||||
export function nodeEntry(node: Node, isInString?: true): NodeEntry {
|
||||
return { type: "node", node, isInString };
|
||||
return { type: "node", node: (node as NamedDeclaration).name || node, isInString };
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
@@ -40,7 +40,7 @@ namespace ts.FindAllReferences {
|
||||
}
|
||||
|
||||
export function findReferencedSymbols(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, sourceFile: SourceFile, position: number): ReferencedSymbol[] | undefined {
|
||||
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
const node = getTouchingPropertyName(sourceFile, position);
|
||||
const referencedSymbols = Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken);
|
||||
const checker = program.getTypeChecker();
|
||||
return !referencedSymbols || !referencedSymbols.length ? undefined : mapDefined<SymbolAndEntries, ReferencedSymbol>(referencedSymbols, ({ definition, references }) =>
|
||||
@@ -52,8 +52,7 @@ namespace ts.FindAllReferences {
|
||||
}
|
||||
|
||||
export function getImplementationsAtPosition(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, sourceFile: SourceFile, position: number): ImplementationLocation[] | undefined {
|
||||
// A node in a JSDoc comment can't have an implementation anyway.
|
||||
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ false);
|
||||
const node = getTouchingPropertyName(sourceFile, position);
|
||||
const referenceEntries = getImplementationReferenceEntries(program, cancellationToken, sourceFiles, node, position);
|
||||
const checker = program.getTypeChecker();
|
||||
return map(referenceEntries, entry => toImplementationLocation(entry, checker));
|
||||
@@ -85,7 +84,7 @@ namespace ts.FindAllReferences {
|
||||
}
|
||||
|
||||
export function findReferencedEntries(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, sourceFile: SourceFile, position: number, options?: Options): ReferenceEntry[] | undefined {
|
||||
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
const node = getTouchingPropertyName(sourceFile, position);
|
||||
return map(flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options)), toReferenceEntry);
|
||||
}
|
||||
|
||||
@@ -732,7 +731,7 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
function getPossibleSymbolReferenceNodes(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile): ReadonlyArray<Node> {
|
||||
return getPossibleSymbolReferencePositions(sourceFile, symbolName, container).map(pos => getTouchingPropertyName(sourceFile, pos, /*includeJsDocComment*/ true));
|
||||
return getPossibleSymbolReferencePositions(sourceFile, symbolName, container).map(pos => getTouchingPropertyName(sourceFile, pos));
|
||||
}
|
||||
|
||||
function getPossibleSymbolReferencePositions(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile): ReadonlyArray<number> {
|
||||
@@ -836,7 +835,7 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
function getReferencesAtLocation(sourceFile: SourceFile, position: number, search: Search, state: State, addReferencesHere: boolean): void {
|
||||
const referenceLocation = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
const referenceLocation = getTouchingPropertyName(sourceFile, position);
|
||||
|
||||
if (!isValidReferencePosition(referenceLocation, search.text)) {
|
||||
// This wasn't the start of a token. Check to see if it might be a
|
||||
@@ -1096,7 +1095,7 @@ namespace ts.FindAllReferences.Core {
|
||||
function addImplementationReferences(refNode: Node, addReference: (node: Node) => void, state: State): void {
|
||||
// Check if we found a function/propertyAssignment/method with an implementation or initializer
|
||||
if (isDeclarationName(refNode) && isImplementation(refNode.parent)) {
|
||||
addReference(refNode.parent);
|
||||
addReference(refNode);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,68 +1,189 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export function getEditsForFileRename(program: Program, oldFilePath: string, newFilePath: string, host: LanguageServiceHost, formatContext: formatting.FormatContext): ReadonlyArray<FileTextChanges> {
|
||||
const pathUpdater = getPathUpdater(oldFilePath, newFilePath, host);
|
||||
export function getEditsForFileRename(program: Program, oldFileOrDirPath: string, newFileOrDirPath: string, host: LanguageServiceHost, formatContext: formatting.FormatContext, preferences: UserPreferences): ReadonlyArray<FileTextChanges> {
|
||||
const useCaseSensitiveFileNames = hostUsesCaseSensitiveFileNames(host);
|
||||
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
const oldToNew = getPathUpdater(oldFileOrDirPath, newFileOrDirPath, getCanonicalFileName);
|
||||
const newToOld = getPathUpdater(newFileOrDirPath, oldFileOrDirPath, getCanonicalFileName);
|
||||
return textChanges.ChangeTracker.with({ host, formatContext }, changeTracker => {
|
||||
updateTsconfigFiles(program, changeTracker, oldFilePath, newFilePath);
|
||||
for (const { sourceFile, toUpdate } of getImportsToUpdate(program, oldFilePath, host)) {
|
||||
const newPath = pathUpdater(isRef(toUpdate) ? toUpdate.fileName : toUpdate.text);
|
||||
if (newPath !== undefined) {
|
||||
const range = isRef(toUpdate) ? toUpdate : createStringRange(toUpdate, sourceFile);
|
||||
changeTracker.replaceRangeWithText(sourceFile, range, isRef(toUpdate) ? newPath : removeFileExtension(newPath));
|
||||
}
|
||||
}
|
||||
updateTsconfigFiles(program, changeTracker, oldToNew, newFileOrDirPath, host.getCurrentDirectory(), useCaseSensitiveFileNames);
|
||||
updateImports(program, changeTracker, oldToNew, newToOld, host, getCanonicalFileName, preferences);
|
||||
});
|
||||
}
|
||||
|
||||
function updateTsconfigFiles(program: Program, changeTracker: textChanges.ChangeTracker, oldFilePath: string, newFilePath: string): void {
|
||||
const configFile = program.getCompilerOptions().configFile;
|
||||
if (!configFile) return;
|
||||
const oldFile = getTsConfigPropArrayElementValue(configFile, "files", oldFilePath);
|
||||
if (oldFile) {
|
||||
changeTracker.replaceRangeWithText(configFile, createStringRange(oldFile, configFile), newFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
interface ToUpdate {
|
||||
readonly sourceFile: SourceFile;
|
||||
readonly toUpdate: StringLiteralLike | FileReference;
|
||||
}
|
||||
function isRef(toUpdate: StringLiteralLike | FileReference): toUpdate is FileReference {
|
||||
return "fileName" in toUpdate;
|
||||
}
|
||||
|
||||
function getImportsToUpdate(program: Program, oldFilePath: string, host: LanguageServiceHost): ReadonlyArray<ToUpdate> {
|
||||
const result: ToUpdate[] = [];
|
||||
for (const sourceFile of program.getSourceFiles()) {
|
||||
for (const ref of sourceFile.referencedFiles) {
|
||||
if (resolveTripleslashReference(ref.fileName, sourceFile.fileName) === oldFilePath) {
|
||||
result.push({ sourceFile, toUpdate: ref });
|
||||
}
|
||||
}
|
||||
|
||||
for (const importStringLiteral of sourceFile.imports) {
|
||||
const resolved = host.resolveModuleNames
|
||||
? host.getResolvedModuleWithFailedLookupLocationsFromCache && host.getResolvedModuleWithFailedLookupLocationsFromCache(importStringLiteral.text, sourceFile.fileName)
|
||||
: program.getResolvedModuleWithFailedLookupLocationsFromCache(importStringLiteral.text, sourceFile.fileName);
|
||||
// We may or may not have picked up on the file being renamed, so maybe successfully resolved to oldFilePath, or maybe that's in failedLookupLocations
|
||||
if (resolved && contains(resolved.resolvedModule ? [resolved.resolvedModule.resolvedFileName] : resolved.failedLookupLocations, oldFilePath)) {
|
||||
result.push({ sourceFile, toUpdate: importStringLiteral });
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getPathUpdater(oldFilePath: string, newFilePath: string, host: LanguageServiceHost): (oldPath: string) => string | undefined {
|
||||
// Get the relative path from old to new location, and append it on to the end of imports and normalize.
|
||||
const rel = getRelativePathFromFile(oldFilePath, newFilePath, createGetCanonicalFileName(hostUsesCaseSensitiveFileNames(host)));
|
||||
return oldPath => {
|
||||
if (!pathIsRelative(oldPath)) return;
|
||||
return ensurePathIsNonModuleName(normalizePath(combinePaths(getDirectoryPath(oldPath), rel)));
|
||||
/** If 'path' refers to an old directory, returns path in the new directory. */
|
||||
type PathUpdater = (path: string) => string | undefined;
|
||||
function getPathUpdater(oldFileOrDirPath: string, newFileOrDirPath: string, getCanonicalFileName: GetCanonicalFileName): PathUpdater {
|
||||
const canonicalOldPath = getCanonicalFileName(oldFileOrDirPath);
|
||||
return path => {
|
||||
const canonicalPath = getCanonicalFileName(path);
|
||||
if (canonicalPath === canonicalOldPath) return newFileOrDirPath;
|
||||
const suffix = tryRemoveDirectoryPrefix(canonicalPath, canonicalOldPath);
|
||||
return suffix === undefined ? undefined : newFileOrDirPath + "/" + suffix;
|
||||
};
|
||||
}
|
||||
|
||||
function updateTsconfigFiles(program: Program, changeTracker: textChanges.ChangeTracker, oldToNew: PathUpdater, newFileOrDirPath: string, currentDirectory: string, useCaseSensitiveFileNames: boolean): void {
|
||||
const { configFile } = program.getCompilerOptions();
|
||||
if (!configFile) return;
|
||||
const configDir = getDirectoryPath(configFile.fileName);
|
||||
|
||||
const jsonObjectLiteral = getTsConfigObjectLiteralExpression(configFile);
|
||||
if (!jsonObjectLiteral) return;
|
||||
|
||||
forEachProperty(jsonObjectLiteral, (property, propertyName) => {
|
||||
switch (propertyName) {
|
||||
case "files":
|
||||
case "include":
|
||||
case "exclude": {
|
||||
const foundExactMatch = updatePaths(property);
|
||||
if (!foundExactMatch && propertyName === "include" && isArrayLiteralExpression(property.initializer)) {
|
||||
const includes = mapDefined(property.initializer.elements, e => isStringLiteral(e) ? e.text : undefined);
|
||||
const matchers = getFileMatcherPatterns(configDir, /*excludes*/ [], includes, useCaseSensitiveFileNames, currentDirectory);
|
||||
// If there isn't some include for this, add a new one.
|
||||
if (!getRegexFromPattern(Debug.assertDefined(matchers.includeFilePattern), useCaseSensitiveFileNames).test(newFileOrDirPath)) {
|
||||
changeTracker.insertNodeAfter(configFile, last(property.initializer.elements), createStringLiteral(relativePath(newFileOrDirPath)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "compilerOptions":
|
||||
forEachProperty(property.initializer, (property, propertyName) => {
|
||||
const option = getOptionFromName(propertyName);
|
||||
if (option && (option.isFilePath || option.type === "list" && (option as CommandLineOptionOfListType).element.isFilePath)) {
|
||||
updatePaths(property);
|
||||
}
|
||||
else if (propertyName === "paths") {
|
||||
forEachProperty(property.initializer, (pathsProperty) => {
|
||||
if (!isArrayLiteralExpression(pathsProperty.initializer)) return;
|
||||
for (const e of pathsProperty.initializer.elements) {
|
||||
tryUpdateString(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
function updatePaths(property: PropertyAssignment): boolean {
|
||||
// Type annotation needed due to #7294
|
||||
const elements: ReadonlyArray<Expression> = isArrayLiteralExpression(property.initializer) ? property.initializer.elements : [property.initializer];
|
||||
let foundExactMatch = false;
|
||||
for (const element of elements) {
|
||||
foundExactMatch = tryUpdateString(element) || foundExactMatch;
|
||||
}
|
||||
return foundExactMatch;
|
||||
}
|
||||
|
||||
function tryUpdateString(element: Expression): boolean {
|
||||
if (!isStringLiteral(element)) return false;
|
||||
const elementFileName = combinePathsSafe(configDir, element.text);
|
||||
|
||||
const updated = oldToNew(elementFileName);
|
||||
if (updated !== undefined) {
|
||||
changeTracker.replaceRangeWithText(configFile!, createStringRange(element, configFile!), relativePath(updated));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function relativePath(path: string): string {
|
||||
return getRelativePathFromDirectory(configDir, path, /*ignoreCase*/ !useCaseSensitiveFileNames);
|
||||
}
|
||||
}
|
||||
|
||||
function updateImports(
|
||||
program: Program,
|
||||
changeTracker: textChanges.ChangeTracker,
|
||||
oldToNew: PathUpdater,
|
||||
newToOld: PathUpdater,
|
||||
host: LanguageServiceHost,
|
||||
getCanonicalFileName: GetCanonicalFileName,
|
||||
preferences: UserPreferences,
|
||||
): void {
|
||||
for (const sourceFile of program.getSourceFiles()) {
|
||||
const newImportFromPath = oldToNew(sourceFile.fileName) || sourceFile.fileName;
|
||||
const newImportFromDirectory = getDirectoryPath(newImportFromPath);
|
||||
|
||||
const oldFromNew: string | undefined = newToOld(sourceFile.fileName);
|
||||
const oldImportFromPath: string = oldFromNew || sourceFile.fileName;
|
||||
const oldImportFromDirectory = getDirectoryPath(oldImportFromPath);
|
||||
|
||||
updateImportsWorker(sourceFile, changeTracker,
|
||||
referenceText => {
|
||||
if (!pathIsRelative(referenceText)) return undefined;
|
||||
const oldAbsolute = combinePathsSafe(oldImportFromDirectory, referenceText);
|
||||
const newAbsolute = oldToNew(oldAbsolute);
|
||||
return newAbsolute === undefined ? undefined : ensurePathIsNonModuleName(getRelativePathFromDirectory(newImportFromDirectory, newAbsolute, getCanonicalFileName));
|
||||
},
|
||||
importLiteral => {
|
||||
const toImport = oldFromNew !== undefined
|
||||
// If we're at the new location (file was already renamed), need to redo module resolution starting from the old location.
|
||||
// TODO:GH#18217
|
||||
? getSourceFileToImportFromResolved(resolveModuleName(importLiteral.text, oldImportFromPath, program.getCompilerOptions(), host as ModuleResolutionHost), oldToNew, program)
|
||||
: getSourceFileToImport(importLiteral, sourceFile, program, host, oldToNew);
|
||||
return toImport === undefined ? undefined : moduleSpecifiers.getModuleSpecifier(program.getCompilerOptions(), sourceFile, newImportFromPath, toImport, host, preferences);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function combineNormal(pathA: string, pathB: string): string {
|
||||
return normalizePath(combinePaths(pathA, pathB));
|
||||
}
|
||||
function combinePathsSafe(pathA: string, pathB: string): string {
|
||||
return ensurePathIsNonModuleName(combineNormal(pathA, pathB));
|
||||
}
|
||||
|
||||
function getSourceFileToImport(importLiteral: StringLiteralLike, importingSourceFile: SourceFile, program: Program, host: LanguageServiceHost, oldToNew: PathUpdater): string | undefined {
|
||||
const symbol = program.getTypeChecker().getSymbolAtLocation(importLiteral);
|
||||
if (symbol) {
|
||||
if (symbol.declarations.some(d => isAmbientModule(d))) return undefined; // No need to update if it's an ambient module
|
||||
const oldFileName = find(symbol.declarations, isSourceFile)!.fileName;
|
||||
return oldToNew(oldFileName) || oldFileName;
|
||||
}
|
||||
else {
|
||||
const resolved = host.resolveModuleNames
|
||||
? host.getResolvedModuleWithFailedLookupLocationsFromCache && host.getResolvedModuleWithFailedLookupLocationsFromCache(importLiteral.text, importingSourceFile.fileName)
|
||||
: program.getResolvedModuleWithFailedLookupLocationsFromCache(importLiteral.text, importingSourceFile.fileName);
|
||||
return getSourceFileToImportFromResolved(resolved, oldToNew, program);
|
||||
}
|
||||
}
|
||||
|
||||
function getSourceFileToImportFromResolved(resolved: ResolvedModuleWithFailedLookupLocations | undefined, oldToNew: PathUpdater, program: Program): string | undefined {
|
||||
return resolved && (
|
||||
(resolved.resolvedModule && getIfInProgram(resolved.resolvedModule.resolvedFileName)) || firstDefined(resolved.failedLookupLocations, getIfInProgram));
|
||||
|
||||
function getIfInProgram(oldLocation: string): string | undefined {
|
||||
const newLocation = oldToNew(oldLocation);
|
||||
return program.getSourceFile(oldLocation) || newLocation !== undefined && program.getSourceFile(newLocation)
|
||||
? newLocation || oldLocation
|
||||
: undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function updateImportsWorker(sourceFile: SourceFile, changeTracker: textChanges.ChangeTracker, updateRef: (refText: string) => string | undefined, updateImport: (importLiteral: StringLiteralLike) => string | undefined) {
|
||||
for (const ref of sourceFile.referencedFiles) {
|
||||
const updated = updateRef(ref.fileName);
|
||||
if (updated !== undefined && updated !== sourceFile.text.slice(ref.pos, ref.end)) changeTracker.replaceRangeWithText(sourceFile, ref, updated);
|
||||
}
|
||||
|
||||
for (const importStringLiteral of sourceFile.imports) {
|
||||
const updated = updateImport(importStringLiteral);
|
||||
if (updated !== undefined && updated !== importStringLiteral.text) changeTracker.replaceRangeWithText(sourceFile, createStringRange(importStringLiteral, sourceFile), updated);
|
||||
}
|
||||
}
|
||||
|
||||
function createStringRange(node: StringLiteralLike, sourceFile: SourceFileLike): TextRange {
|
||||
return createTextRange(node.getStart(sourceFile) + 1, node.end - 1);
|
||||
}
|
||||
|
||||
function forEachProperty(objectLiteral: Expression, cb: (property: PropertyAssignment, propertyName: string) => void) {
|
||||
if (!isObjectLiteralExpression(objectLiteral)) return;
|
||||
for (const property of objectLiteral.properties) {
|
||||
if (isPropertyAssignment(property) && isStringLiteral(property.name)) {
|
||||
cb(property, property.name.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace ts.GoToDefinition {
|
||||
return [getDefinitionInfoForFileReference(reference.fileName, reference.file.fileName)];
|
||||
}
|
||||
|
||||
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
const node = getTouchingPropertyName(sourceFile, position);
|
||||
if (node === sourceFile) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -32,11 +32,16 @@ namespace ts.GoToDefinition {
|
||||
const sigInfo = createDefinitionFromSignatureDeclaration(typeChecker, calledDeclaration);
|
||||
// For a function, if this is the original function definition, return just sigInfo.
|
||||
// If this is the original constructor definition, parent is the class.
|
||||
return typeChecker.getRootSymbols(symbol).some(s => calledDeclaration.symbol === s || calledDeclaration.symbol.parent === s) ||
|
||||
if (typeChecker.getRootSymbols(symbol).some(s => calledDeclaration.symbol === s || calledDeclaration.symbol.parent === s) ||
|
||||
// TODO: GH#23742 Following check shouldn't be necessary if 'require' is an alias
|
||||
symbol.declarations.some(d => isVariableDeclaration(d) && !!d.initializer && isRequireCall(d.initializer, /*checkArgumentIsStringLiteralLike*/ false))
|
||||
? [sigInfo]
|
||||
: [sigInfo, ...getDefinitionFromSymbol(typeChecker, symbol, node)!];
|
||||
symbol.declarations.some(d => isVariableDeclaration(d) && !!d.initializer && isRequireCall(d.initializer, /*checkArgumentIsStringLiteralLike*/ false))) {
|
||||
return [sigInfo];
|
||||
}
|
||||
else {
|
||||
const defs = getDefinitionFromSymbol(typeChecker, symbol, node)!;
|
||||
// For a 'super()' call, put the signature first, else put the variable first.
|
||||
return node.kind === SyntaxKind.SuperKeyword ? [sigInfo, ...defs] : [...defs, sigInfo];
|
||||
}
|
||||
}
|
||||
|
||||
// Because name in short-hand property assignment has two different meanings: property name and property value,
|
||||
@@ -102,12 +107,18 @@ namespace ts.GoToDefinition {
|
||||
return file && { fileName: typeReferenceDirective.fileName, file };
|
||||
}
|
||||
|
||||
const libReferenceDirective = findReferenceInPosition(sourceFile.libReferenceDirectives, position);
|
||||
if (libReferenceDirective) {
|
||||
const file = program.getLibFileFromReference(libReferenceDirective);
|
||||
return file && { fileName: libReferenceDirective.fileName, file };
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/// Goto type
|
||||
export function getTypeDefinitionAtPosition(typeChecker: TypeChecker, sourceFile: SourceFile, position: number): DefinitionInfo[] | undefined {
|
||||
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
const node = getTouchingPropertyName(sourceFile, position);
|
||||
if (node === sourceFile) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -133,12 +144,15 @@ namespace ts.GoToDefinition {
|
||||
}
|
||||
|
||||
// Check if position is on triple slash reference.
|
||||
const comment = findReferenceInPosition(sourceFile.referencedFiles, position) || findReferenceInPosition(sourceFile.typeReferenceDirectives, position);
|
||||
const comment = findReferenceInPosition(sourceFile.referencedFiles, position) ||
|
||||
findReferenceInPosition(sourceFile.typeReferenceDirectives, position) ||
|
||||
findReferenceInPosition(sourceFile.libReferenceDirectives, position);
|
||||
|
||||
if (comment) {
|
||||
return { definitions, textSpan: createTextSpanFromRange(comment) };
|
||||
}
|
||||
|
||||
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
const node = getTouchingPropertyName(sourceFile, position);
|
||||
const textSpan = createTextSpan(node.getStart(), node.getWidth());
|
||||
|
||||
return { definitions, textSpan };
|
||||
|
||||
@@ -160,7 +160,8 @@ namespace ts.JsTyping {
|
||||
}
|
||||
// Add the cached typing locations for inferred typings that are already installed
|
||||
packageNameToTypingLocation.forEach((typing, name) => {
|
||||
if (inferredTypings.has(name) && inferredTypings.get(name) === undefined && isTypingUpToDate(typing, typesRegistry.get(name)!)) {
|
||||
const registryEntry = typesRegistry.get(name);
|
||||
if (inferredTypings.has(name) && inferredTypings.get(name) === undefined && registryEntry !== undefined && isTypingUpToDate(typing, registryEntry)) {
|
||||
inferredTypings.set(name, typing.typingLocation);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace ts {
|
||||
checkJsDirective: undefined,
|
||||
referencedFiles: [],
|
||||
typeReferenceDirectives: [],
|
||||
libReferenceDirectives: [],
|
||||
amdDependencies: [],
|
||||
hasNoDefaultLib: undefined,
|
||||
moduleName: undefined
|
||||
@@ -336,7 +337,7 @@ namespace ts {
|
||||
importedFiles.push(decl.ref);
|
||||
}
|
||||
}
|
||||
return { referencedFiles: pragmaContext.referencedFiles, typeReferenceDirectives: pragmaContext.typeReferenceDirectives, importedFiles, isLibFile: !!pragmaContext.hasNoDefaultLib, ambientExternalModules: undefined };
|
||||
return { referencedFiles: pragmaContext.referencedFiles, typeReferenceDirectives: pragmaContext.typeReferenceDirectives, libReferenceDirectives: pragmaContext.libReferenceDirectives, importedFiles, isLibFile: !!pragmaContext.hasNoDefaultLib, ambientExternalModules: undefined };
|
||||
}
|
||||
else {
|
||||
// for global scripts ambient modules still can have augmentations - look for ambient modules with depth > 0
|
||||
@@ -354,7 +355,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
return { referencedFiles: pragmaContext.referencedFiles, typeReferenceDirectives: pragmaContext.typeReferenceDirectives, importedFiles, isLibFile: !!pragmaContext.hasNoDefaultLib, ambientExternalModules: ambientModuleNames };
|
||||
return { referencedFiles: pragmaContext.referencedFiles, typeReferenceDirectives: pragmaContext.typeReferenceDirectives, libReferenceDirectives: pragmaContext.libReferenceDirectives, importedFiles, isLibFile: !!pragmaContext.hasNoDefaultLib, ambientExternalModules: ambientModuleNames };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,6 +153,8 @@ namespace ts.refactor {
|
||||
if (sourceFile === oldFile) continue;
|
||||
for (const statement of sourceFile.statements) {
|
||||
forEachImportInStatement(statement, importNode => {
|
||||
if (checker.getSymbolAtLocation(moduleSpecifierFromImport(importNode)) !== oldFile.symbol) return;
|
||||
|
||||
const shouldMove = (name: Identifier): boolean => {
|
||||
const symbol = isBindingElement(name.parent)
|
||||
? getPropertySymbolFromBindingElement(checker, name.parent as BindingElement & { name: Identifier })
|
||||
@@ -163,11 +165,76 @@ namespace ts.refactor {
|
||||
const newModuleSpecifier = combinePaths(getDirectoryPath(moduleSpecifierFromImport(importNode).text), newModuleName);
|
||||
const newImportDeclaration = filterImport(importNode, createLiteral(newModuleSpecifier), shouldMove);
|
||||
if (newImportDeclaration) changes.insertNodeAfter(sourceFile, statement, newImportDeclaration);
|
||||
|
||||
const ns = getNamespaceLikeImport(importNode);
|
||||
if (ns) updateNamespaceLikeImport(changes, sourceFile, checker, movedSymbols, newModuleName, newModuleSpecifier, ns, importNode);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getNamespaceLikeImport(node: SupportedImport): Identifier | undefined {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
return node.importClause && node.importClause.namedBindings && node.importClause.namedBindings.kind === SyntaxKind.NamespaceImport ?
|
||||
node.importClause.namedBindings.name : undefined;
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
return node.name;
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return tryCast(node.name, isIdentifier);
|
||||
default:
|
||||
return Debug.assertNever(node);
|
||||
}
|
||||
}
|
||||
|
||||
function updateNamespaceLikeImport(
|
||||
changes: textChanges.ChangeTracker,
|
||||
sourceFile: SourceFile,
|
||||
checker: TypeChecker,
|
||||
movedSymbols: ReadonlySymbolSet,
|
||||
newModuleName: string,
|
||||
newModuleSpecifier: string,
|
||||
oldImportId: Identifier,
|
||||
oldImportNode: SupportedImport,
|
||||
): void {
|
||||
const preferredNewNamespaceName = codefix.moduleSpecifierToValidIdentifier(newModuleName, ScriptTarget.ESNext);
|
||||
let needUniqueName = false;
|
||||
const toChange: Identifier[] = [];
|
||||
FindAllReferences.Core.eachSymbolReferenceInFile(oldImportId, checker, sourceFile, ref => {
|
||||
if (!isPropertyAccessExpression(ref.parent)) return;
|
||||
needUniqueName = needUniqueName || !!checker.resolveName(preferredNewNamespaceName, ref, SymbolFlags.All, /*excludeGlobals*/ true);
|
||||
if (movedSymbols.has(checker.getSymbolAtLocation(ref.parent.name)!)) {
|
||||
toChange.push(ref);
|
||||
}
|
||||
});
|
||||
|
||||
if (toChange.length) {
|
||||
const newNamespaceName = needUniqueName ? getUniqueName(preferredNewNamespaceName, sourceFile) : preferredNewNamespaceName;
|
||||
for (const ref of toChange) {
|
||||
changes.replaceNode(sourceFile, ref, createIdentifier(newNamespaceName));
|
||||
}
|
||||
changes.insertNodeAfter(sourceFile, oldImportNode, updateNamespaceLikeImportNode(oldImportNode, newModuleName, newModuleSpecifier));
|
||||
}
|
||||
}
|
||||
|
||||
function updateNamespaceLikeImportNode(node: SupportedImport, newNamespaceName: string, newModuleSpecifier: string): Node {
|
||||
const newNamespaceId = createIdentifier(newNamespaceName);
|
||||
const newModuleString = createLiteral(newModuleSpecifier);
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
return createImportDeclaration(
|
||||
/*decorators*/ undefined, /*modifiers*/ undefined,
|
||||
createImportClause(/*name*/ undefined, createNamespaceImport(newNamespaceId)),
|
||||
newModuleString);
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
return createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, newNamespaceId, createExternalModuleReference(newModuleString));
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return createVariableDeclaration(newNamespaceId, /*type*/ undefined, createRequireCall(newModuleString));
|
||||
default:
|
||||
return Debug.assertNever(node);
|
||||
}
|
||||
}
|
||||
|
||||
function moduleSpecifierFromImport(i: SupportedImport): StringLiteralLike {
|
||||
return (i.kind === SyntaxKind.ImportDeclaration ? i.moduleSpecifier
|
||||
: i.kind === SyntaxKind.ImportEqualsDeclaration ? i.moduleReference.expression
|
||||
@@ -404,7 +471,7 @@ namespace ts.refactor {
|
||||
if (isInImport(decl)) {
|
||||
oldImportsNeededByNewFile.add(symbol);
|
||||
}
|
||||
else if (isTopLevelDeclaration(decl) && !movedSymbols.has(symbol)) {
|
||||
else if (isTopLevelDeclaration(decl) && sourceFileOfTopLevelDeclaration(decl) === oldFile && !movedSymbols.has(symbol)) {
|
||||
newFileImportsFromOldFile.add(symbol);
|
||||
}
|
||||
}
|
||||
@@ -546,7 +613,11 @@ namespace ts.refactor {
|
||||
interface TopLevelVariableDeclaration extends VariableDeclaration { parent: VariableDeclarationList & { parent: VariableStatement; }; }
|
||||
type TopLevelDeclaration = NonVariableTopLevelDeclaration | TopLevelVariableDeclaration;
|
||||
function isTopLevelDeclaration(node: Node): node is TopLevelDeclaration {
|
||||
return isNonVariableTopLevelDeclaration(node) || isVariableDeclaration(node) && isSourceFile(node.parent.parent.parent);
|
||||
return isNonVariableTopLevelDeclaration(node) && isSourceFile(node.parent) || isVariableDeclaration(node) && isSourceFile(node.parent.parent.parent);
|
||||
}
|
||||
|
||||
function sourceFileOfTopLevelDeclaration(node: TopLevelDeclaration): Node {
|
||||
return isVariableDeclaration(node) ? node.parent.parent.parent : node.parent;
|
||||
}
|
||||
|
||||
function isTopLevelDeclarationStatement(node: Node): node is TopLevelDeclarationStatement {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
namespace ts.Rename {
|
||||
export function getRenameInfo(typeChecker: TypeChecker, defaultLibFileName: string, getCanonicalFileName: GetCanonicalFileName, sourceFile: SourceFile, position: number): RenameInfo {
|
||||
const getCanonicalDefaultLibName = memoize(() => getCanonicalFileName(normalizePath(defaultLibFileName)));
|
||||
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
const node = getTouchingPropertyName(sourceFile, position);
|
||||
const renameInfo = node && nodeIsEligibleForRename(node)
|
||||
? getRenameInfoForNode(node, typeChecker, sourceFile, isDefinedInLibraryFile)
|
||||
: undefined;
|
||||
|
||||
+18
-10
@@ -552,6 +552,7 @@ namespace ts {
|
||||
public moduleName: string;
|
||||
public referencedFiles: FileReference[];
|
||||
public typeReferenceDirectives: FileReference[];
|
||||
public libReferenceDirectives: FileReference[];
|
||||
|
||||
public syntacticDiagnostics: DiagnosticWithLocation[];
|
||||
public parseDiagnostics: DiagnosticWithLocation[];
|
||||
@@ -1416,7 +1417,7 @@ namespace ts {
|
||||
|
||||
function getSuggestionDiagnostics(fileName: string): DiagnosticWithLocation[] {
|
||||
synchronizeHostData();
|
||||
return computeSuggestionDiagnostics(getValidSourceFile(fileName), program);
|
||||
return computeSuggestionDiagnostics(getValidSourceFile(fileName), program, cancellationToken);
|
||||
}
|
||||
|
||||
function getCompilerOptionsDiagnostics() {
|
||||
@@ -1467,7 +1468,7 @@ namespace ts {
|
||||
synchronizeHostData();
|
||||
|
||||
const sourceFile = getValidSourceFile(fileName);
|
||||
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
const node = getTouchingPropertyName(sourceFile, position);
|
||||
if (node === sourceFile) {
|
||||
// Avoid giving quickInfo for the sourceFile as a whole.
|
||||
return undefined;
|
||||
@@ -1781,15 +1782,11 @@ namespace ts {
|
||||
return syntaxTreeCache.getCurrentSourceFile(fileName);
|
||||
}
|
||||
|
||||
function getSourceFile(fileName: string): SourceFile {
|
||||
return getNonBoundSourceFile(fileName);
|
||||
}
|
||||
|
||||
function getNameOrDottedNameSpan(fileName: string, startPos: number, _endPos: number): TextSpan | undefined {
|
||||
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
||||
|
||||
// Get node at the location
|
||||
const node = getTouchingPropertyName(sourceFile, startPos, /*includeJsDocComment*/ false);
|
||||
const node = getTouchingPropertyName(sourceFile, startPos);
|
||||
|
||||
if (node === sourceFile) {
|
||||
return undefined;
|
||||
@@ -1986,8 +1983,8 @@ namespace ts {
|
||||
return OrganizeImports.organizeImports(sourceFile, formatContext, host, program, preferences);
|
||||
}
|
||||
|
||||
function getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings): ReadonlyArray<FileTextChanges> {
|
||||
return ts.getEditsForFileRename(getProgram()!, oldFilePath, newFilePath, host, formatting.getFormatContext(formatOptions));
|
||||
function getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences = defaultPreferences): ReadonlyArray<FileTextChanges> {
|
||||
return ts.getEditsForFileRename(getProgram()!, oldFilePath, newFilePath, host, formatting.getFormatContext(formatOptions), preferences);
|
||||
}
|
||||
|
||||
function applyCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
|
||||
@@ -2052,6 +2049,17 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
function getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined {
|
||||
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
||||
const token = findPrecedingToken(position, sourceFile);
|
||||
if (!token) return undefined;
|
||||
const element = token.kind === SyntaxKind.GreaterThanToken && isJsxOpeningElement(token.parent) ? token.parent.parent
|
||||
: isJsxText(token) ? token.parent : undefined;
|
||||
if (element && !tagNamesAreEquivalent(element.openingElement.tagName, element.closingElement.tagName)) {
|
||||
return { newText: `</${element.openingElement.tagName.getText(sourceFile)}>` };
|
||||
}
|
||||
}
|
||||
|
||||
function getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined {
|
||||
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
||||
const range = formatting.getRangeOfEnclosingComment(sourceFile, position, onlyMultiLine);
|
||||
@@ -2284,6 +2292,7 @@ namespace ts {
|
||||
getFormattingEditsAfterKeystroke,
|
||||
getDocCommentTemplateAtPosition,
|
||||
isValidBraceCompletionAtPosition,
|
||||
getJsxClosingTagAtPosition,
|
||||
getSpanOfEnclosingComment,
|
||||
getCodeFixesAtPosition,
|
||||
getCombinedCodeFix,
|
||||
@@ -2292,7 +2301,6 @@ namespace ts {
|
||||
getEditsForFileRename,
|
||||
getEmitOutput,
|
||||
getNonBoundSourceFile,
|
||||
getSourceFile,
|
||||
getProgram,
|
||||
getApplicableRefactors,
|
||||
getEditsForRefactor,
|
||||
|
||||
@@ -1104,7 +1104,8 @@ namespace ts {
|
||||
importedFiles: this.convertFileReferences(result.importedFiles),
|
||||
ambientExternalModules: result.ambientExternalModules,
|
||||
isLibFile: result.isLibFile,
|
||||
typeReferenceDirectives: this.convertFileReferences(result.typeReferenceDirectives)
|
||||
typeReferenceDirectives: this.convertFileReferences(result.typeReferenceDirectives),
|
||||
libReferenceDirectives: this.convertFileReferences(result.libReferenceDirectives)
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Program): DiagnosticWithLocation[] {
|
||||
program.getSemanticDiagnostics(sourceFile);
|
||||
const checker = program.getDiagnosticsProducingTypeChecker();
|
||||
export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): DiagnosticWithLocation[] {
|
||||
program.getSemanticDiagnostics(sourceFile, cancellationToken);
|
||||
const diags: DiagnosticWithLocation[] = [];
|
||||
|
||||
if (sourceFile.commonJsModuleIndicator &&
|
||||
@@ -13,39 +12,8 @@ namespace ts {
|
||||
|
||||
const isJsFile = isSourceFileJavaScript(sourceFile);
|
||||
|
||||
function check(node: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
if (isJsFile) {
|
||||
if (node.symbol.members && (node.symbol.members.size > 0)) {
|
||||
diags.push(createDiagnosticForNode(isVariableDeclaration(node.parent) ? node.parent.name : node, Diagnostics.This_constructor_function_may_be_converted_to_a_class_declaration));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isJsFile && codefix.parameterShouldGetTypeFromJSDoc(node)) {
|
||||
diags.push(createDiagnosticForNode(node.name || node, Diagnostics.JSDoc_types_may_be_moved_to_TypeScript_types));
|
||||
}
|
||||
|
||||
node.forEachChild(check);
|
||||
}
|
||||
check(sourceFile);
|
||||
|
||||
if (!isJsFile) {
|
||||
for (const statement of sourceFile.statements) {
|
||||
if (isVariableStatement(statement) &&
|
||||
statement.declarationList.flags & NodeFlags.Const &&
|
||||
statement.declarationList.declarations.length === 1) {
|
||||
const init = statement.declarationList.declarations[0].initializer;
|
||||
if (init && isRequireCall(init, /*checkArgumentIsStringLiteralLike*/ true)) {
|
||||
diags.push(createDiagnosticForNode(init, Diagnostics.require_call_may_be_converted_to_an_import));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (getAllowSyntheticDefaultImports(program.getCompilerOptions())) {
|
||||
for (const moduleSpecifier of sourceFile.imports) {
|
||||
const importNode = importFromModuleSpecifier(moduleSpecifier);
|
||||
@@ -60,7 +28,48 @@ namespace ts {
|
||||
}
|
||||
|
||||
addRange(diags, sourceFile.bindSuggestionDiagnostics);
|
||||
return diags.concat(checker.getSuggestionDiagnostics(sourceFile)).sort((d1, d2) => d1.start - d2.start);
|
||||
addRange(diags, program.getSuggestionDiagnostics(sourceFile, cancellationToken));
|
||||
return diags.sort((d1, d2) => d1.start - d2.start);
|
||||
|
||||
function check(node: Node) {
|
||||
if (isJsFile) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.FunctionExpression:
|
||||
const decl = getDeclarationOfJSInitializer(node);
|
||||
if (decl) {
|
||||
const symbol = decl.symbol;
|
||||
if (symbol && (symbol.exports && symbol.exports.size || symbol.members && symbol.members.size)) {
|
||||
diags.push(createDiagnosticForNode(isVariableDeclaration(node.parent) ? node.parent.name : node, Diagnostics.This_constructor_function_may_be_converted_to_a_class_declaration));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// falls through if no diagnostic was created
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
const symbol = node.symbol;
|
||||
if (symbol.members && (symbol.members.size > 0)) {
|
||||
diags.push(createDiagnosticForNode(isVariableDeclaration(node.parent) ? node.parent.name : node, Diagnostics.This_constructor_function_may_be_converted_to_a_class_declaration));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (isVariableStatement(node) &&
|
||||
node.parent === sourceFile &&
|
||||
node.declarationList.flags & NodeFlags.Const &&
|
||||
node.declarationList.declarations.length === 1) {
|
||||
const init = node.declarationList.declarations[0].initializer;
|
||||
if (init && isRequireCall(init, /*checkArgumentIsStringLiteralLike*/ true)) {
|
||||
diags.push(createDiagnosticForNode(init, Diagnostics.require_call_may_be_converted_to_an_import));
|
||||
}
|
||||
}
|
||||
|
||||
if (codefix.parameterShouldGetTypeFromJSDoc(node)) {
|
||||
diags.push(createDiagnosticForNode(node.name || node, Diagnostics.JSDoc_types_may_be_moved_to_TypeScript_types));
|
||||
}
|
||||
}
|
||||
|
||||
node.forEachChild(check);
|
||||
}
|
||||
}
|
||||
|
||||
// convertToEs6Module only works on top-level, so don't trigger it if commonjs code only appears in nested scopes.
|
||||
|
||||
@@ -496,7 +496,7 @@ namespace ts.textChanges {
|
||||
else if (isStatement(node) || isClassOrTypeElement(node)) {
|
||||
return { suffix: this.newLineCharacter };
|
||||
}
|
||||
else if (isVariableDeclaration(node)) {
|
||||
else if (isVariableDeclaration(node) || isStringLiteral(node)) {
|
||||
return { prefix: ", " };
|
||||
}
|
||||
else if (isPropertyAssignment(node)) {
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
"../compiler/builderState.ts",
|
||||
"../compiler/builder.ts",
|
||||
"../compiler/resolutionCache.ts",
|
||||
"../compiler/moduleSpecifiers.ts",
|
||||
"../compiler/watch.ts",
|
||||
"../compiler/commandLineParser.ts",
|
||||
|
||||
@@ -108,7 +109,6 @@
|
||||
"codefixes/inferFromUsage.ts",
|
||||
"codefixes/fixInvalidImportSyntax.ts",
|
||||
"codefixes/fixStrictClassInitialization.ts",
|
||||
"codefixes/moduleSpecifiers.ts",
|
||||
"codefixes/requireInTs.ts",
|
||||
"codefixes/useDefaultImport.ts",
|
||||
"codefixes/fixAddModuleReferTypeMissingTypeof.ts",
|
||||
|
||||
+12
-7
@@ -151,9 +151,11 @@ namespace ts {
|
||||
return new StringScriptSnapshot(text);
|
||||
}
|
||||
}
|
||||
|
||||
export interface PreProcessedFileInfo {
|
||||
referencedFiles: FileReference[];
|
||||
typeReferenceDirectives: FileReference[];
|
||||
libReferenceDirectives: FileReference[];
|
||||
importedFiles: FileReference[];
|
||||
ambientExternalModules?: string[];
|
||||
isLibFile: boolean;
|
||||
@@ -323,6 +325,11 @@ namespace ts {
|
||||
getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion | undefined;
|
||||
|
||||
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean;
|
||||
/**
|
||||
* This will return a defined result if the position is after the `>` of the opening tag, or somewhere in the text, of a JSXElement with no closing tag.
|
||||
* Editors should call this after `>` is typed.
|
||||
*/
|
||||
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
|
||||
|
||||
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
|
||||
|
||||
@@ -342,7 +349,7 @@ namespace ts {
|
||||
getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined): ApplicableRefactorInfo[];
|
||||
getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string, preferences: UserPreferences | undefined): RefactorEditInfo | undefined;
|
||||
organizeImports(scope: OrganizeImportsScope, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): ReadonlyArray<FileTextChanges>;
|
||||
getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings): ReadonlyArray<FileTextChanges>;
|
||||
getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): ReadonlyArray<FileTextChanges>;
|
||||
|
||||
getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean): EmitOutput;
|
||||
|
||||
@@ -350,15 +357,13 @@ namespace ts {
|
||||
|
||||
/* @internal */ getNonBoundSourceFile(fileName: string): SourceFile;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated Use ts.createSourceFile instead.
|
||||
*/
|
||||
getSourceFile(fileName: string): SourceFile;
|
||||
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export interface JsxClosingTagInfo {
|
||||
readonly newText: string;
|
||||
}
|
||||
|
||||
export interface CombinedCodeFixScope { type: "file"; fileName: string; }
|
||||
|
||||
export type OrganizeImportsScope = CombinedCodeFixScope;
|
||||
|
||||
@@ -648,8 +648,8 @@ namespace ts {
|
||||
* Gets the token whose text has range [start, end) and
|
||||
* position >= start and (position < end or (position === end && token is literal or keyword or identifier))
|
||||
*/
|
||||
export function getTouchingPropertyName(sourceFile: SourceFile, position: number, includeJsDocComment: boolean): Node {
|
||||
return getTouchingToken(sourceFile, position, includeJsDocComment, n => isPropertyNameLiteral(n) || isKeyword(n.kind));
|
||||
export function getTouchingPropertyName(sourceFile: SourceFile, position: number): Node {
|
||||
return getTouchingToken(sourceFile, position, /*includeJsDocComment*/ true, n => isPropertyNameLiteral(n) || isKeyword(n.kind));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1196,6 +1196,7 @@ namespace ts {
|
||||
SyntaxKind.VoidKeyword,
|
||||
SyntaxKind.UndefinedKeyword,
|
||||
SyntaxKind.UniqueKeyword,
|
||||
SyntaxKind.UnknownKeyword,
|
||||
];
|
||||
|
||||
export function isTypeKeyword(kind: SyntaxKind): boolean {
|
||||
|
||||
Reference in New Issue
Block a user