mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
'Move to file' refactor (#53542)
This commit is contained in:
@@ -7600,6 +7600,10 @@
|
||||
"category": "Message",
|
||||
"code": 95177
|
||||
},
|
||||
"Move to file": {
|
||||
"category": "Message",
|
||||
"code": 95178
|
||||
},
|
||||
|
||||
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -151,11 +151,18 @@ function getPreferences(
|
||||
? [ModuleSpecifierEnding.JsExtension, ModuleSpecifierEnding.Index]
|
||||
: [ModuleSpecifierEnding.Index, ModuleSpecifierEnding.JsExtension];
|
||||
}
|
||||
const allowImportingTsExtension = shouldAllowImportingTsExtension(compilerOptions, importingSourceFile.fileName);
|
||||
switch (preferredEnding) {
|
||||
case ModuleSpecifierEnding.JsExtension: return [ModuleSpecifierEnding.JsExtension, ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.Index];
|
||||
case ModuleSpecifierEnding.JsExtension: return allowImportingTsExtension
|
||||
? [ModuleSpecifierEnding.JsExtension, ModuleSpecifierEnding.TsExtension, ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.Index]
|
||||
: [ModuleSpecifierEnding.JsExtension, ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.Index];
|
||||
case ModuleSpecifierEnding.TsExtension: return [ModuleSpecifierEnding.TsExtension, ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.JsExtension, ModuleSpecifierEnding.Index];
|
||||
case ModuleSpecifierEnding.Index: return [ModuleSpecifierEnding.Index, ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.JsExtension];
|
||||
case ModuleSpecifierEnding.Minimal: return [ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.Index, ModuleSpecifierEnding.JsExtension];
|
||||
case ModuleSpecifierEnding.Index: return allowImportingTsExtension
|
||||
? [ModuleSpecifierEnding.Index, ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.TsExtension, ModuleSpecifierEnding.JsExtension]
|
||||
: [ModuleSpecifierEnding.Index, ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.JsExtension];
|
||||
case ModuleSpecifierEnding.Minimal: return allowImportingTsExtension
|
||||
? [ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.Index, ModuleSpecifierEnding.TsExtension, ModuleSpecifierEnding.JsExtension]
|
||||
: [ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.Index, ModuleSpecifierEnding.JsExtension];
|
||||
default: Debug.assertNever(preferredEnding);
|
||||
}
|
||||
},
|
||||
@@ -1046,7 +1053,12 @@ function processEnding(fileName: string, allowedEndings: readonly ModuleSpecifie
|
||||
return fileName;
|
||||
}
|
||||
|
||||
if (fileExtensionIsOneOf(fileName, [Extension.Dmts, Extension.Mts, Extension.Dcts, Extension.Cts])) {
|
||||
const jsPriority = allowedEndings.indexOf(ModuleSpecifierEnding.JsExtension);
|
||||
const tsPriority = allowedEndings.indexOf(ModuleSpecifierEnding.TsExtension);
|
||||
if (fileExtensionIsOneOf(fileName, [Extension.Mts, Extension.Cts]) && tsPriority !== -1 && tsPriority < jsPriority) {
|
||||
return fileName;
|
||||
}
|
||||
else if (fileExtensionIsOneOf(fileName, [Extension.Dmts, Extension.Mts, Extension.Dcts, Extension.Cts])) {
|
||||
return noExtension + getJSExtensionForFile(fileName, options);
|
||||
}
|
||||
else if (!fileExtensionIsOneOf(fileName, [Extension.Dts]) && fileExtensionIsOneOf(fileName, [Extension.Ts]) && stringContains(fileName, ".d.")) {
|
||||
@@ -1072,7 +1084,6 @@ function processEnding(fileName: string, allowedEndings: readonly ModuleSpecifie
|
||||
// know if a .d.ts extension is valid, so use no extension or a .js extension
|
||||
if (isDeclarationFileName(fileName)) {
|
||||
const extensionlessPriority = allowedEndings.findIndex(e => e === ModuleSpecifierEnding.Minimal || e === ModuleSpecifierEnding.Index);
|
||||
const jsPriority = allowedEndings.indexOf(ModuleSpecifierEnding.JsExtension);
|
||||
return extensionlessPriority !== -1 && extensionlessPriority < jsPriority
|
||||
? noExtension
|
||||
: noExtension + getJSExtensionForFile(fileName, options);
|
||||
|
||||
@@ -4239,7 +4239,6 @@ export interface SourceFileLike {
|
||||
getPositionOfLineAndCharacter?(line: number, character: number, allowEdits?: true): number;
|
||||
}
|
||||
|
||||
|
||||
/** @internal */
|
||||
export interface RedirectInfo {
|
||||
/** Source file this redirects to. */
|
||||
|
||||
@@ -795,6 +795,14 @@ export class SessionClient implements LanguageService {
|
||||
return response.body!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
getMoveToRefactoringFileSuggestions(fileName: string, positionOrRange: number | TextRange): { newFileName: string; files: string[]; } {
|
||||
const args = this.createFileLocationOrRangeRequestArgs(positionOrRange, fileName);
|
||||
|
||||
const request = this.processRequest<protocol.GetMoveToRefactoringFileSuggestionsRequest>(protocol.CommandTypes.GetMoveToRefactoringFileSuggestions, args);
|
||||
const response = this.processResponse<protocol.GetMoveToRefactoringFileSuggestions>(request);
|
||||
return { newFileName: response.body?.newFileName, files:response.body?.files }!;
|
||||
}
|
||||
|
||||
getEditsForRefactor(
|
||||
fileName: string,
|
||||
_formatOptions: FormatCodeSettings,
|
||||
@@ -818,7 +826,7 @@ export class SessionClient implements LanguageService {
|
||||
const renameFilename: string | undefined = response.body.renameFilename;
|
||||
let renameLocation: number | undefined;
|
||||
if (renameFilename !== undefined) {
|
||||
renameLocation = this.lineOffsetToPosition(renameFilename, response.body.renameLocation!); // TODO: GH#18217
|
||||
renameLocation = this.lineOffsetToPosition(renameFilename, response.body.renameLocation!);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -3299,7 +3299,6 @@ export class TestState {
|
||||
ts.Debug.fail(`Did not expect a change in ${change.fileName}`);
|
||||
}
|
||||
const oldText = this.tryGetFileContent(change.fileName);
|
||||
ts.Debug.assert(!!change.isNewFile === (oldText === undefined));
|
||||
const newContent = change.isNewFile ? ts.first(change.textChanges).newText : ts.textChanges.applyChanges(oldText!, change.textChanges);
|
||||
this.verifyTextMatches(newContent, /*includeWhitespace*/ true, expectedNewContent);
|
||||
}
|
||||
@@ -3912,6 +3911,18 @@ export class TestState {
|
||||
this.verifyNewContent({ newFileContent: options.newFileContents }, editInfo.edits);
|
||||
}
|
||||
|
||||
public moveToFile(options: FourSlashInterface.MoveToFileOptions): void {
|
||||
assert(this.getRanges().length === 1, "Must have exactly one fourslash range (source enclosed between '[|' and '|]' delimiters) in the source file");
|
||||
const range = this.getRanges()[0];
|
||||
const refactor = ts.find(this.getApplicableRefactors(range, { allowTextChangesInNewFiles: true }, /*triggerReason*/ undefined, /*kind*/ undefined, /*includeInteractiveActions*/ true), r => r.name === "Move to file")!;
|
||||
assert(refactor.actions.length === 1);
|
||||
const action = ts.first(refactor.actions);
|
||||
assert(action.name === "Move to file" && action.description === "Move to file");
|
||||
|
||||
const editInfo = this.languageService.getEditsForRefactor(range.fileName, this.formatCodeSettings, range, refactor.name, action.name, options.preferences || ts.emptyOptions, options.interactiveRefactorArguments)!;
|
||||
this.verifyNewContent({ newFileContent: options.newFileContents }, editInfo.edits);
|
||||
}
|
||||
|
||||
private testNewFileContents(edits: readonly ts.FileTextChanges[], newFileContents: { [fileName: string]: string }, description: string): void {
|
||||
for (const { fileName, textChanges } of edits) {
|
||||
const newContent = newFileContents[fileName];
|
||||
@@ -4217,11 +4228,11 @@ export class TestState {
|
||||
private getApplicableRefactorsAtSelection(triggerReason: ts.RefactorTriggerReason = "implicit", kind?: string, preferences = ts.emptyOptions) {
|
||||
return this.getApplicableRefactorsWorker(this.getSelection(), this.activeFile.fileName, preferences, triggerReason, kind);
|
||||
}
|
||||
private getApplicableRefactors(rangeOrMarker: Range | Marker, preferences = ts.emptyOptions, triggerReason: ts.RefactorTriggerReason = "implicit", kind?: string): readonly ts.ApplicableRefactorInfo[] {
|
||||
return this.getApplicableRefactorsWorker("position" in rangeOrMarker ? rangeOrMarker.position : rangeOrMarker, rangeOrMarker.fileName, preferences, triggerReason, kind); // eslint-disable-line local/no-in-operator
|
||||
private getApplicableRefactors(rangeOrMarker: Range | Marker, preferences = ts.emptyOptions, triggerReason: ts.RefactorTriggerReason = "implicit", kind?: string, includeInteractiveActions?: boolean): readonly ts.ApplicableRefactorInfo[] {
|
||||
return this.getApplicableRefactorsWorker("position" in rangeOrMarker ? rangeOrMarker.position : rangeOrMarker, rangeOrMarker.fileName, preferences, triggerReason, kind, includeInteractiveActions); // eslint-disable-line local/no-in-operator
|
||||
}
|
||||
private getApplicableRefactorsWorker(positionOrRange: number | ts.TextRange, fileName: string, preferences = ts.emptyOptions, triggerReason: ts.RefactorTriggerReason, kind?: string): readonly ts.ApplicableRefactorInfo[] {
|
||||
return this.languageService.getApplicableRefactors(fileName, positionOrRange, preferences, triggerReason, kind) || ts.emptyArray;
|
||||
private getApplicableRefactorsWorker(positionOrRange: number | ts.TextRange, fileName: string, preferences = ts.emptyOptions, triggerReason: ts.RefactorTriggerReason, kind?: string, includeInteractiveActions?: boolean): readonly ts.ApplicableRefactorInfo[] {
|
||||
return this.languageService.getApplicableRefactors(fileName, positionOrRange, preferences, triggerReason, kind, includeInteractiveActions) || ts.emptyArray;
|
||||
}
|
||||
|
||||
public configurePlugin(pluginName: string, configuration: any): void {
|
||||
|
||||
@@ -610,6 +610,10 @@ export class Verify extends VerifyNegatable {
|
||||
this.state.moveToNewFile(options);
|
||||
}
|
||||
|
||||
public moveToFile(options: MoveToFileOptions): void {
|
||||
this.state.moveToFile(options);
|
||||
}
|
||||
|
||||
public noMoveToNewFile(): void {
|
||||
this.state.noMoveToNewFile();
|
||||
}
|
||||
@@ -1896,6 +1900,12 @@ export interface MoveToNewFileOptions {
|
||||
readonly preferences?: ts.UserPreferences;
|
||||
}
|
||||
|
||||
export interface MoveToFileOptions {
|
||||
readonly newFileContents: { readonly [fileName: string]: string };
|
||||
readonly interactiveRefactorArguments: ts.InteractiveRefactorArguments;
|
||||
readonly preferences?: ts.UserPreferences;
|
||||
}
|
||||
|
||||
export type RenameLocationsOptions = readonly RenameLocationOptions[] | {
|
||||
readonly findInStrings?: boolean;
|
||||
readonly findInComments?: boolean;
|
||||
|
||||
@@ -616,6 +616,9 @@ class LanguageServiceShimProxy implements ts.LanguageService {
|
||||
getApplicableRefactors(): ts.ApplicableRefactorInfo[] {
|
||||
throw new Error("Not supported on the shim.");
|
||||
}
|
||||
getMoveToRefactoringFileSuggestions(): { newFileName: string, files: string[] } {
|
||||
throw new Error("Not supported on the shim.");
|
||||
}
|
||||
organizeImports(_args: ts.OrganizeImportsArgs, _formatOptions: ts.FormatCodeSettings): readonly ts.FileTextChanges[] {
|
||||
throw new Error("Not supported on the shim.");
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import type {
|
||||
EndOfLineState,
|
||||
FileExtensionInfo,
|
||||
HighlightSpanKind,
|
||||
InteractiveRefactorArguments,
|
||||
MapLike,
|
||||
OutliningSpanKind,
|
||||
OutputFile,
|
||||
@@ -142,6 +143,7 @@ export const enum CommandTypes {
|
||||
|
||||
GetApplicableRefactors = "getApplicableRefactors",
|
||||
GetEditsForRefactor = "getEditsForRefactor",
|
||||
GetMoveToRefactoringFileSuggestions = "getMoveToRefactoringFileSuggestions",
|
||||
/** @internal */
|
||||
GetEditsForRefactorFull = "getEditsForRefactor-full",
|
||||
|
||||
@@ -606,6 +608,27 @@ export interface GetApplicableRefactorsResponse extends Response {
|
||||
body?: ApplicableRefactorInfo[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Request refactorings at a given position or selection area to move to an existing file.
|
||||
*/
|
||||
export interface GetMoveToRefactoringFileSuggestionsRequest extends Request {
|
||||
command: CommandTypes.GetMoveToRefactoringFileSuggestions;
|
||||
arguments: GetMoveToRefactoringFileSuggestionsRequestArgs;
|
||||
}
|
||||
export type GetMoveToRefactoringFileSuggestionsRequestArgs = FileLocationOrRangeRequestArgs & {
|
||||
kind?: string;
|
||||
};
|
||||
/**
|
||||
* Response is a list of available files.
|
||||
* Each refactoring exposes one or more "Actions"; a user selects one action to invoke a refactoring
|
||||
*/
|
||||
export interface GetMoveToRefactoringFileSuggestions extends Response {
|
||||
body: {
|
||||
newFileName: string;
|
||||
files: string[];
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of one or more available refactoring actions, grouped under a parent refactoring.
|
||||
*/
|
||||
@@ -680,6 +703,8 @@ export type GetEditsForRefactorRequestArgs = FileLocationOrRangeRequestArgs & {
|
||||
refactor: string;
|
||||
/* The 'name' property from the refactoring action */
|
||||
action: string;
|
||||
/* Arguments for interactive action */
|
||||
interactiveRefactorArguments?: InteractiveRefactorArguments;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+17
-4
@@ -881,6 +881,7 @@ const invalidPartialSemanticModeCommands: readonly protocol.CommandTypes[] = [
|
||||
protocol.CommandTypes.ApplyCodeActionCommand,
|
||||
protocol.CommandTypes.GetSupportedCodeFixes,
|
||||
protocol.CommandTypes.GetApplicableRefactors,
|
||||
protocol.CommandTypes.GetMoveToRefactoringFileSuggestions,
|
||||
protocol.CommandTypes.GetEditsForRefactor,
|
||||
protocol.CommandTypes.GetEditsForRefactorFull,
|
||||
protocol.CommandTypes.OrganizeImports,
|
||||
@@ -2687,6 +2688,7 @@ export class Session<TMessage = string> implements EventSender {
|
||||
args.refactor,
|
||||
args.action,
|
||||
this.getPreferences(file),
|
||||
args.interactiveRefactorArguments
|
||||
);
|
||||
|
||||
if (result === undefined) {
|
||||
@@ -2702,11 +2704,19 @@ export class Session<TMessage = string> implements EventSender {
|
||||
const renameScriptInfo = project.getScriptInfoForNormalizedPath(toNormalizedPath(renameFilename))!;
|
||||
mappedRenameLocation = getLocationInNewDocument(getSnapshotText(renameScriptInfo.getSnapshot()), renameFilename, renameLocation, edits);
|
||||
}
|
||||
return { renameLocation: mappedRenameLocation, renameFilename, edits: this.mapTextChangesToCodeEdits(edits) };
|
||||
}
|
||||
else {
|
||||
return result;
|
||||
return {
|
||||
renameLocation: mappedRenameLocation,
|
||||
renameFilename,
|
||||
edits: this.mapTextChangesToCodeEdits(edits)
|
||||
};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private getMoveToRefactoringFileSuggestions(args: protocol.GetMoveToRefactoringFileSuggestionsRequestArgs): { newFileName: string, files: string[] }{
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file)!;
|
||||
return project.getLanguageService().getMoveToRefactoringFileSuggestions(file, this.extractPositionOrRange(args, scriptInfo), this.getPreferences(file));
|
||||
}
|
||||
|
||||
private organizeImports(args: protocol.OrganizeImportsRequestArgs, simplifiedResult: boolean): readonly protocol.FileCodeEdits[] | readonly FileTextChanges[] {
|
||||
@@ -3429,6 +3439,9 @@ export class Session<TMessage = string> implements EventSender {
|
||||
[protocol.CommandTypes.GetEditsForRefactor]: (request: protocol.GetEditsForRefactorRequest) => {
|
||||
return this.requiredResponse(this.getEditsForRefactor(request.arguments, /*simplifiedResult*/ true));
|
||||
},
|
||||
[protocol.CommandTypes.GetMoveToRefactoringFileSuggestions]: (request: protocol.GetMoveToRefactoringFileSuggestionsRequest) => {
|
||||
return this.requiredResponse(this.getMoveToRefactoringFileSuggestions(request.arguments));
|
||||
},
|
||||
[protocol.CommandTypes.GetEditsForRefactorFull]: (request: protocol.GetEditsForRefactorRequest) => {
|
||||
return this.requiredResponse(this.getEditsForRefactor(request.arguments, /*simplifiedResult*/ false));
|
||||
},
|
||||
|
||||
@@ -6,6 +6,7 @@ export * from "../refactors/convertImport";
|
||||
export * from "../refactors/extractType";
|
||||
export * from "../refactors/helpers";
|
||||
export * from "../refactors/moveToNewFile";
|
||||
export * from "../refactors/moveToFile";
|
||||
import * as addOrRemoveBracesToArrowFunction from "./ts.refactor.addOrRemoveBracesToArrowFunction";
|
||||
export { addOrRemoveBracesToArrowFunction };
|
||||
import * as convertArrowFunctionOrFunctionExpression from "./ts.refactor.convertArrowFunctionOrFunctionExpression";
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
ApplicableRefactorInfo,
|
||||
arrayFrom,
|
||||
flatMapIterator,
|
||||
InteractiveRefactorArguments,
|
||||
Refactor,
|
||||
RefactorContext,
|
||||
RefactorEditInfo,
|
||||
@@ -30,7 +31,7 @@ export function getApplicableRefactors(context: RefactorContext, includeInteract
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getEditsForRefactor(context: RefactorContext, refactorName: string, actionName: string): RefactorEditInfo | undefined {
|
||||
export function getEditsForRefactor(context: RefactorContext, refactorName: string, actionName: string, interactiveRefactorArguments?: InteractiveRefactorArguments): RefactorEditInfo | undefined {
|
||||
const refactor = refactors.get(refactorName);
|
||||
return refactor && refactor.getEditsForAction(context, actionName);
|
||||
return refactor && refactor.getEditsForAction(context, actionName, interactiveRefactorArguments);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,135 +1,56 @@
|
||||
import { getModuleSpecifier } from "../../compiler/moduleSpecifiers";
|
||||
import {
|
||||
AnyImportOrRequireStatement,
|
||||
append,
|
||||
ApplicableRefactorInfo,
|
||||
AssignmentDeclarationKind,
|
||||
BinaryExpression,
|
||||
BindingElement,
|
||||
BindingName,
|
||||
CallExpression,
|
||||
canHaveDecorators,
|
||||
canHaveModifiers,
|
||||
canHaveSymbol, cast,
|
||||
ClassDeclaration,
|
||||
codefix,
|
||||
combinePaths,
|
||||
concatenate,
|
||||
contains,
|
||||
copyEntries,
|
||||
createModuleSpecifierResolutionHost,
|
||||
createTextRangeFromSpan,
|
||||
Debug,
|
||||
Declaration,
|
||||
DeclarationStatement,
|
||||
Diagnostics,
|
||||
emptyArray,
|
||||
EnumDeclaration,
|
||||
escapeLeadingUnderscores,
|
||||
Expression,
|
||||
ExpressionStatement,
|
||||
extensionFromPath,
|
||||
ExternalModuleReference,
|
||||
factory,
|
||||
find,
|
||||
FindAllReferences,
|
||||
findIndex,
|
||||
firstDefined,
|
||||
flatMap,
|
||||
forEachEntry,
|
||||
FunctionDeclaration,
|
||||
getAssignmentDeclarationKind,
|
||||
fileShouldUseJavaScriptRequire,
|
||||
getBaseFileName,
|
||||
GetCanonicalFileName,
|
||||
getDecorators,
|
||||
getDirectoryPath,
|
||||
getLocaleSpecificMessage,
|
||||
getModifiers,
|
||||
getPropertySymbolFromBindingElement,
|
||||
getQuotePreference,
|
||||
getRangesWhere,
|
||||
getRefactorContextSpan,
|
||||
getRelativePathFromFile,
|
||||
getSymbolId,
|
||||
getUniqueName,
|
||||
hasSyntacticModifier,
|
||||
hostGetCanonicalFileName,
|
||||
Identifier,
|
||||
ImportDeclaration,
|
||||
ImportEqualsDeclaration,
|
||||
insertImports,
|
||||
InterfaceDeclaration,
|
||||
InternalSymbolName,
|
||||
isArrayLiteralExpression,
|
||||
isBinaryExpression,
|
||||
isBindingElement,
|
||||
isDeclarationName,
|
||||
isExpressionStatement,
|
||||
isExternalModuleReference,
|
||||
isIdentifier,
|
||||
isImportDeclaration,
|
||||
isImportEqualsDeclaration,
|
||||
isNamedDeclaration,
|
||||
isObjectLiteralExpression,
|
||||
isOmittedExpression,
|
||||
isPrologueDirective,
|
||||
isPropertyAccessExpression,
|
||||
isPropertyAssignment,
|
||||
isRequireCall,
|
||||
isSourceFile,
|
||||
isStringLiteral,
|
||||
isStringLiteralLike,
|
||||
isVariableDeclaration,
|
||||
isVariableDeclarationList,
|
||||
isVariableStatement,
|
||||
LanguageServiceHost,
|
||||
last,
|
||||
length,
|
||||
makeImportIfNecessary,
|
||||
makeStringLiteral,
|
||||
mapDefined,
|
||||
ModifierFlags,
|
||||
ModifierLike,
|
||||
ModuleDeclaration,
|
||||
NamedImportBindings,
|
||||
Node,
|
||||
NodeFlags,
|
||||
nodeSeenTracker,
|
||||
normalizePath,
|
||||
ObjectBindingElementWithoutPropertyName,
|
||||
Program,
|
||||
PropertyAccessExpression,
|
||||
PropertyAssignment,
|
||||
QuotePreference,
|
||||
rangeContainsRange,
|
||||
RefactorContext,
|
||||
RefactorEditInfo,
|
||||
RequireOrImportCall,
|
||||
RequireVariableStatement,
|
||||
resolvePath,
|
||||
ScriptTarget,
|
||||
skipAlias,
|
||||
some,
|
||||
SourceFile,
|
||||
Statement,
|
||||
StringLiteralLike,
|
||||
Symbol,
|
||||
SymbolFlags,
|
||||
symbolNameNoDefault,
|
||||
SyntaxKind,
|
||||
takeWhile,
|
||||
textChanges,
|
||||
TransformFlags,
|
||||
tryCast,
|
||||
TypeAliasDeclaration,
|
||||
TypeChecker,
|
||||
TypeNode,
|
||||
UserPreferences,
|
||||
VariableDeclaration,
|
||||
VariableDeclarationList,
|
||||
VariableStatement,
|
||||
} from "../_namespaces/ts";
|
||||
import { registerRefactor } from "../_namespaces/ts.refactor";
|
||||
import {
|
||||
addExports,
|
||||
addExportToChanges,
|
||||
addNewFileToTsconfig,
|
||||
createNewFileName,
|
||||
createOldFileImportsFromTargetFile,
|
||||
deleteMovedStatements,
|
||||
deleteUnusedOldImports,
|
||||
filterImport,
|
||||
forEachImportInStatement,
|
||||
getStatementsToMove,
|
||||
getTopLevelDeclarationStatement,
|
||||
getUsageInfo,
|
||||
isTopLevelDeclaration,
|
||||
makeImportOrRequire,
|
||||
moduleSpecifierFromImport,
|
||||
nameOfTopLevelDeclaration,
|
||||
registerRefactor,
|
||||
SupportedImportStatement,
|
||||
ToMove,
|
||||
updateImportsInOtherFiles,
|
||||
UsageInfo
|
||||
} from "../_namespaces/ts.refactor";
|
||||
|
||||
const refactorName = "Move to a new file";
|
||||
const description = getLocaleSpecificMessage(Diagnostics.Move_to_a_new_file);
|
||||
@@ -156,55 +77,16 @@ registerRefactor(refactorName, {
|
||||
getEditsForAction: function getRefactorEditsToMoveToNewFile(context, actionName): RefactorEditInfo {
|
||||
Debug.assert(actionName === refactorName, "Wrong refactor invoked");
|
||||
const statements = Debug.checkDefined(getStatementsToMove(context));
|
||||
const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, statements, t, context.host, context.preferences));
|
||||
const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, statements, t, context.host, context.preferences, context));
|
||||
return { edits, renameFilename: undefined, renameLocation: undefined };
|
||||
}
|
||||
});
|
||||
|
||||
interface RangeToMove { readonly toMove: readonly Statement[]; readonly afterLast: Statement | undefined; }
|
||||
function getRangeToMove(context: RefactorContext): RangeToMove | undefined {
|
||||
const { file } = context;
|
||||
const range = createTextRangeFromSpan(getRefactorContextSpan(context));
|
||||
const { statements } = file;
|
||||
|
||||
const startNodeIndex = findIndex(statements, s => s.end > range.pos);
|
||||
if (startNodeIndex === -1) return undefined;
|
||||
|
||||
const startStatement = statements[startNodeIndex];
|
||||
if (isNamedDeclaration(startStatement) && startStatement.name && rangeContainsRange(startStatement.name, range)) {
|
||||
return { toMove: [statements[startNodeIndex]], afterLast: statements[startNodeIndex + 1] };
|
||||
}
|
||||
|
||||
// Can't only partially include the start node or be partially into the next node
|
||||
if (range.pos > startStatement.getStart(file)) return undefined;
|
||||
const afterEndNodeIndex = findIndex(statements, s => s.end > range.end, startNodeIndex);
|
||||
// Can't be partially into the next node
|
||||
if (afterEndNodeIndex !== -1 && (afterEndNodeIndex === 0 || statements[afterEndNodeIndex].getStart(file) < range.end)) return undefined;
|
||||
|
||||
return {
|
||||
toMove: statements.slice(startNodeIndex, afterEndNodeIndex === -1 ? statements.length : afterEndNodeIndex),
|
||||
afterLast: afterEndNodeIndex === -1 ? undefined : statements[afterEndNodeIndex],
|
||||
};
|
||||
}
|
||||
|
||||
function doChange(oldFile: SourceFile, program: Program, toMove: ToMove, changes: textChanges.ChangeTracker, host: LanguageServiceHost, preferences: UserPreferences): void {
|
||||
function doChange(oldFile: SourceFile, program: Program, toMove: ToMove, changes: textChanges.ChangeTracker, host: LanguageServiceHost, preferences: UserPreferences, context: RefactorContext): void {
|
||||
const checker = program.getTypeChecker();
|
||||
const usage = getUsageInfo(oldFile, toMove.all, checker);
|
||||
|
||||
const currentDirectory = getDirectoryPath(oldFile.fileName);
|
||||
const extension = extensionFromPath(oldFile.fileName);
|
||||
const newFilename = combinePaths(
|
||||
// new file is always placed in the same directory as the old file
|
||||
currentDirectory,
|
||||
// ensures the filename computed below isn't already taken
|
||||
makeUniqueFilename(
|
||||
// infers a name for the new file from the symbols being moved
|
||||
inferNewFilename(usage.oldFileImportsFromNewFile, usage.movedSymbols),
|
||||
extension,
|
||||
currentDirectory,
|
||||
host))
|
||||
// new file has same extension as old file
|
||||
+ extension;
|
||||
const newFilename = createNewFileName(oldFile, program, context, host);
|
||||
|
||||
// If previous file was global, this is easy.
|
||||
changes.createNewFile(oldFile, newFilename, getNewStatementsAndRemoveFromOldFile(oldFile, usage, changes, toMove, program, host, newFilename, preferences));
|
||||
@@ -212,76 +94,19 @@ function doChange(oldFile: SourceFile, program: Program, toMove: ToMove, changes
|
||||
addNewFileToTsconfig(program, changes, oldFile.fileName, newFilename, hostGetCanonicalFileName(host));
|
||||
}
|
||||
|
||||
interface StatementRange {
|
||||
readonly first: Statement;
|
||||
readonly afterLast: Statement | undefined;
|
||||
}
|
||||
interface ToMove {
|
||||
readonly all: readonly Statement[];
|
||||
readonly ranges: readonly StatementRange[];
|
||||
}
|
||||
|
||||
function getStatementsToMove(context: RefactorContext): ToMove | undefined {
|
||||
const rangeToMove = getRangeToMove(context);
|
||||
if (rangeToMove === undefined) return undefined;
|
||||
const all: Statement[] = [];
|
||||
const ranges: StatementRange[] = [];
|
||||
const { toMove, afterLast } = rangeToMove;
|
||||
getRangesWhere(toMove, isAllowedStatementToMove, (start, afterEndIndex) => {
|
||||
for (let i = start; i < afterEndIndex; i++) all.push(toMove[i]);
|
||||
ranges.push({ first: toMove[start], afterLast });
|
||||
});
|
||||
return all.length === 0 ? undefined : { all, ranges };
|
||||
}
|
||||
|
||||
function isAllowedStatementToMove(statement: Statement): boolean {
|
||||
// Filters imports and prologue directives out of the range of statements to move.
|
||||
// Imports will be copied to the new file anyway, and may still be needed in the old file.
|
||||
// Prologue directives will be copied to the new file and should be left in the old file.
|
||||
return !isPureImport(statement) && !isPrologueDirective(statement);
|
||||
}
|
||||
|
||||
function isPureImport(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
return true;
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
return !hasSyntacticModifier(node, ModifierFlags.Export);
|
||||
case SyntaxKind.VariableStatement:
|
||||
return (node as VariableStatement).declarationList.declarations.every(d => !!d.initializer && isRequireCall(d.initializer, /*requireStringLiteralLikeArgument*/ true));
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function addNewFileToTsconfig(program: Program, changes: textChanges.ChangeTracker, oldFileName: string, newFileNameWithExtension: string, getCanonicalFileName: GetCanonicalFileName): void {
|
||||
const cfg = program.getCompilerOptions().configFile;
|
||||
if (!cfg) return;
|
||||
|
||||
const newFileAbsolutePath = normalizePath(combinePaths(oldFileName, "..", newFileNameWithExtension));
|
||||
const newFilePath = getRelativePathFromFile(cfg.fileName, newFileAbsolutePath, getCanonicalFileName);
|
||||
|
||||
const cfgObject = cfg.statements[0] && tryCast(cfg.statements[0].expression, isObjectLiteralExpression);
|
||||
const filesProp = cfgObject && find(cfgObject.properties, (prop): prop is PropertyAssignment =>
|
||||
isPropertyAssignment(prop) && isStringLiteral(prop.name) && prop.name.text === "files");
|
||||
if (filesProp && isArrayLiteralExpression(filesProp.initializer)) {
|
||||
changes.insertNodeInListAfter(cfg, last(filesProp.initializer.elements), factory.createStringLiteral(newFilePath), filesProp.initializer.elements);
|
||||
}
|
||||
}
|
||||
|
||||
function getNewStatementsAndRemoveFromOldFile(
|
||||
oldFile: SourceFile, usage: UsageInfo, changes: textChanges.ChangeTracker, toMove: ToMove, program: Program, host: LanguageServiceHost, newFilename: string, preferences: UserPreferences,
|
||||
) {
|
||||
const checker = program.getTypeChecker();
|
||||
const prologueDirectives = takeWhile(oldFile.statements, isPrologueDirective);
|
||||
if (oldFile.externalModuleIndicator === undefined && oldFile.commonJsModuleIndicator === undefined && usage.oldImportsNeededByNewFile.size() === 0) {
|
||||
if (oldFile.externalModuleIndicator === undefined && oldFile.commonJsModuleIndicator === undefined && usage.oldImportsNeededByTargetFile.size === 0) {
|
||||
deleteMovedStatements(oldFile, toMove.ranges, changes);
|
||||
return [...prologueDirectives, ...toMove.all];
|
||||
}
|
||||
|
||||
const useEsModuleSyntax = !!oldFile.externalModuleIndicator;
|
||||
const useEsModuleSyntax = !fileShouldUseJavaScriptRequire(newFilename, program, host, !!oldFile.commonJsModuleIndicator);
|
||||
const quotePreference = getQuotePreference(oldFile, preferences);
|
||||
const importsFromNewFile = createOldFileImportsFromNewFile(oldFile, usage.oldFileImportsFromNewFile, newFilename, program, host, useEsModuleSyntax, quotePreference);
|
||||
const importsFromNewFile = createOldFileImportsFromTargetFile(oldFile, usage.oldFileImportsFromTargetFile, newFilename, program, host, useEsModuleSyntax, quotePreference);
|
||||
if (importsFromNewFile) {
|
||||
insertImports(changes, oldFile, importsFromNewFile, /*blankLineBetween*/ true, preferences);
|
||||
}
|
||||
@@ -290,8 +115,8 @@ function getNewStatementsAndRemoveFromOldFile(
|
||||
deleteMovedStatements(oldFile, toMove.ranges, changes);
|
||||
updateImportsInOtherFiles(changes, program, host, oldFile, usage.movedSymbols, newFilename, quotePreference);
|
||||
|
||||
const imports = getNewFileImportsAndAddExportInOldFile(oldFile, usage.oldImportsNeededByNewFile, usage.newFileImportsFromOldFile, changes, checker, program, host, useEsModuleSyntax, quotePreference);
|
||||
const body = addExports(oldFile, toMove.all, usage.oldFileImportsFromNewFile, useEsModuleSyntax);
|
||||
const imports = getNewFileImportsAndAddExportInOldFile(oldFile, usage.oldImportsNeededByTargetFile, usage.targetFileImportsFromOldFile, changes, checker, program, host, useEsModuleSyntax, quotePreference);
|
||||
const body = addExports(oldFile, toMove.all, usage.oldFileImportsFromTargetFile, useEsModuleSyntax);
|
||||
if (imports.length && body.length) {
|
||||
return [
|
||||
...prologueDirectives,
|
||||
@@ -308,295 +133,10 @@ function getNewStatementsAndRemoveFromOldFile(
|
||||
];
|
||||
}
|
||||
|
||||
function deleteMovedStatements(sourceFile: SourceFile, moved: readonly StatementRange[], changes: textChanges.ChangeTracker) {
|
||||
for (const { first, afterLast } of moved) {
|
||||
changes.deleteNodeRangeExcludingEnd(sourceFile, first, afterLast);
|
||||
}
|
||||
}
|
||||
|
||||
function deleteUnusedOldImports(oldFile: SourceFile, toMove: readonly Statement[], changes: textChanges.ChangeTracker, toDelete: ReadonlySymbolSet, checker: TypeChecker) {
|
||||
for (const statement of oldFile.statements) {
|
||||
if (contains(toMove, statement)) continue;
|
||||
forEachImportInStatement(statement, i => deleteUnusedImports(oldFile, i, changes, name => toDelete.has(checker.getSymbolAtLocation(name)!)));
|
||||
}
|
||||
}
|
||||
|
||||
function updateImportsInOtherFiles(
|
||||
changes: textChanges.ChangeTracker, program: Program, host: LanguageServiceHost, oldFile: SourceFile, movedSymbols: ReadonlySymbolSet, newFilename: string, quotePreference: QuotePreference
|
||||
): void {
|
||||
const checker = program.getTypeChecker();
|
||||
for (const sourceFile of program.getSourceFiles()) {
|
||||
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 ObjectBindingElementWithoutPropertyName)
|
||||
: skipAlias(checker.getSymbolAtLocation(name)!, checker); // TODO: GH#18217
|
||||
return !!symbol && movedSymbols.has(symbol);
|
||||
};
|
||||
deleteUnusedImports(sourceFile, importNode, changes, shouldMove); // These will be changed to imports from the new file
|
||||
|
||||
const pathToNewFileWithExtension = resolvePath(getDirectoryPath(oldFile.path), newFilename);
|
||||
const newModuleSpecifier = getModuleSpecifier(program.getCompilerOptions(), sourceFile, sourceFile.path, pathToNewFileWithExtension, createModuleSpecifierResolutionHost(program, host));
|
||||
const newImportDeclaration = filterImport(importNode, makeStringLiteral(newModuleSpecifier, quotePreference), shouldMove);
|
||||
if (newImportDeclaration) changes.insertNodeAfter(sourceFile, statement, newImportDeclaration);
|
||||
|
||||
const ns = getNamespaceLikeImport(importNode);
|
||||
if (ns) updateNamespaceLikeImport(changes, sourceFile, checker, movedSymbols, newModuleSpecifier, ns, importNode, quotePreference);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, `Unexpected node kind ${(node as SupportedImport).kind}`);
|
||||
}
|
||||
}
|
||||
|
||||
function updateNamespaceLikeImport(
|
||||
changes: textChanges.ChangeTracker,
|
||||
sourceFile: SourceFile,
|
||||
checker: TypeChecker,
|
||||
movedSymbols: ReadonlySymbolSet,
|
||||
newModuleSpecifier: string,
|
||||
oldImportId: Identifier,
|
||||
oldImportNode: SupportedImport,
|
||||
quotePreference: QuotePreference
|
||||
): void {
|
||||
const preferredNewNamespaceName = codefix.moduleSpecifierToValidIdentifier(newModuleSpecifier, 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, factory.createIdentifier(newNamespaceName));
|
||||
}
|
||||
changes.insertNodeAfter(sourceFile, oldImportNode, updateNamespaceLikeImportNode(oldImportNode, preferredNewNamespaceName, newModuleSpecifier, quotePreference));
|
||||
}
|
||||
}
|
||||
|
||||
function updateNamespaceLikeImportNode(node: SupportedImport, newNamespaceName: string, newModuleSpecifier: string, quotePreference: QuotePreference): Node {
|
||||
const newNamespaceId = factory.createIdentifier(newNamespaceName);
|
||||
const newModuleString = makeStringLiteral(newModuleSpecifier, quotePreference);
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
return factory.createImportDeclaration(
|
||||
/*modifiers*/ undefined,
|
||||
factory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, factory.createNamespaceImport(newNamespaceId)),
|
||||
newModuleString,
|
||||
/*assertClause*/ undefined);
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
return factory.createImportEqualsDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, newNamespaceId, factory.createExternalModuleReference(newModuleString));
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return factory.createVariableDeclaration(newNamespaceId, /*exclamationToken*/ undefined, /*type*/ undefined, createRequireCall(newModuleString));
|
||||
default:
|
||||
return Debug.assertNever(node, `Unexpected node kind ${(node as SupportedImport).kind}`);
|
||||
}
|
||||
}
|
||||
|
||||
function moduleSpecifierFromImport(i: SupportedImport): StringLiteralLike {
|
||||
return (i.kind === SyntaxKind.ImportDeclaration ? i.moduleSpecifier
|
||||
: i.kind === SyntaxKind.ImportEqualsDeclaration ? i.moduleReference.expression
|
||||
: i.initializer.arguments[0]);
|
||||
}
|
||||
|
||||
function forEachImportInStatement(statement: Statement, cb: (importNode: SupportedImport) => void): void {
|
||||
if (isImportDeclaration(statement)) {
|
||||
if (isStringLiteral(statement.moduleSpecifier)) cb(statement as SupportedImport);
|
||||
}
|
||||
else if (isImportEqualsDeclaration(statement)) {
|
||||
if (isExternalModuleReference(statement.moduleReference) && isStringLiteralLike(statement.moduleReference.expression)) {
|
||||
cb(statement as SupportedImport);
|
||||
}
|
||||
}
|
||||
else if (isVariableStatement(statement)) {
|
||||
for (const decl of statement.declarationList.declarations) {
|
||||
if (decl.initializer && isRequireCall(decl.initializer, /*requireStringLiteralLikeArgument*/ true)) {
|
||||
cb(decl as SupportedImport);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type SupportedImport =
|
||||
| ImportDeclaration & { moduleSpecifier: StringLiteralLike }
|
||||
| ImportEqualsDeclaration & { moduleReference: ExternalModuleReference & { expression: StringLiteralLike } }
|
||||
| VariableDeclaration & { initializer: RequireOrImportCall };
|
||||
type SupportedImportStatement =
|
||||
| ImportDeclaration
|
||||
| ImportEqualsDeclaration
|
||||
| VariableStatement;
|
||||
|
||||
function createOldFileImportsFromNewFile(
|
||||
sourceFile: SourceFile,
|
||||
newFileNeedExport: ReadonlySymbolSet,
|
||||
newFileNameWithExtension: string,
|
||||
program: Program,
|
||||
host: LanguageServiceHost,
|
||||
useEs6Imports: boolean,
|
||||
quotePreference: QuotePreference
|
||||
): AnyImportOrRequireStatement | undefined {
|
||||
let defaultImport: Identifier | undefined;
|
||||
const imports: string[] = [];
|
||||
newFileNeedExport.forEach(symbol => {
|
||||
if (symbol.escapedName === InternalSymbolName.Default) {
|
||||
defaultImport = factory.createIdentifier(symbolNameNoDefault(symbol)!); // TODO: GH#18217
|
||||
}
|
||||
else {
|
||||
imports.push(symbol.name);
|
||||
}
|
||||
});
|
||||
return makeImportOrRequire(sourceFile, defaultImport, imports, newFileNameWithExtension, program, host, useEs6Imports, quotePreference);
|
||||
}
|
||||
|
||||
function makeImportOrRequire(
|
||||
sourceFile: SourceFile,
|
||||
defaultImport: Identifier | undefined,
|
||||
imports: readonly string[],
|
||||
newFileNameWithExtension: string,
|
||||
program: Program,
|
||||
host: LanguageServiceHost,
|
||||
useEs6Imports: boolean,
|
||||
quotePreference: QuotePreference
|
||||
): AnyImportOrRequireStatement | undefined {
|
||||
const pathToNewFile = resolvePath(getDirectoryPath(sourceFile.path), newFileNameWithExtension);
|
||||
const pathToNewFileWithCorrectExtension = getModuleSpecifier(program.getCompilerOptions(), sourceFile, sourceFile.path, pathToNewFile, createModuleSpecifierResolutionHost(program, host));
|
||||
|
||||
if (useEs6Imports) {
|
||||
const specifiers = imports.map(i => factory.createImportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, factory.createIdentifier(i)));
|
||||
return makeImportIfNecessary(defaultImport, specifiers, pathToNewFileWithCorrectExtension, quotePreference);
|
||||
}
|
||||
else {
|
||||
Debug.assert(!defaultImport, "No default import should exist"); // If there's a default export, it should have been an es6 module.
|
||||
const bindingElements = imports.map(i => factory.createBindingElement(/*dotDotDotToken*/ undefined, /*propertyName*/ undefined, i));
|
||||
return bindingElements.length
|
||||
? makeVariableStatement(factory.createObjectBindingPattern(bindingElements), /*type*/ undefined, createRequireCall(makeStringLiteral(pathToNewFileWithCorrectExtension, quotePreference))) as RequireVariableStatement
|
||||
: undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function makeVariableStatement(name: BindingName, type: TypeNode | undefined, initializer: Expression | undefined, flags: NodeFlags = NodeFlags.Const) {
|
||||
return factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, type, initializer)], flags));
|
||||
}
|
||||
|
||||
function createRequireCall(moduleSpecifier: StringLiteralLike): CallExpression {
|
||||
return factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, [moduleSpecifier]);
|
||||
}
|
||||
|
||||
function addExports(sourceFile: SourceFile, toMove: readonly Statement[], needExport: ReadonlySymbolSet, useEs6Exports: boolean): readonly Statement[] {
|
||||
return flatMap(toMove, statement => {
|
||||
if (isTopLevelDeclarationStatement(statement) &&
|
||||
!isExported(sourceFile, statement, useEs6Exports) &&
|
||||
forEachTopLevelDeclaration(statement, d => needExport.has(Debug.checkDefined(tryCast(d, canHaveSymbol)?.symbol)))) {
|
||||
const exports = addExport(statement, useEs6Exports);
|
||||
if (exports) return exports;
|
||||
}
|
||||
return statement;
|
||||
});
|
||||
}
|
||||
|
||||
function deleteUnusedImports(sourceFile: SourceFile, importDecl: SupportedImport, changes: textChanges.ChangeTracker, isUnused: (name: Identifier) => boolean): void {
|
||||
switch (importDecl.kind) {
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
deleteUnusedImportsInDeclaration(sourceFile, importDecl, changes, isUnused);
|
||||
break;
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
if (isUnused(importDecl.name)) {
|
||||
changes.delete(sourceFile, importDecl);
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
deleteUnusedImportsInVariableDeclaration(sourceFile, importDecl, changes, isUnused);
|
||||
break;
|
||||
default:
|
||||
Debug.assertNever(importDecl, `Unexpected import decl kind ${(importDecl as SupportedImport).kind}`);
|
||||
}
|
||||
}
|
||||
function deleteUnusedImportsInDeclaration(sourceFile: SourceFile, importDecl: ImportDeclaration, changes: textChanges.ChangeTracker, isUnused: (name: Identifier) => boolean): void {
|
||||
if (!importDecl.importClause) return;
|
||||
const { name, namedBindings } = importDecl.importClause;
|
||||
const defaultUnused = !name || isUnused(name);
|
||||
const namedBindingsUnused = !namedBindings ||
|
||||
(namedBindings.kind === SyntaxKind.NamespaceImport ? isUnused(namedBindings.name) : namedBindings.elements.length !== 0 && namedBindings.elements.every(e => isUnused(e.name)));
|
||||
if (defaultUnused && namedBindingsUnused) {
|
||||
changes.delete(sourceFile, importDecl);
|
||||
}
|
||||
else {
|
||||
if (name && defaultUnused) {
|
||||
changes.delete(sourceFile, name);
|
||||
}
|
||||
if (namedBindings) {
|
||||
if (namedBindingsUnused) {
|
||||
changes.replaceNode(
|
||||
sourceFile,
|
||||
importDecl.importClause,
|
||||
factory.updateImportClause(importDecl.importClause, importDecl.importClause.isTypeOnly, name, /*namedBindings*/ undefined)
|
||||
);
|
||||
}
|
||||
else if (namedBindings.kind === SyntaxKind.NamedImports) {
|
||||
for (const element of namedBindings.elements) {
|
||||
if (isUnused(element.name)) changes.delete(sourceFile, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function deleteUnusedImportsInVariableDeclaration(sourceFile: SourceFile, varDecl: VariableDeclaration, changes: textChanges.ChangeTracker, isUnused: (name: Identifier) => boolean) {
|
||||
const { name } = varDecl;
|
||||
switch (name.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
if (isUnused(name)) {
|
||||
if (varDecl.initializer && isRequireCall(varDecl.initializer, /*requireStringLiteralLikeArgument*/ true)) {
|
||||
changes.delete(sourceFile,
|
||||
isVariableDeclarationList(varDecl.parent) && length(varDecl.parent.declarations) === 1 ? varDecl.parent.parent : varDecl);
|
||||
}
|
||||
else {
|
||||
changes.delete(sourceFile, name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.ArrayBindingPattern:
|
||||
break;
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
if (name.elements.every(e => isIdentifier(e.name) && isUnused(e.name))) {
|
||||
changes.delete(sourceFile,
|
||||
isVariableDeclarationList(varDecl.parent) && varDecl.parent.declarations.length === 1 ? varDecl.parent.parent : varDecl);
|
||||
}
|
||||
else {
|
||||
for (const element of name.elements) {
|
||||
if (isIdentifier(element.name) && isUnused(element.name)) {
|
||||
changes.delete(sourceFile, element.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function getNewFileImportsAndAddExportInOldFile(
|
||||
oldFile: SourceFile,
|
||||
importsToCopy: ReadonlySymbolSet,
|
||||
newFileImportsFromOldFile: ReadonlySymbolSet,
|
||||
importsToCopy: Map<Symbol, boolean>,
|
||||
newFileImportsFromOldFile: Set<Symbol>,
|
||||
changes: textChanges.ChangeTracker,
|
||||
checker: TypeChecker,
|
||||
program: Program,
|
||||
@@ -640,379 +180,3 @@ function getNewFileImportsAndAddExportInOldFile(
|
||||
append(copiedOldImports, makeImportOrRequire(oldFile, oldFileDefault, oldFileNamedImports, getBaseFileName(oldFile.fileName), program, host, useEsModuleSyntax, quotePreference));
|
||||
return copiedOldImports;
|
||||
}
|
||||
|
||||
function makeUniqueFilename(proposedFilename: string, extension: string, inDirectory: string, host: LanguageServiceHost): string {
|
||||
let newFilename = proposedFilename;
|
||||
for (let i = 1; ; i++) {
|
||||
const name = combinePaths(inDirectory, newFilename + extension);
|
||||
if (!host.fileExists(name)) return newFilename;
|
||||
newFilename = `${proposedFilename}.${i}`;
|
||||
}
|
||||
}
|
||||
|
||||
function inferNewFilename(importsFromNewFile: ReadonlySymbolSet, movedSymbols: ReadonlySymbolSet): string {
|
||||
return importsFromNewFile.forEachEntry(symbolNameNoDefault) || movedSymbols.forEachEntry(symbolNameNoDefault) || "newFile";
|
||||
}
|
||||
|
||||
interface UsageInfo {
|
||||
// Symbols whose declarations are moved from the old file to the new file.
|
||||
readonly movedSymbols: ReadonlySymbolSet;
|
||||
|
||||
// Symbols declared in the old file that must be imported by the new file. (May not already be exported.)
|
||||
readonly newFileImportsFromOldFile: ReadonlySymbolSet;
|
||||
// Subset of movedSymbols that are still used elsewhere in the old file and must be imported back.
|
||||
readonly oldFileImportsFromNewFile: ReadonlySymbolSet;
|
||||
|
||||
readonly oldImportsNeededByNewFile: ReadonlySymbolSet;
|
||||
// Subset of oldImportsNeededByNewFile that are will no longer be used in the old file.
|
||||
readonly unusedImportsFromOldFile: ReadonlySymbolSet;
|
||||
}
|
||||
function getUsageInfo(oldFile: SourceFile, toMove: readonly Statement[], checker: TypeChecker): UsageInfo {
|
||||
const movedSymbols = new SymbolSet();
|
||||
const oldImportsNeededByNewFile = new SymbolSet();
|
||||
const newFileImportsFromOldFile = new SymbolSet();
|
||||
|
||||
const containsJsx = find(toMove, statement => !!(statement.transformFlags & TransformFlags.ContainsJsx));
|
||||
const jsxNamespaceSymbol = getJsxNamespaceSymbol(containsJsx);
|
||||
if (jsxNamespaceSymbol) { // Might not exist (e.g. in non-compiling code)
|
||||
oldImportsNeededByNewFile.add(jsxNamespaceSymbol);
|
||||
}
|
||||
|
||||
for (const statement of toMove) {
|
||||
forEachTopLevelDeclaration(statement, decl => {
|
||||
movedSymbols.add(Debug.checkDefined(isExpressionStatement(decl) ? checker.getSymbolAtLocation(decl.expression.left) : decl.symbol, "Need a symbol here"));
|
||||
});
|
||||
}
|
||||
for (const statement of toMove) {
|
||||
forEachReference(statement, checker, symbol => {
|
||||
if (!symbol.declarations) return;
|
||||
for (const decl of symbol.declarations) {
|
||||
if (isInImport(decl)) {
|
||||
oldImportsNeededByNewFile.add(symbol);
|
||||
}
|
||||
else if (isTopLevelDeclaration(decl) && sourceFileOfTopLevelDeclaration(decl) === oldFile && !movedSymbols.has(symbol)) {
|
||||
newFileImportsFromOldFile.add(symbol);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const unusedImportsFromOldFile = oldImportsNeededByNewFile.clone();
|
||||
|
||||
const oldFileImportsFromNewFile = new SymbolSet();
|
||||
for (const statement of oldFile.statements) {
|
||||
if (contains(toMove, statement)) continue;
|
||||
|
||||
// jsxNamespaceSymbol will only be set iff it is in oldImportsNeededByNewFile.
|
||||
if (jsxNamespaceSymbol && !!(statement.transformFlags & TransformFlags.ContainsJsx)) {
|
||||
unusedImportsFromOldFile.delete(jsxNamespaceSymbol);
|
||||
}
|
||||
|
||||
forEachReference(statement, checker, symbol => {
|
||||
if (movedSymbols.has(symbol)) oldFileImportsFromNewFile.add(symbol);
|
||||
unusedImportsFromOldFile.delete(symbol);
|
||||
});
|
||||
}
|
||||
|
||||
return { movedSymbols, newFileImportsFromOldFile, oldFileImportsFromNewFile, oldImportsNeededByNewFile, unusedImportsFromOldFile };
|
||||
|
||||
function getJsxNamespaceSymbol(containsJsx: Node | undefined) {
|
||||
if (containsJsx === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const jsxNamespace = checker.getJsxNamespace(containsJsx);
|
||||
|
||||
// Strictly speaking, this could resolve to a symbol other than the JSX namespace.
|
||||
// This will produce erroneous output (probably, an incorrectly copied import) but
|
||||
// is expected to be very rare and easily reversible.
|
||||
const jsxNamespaceSymbol = checker.resolveName(jsxNamespace, containsJsx, SymbolFlags.Namespace, /*excludeGlobals*/ true);
|
||||
|
||||
return !!jsxNamespaceSymbol && some(jsxNamespaceSymbol.declarations, isInImport)
|
||||
? jsxNamespaceSymbol
|
||||
: undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Below should all be utilities
|
||||
|
||||
function isInImport(decl: Declaration) {
|
||||
switch (decl.kind) {
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
case SyntaxKind.ImportClause:
|
||||
case SyntaxKind.NamespaceImport:
|
||||
return true;
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return isVariableDeclarationInImport(decl as VariableDeclaration);
|
||||
case SyntaxKind.BindingElement:
|
||||
return isVariableDeclaration(decl.parent.parent) && isVariableDeclarationInImport(decl.parent.parent);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function isVariableDeclarationInImport(decl: VariableDeclaration) {
|
||||
return isSourceFile(decl.parent.parent.parent) &&
|
||||
!!decl.initializer && isRequireCall(decl.initializer, /*requireStringLiteralLikeArgument*/ true);
|
||||
}
|
||||
|
||||
function filterImport(i: SupportedImport, moduleSpecifier: StringLiteralLike, keep: (name: Identifier) => boolean): SupportedImportStatement | undefined {
|
||||
switch (i.kind) {
|
||||
case SyntaxKind.ImportDeclaration: {
|
||||
const clause = i.importClause;
|
||||
if (!clause) return undefined;
|
||||
const defaultImport = clause.name && keep(clause.name) ? clause.name : undefined;
|
||||
const namedBindings = clause.namedBindings && filterNamedBindings(clause.namedBindings, keep);
|
||||
return defaultImport || namedBindings
|
||||
? factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(clause.isTypeOnly, defaultImport, namedBindings), moduleSpecifier, /*assertClause*/ undefined)
|
||||
: undefined;
|
||||
}
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
return keep(i.name) ? i : undefined;
|
||||
case SyntaxKind.VariableDeclaration: {
|
||||
const name = filterBindingName(i.name, keep);
|
||||
return name ? makeVariableStatement(name, i.type, createRequireCall(moduleSpecifier), i.parent.flags) : undefined;
|
||||
}
|
||||
default:
|
||||
return Debug.assertNever(i, `Unexpected import kind ${(i as SupportedImport).kind}`);
|
||||
}
|
||||
}
|
||||
function filterNamedBindings(namedBindings: NamedImportBindings, keep: (name: Identifier) => boolean): NamedImportBindings | undefined {
|
||||
if (namedBindings.kind === SyntaxKind.NamespaceImport) {
|
||||
return keep(namedBindings.name) ? namedBindings : undefined;
|
||||
}
|
||||
else {
|
||||
const newElements = namedBindings.elements.filter(e => keep(e.name));
|
||||
return newElements.length ? factory.createNamedImports(newElements) : undefined;
|
||||
}
|
||||
}
|
||||
function filterBindingName(name: BindingName, keep: (name: Identifier) => boolean): BindingName | undefined {
|
||||
switch (name.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
return keep(name) ? name : undefined;
|
||||
case SyntaxKind.ArrayBindingPattern:
|
||||
return name;
|
||||
case SyntaxKind.ObjectBindingPattern: {
|
||||
// We can't handle nested destructurings or property names well here, so just copy them all.
|
||||
const newElements = name.elements.filter(prop => prop.propertyName || !isIdentifier(prop.name) || keep(prop.name));
|
||||
return newElements.length ? factory.createObjectBindingPattern(newElements) : undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function forEachReference(node: Node, checker: TypeChecker, onReference: (s: Symbol) => void) {
|
||||
node.forEachChild(function cb(node) {
|
||||
if (isIdentifier(node) && !isDeclarationName(node)) {
|
||||
const sym = checker.getSymbolAtLocation(node);
|
||||
if (sym) onReference(sym);
|
||||
}
|
||||
else {
|
||||
node.forEachChild(cb);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
interface ReadonlySymbolSet {
|
||||
size(): number;
|
||||
has(symbol: Symbol): boolean;
|
||||
forEach(cb: (symbol: Symbol) => void): void;
|
||||
forEachEntry<T>(cb: (symbol: Symbol) => T | undefined): T | undefined;
|
||||
}
|
||||
|
||||
class SymbolSet implements ReadonlySymbolSet {
|
||||
private map = new Map<string, Symbol>();
|
||||
add(symbol: Symbol): void {
|
||||
this.map.set(String(getSymbolId(symbol)), symbol);
|
||||
}
|
||||
has(symbol: Symbol): boolean {
|
||||
return this.map.has(String(getSymbolId(symbol)));
|
||||
}
|
||||
delete(symbol: Symbol): void {
|
||||
this.map.delete(String(getSymbolId(symbol)));
|
||||
}
|
||||
forEach(cb: (symbol: Symbol) => void): void {
|
||||
this.map.forEach(cb);
|
||||
}
|
||||
forEachEntry<T>(cb: (symbol: Symbol) => T | undefined): T | undefined {
|
||||
return forEachEntry(this.map, cb);
|
||||
}
|
||||
clone(): SymbolSet {
|
||||
const clone = new SymbolSet();
|
||||
copyEntries(this.map, clone.map);
|
||||
return clone;
|
||||
}
|
||||
size() {
|
||||
return this.map.size;
|
||||
}
|
||||
}
|
||||
|
||||
type TopLevelExpressionStatement = ExpressionStatement & { expression: BinaryExpression & { left: PropertyAccessExpression } }; // 'exports.x = ...'
|
||||
type NonVariableTopLevelDeclaration =
|
||||
| FunctionDeclaration
|
||||
| ClassDeclaration
|
||||
| EnumDeclaration
|
||||
| TypeAliasDeclaration
|
||||
| InterfaceDeclaration
|
||||
| ModuleDeclaration
|
||||
| TopLevelExpressionStatement
|
||||
| ImportEqualsDeclaration;
|
||||
type TopLevelDeclarationStatement = NonVariableTopLevelDeclaration | VariableStatement;
|
||||
interface TopLevelVariableDeclaration extends VariableDeclaration { parent: VariableDeclarationList & { parent: VariableStatement; }; }
|
||||
type TopLevelDeclaration = NonVariableTopLevelDeclaration | TopLevelVariableDeclaration | BindingElement;
|
||||
function isTopLevelDeclaration(node: Node): node is TopLevelDeclaration {
|
||||
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 {
|
||||
Debug.assert(isSourceFile(node.parent), "Node parent should be a SourceFile");
|
||||
return isNonVariableTopLevelDeclaration(node) || isVariableStatement(node);
|
||||
}
|
||||
|
||||
function isNonVariableTopLevelDeclaration(node: Node): node is NonVariableTopLevelDeclaration {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function forEachTopLevelDeclaration<T>(statement: Statement, cb: (node: TopLevelDeclaration) => T): T | undefined {
|
||||
switch (statement.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
return cb(statement as FunctionDeclaration | ClassDeclaration | EnumDeclaration | ModuleDeclaration | TypeAliasDeclaration | InterfaceDeclaration | ImportEqualsDeclaration);
|
||||
|
||||
case SyntaxKind.VariableStatement:
|
||||
return firstDefined((statement as VariableStatement).declarationList.declarations, decl => forEachTopLevelDeclarationInBindingName(decl.name, cb));
|
||||
|
||||
case SyntaxKind.ExpressionStatement: {
|
||||
const { expression } = statement as ExpressionStatement;
|
||||
return isBinaryExpression(expression) && getAssignmentDeclarationKind(expression) === AssignmentDeclarationKind.ExportsProperty
|
||||
? cb(statement as TopLevelExpressionStatement)
|
||||
: undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
function forEachTopLevelDeclarationInBindingName<T>(name: BindingName, cb: (node: TopLevelDeclaration) => T): T | undefined {
|
||||
switch (name.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
return cb(cast(name.parent, (x): x is TopLevelVariableDeclaration | BindingElement => isVariableDeclaration(x) || isBindingElement(x)));
|
||||
case SyntaxKind.ArrayBindingPattern:
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
return firstDefined(name.elements, em => isOmittedExpression(em) ? undefined : forEachTopLevelDeclarationInBindingName(em.name, cb));
|
||||
default:
|
||||
return Debug.assertNever(name, `Unexpected name kind ${(name as BindingName).kind}`);
|
||||
}
|
||||
}
|
||||
|
||||
function nameOfTopLevelDeclaration(d: TopLevelDeclaration): Identifier | undefined {
|
||||
return isExpressionStatement(d) ? tryCast(d.expression.left.name, isIdentifier) : tryCast(d.name, isIdentifier);
|
||||
}
|
||||
|
||||
function getTopLevelDeclarationStatement(d: TopLevelDeclaration): TopLevelDeclarationStatement {
|
||||
switch (d.kind) {
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return d.parent.parent;
|
||||
case SyntaxKind.BindingElement:
|
||||
return getTopLevelDeclarationStatement(
|
||||
cast(d.parent.parent, (p): p is TopLevelVariableDeclaration | BindingElement => isVariableDeclaration(p) || isBindingElement(p)));
|
||||
default:
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
function addExportToChanges(sourceFile: SourceFile, decl: TopLevelDeclarationStatement, name: Identifier, changes: textChanges.ChangeTracker, useEs6Exports: boolean): void {
|
||||
if (isExported(sourceFile, decl, useEs6Exports, name)) return;
|
||||
if (useEs6Exports) {
|
||||
if (!isExpressionStatement(decl)) changes.insertExportModifier(sourceFile, decl);
|
||||
}
|
||||
else {
|
||||
const names = getNamesToExportInCommonJS(decl);
|
||||
if (names.length !== 0) changes.insertNodesAfter(sourceFile, decl, names.map(createExportAssignment));
|
||||
}
|
||||
}
|
||||
|
||||
function isExported(sourceFile: SourceFile, decl: TopLevelDeclarationStatement, useEs6Exports: boolean, name?: Identifier): boolean {
|
||||
if (useEs6Exports) {
|
||||
return !isExpressionStatement(decl) && hasSyntacticModifier(decl, ModifierFlags.Export) || !!(name && sourceFile.symbol.exports?.has(name.escapedText));
|
||||
}
|
||||
return !!sourceFile.symbol && !!sourceFile.symbol.exports &&
|
||||
getNamesToExportInCommonJS(decl).some(name => sourceFile.symbol.exports!.has(escapeLeadingUnderscores(name)));
|
||||
}
|
||||
|
||||
function addExport(decl: TopLevelDeclarationStatement, useEs6Exports: boolean): readonly Statement[] | undefined {
|
||||
return useEs6Exports ? [addEs6Export(decl)] : addCommonjsExport(decl);
|
||||
}
|
||||
function addEs6Export(d: TopLevelDeclarationStatement): TopLevelDeclarationStatement {
|
||||
const modifiers = canHaveModifiers(d) ? concatenate([factory.createModifier(SyntaxKind.ExportKeyword)], getModifiers(d)) : undefined;
|
||||
switch (d.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
return factory.updateFunctionDeclaration(d, modifiers, d.asteriskToken, d.name, d.typeParameters, d.parameters, d.type, d.body);
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
const decorators = canHaveDecorators(d) ? getDecorators(d) : undefined;
|
||||
return factory.updateClassDeclaration(d, concatenate<ModifierLike>(decorators, modifiers), d.name, d.typeParameters, d.heritageClauses, d.members);
|
||||
case SyntaxKind.VariableStatement:
|
||||
return factory.updateVariableStatement(d, modifiers, d.declarationList);
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
return factory.updateModuleDeclaration(d, modifiers, d.name, d.body);
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
return factory.updateEnumDeclaration(d, modifiers, d.name, d.members);
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
return factory.updateTypeAliasDeclaration(d, modifiers, d.name, d.typeParameters, d.type);
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
return factory.updateInterfaceDeclaration(d, modifiers, d.name, d.typeParameters, d.heritageClauses, d.members);
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
return factory.updateImportEqualsDeclaration(d, modifiers, d.isTypeOnly, d.name, d.moduleReference);
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
return Debug.fail(); // Shouldn't try to add 'export' keyword to `exports.x = ...`
|
||||
default:
|
||||
return Debug.assertNever(d, `Unexpected declaration kind ${(d as DeclarationStatement).kind}`);
|
||||
}
|
||||
}
|
||||
function addCommonjsExport(decl: TopLevelDeclarationStatement): readonly Statement[] | undefined {
|
||||
return [decl, ...getNamesToExportInCommonJS(decl).map(createExportAssignment)];
|
||||
}
|
||||
function getNamesToExportInCommonJS(decl: TopLevelDeclarationStatement): readonly string[] {
|
||||
switch (decl.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
return [decl.name!.text]; // TODO: GH#18217
|
||||
case SyntaxKind.VariableStatement:
|
||||
return mapDefined(decl.declarationList.declarations, d => isIdentifier(d.name) ? d.name.text : undefined);
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
return emptyArray;
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
return Debug.fail("Can't export an ExpressionStatement"); // Shouldn't try to add 'export' keyword to `exports.x = ...`
|
||||
default:
|
||||
return Debug.assertNever(decl, `Unexpected decl kind ${(decl as TopLevelDeclarationStatement).kind}`);
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates `exports.x = x;` */
|
||||
function createExportAssignment(name: string): Statement {
|
||||
return factory.createExpressionStatement(
|
||||
factory.createBinaryExpression(
|
||||
factory.createPropertyAccessExpression(factory.createIdentifier("exports"), factory.createIdentifier(name)),
|
||||
SyntaxKind.EqualsToken,
|
||||
factory.createIdentifier(name)));
|
||||
}
|
||||
|
||||
@@ -65,6 +65,8 @@ import {
|
||||
EntityName,
|
||||
equateValues,
|
||||
ExportDeclaration,
|
||||
Extension,
|
||||
extensionFromPath,
|
||||
FileReference,
|
||||
FileTextChanges,
|
||||
filter,
|
||||
@@ -86,6 +88,7 @@ import {
|
||||
getAdjustedRenameLocation,
|
||||
getAllSuperTypeNodes,
|
||||
getAssignmentDeclarationKind,
|
||||
getBaseFileName,
|
||||
GetCompletionsAtPositionOptions,
|
||||
getContainerNode,
|
||||
getDefaultLibFileName,
|
||||
@@ -135,6 +138,7 @@ import {
|
||||
InlayHints,
|
||||
InlayHintsContext,
|
||||
insertSorted,
|
||||
InteractiveRefactorArguments,
|
||||
InterfaceType,
|
||||
IntersectionType,
|
||||
isArray,
|
||||
@@ -277,6 +281,7 @@ import {
|
||||
SourceFile,
|
||||
SourceFileLike,
|
||||
SourceMapSource,
|
||||
startsWith,
|
||||
Statement,
|
||||
stringContains,
|
||||
StringLiteral,
|
||||
@@ -320,6 +325,7 @@ import {
|
||||
} from "./_namespaces/ts";
|
||||
import * as NavigateTo from "./_namespaces/ts.NavigateTo";
|
||||
import * as NavigationBar from "./_namespaces/ts.NavigationBar";
|
||||
import { createNewFileName } from "./_namespaces/ts.refactor";
|
||||
import * as classifier from "./classifier";
|
||||
import * as classifier2020 from "./classifier2020";
|
||||
|
||||
@@ -2990,6 +2996,19 @@ export function createLanguageService(
|
||||
return refactor.getApplicableRefactors(getRefactorContext(file, positionOrRange, preferences, emptyOptions, triggerReason, kind), includeInteractiveActions);
|
||||
}
|
||||
|
||||
function getMoveToRefactoringFileSuggestions(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences = emptyOptions): { newFileName: string, files: string[] } {
|
||||
synchronizeHostData();
|
||||
const sourceFile = getValidSourceFile(fileName);
|
||||
const allFiles = Debug.checkDefined(program.getSourceFiles());
|
||||
const extension = extensionFromPath(fileName);
|
||||
const files = mapDefined(allFiles, file => !program?.isSourceFileFromExternalLibrary(sourceFile) &&
|
||||
!(sourceFile === getValidSourceFile(file.fileName) || extension === Extension.Ts && extensionFromPath(file.fileName) === Extension.Dts || extension === Extension.Dts && startsWith(getBaseFileName(file.fileName), "lib.") && extensionFromPath(file.fileName) === Extension.Dts)
|
||||
&& extension === extensionFromPath(file.fileName) ? file.fileName : undefined);
|
||||
|
||||
const newFileName = createNewFileName(sourceFile, program, getRefactorContext(sourceFile, positionOrRange, preferences, emptyOptions), host);
|
||||
return { newFileName, files };
|
||||
}
|
||||
|
||||
function getEditsForRefactor(
|
||||
fileName: string,
|
||||
formatOptions: FormatCodeSettings,
|
||||
@@ -2997,10 +3016,11 @@ export function createLanguageService(
|
||||
refactorName: string,
|
||||
actionName: string,
|
||||
preferences: UserPreferences = emptyOptions,
|
||||
interactiveRefactorArguments?: InteractiveRefactorArguments,
|
||||
): RefactorEditInfo | undefined {
|
||||
synchronizeHostData();
|
||||
const file = getValidSourceFile(fileName);
|
||||
return refactor.getEditsForRefactor(getRefactorContext(file, positionOrRange, preferences, formatOptions), refactorName, actionName);
|
||||
return refactor.getEditsForRefactor(getRefactorContext(file, positionOrRange, preferences, formatOptions), refactorName, actionName, interactiveRefactorArguments);
|
||||
}
|
||||
|
||||
function toLineColumnOffset(fileName: string, position: number): LineAndCharacter {
|
||||
@@ -3097,6 +3117,7 @@ export function createLanguageService(
|
||||
updateIsDefinitionOfReferencedSymbols,
|
||||
getApplicableRefactors,
|
||||
getEditsForRefactor,
|
||||
getMoveToRefactoringFileSuggestions,
|
||||
toLineColumnOffset,
|
||||
getSourceMapper: () => sourceMapper,
|
||||
clearSourceMapperCache: () => sourceMapper.clearCache(),
|
||||
|
||||
+24
-14
@@ -10,6 +10,7 @@ import {
|
||||
concatenate,
|
||||
ConstructorDeclaration,
|
||||
contains,
|
||||
createMultiMap,
|
||||
createNodeFactory,
|
||||
createPrinter,
|
||||
createRange,
|
||||
@@ -116,6 +117,7 @@ import {
|
||||
mapDefined,
|
||||
MethodSignature,
|
||||
Modifier,
|
||||
MultiMap,
|
||||
NamedImportBindings,
|
||||
NamedImports,
|
||||
NamespaceImport,
|
||||
@@ -337,6 +339,11 @@ interface ChangeText extends BaseChange {
|
||||
readonly text: string;
|
||||
}
|
||||
|
||||
interface NewFileInsertion {
|
||||
readonly oldFile?: SourceFile;
|
||||
readonly statements: readonly (Statement | SyntaxKind.NewLineTrivia)[];
|
||||
}
|
||||
|
||||
function getAdjustedRange(sourceFile: SourceFile, startNode: Node, endNode: Node, options: ConfigurableStartEnd): TextRange {
|
||||
return { pos: getAdjustedStartPosition(sourceFile, startNode, options), end: getAdjustedEndPosition(sourceFile, endNode, options) };
|
||||
}
|
||||
@@ -480,7 +487,7 @@ export function isThisTypeAnnotatable(containingFunction: SignatureDeclaration):
|
||||
/** @internal */
|
||||
export class ChangeTracker {
|
||||
private readonly changes: Change[] = [];
|
||||
private readonly newFiles: { readonly oldFile: SourceFile | undefined, readonly fileName: string, readonly statements: readonly (Statement | SyntaxKind.NewLineTrivia)[] }[] = [];
|
||||
private newFileChanges?: MultiMap<string, NewFileInsertion> ;
|
||||
private readonly classesWithNodesInsertedAtStart = new Map<number, { readonly node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression, readonly sourceFile: SourceFile }>(); // Set<ClassDeclaration> implemented as Map<node id, ClassDeclaration>
|
||||
private readonly deletedNodes: { readonly sourceFile: SourceFile, readonly node: Node | NodeArray<TypeParameterDeclaration> }[] = [];
|
||||
|
||||
@@ -622,6 +629,13 @@ export class ChangeTracker {
|
||||
}
|
||||
}
|
||||
|
||||
private insertStatementsInNewFile(fileName: string, statements: readonly (Statement | SyntaxKind.NewLineTrivia)[], oldFile?: SourceFile): void {
|
||||
if (!this.newFileChanges) {
|
||||
this.newFileChanges = createMultiMap<string, NewFileInsertion>();
|
||||
}
|
||||
this.newFileChanges.add(fileName, { oldFile, statements });
|
||||
}
|
||||
|
||||
public insertFirstParameter(sourceFile: SourceFile, parameters: NodeArray<ParameterDeclaration>, newParam: ParameterDeclaration): void {
|
||||
const p0 = firstOrUndefined(parameters);
|
||||
if (p0) {
|
||||
@@ -1128,14 +1142,16 @@ export class ChangeTracker {
|
||||
this.finishDeleteDeclarations();
|
||||
this.finishClassesWithNodesInsertedAtStart();
|
||||
const changes = changesToText.getTextChangesFromChanges(this.changes, this.newLineCharacter, this.formatContext, validate);
|
||||
for (const { oldFile, fileName, statements } of this.newFiles) {
|
||||
changes.push(changesToText.newFileChanges(oldFile, fileName, statements, this.newLineCharacter, this.formatContext));
|
||||
if (this.newFileChanges) {
|
||||
this.newFileChanges.forEach((insertions, fileName) => {
|
||||
changes.push(changesToText.newFileChanges(fileName, insertions, this.newLineCharacter, this.formatContext));
|
||||
});
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
public createNewFile(oldFile: SourceFile | undefined, fileName: string, statements: readonly (Statement | SyntaxKind.NewLineTrivia)[]): void {
|
||||
this.newFiles.push({ oldFile, fileName, statements });
|
||||
this.insertStatementsInNewFile(fileName, statements, oldFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1207,11 +1223,6 @@ function getMembersOrProperties(node: ClassLikeDeclaration | InterfaceDeclaratio
|
||||
/** @internal */
|
||||
export type ValidateNonFormattedText = (node: Node, text: string) => void;
|
||||
|
||||
/** @internal */
|
||||
export function getNewFileText(statements: readonly Statement[], scriptKind: ScriptKind, newLineCharacter: string, formatContext: formatting.FormatContext): string {
|
||||
return changesToText.newFileChangesWorker(/*oldFile*/ undefined, scriptKind, statements, newLineCharacter, formatContext);
|
||||
}
|
||||
|
||||
namespace changesToText {
|
||||
export function getTextChangesFromChanges(changes: readonly Change[], newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): FileTextChanges[] {
|
||||
return mapDefined(group(changes, c => c.sourceFile.path), changesInFile => {
|
||||
@@ -1228,7 +1239,6 @@ namespace changesToText {
|
||||
const textChanges = mapDefined(normalized, c => {
|
||||
const span = createTextSpanFromRange(c.range);
|
||||
const newText = computeNewText(c, sourceFile, newLineCharacter, formatContext, validate);
|
||||
|
||||
// Filter out redundant changes.
|
||||
if (span.length === newText.length && stringContainsAt(sourceFile.text, newText, span.start)) {
|
||||
return undefined;
|
||||
@@ -1241,14 +1251,14 @@ namespace changesToText {
|
||||
});
|
||||
}
|
||||
|
||||
export function newFileChanges(oldFile: SourceFile | undefined, fileName: string, statements: readonly (Statement | SyntaxKind.NewLineTrivia)[], newLineCharacter: string, formatContext: formatting.FormatContext): FileTextChanges {
|
||||
const text = newFileChangesWorker(oldFile, getScriptKindFromFileName(fileName), statements, newLineCharacter, formatContext);
|
||||
export function newFileChanges(fileName: string, insertions: readonly NewFileInsertion[], newLineCharacter: string, formatContext: formatting.FormatContext): FileTextChanges {
|
||||
const text = newFileChangesWorker(getScriptKindFromFileName(fileName), insertions, newLineCharacter, formatContext);
|
||||
return { fileName, textChanges: [createTextChange(createTextSpan(0, 0), text)], isNewFile: true };
|
||||
}
|
||||
|
||||
export function newFileChangesWorker(oldFile: SourceFile | undefined, scriptKind: ScriptKind, statements: readonly (Statement | SyntaxKind.NewLineTrivia)[], newLineCharacter: string, formatContext: formatting.FormatContext): string {
|
||||
export function newFileChangesWorker(scriptKind: ScriptKind, insertions: readonly NewFileInsertion[], newLineCharacter: string, formatContext: formatting.FormatContext): string {
|
||||
// TODO: this emits the file, parses it back, then formats it that -- may be a less roundabout way to do this
|
||||
const nonFormattedText = statements.map(s => s === SyntaxKind.NewLineTrivia ? "" : getNonformattedText(s, oldFile, newLineCharacter).text).join(newLineCharacter);
|
||||
const nonFormattedText = flatMap(insertions, insertion => insertion.statements.map(s => s === SyntaxKind.NewLineTrivia ? "" : getNonformattedText(s, insertion.oldFile, newLineCharacter).text)).join(newLineCharacter);
|
||||
const sourceFile = createSourceFile("any file name", nonFormattedText, ScriptTarget.ESNext, /*setParentNodes*/ true, scriptKind);
|
||||
const changes = formatting.formatDocument(sourceFile, formatContext);
|
||||
return applyChanges(nonFormattedText, changes) + newLineCharacter;
|
||||
|
||||
@@ -652,7 +652,8 @@ export interface LanguageService {
|
||||
* arguments for any interactive action before offering it.
|
||||
*/
|
||||
getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined, triggerReason?: RefactorTriggerReason, kind?: string, includeInteractiveActions?: boolean): ApplicableRefactorInfo[];
|
||||
getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string, preferences: UserPreferences | undefined): RefactorEditInfo | undefined;
|
||||
getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string, preferences: UserPreferences | undefined, includeInteractiveActions?: InteractiveRefactorArguments): RefactorEditInfo | undefined;
|
||||
getMoveToRefactoringFileSuggestions(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined, triggerReason?: RefactorTriggerReason, kind?: string): { newFileName: string, files: string[] };
|
||||
organizeImports(args: OrganizeImportsArgs, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
|
||||
getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
|
||||
|
||||
@@ -1293,6 +1294,10 @@ export interface DocCommentTemplateOptions {
|
||||
readonly generateReturnInDocTemplate?: boolean;
|
||||
}
|
||||
|
||||
export interface InteractiveRefactorArguments {
|
||||
targetFile: string;
|
||||
}
|
||||
|
||||
export interface SignatureHelpParameter {
|
||||
name: string;
|
||||
documentation: SymbolDisplayPart[];
|
||||
@@ -1785,10 +1790,10 @@ export interface Refactor {
|
||||
kinds?: string[];
|
||||
|
||||
/** Compute the associated code actions */
|
||||
getEditsForAction(context: RefactorContext, actionName: string): RefactorEditInfo | undefined;
|
||||
getEditsForAction(context: RefactorContext, actionName: string, interactiveRefactorArguments?: InteractiveRefactorArguments): RefactorEditInfo | undefined;
|
||||
|
||||
/** Compute (quickly) which actions are available here */
|
||||
getAvailableActions(context: RefactorContext, includeInteractive?: boolean): readonly ApplicableRefactorInfo[];
|
||||
getAvailableActions(context: RefactorContext, includeInteractive?: boolean, interactiveRefactorArguments?: InteractiveRefactorArguments): readonly ApplicableRefactorInfo[];
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
||||
@@ -54,6 +54,7 @@ import {
|
||||
ElementAccessExpression,
|
||||
EmitFlags,
|
||||
EmitHint,
|
||||
emitModuleKindIsNonNodeESM,
|
||||
emptyArray,
|
||||
EndOfFileToken,
|
||||
endsWith,
|
||||
@@ -88,8 +89,10 @@ import {
|
||||
getAssignmentDeclarationKind,
|
||||
getCombinedNodeFlagsAlwaysIncludeJSDoc,
|
||||
getDirectoryPath,
|
||||
getEmitModuleKind,
|
||||
getEmitScriptTarget,
|
||||
getExternalModuleImportEqualsDeclarationExpression,
|
||||
getImpliedNodeFormatForFile,
|
||||
getIndentString,
|
||||
getJSDocEnumTag,
|
||||
getLastChild,
|
||||
@@ -108,8 +111,10 @@ import {
|
||||
getTextOfIdentifierOrLiteral,
|
||||
getTextOfNode,
|
||||
getTypesPackageName,
|
||||
hasJSFileExtension,
|
||||
hasSyntacticModifier,
|
||||
HeritageClause,
|
||||
hostGetCanonicalFileName,
|
||||
Identifier,
|
||||
identifierIsThisKeyword,
|
||||
identity,
|
||||
@@ -267,6 +272,7 @@ import {
|
||||
ModifierFlags,
|
||||
ModuleDeclaration,
|
||||
ModuleInstanceState,
|
||||
ModuleKind,
|
||||
ModuleResolutionKind,
|
||||
ModuleSpecifierResolutionHost,
|
||||
moduleSpecifiers,
|
||||
@@ -350,6 +356,7 @@ import {
|
||||
textSpanEnd,
|
||||
Token,
|
||||
tokenToString,
|
||||
toPath,
|
||||
tryCast,
|
||||
Type,
|
||||
TypeChecker,
|
||||
@@ -3137,7 +3144,12 @@ export function getSynthesizedDeepClones<T extends Node>(nodes: NodeArray<T>, in
|
||||
export function getSynthesizedDeepClones<T extends Node>(nodes: NodeArray<T> | undefined, includeTrivia?: boolean): NodeArray<T> | undefined;
|
||||
/** @internal */
|
||||
export function getSynthesizedDeepClones<T extends Node>(nodes: NodeArray<T> | undefined, includeTrivia = true): NodeArray<T> | undefined {
|
||||
return nodes && factory.createNodeArray(nodes.map(n => getSynthesizedDeepClone(n, includeTrivia)), nodes.hasTrailingComma);
|
||||
if (nodes) {
|
||||
const cloned = factory.createNodeArray(nodes.map(n => getSynthesizedDeepClone(n, includeTrivia)), nodes.hasTrailingComma);
|
||||
setTextRange(cloned, nodes);
|
||||
return cloned;
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -4165,3 +4177,45 @@ export function newCaseClauseTracker(checker: TypeChecker, clauses: readonly (Ca
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function fileShouldUseJavaScriptRequire(file: SourceFile | string, program: Program, host: LanguageServiceHost, preferRequire?: boolean) {
|
||||
const fileName = typeof file === "string" ? file : file.fileName;
|
||||
if (!hasJSFileExtension(fileName)) {
|
||||
return false;
|
||||
}
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
const moduleKind = getEmitModuleKind(compilerOptions);
|
||||
const impliedNodeFormat = typeof file === "string"
|
||||
? getImpliedNodeFormatForFile(toPath(file, host.getCurrentDirectory(), hostGetCanonicalFileName(host)), program.getPackageJsonInfoCache?.(), host, compilerOptions)
|
||||
: file.impliedNodeFormat;
|
||||
|
||||
if (impliedNodeFormat === ModuleKind.ESNext) {
|
||||
return false;
|
||||
}
|
||||
if (impliedNodeFormat === ModuleKind.CommonJS) {
|
||||
// Since we're in a JS file, assume the user is writing the JS that will run
|
||||
// (i.e., assume `noEmit`), so a CJS-format file should just have require
|
||||
// syntax, rather than imports that will be downleveled to `require`.
|
||||
return true;
|
||||
}
|
||||
if (compilerOptions.verbatimModuleSyntax && moduleKind === ModuleKind.CommonJS) {
|
||||
// Using ESM syntax under these options would result in an error.
|
||||
return true;
|
||||
}
|
||||
if (compilerOptions.verbatimModuleSyntax && emitModuleKindIsNonNodeESM(moduleKind)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// impliedNodeFormat is undefined and `verbatimModuleSyntax` is off (or in an invalid combo)
|
||||
// Use heuristics from existing code
|
||||
if (typeof file === "object") {
|
||||
if (file.commonJsModuleIndicator) {
|
||||
return true;
|
||||
}
|
||||
if (file.externalModuleIndicator) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return preferRequire;
|
||||
}
|
||||
@@ -199,3 +199,4 @@ import "./unittests/tsserver/versionCache";
|
||||
import "./unittests/tsserver/watchEnvironment";
|
||||
import "./unittests/debugDeprecation";
|
||||
import "./unittests/tsserver/inconsistentErrorInEditor";
|
||||
import "./unittests/tsserver/getMoveToRefactoringFileSuggestions";
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import {
|
||||
baselineTsserverLogs,
|
||||
createLoggerWithInMemoryLogs,
|
||||
createSession,
|
||||
openFilesForSession
|
||||
} from "../helpers/tsserver";
|
||||
import {
|
||||
createServerHost,
|
||||
File
|
||||
} from "../helpers/virtualFileSystemWithWatch";
|
||||
|
||||
describe("unittests:: tsserver:: getMoveToRefactoringFileSuggestions", () => {
|
||||
it("works for suggesting a list of files, excluding node_modules within a project", () => {
|
||||
const file1: File = {
|
||||
path: "/project/a/file1.ts",
|
||||
content: `interface ka {
|
||||
name: string;
|
||||
}
|
||||
`
|
||||
};
|
||||
const file2: File = { path: "/project/b/file2.ts", content: "" };
|
||||
const file3: File = { path: "/project/d/e/file3.ts", content: "" };
|
||||
const file4: File = {
|
||||
path: "/project/a/file4.ts",
|
||||
content: `import { value } from "../node_modules/@types/node/someFile.d.ts";
|
||||
import { value1 } from "../node_modules/.cache/someFile.d.ts";`
|
||||
};
|
||||
const nodeModulesFile1: File = {
|
||||
path: "project/node_modules/@types/node/someFile.d.ts",
|
||||
content: `export const value = 0;`
|
||||
};
|
||||
const nodeModulesFile2: File = {
|
||||
path: "project/node_modules/.cache/someFile.d.ts",
|
||||
content: `export const value1 = 0;`
|
||||
};
|
||||
const tsconfig: File = {
|
||||
path: "/project/tsconfig.json",
|
||||
content: "{}",
|
||||
};
|
||||
const host = createServerHost([file1, file2, file3, file3, file4, nodeModulesFile1, nodeModulesFile2, tsconfig]);
|
||||
const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
openFilesForSession([file1], session);
|
||||
session.executeCommandSeq<ts.server.protocol.GetMoveToRefactoringFileSuggestionsRequest>({
|
||||
command: ts.server.protocol.CommandTypes.GetMoveToRefactoringFileSuggestions,
|
||||
arguments: { file: file1.path, line: 1, offset: 11 }
|
||||
});
|
||||
baselineTsserverLogs("getMoveToRefactoringFileSuggestions", "works for suggesting a list of files, excluding node_modules within a project", session);
|
||||
});
|
||||
it("suggests only .ts file for a .ts filepath", () => {
|
||||
const file1: File = {
|
||||
path: "/file1.ts",
|
||||
content: `interface ka {
|
||||
name: string;
|
||||
}
|
||||
`
|
||||
};
|
||||
const file2: File = { path: "/file2.tsx", content: "" };
|
||||
const file3: File = { path: "/file3.mts", content: "" };
|
||||
const file4: File = { path: "/file4.cts", content: "" };
|
||||
const file5: File = { path: "/file5.js", content: "" };
|
||||
const file6: File = { path: "/file6.d.ts", content: "" };
|
||||
const file7: File = { path: "/file7.ts", content: "" };
|
||||
const tsconfig: File = { path: "/tsconfig.json", content: JSON.stringify({ files: ["./file1.ts", "./file2.tsx", "./file3.mts", "./file4.cts", "./file5.js", "./file6.d.ts", "./file7.ts"] }) };
|
||||
|
||||
const host = createServerHost([file1, file2, file3, file4, file5, file6, file7, tsconfig]);
|
||||
const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
openFilesForSession([file1], session);
|
||||
|
||||
session.executeCommandSeq<ts.server.protocol.GetMoveToRefactoringFileSuggestionsRequest>({
|
||||
command: ts.server.protocol.CommandTypes.GetMoveToRefactoringFileSuggestions,
|
||||
arguments: { file: file1.path, line: 1, offset: 11 }
|
||||
});
|
||||
baselineTsserverLogs("getMoveToRefactoringFileSuggestions", "suggests only .ts file for a .ts filepath", session);
|
||||
});
|
||||
it("suggests only .js file for a .js filepath", () => {
|
||||
const file1: File = {
|
||||
path: "/file1.js",
|
||||
content: `class C {}`
|
||||
};
|
||||
const file2: File = { path: "/file2.js", content: "" };
|
||||
const file3: File = { path: "/file3.mts", content: "" };
|
||||
const file4: File = { path: "/file4.ts", content: "" };
|
||||
const file5: File = { path: "/file5.js", content: "" };
|
||||
const tsconfig: File = { path: "/tsconfig.json", content: JSON.stringify({ files: ["./file1.js", "./file2.js", "./file3.mts", "./file4.ts", "./file5.js"] }) };
|
||||
|
||||
const host = createServerHost([file1, file2, file3, file4, file5, tsconfig]);
|
||||
const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
openFilesForSession([file1], session);
|
||||
|
||||
session.executeCommandSeq<ts.server.protocol.GetMoveToRefactoringFileSuggestionsRequest>({
|
||||
command: ts.server.protocol.CommandTypes.GetMoveToRefactoringFileSuggestions,
|
||||
arguments: { file: file1.path, line: 1, offset: 7 }
|
||||
});
|
||||
baselineTsserverLogs("getMoveToRefactoringFileSuggestions", "suggests only .js file for a .js filepath", session);
|
||||
});
|
||||
it("skips lib.d.ts files", () => {
|
||||
const file1: File = {
|
||||
path: "/file1.d.ts",
|
||||
content: `class C {}`
|
||||
};
|
||||
const file2: File = { path: "/a/lib.d.ts", content: "" };
|
||||
const file3: File = { path: "/a/file3.d.ts", content: "" };
|
||||
const file4: File = { path: "/a/lib.es6.d.ts", content: "" };
|
||||
const tsconfig: File = { path: "/tsconfig.json", content: JSON.stringify({ files: ["./file1.d.ts", "./a/lib.d.ts", "./a/file3.d.ts", "/a/lib.es6.d.ts"] }) };
|
||||
|
||||
const host = createServerHost([file1, file2, file3, file4, tsconfig]);
|
||||
const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
openFilesForSession([file1], session);
|
||||
|
||||
session.executeCommandSeq<ts.server.protocol.GetMoveToRefactoringFileSuggestionsRequest>({
|
||||
command: ts.server.protocol.CommandTypes.GetMoveToRefactoringFileSuggestions,
|
||||
arguments: { file: file1.path, line: 1, offset: 7 }
|
||||
});
|
||||
baselineTsserverLogs("getMoveToRefactoringFileSuggestions", "skips lib.d.ts files", session);
|
||||
});
|
||||
});
|
||||
@@ -94,4 +94,30 @@ describe("unittests:: tsserver:: refactors", () => {
|
||||
});
|
||||
baselineTsserverLogs("refactors", "handles canonicalization of tsconfig path", session);
|
||||
});
|
||||
|
||||
it("handles moving statement to an existing file", () => {
|
||||
const aTs: File = { path: "/Foo/a.ts", content: "const x = 0;" };
|
||||
const bTs: File = {
|
||||
path: "/Foo/b.ts", content: `import {} from "./bar";
|
||||
const a = 1;`};
|
||||
const tsconfig: File = { path: "/Foo/tsconfig.json", content: `{ "files": ["./a.ts", "./b.ts"] }` };
|
||||
const host = createServerHost([aTs, bTs, tsconfig]);
|
||||
const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
openFilesForSession([aTs], session);
|
||||
|
||||
session.executeCommandSeq<ts.server.protocol.GetEditsForRefactorRequest>({
|
||||
command: ts.server.protocol.CommandTypes.GetEditsForRefactor,
|
||||
arguments: {
|
||||
file: aTs.path,
|
||||
startLine: 1,
|
||||
startOffset: 1,
|
||||
endLine: 2,
|
||||
endOffset: aTs.content.length,
|
||||
refactor: "Move to file",
|
||||
action: "Move to file",
|
||||
interactiveRefactorArguments: { targetFile: "/Foo/b.ts" },
|
||||
}
|
||||
});
|
||||
baselineTsserverLogs("refactors", "handles moving statement to an existing file", session);
|
||||
});
|
||||
});
|
||||
|
||||
+31
-1
@@ -155,6 +155,7 @@ declare namespace ts {
|
||||
GetSupportedCodeFixes = "getSupportedCodeFixes",
|
||||
GetApplicableRefactors = "getApplicableRefactors",
|
||||
GetEditsForRefactor = "getEditsForRefactor",
|
||||
GetMoveToRefactoringFileSuggestions = "getMoveToRefactoringFileSuggestions",
|
||||
OrganizeImports = "organizeImports",
|
||||
GetEditsForFileRename = "getEditsForFileRename",
|
||||
ConfigurePlugin = "configurePlugin",
|
||||
@@ -518,6 +519,26 @@ declare namespace ts {
|
||||
interface GetApplicableRefactorsResponse extends Response {
|
||||
body?: ApplicableRefactorInfo[];
|
||||
}
|
||||
/**
|
||||
* Request refactorings at a given position or selection area to move to an existing file.
|
||||
*/
|
||||
interface GetMoveToRefactoringFileSuggestionsRequest extends Request {
|
||||
command: CommandTypes.GetMoveToRefactoringFileSuggestions;
|
||||
arguments: GetMoveToRefactoringFileSuggestionsRequestArgs;
|
||||
}
|
||||
type GetMoveToRefactoringFileSuggestionsRequestArgs = FileLocationOrRangeRequestArgs & {
|
||||
kind?: string;
|
||||
};
|
||||
/**
|
||||
* Response is a list of available files.
|
||||
* Each refactoring exposes one or more "Actions"; a user selects one action to invoke a refactoring
|
||||
*/
|
||||
interface GetMoveToRefactoringFileSuggestions extends Response {
|
||||
body: {
|
||||
newFileName: string;
|
||||
files: string[];
|
||||
};
|
||||
}
|
||||
/**
|
||||
* A set of one or more available refactoring actions, grouped under a parent refactoring.
|
||||
*/
|
||||
@@ -582,6 +603,7 @@ declare namespace ts {
|
||||
type GetEditsForRefactorRequestArgs = FileLocationOrRangeRequestArgs & {
|
||||
refactor: string;
|
||||
action: string;
|
||||
interactiveRefactorArguments?: InteractiveRefactorArguments;
|
||||
};
|
||||
interface GetEditsForRefactorResponse extends Response {
|
||||
body?: RefactorEditInfo;
|
||||
@@ -3987,6 +4009,7 @@ declare namespace ts {
|
||||
private getRange;
|
||||
private getApplicableRefactors;
|
||||
private getEditsForRefactor;
|
||||
private getMoveToRefactoringFileSuggestions;
|
||||
private organizeImports;
|
||||
private getEditsForFileRename;
|
||||
private getCodeFixes;
|
||||
@@ -10149,7 +10172,11 @@ declare namespace ts {
|
||||
* arguments for any interactive action before offering it.
|
||||
*/
|
||||
getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined, triggerReason?: RefactorTriggerReason, kind?: string, includeInteractiveActions?: boolean): ApplicableRefactorInfo[];
|
||||
getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string, preferences: UserPreferences | undefined): RefactorEditInfo | undefined;
|
||||
getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string, preferences: UserPreferences | undefined, includeInteractiveActions?: InteractiveRefactorArguments): RefactorEditInfo | undefined;
|
||||
getMoveToRefactoringFileSuggestions(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined, triggerReason?: RefactorTriggerReason, kind?: string): {
|
||||
newFileName: string;
|
||||
files: string[];
|
||||
};
|
||||
organizeImports(args: OrganizeImportsArgs, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
|
||||
getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
|
||||
getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean, forceDtsEmit?: boolean): EmitOutput;
|
||||
@@ -10657,6 +10684,9 @@ declare namespace ts {
|
||||
interface DocCommentTemplateOptions {
|
||||
readonly generateReturnInDocTemplate?: boolean;
|
||||
}
|
||||
interface InteractiveRefactorArguments {
|
||||
targetFile: string;
|
||||
}
|
||||
interface SignatureHelpParameter {
|
||||
name: string;
|
||||
documentation: SymbolDisplayPart[];
|
||||
|
||||
+8
-1
@@ -6207,7 +6207,11 @@ declare namespace ts {
|
||||
* arguments for any interactive action before offering it.
|
||||
*/
|
||||
getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined, triggerReason?: RefactorTriggerReason, kind?: string, includeInteractiveActions?: boolean): ApplicableRefactorInfo[];
|
||||
getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string, preferences: UserPreferences | undefined): RefactorEditInfo | undefined;
|
||||
getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string, preferences: UserPreferences | undefined, includeInteractiveActions?: InteractiveRefactorArguments): RefactorEditInfo | undefined;
|
||||
getMoveToRefactoringFileSuggestions(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined, triggerReason?: RefactorTriggerReason, kind?: string): {
|
||||
newFileName: string;
|
||||
files: string[];
|
||||
};
|
||||
organizeImports(args: OrganizeImportsArgs, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
|
||||
getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
|
||||
getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean, forceDtsEmit?: boolean): EmitOutput;
|
||||
@@ -6715,6 +6719,9 @@ declare namespace ts {
|
||||
interface DocCommentTemplateOptions {
|
||||
readonly generateReturnInDocTemplate?: boolean;
|
||||
}
|
||||
interface InteractiveRefactorArguments {
|
||||
targetFile: string;
|
||||
}
|
||||
interface SignatureHelpParameter {
|
||||
name: string;
|
||||
documentation: SymbolDisplayPart[];
|
||||
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
currentDirectory:: / useCaseSensitiveFileNames: false
|
||||
Info seq [hh:mm:ss:mss] Provided types map file "/a/lib/typesMap.json" doesn't exist
|
||||
Before request
|
||||
//// [/file1.d.ts]
|
||||
class C {}
|
||||
|
||||
//// [/a/lib.d.ts]
|
||||
|
||||
|
||||
//// [/a/file3.d.ts]
|
||||
|
||||
|
||||
//// [/a/lib.es6.d.ts]
|
||||
|
||||
|
||||
//// [/tsconfig.json]
|
||||
{"files":["./file1.d.ts","./a/lib.d.ts","./a/file3.d.ts","/a/lib.es6.d.ts"]}
|
||||
|
||||
|
||||
Info seq [hh:mm:ss:mss] request:
|
||||
{
|
||||
"command": "open",
|
||||
"arguments": {
|
||||
"file": "/file1.d.ts"
|
||||
},
|
||||
"seq": 1,
|
||||
"type": "request"
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] Search path: /
|
||||
Info seq [hh:mm:ss:mss] For info: /file1.d.ts :: Config file name: /tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file
|
||||
Info seq [hh:mm:ss:mss] Config: /tsconfig.json : {
|
||||
"rootNames": [
|
||||
"/file1.d.ts",
|
||||
"/a/lib.d.ts",
|
||||
"/a/file3.d.ts",
|
||||
"/a/lib.es6.d.ts"
|
||||
],
|
||||
"options": {
|
||||
"configFilePath": "/tsconfig.json"
|
||||
}
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib.d.ts 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/file3.d.ts 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib.es6.d.ts 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /tsconfig.json WatchType: Missing file
|
||||
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
|
||||
Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured)
|
||||
Info seq [hh:mm:ss:mss] Files (4)
|
||||
/file1.d.ts SVC-1-0 "class C {}"
|
||||
/a/lib.d.ts Text-1 ""
|
||||
/a/file3.d.ts Text-1 ""
|
||||
/a/lib.es6.d.ts Text-1 ""
|
||||
|
||||
|
||||
file1.d.ts
|
||||
Part of 'files' list in tsconfig.json
|
||||
a/lib.d.ts
|
||||
Part of 'files' list in tsconfig.json
|
||||
a/file3.d.ts
|
||||
Part of 'files' list in tsconfig.json
|
||||
a/lib.es6.d.ts
|
||||
Part of 'files' list in tsconfig.json
|
||||
|
||||
Info seq [hh:mm:ss:mss] -----------------------------------------------
|
||||
Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured)
|
||||
Info seq [hh:mm:ss:mss] Files (4)
|
||||
|
||||
Info seq [hh:mm:ss:mss] -----------------------------------------------
|
||||
Info seq [hh:mm:ss:mss] Open files:
|
||||
Info seq [hh:mm:ss:mss] FileName: /file1.d.ts ProjectRootPath: undefined
|
||||
Info seq [hh:mm:ss:mss] Projects: /tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] response:
|
||||
{
|
||||
"responseRequired": false
|
||||
}
|
||||
After request
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts: *new*
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
/tsconfig.json: *new*
|
||||
{}
|
||||
/a/lib.d.ts: *new*
|
||||
{}
|
||||
/a/file3.d.ts: *new*
|
||||
{}
|
||||
/a/lib.es6.d.ts: *new*
|
||||
{}
|
||||
|
||||
Before request
|
||||
|
||||
Info seq [hh:mm:ss:mss] request:
|
||||
{
|
||||
"command": "getMoveToRefactoringFileSuggestions",
|
||||
"arguments": {
|
||||
"file": "/file1.d.ts",
|
||||
"line": 1,
|
||||
"offset": 7
|
||||
},
|
||||
"seq": 2,
|
||||
"type": "request"
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] response:
|
||||
{
|
||||
"response": {
|
||||
"newFileName": "/C.d.ts",
|
||||
"files": [
|
||||
"/a/file3.d.ts"
|
||||
]
|
||||
},
|
||||
"responseRequired": true
|
||||
}
|
||||
After request
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
currentDirectory:: / useCaseSensitiveFileNames: false
|
||||
Info seq [hh:mm:ss:mss] Provided types map file "/a/lib/typesMap.json" doesn't exist
|
||||
Before request
|
||||
//// [/file1.js]
|
||||
class C {}
|
||||
|
||||
//// [/file2.js]
|
||||
|
||||
|
||||
//// [/file3.mts]
|
||||
|
||||
|
||||
//// [/file4.ts]
|
||||
|
||||
|
||||
//// [/file5.js]
|
||||
|
||||
|
||||
//// [/tsconfig.json]
|
||||
{"files":["./file1.js","./file2.js","./file3.mts","./file4.ts","./file5.js"]}
|
||||
|
||||
|
||||
Info seq [hh:mm:ss:mss] request:
|
||||
{
|
||||
"command": "open",
|
||||
"arguments": {
|
||||
"file": "/file1.js"
|
||||
},
|
||||
"seq": 1,
|
||||
"type": "request"
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] Search path: /
|
||||
Info seq [hh:mm:ss:mss] For info: /file1.js :: Config file name: /tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file
|
||||
Info seq [hh:mm:ss:mss] Config: /tsconfig.json : {
|
||||
"rootNames": [
|
||||
"/file1.js",
|
||||
"/file2.js",
|
||||
"/file3.mts",
|
||||
"/file4.ts",
|
||||
"/file5.js"
|
||||
],
|
||||
"options": {
|
||||
"configFilePath": "/tsconfig.json"
|
||||
}
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file2.js 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file3.mts 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file4.ts 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file5.js 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /tsconfig.json WatchType: Missing file
|
||||
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
|
||||
Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured)
|
||||
Info seq [hh:mm:ss:mss] Files (5)
|
||||
/file1.js SVC-1-0 "class C {}"
|
||||
/file2.js Text-1 ""
|
||||
/file3.mts Text-1 ""
|
||||
/file4.ts Text-1 ""
|
||||
/file5.js Text-1 ""
|
||||
|
||||
|
||||
file1.js
|
||||
Part of 'files' list in tsconfig.json
|
||||
file2.js
|
||||
Part of 'files' list in tsconfig.json
|
||||
file3.mts
|
||||
Part of 'files' list in tsconfig.json
|
||||
file4.ts
|
||||
Part of 'files' list in tsconfig.json
|
||||
file5.js
|
||||
Part of 'files' list in tsconfig.json
|
||||
|
||||
Info seq [hh:mm:ss:mss] -----------------------------------------------
|
||||
Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured)
|
||||
Info seq [hh:mm:ss:mss] Files (5)
|
||||
|
||||
Info seq [hh:mm:ss:mss] -----------------------------------------------
|
||||
Info seq [hh:mm:ss:mss] Open files:
|
||||
Info seq [hh:mm:ss:mss] FileName: /file1.js ProjectRootPath: undefined
|
||||
Info seq [hh:mm:ss:mss] Projects: /tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] response:
|
||||
{
|
||||
"responseRequired": false
|
||||
}
|
||||
After request
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts: *new*
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
/tsconfig.json: *new*
|
||||
{}
|
||||
/file2.js: *new*
|
||||
{}
|
||||
/file3.mts: *new*
|
||||
{}
|
||||
/file4.ts: *new*
|
||||
{}
|
||||
/file5.js: *new*
|
||||
{}
|
||||
|
||||
Before request
|
||||
|
||||
Info seq [hh:mm:ss:mss] request:
|
||||
{
|
||||
"command": "getMoveToRefactoringFileSuggestions",
|
||||
"arguments": {
|
||||
"file": "/file1.js",
|
||||
"line": 1,
|
||||
"offset": 7
|
||||
},
|
||||
"seq": 2,
|
||||
"type": "request"
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] response:
|
||||
{
|
||||
"response": {
|
||||
"newFileName": "/C.js",
|
||||
"files": [
|
||||
"/file2.js",
|
||||
"/file5.js"
|
||||
]
|
||||
},
|
||||
"responseRequired": true
|
||||
}
|
||||
After request
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
currentDirectory:: / useCaseSensitiveFileNames: false
|
||||
Info seq [hh:mm:ss:mss] Provided types map file "/a/lib/typesMap.json" doesn't exist
|
||||
Before request
|
||||
//// [/file1.ts]
|
||||
interface ka {
|
||||
name: string;
|
||||
}
|
||||
|
||||
|
||||
//// [/file2.tsx]
|
||||
|
||||
|
||||
//// [/file3.mts]
|
||||
|
||||
|
||||
//// [/file4.cts]
|
||||
|
||||
|
||||
//// [/file5.js]
|
||||
|
||||
|
||||
//// [/file6.d.ts]
|
||||
|
||||
|
||||
//// [/file7.ts]
|
||||
|
||||
|
||||
//// [/tsconfig.json]
|
||||
{"files":["./file1.ts","./file2.tsx","./file3.mts","./file4.cts","./file5.js","./file6.d.ts","./file7.ts"]}
|
||||
|
||||
|
||||
Info seq [hh:mm:ss:mss] request:
|
||||
{
|
||||
"command": "open",
|
||||
"arguments": {
|
||||
"file": "/file1.ts"
|
||||
},
|
||||
"seq": 1,
|
||||
"type": "request"
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] Search path: /
|
||||
Info seq [hh:mm:ss:mss] For info: /file1.ts :: Config file name: /tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file
|
||||
Info seq [hh:mm:ss:mss] Config: /tsconfig.json : {
|
||||
"rootNames": [
|
||||
"/file1.ts",
|
||||
"/file2.tsx",
|
||||
"/file3.mts",
|
||||
"/file4.cts",
|
||||
"/file5.js",
|
||||
"/file6.d.ts",
|
||||
"/file7.ts"
|
||||
],
|
||||
"options": {
|
||||
"configFilePath": "/tsconfig.json"
|
||||
}
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file2.tsx 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file3.mts 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file4.cts 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file5.js 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file6.d.ts 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file7.ts 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /tsconfig.json WatchType: Missing file
|
||||
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
|
||||
Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured)
|
||||
Info seq [hh:mm:ss:mss] Files (7)
|
||||
/file1.ts SVC-1-0 "interface ka {\n name: string;\n }\n "
|
||||
/file2.tsx Text-1 ""
|
||||
/file3.mts Text-1 ""
|
||||
/file4.cts Text-1 ""
|
||||
/file5.js Text-1 ""
|
||||
/file6.d.ts Text-1 ""
|
||||
/file7.ts Text-1 ""
|
||||
|
||||
|
||||
file1.ts
|
||||
Part of 'files' list in tsconfig.json
|
||||
file2.tsx
|
||||
Part of 'files' list in tsconfig.json
|
||||
file3.mts
|
||||
Part of 'files' list in tsconfig.json
|
||||
file4.cts
|
||||
Part of 'files' list in tsconfig.json
|
||||
file5.js
|
||||
Part of 'files' list in tsconfig.json
|
||||
file6.d.ts
|
||||
Part of 'files' list in tsconfig.json
|
||||
file7.ts
|
||||
Part of 'files' list in tsconfig.json
|
||||
|
||||
Info seq [hh:mm:ss:mss] -----------------------------------------------
|
||||
Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured)
|
||||
Info seq [hh:mm:ss:mss] Files (7)
|
||||
|
||||
Info seq [hh:mm:ss:mss] -----------------------------------------------
|
||||
Info seq [hh:mm:ss:mss] Open files:
|
||||
Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined
|
||||
Info seq [hh:mm:ss:mss] Projects: /tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] response:
|
||||
{
|
||||
"responseRequired": false
|
||||
}
|
||||
After request
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts: *new*
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
/tsconfig.json: *new*
|
||||
{}
|
||||
/file2.tsx: *new*
|
||||
{}
|
||||
/file3.mts: *new*
|
||||
{}
|
||||
/file4.cts: *new*
|
||||
{}
|
||||
/file5.js: *new*
|
||||
{}
|
||||
/file6.d.ts: *new*
|
||||
{}
|
||||
/file7.ts: *new*
|
||||
{}
|
||||
|
||||
Before request
|
||||
|
||||
Info seq [hh:mm:ss:mss] request:
|
||||
{
|
||||
"command": "getMoveToRefactoringFileSuggestions",
|
||||
"arguments": {
|
||||
"file": "/file1.ts",
|
||||
"line": 1,
|
||||
"offset": 11
|
||||
},
|
||||
"seq": 2,
|
||||
"type": "request"
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] response:
|
||||
{
|
||||
"response": {
|
||||
"newFileName": "/ka.ts",
|
||||
"files": [
|
||||
"/file7.ts"
|
||||
]
|
||||
},
|
||||
"responseRequired": true
|
||||
}
|
||||
After request
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
currentDirectory:: / useCaseSensitiveFileNames: false
|
||||
Info seq [hh:mm:ss:mss] Provided types map file "/a/lib/typesMap.json" doesn't exist
|
||||
Before request
|
||||
//// [/project/a/file1.ts]
|
||||
interface ka {
|
||||
name: string;
|
||||
}
|
||||
|
||||
|
||||
//// [/project/b/file2.ts]
|
||||
|
||||
|
||||
//// [/project/d/e/file3.ts]
|
||||
|
||||
|
||||
//// [/project/a/file4.ts]
|
||||
import { value } from "../node_modules/@types/node/someFile.d.ts";
|
||||
import { value1 } from "../node_modules/.cache/someFile.d.ts";
|
||||
|
||||
//// [/project/node_modules/@types/node/someFile.d.ts]
|
||||
export const value = 0;
|
||||
|
||||
//// [/project/node_modules/.cache/someFile.d.ts]
|
||||
export const value1 = 0;
|
||||
|
||||
//// [/project/tsconfig.json]
|
||||
{}
|
||||
|
||||
|
||||
Info seq [hh:mm:ss:mss] request:
|
||||
{
|
||||
"command": "open",
|
||||
"arguments": {
|
||||
"file": "/project/a/file1.ts"
|
||||
},
|
||||
"seq": 1,
|
||||
"type": "request"
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] Search path: /project/a
|
||||
Info seq [hh:mm:ss:mss] For info: /project/a/file1.ts :: Config file name: /project/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] Creating configuration project /project/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /project/tsconfig.json 2000 undefined Project: /project/tsconfig.json WatchType: Config file
|
||||
Info seq [hh:mm:ss:mss] Config: /project/tsconfig.json : {
|
||||
"rootNames": [
|
||||
"/project/a/file1.ts",
|
||||
"/project/a/file4.ts",
|
||||
"/project/b/file2.ts",
|
||||
"/project/d/e/file3.ts"
|
||||
],
|
||||
"options": {
|
||||
"configFilePath": "/project/tsconfig.json"
|
||||
}
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /project 1 undefined Config: /project/tsconfig.json WatchType: Wild card directory
|
||||
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /project 1 undefined Config: /project/tsconfig.json WatchType: Wild card directory
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /project/a/file4.ts 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /project/b/file2.ts 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /project/d/e/file3.ts 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /project/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /project/node_modules 1 undefined WatchType: node_modules for closed script infos and package.jsons affecting module specifier cache
|
||||
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /project/node_modules 1 undefined WatchType: node_modules for closed script infos and package.jsons affecting module specifier cache
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /project/tsconfig.json WatchType: Missing file
|
||||
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /project/tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
|
||||
Info seq [hh:mm:ss:mss] Project '/project/tsconfig.json' (Configured)
|
||||
Info seq [hh:mm:ss:mss] Files (6)
|
||||
/project/a/file1.ts SVC-1-0 "interface ka {\n name: string;\n }\n "
|
||||
/project/node_modules/@types/node/someFile.d.ts Text-1 "export const value = 0;"
|
||||
/project/node_modules/.cache/someFile.d.ts Text-1 "export const value1 = 0;"
|
||||
/project/a/file4.ts Text-1 "import { value } from \"../node_modules/@types/node/someFile.d.ts\";\nimport { value1 } from \"../node_modules/.cache/someFile.d.ts\";"
|
||||
/project/b/file2.ts Text-1 ""
|
||||
/project/d/e/file3.ts Text-1 ""
|
||||
|
||||
|
||||
a/file1.ts
|
||||
Matched by default include pattern '**/*'
|
||||
node_modules/@types/node/someFile.d.ts
|
||||
Imported via "../node_modules/@types/node/someFile.d.ts" from file 'a/file4.ts'
|
||||
node_modules/.cache/someFile.d.ts
|
||||
Imported via "../node_modules/.cache/someFile.d.ts" from file 'a/file4.ts'
|
||||
a/file4.ts
|
||||
Matched by default include pattern '**/*'
|
||||
b/file2.ts
|
||||
Matched by default include pattern '**/*'
|
||||
d/e/file3.ts
|
||||
Matched by default include pattern '**/*'
|
||||
|
||||
Info seq [hh:mm:ss:mss] -----------------------------------------------
|
||||
Info seq [hh:mm:ss:mss] Project '/project/tsconfig.json' (Configured)
|
||||
Info seq [hh:mm:ss:mss] Files (6)
|
||||
|
||||
Info seq [hh:mm:ss:mss] -----------------------------------------------
|
||||
Info seq [hh:mm:ss:mss] Open files:
|
||||
Info seq [hh:mm:ss:mss] FileName: /project/a/file1.ts ProjectRootPath: undefined
|
||||
Info seq [hh:mm:ss:mss] Projects: /project/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] response:
|
||||
{
|
||||
"responseRequired": false
|
||||
}
|
||||
After request
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts: *new*
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
/project/tsconfig.json: *new*
|
||||
{}
|
||||
/project/a/file4.ts: *new*
|
||||
{}
|
||||
/project/b/file2.ts: *new*
|
||||
{}
|
||||
/project/d/e/file3.ts: *new*
|
||||
{}
|
||||
|
||||
FsWatchesRecursive::
|
||||
/project: *new*
|
||||
{}
|
||||
/project/node_modules: *new*
|
||||
{}
|
||||
|
||||
Before request
|
||||
|
||||
Info seq [hh:mm:ss:mss] request:
|
||||
{
|
||||
"command": "getMoveToRefactoringFileSuggestions",
|
||||
"arguments": {
|
||||
"file": "/project/a/file1.ts",
|
||||
"line": 1,
|
||||
"offset": 11
|
||||
},
|
||||
"seq": 2,
|
||||
"type": "request"
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] response:
|
||||
{
|
||||
"response": {
|
||||
"newFileName": "/project/a/ka.ts",
|
||||
"files": [
|
||||
"/project/a/file4.ts",
|
||||
"/project/b/file2.ts",
|
||||
"/project/d/e/file3.ts"
|
||||
]
|
||||
},
|
||||
"responseRequired": true
|
||||
}
|
||||
After request
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
currentDirectory:: / useCaseSensitiveFileNames: false
|
||||
Info 0 [00:00:19.000] Provided types map file "/a/lib/typesMap.json" doesn't exist
|
||||
Before request
|
||||
//// [/blah/file1.ts]
|
||||
class CC { }
|
||||
|
||||
//// [/blah/file2.ts]
|
||||
|
||||
|
||||
//// [/blah-tests/file3.ts]
|
||||
import { value1 } from "../blah/file1.ts";
|
||||
|
||||
//// [/blah-tests/file4.ts]
|
||||
|
||||
|
||||
//// [/blah/tsconfig.json]
|
||||
{ "files": ["./file1.ts", "./file2.ts"] }
|
||||
|
||||
//// [/blah-tests/tsconfig.json]
|
||||
{ "files": ["./file3.ts", "./file4.ts"] }
|
||||
|
||||
|
||||
Info 1 [00:00:20.000] request:
|
||||
{
|
||||
"command": "open",
|
||||
"arguments": {
|
||||
"file": "/blah/file1.ts"
|
||||
},
|
||||
"seq": 1,
|
||||
"type": "request"
|
||||
}
|
||||
Info 2 [00:00:21.000] Search path: /blah
|
||||
Info 3 [00:00:22.000] For info: /blah/file1.ts :: Config file name: /blah/tsconfig.json
|
||||
Info 4 [00:00:23.000] Creating configuration project /blah/tsconfig.json
|
||||
Info 5 [00:00:24.000] FileWatcher:: Added:: WatchInfo: /blah/tsconfig.json 2000 undefined Project: /blah/tsconfig.json WatchType: Config file
|
||||
Info 6 [00:00:25.000] Config: /blah/tsconfig.json : {
|
||||
"rootNames": [
|
||||
"/blah/file1.ts",
|
||||
"/blah/file2.ts"
|
||||
],
|
||||
"options": {
|
||||
"configFilePath": "/blah/tsconfig.json"
|
||||
}
|
||||
}
|
||||
Info 7 [00:00:26.000] FileWatcher:: Added:: WatchInfo: /blah/file2.ts 500 undefined WatchType: Closed Script info
|
||||
Info 8 [00:00:27.000] Starting updateGraphWorker: Project: /blah/tsconfig.json
|
||||
Info 9 [00:00:28.000] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /blah/tsconfig.json WatchType: Missing file
|
||||
Info 10 [00:00:29.000] DirectoryWatcher:: Added:: WatchInfo: /blah/node_modules/@types 1 undefined Project: /blah/tsconfig.json WatchType: Type roots
|
||||
Info 11 [00:00:30.000] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /blah/node_modules/@types 1 undefined Project: /blah/tsconfig.json WatchType: Type roots
|
||||
Info 12 [00:00:31.000] Finishing updateGraphWorker: Project: /blah/tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
|
||||
Info 13 [00:00:32.000] Project '/blah/tsconfig.json' (Configured)
|
||||
Info 14 [00:00:33.000] Files (2)
|
||||
/blah/file1.ts SVC-1-0 "class CC { }"
|
||||
/blah/file2.ts Text-1 ""
|
||||
|
||||
|
||||
file1.ts
|
||||
Part of 'files' list in tsconfig.json
|
||||
file2.ts
|
||||
Part of 'files' list in tsconfig.json
|
||||
|
||||
Info 15 [00:00:34.000] -----------------------------------------------
|
||||
Info 16 [00:00:35.000] Project '/blah/tsconfig.json' (Configured)
|
||||
Info 16 [00:00:36.000] Files (2)
|
||||
|
||||
Info 16 [00:00:37.000] -----------------------------------------------
|
||||
Info 16 [00:00:38.000] Open files:
|
||||
Info 16 [00:00:39.000] FileName: /blah/file1.ts ProjectRootPath: undefined
|
||||
Info 16 [00:00:40.000] Projects: /blah/tsconfig.json
|
||||
Info 16 [00:00:41.000] response:
|
||||
{
|
||||
"responseRequired": false
|
||||
}
|
||||
After request
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts: *new*
|
||||
{"pollingInterval":500}
|
||||
/blah/node_modules/@types: *new*
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
/blah/tsconfig.json: *new*
|
||||
{}
|
||||
/blah/file2.ts: *new*
|
||||
{}
|
||||
|
||||
Before request
|
||||
|
||||
Info 17 [00:00:42.000] request:
|
||||
{
|
||||
"command": "getMoveToRefactoringFileSuggestions",
|
||||
"arguments": {
|
||||
"file": "/blah/file1.ts",
|
||||
"line": 1,
|
||||
"offset": 7
|
||||
},
|
||||
"seq": 2,
|
||||
"type": "request"
|
||||
}
|
||||
Info 18 [00:00:43.000] response:
|
||||
{
|
||||
"response": {
|
||||
"newFilename": "/blah/CC.ts",
|
||||
"files": [
|
||||
"/blah/file1.ts",
|
||||
"/blah/file2.ts"
|
||||
]
|
||||
},
|
||||
"responseRequired": true
|
||||
}
|
||||
After request
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
currentDirectory:: / useCaseSensitiveFileNames: false
|
||||
Info 0 [00:00:09.000] Provided types map file "/a/lib/typesMap.json" doesn't exist
|
||||
Before request
|
||||
//// [/file1.js]
|
||||
import {} from "./file.js";
|
||||
|
||||
//// [/file2.js]
|
||||
class C {}
|
||||
|
||||
//// [/jsconfig.json]
|
||||
{"files":["./file1.js","./file.js"]}
|
||||
|
||||
|
||||
Info 1 [00:00:10.000] request:
|
||||
{
|
||||
"command": "open",
|
||||
"arguments": {
|
||||
"file": "/file2.js"
|
||||
},
|
||||
"seq": 1,
|
||||
"type": "request"
|
||||
}
|
||||
Info 2 [00:00:11.000] Search path: /
|
||||
Info 3 [00:00:12.000] For info: /file2.js :: Config file name: /jsconfig.json
|
||||
Info 4 [00:00:13.000] Creating configuration project /jsconfig.json
|
||||
Info 5 [00:00:14.000] FileWatcher:: Added:: WatchInfo: /jsconfig.json 2000 undefined Project: /jsconfig.json WatchType: Config file
|
||||
Info 6 [00:00:15.000] Config: /jsconfig.json : {
|
||||
"rootNames": [
|
||||
"/file1.js",
|
||||
"/file.js"
|
||||
],
|
||||
"options": {
|
||||
"allowJs": true,
|
||||
"maxNodeModuleJsDepth": 2,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"skipLibCheck": true,
|
||||
"noEmit": true,
|
||||
"configFilePath": "/jsconfig.json"
|
||||
}
|
||||
}
|
||||
Info 7 [00:00:16.000] FileWatcher:: Added:: WatchInfo: /file1.js 500 undefined WatchType: Closed Script info
|
||||
Info 8 [00:00:17.000] Starting updateGraphWorker: Project: /jsconfig.json
|
||||
Info 9 [00:00:18.000] DirectoryWatcher:: Added:: WatchInfo: /file.js 1 undefined Project: /jsconfig.json WatchType: Failed Lookup Locations
|
||||
Info 10 [00:00:19.000] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /file.js 1 undefined Project: /jsconfig.json WatchType: Failed Lookup Locations
|
||||
Info 11 [00:00:20.000] DirectoryWatcher:: Added:: WatchInfo: 0 undefined Project: /jsconfig.json WatchType: Failed Lookup Locations
|
||||
Info 12 [00:00:21.000] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: 0 undefined Project: /jsconfig.json WatchType: Failed Lookup Locations
|
||||
Info 13 [00:00:22.000] FileWatcher:: Added:: WatchInfo: /file.js 500 undefined Project: /jsconfig.json WatchType: Missing file
|
||||
Info 14 [00:00:23.000] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /jsconfig.json WatchType: Missing file
|
||||
Info 15 [00:00:24.000] Finishing updateGraphWorker: Project: /jsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
|
||||
Info 16 [00:00:25.000] Project '/jsconfig.json' (Configured)
|
||||
Info 17 [00:00:26.000] Files (1)
|
||||
/file1.js Text-1 "import {} from \"./file.js\";"
|
||||
|
||||
|
||||
file1.js
|
||||
Part of 'files' list in tsconfig.json
|
||||
|
||||
Info 18 [00:00:27.000] -----------------------------------------------
|
||||
TI:: Creating typing installer
|
||||
|
||||
PolledWatches::
|
||||
/file.js: *new*
|
||||
{"pollingInterval":500}
|
||||
/a/lib/lib.d.ts: *new*
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
/jsconfig.json: *new*
|
||||
{}
|
||||
/file1.js: *new*
|
||||
{}
|
||||
/: *new*
|
||||
{}
|
||||
|
||||
TI:: [00:00:28.000] Global cache location '/a/data/', safe file path '/safeList.json', types map path /typesMap.json
|
||||
TI:: [00:00:29.000] Processing cache location '/a/data/'
|
||||
TI:: [00:00:30.000] Trying to find '/a/data/package.json'...
|
||||
TI:: [00:00:31.000] Finished processing cache location '/a/data/'
|
||||
TI:: [00:00:32.000] Npm config file: /a/data/package.json
|
||||
TI:: [00:00:33.000] Npm config file: '/a/data/package.json' is missing, creating new one...
|
||||
Info 19 [00:00:36.000] DirectoryWatcher:: Triggered with a :: WatchInfo: 0 undefined Project: /jsconfig.json WatchType: Failed Lookup Locations
|
||||
Info 20 [00:00:37.000] Elapsed:: *ms DirectoryWatcher:: Triggered with a :: WatchInfo: 0 undefined Project: /jsconfig.json WatchType: Failed Lookup Locations
|
||||
TI:: [00:00:42.000] Updating types-registry npm package...
|
||||
TI:: [00:00:43.000] npm install --ignore-scripts types-registry@latest
|
||||
TI:: [00:00:50.000] TI:: Updated types-registry npm package
|
||||
TI:: typing installer creation complete
|
||||
//// [/a/data/package.json]
|
||||
{ "private": true }
|
||||
|
||||
//// [/a/data/node_modules/types-registry/index.json]
|
||||
{
|
||||
"entries": {}
|
||||
}
|
||||
|
||||
|
||||
TI:: [00:00:51.000] Got install request {"projectName":"/jsconfig.json","fileNames":["/file1.js"],"compilerOptions":{"allowJs":true,"maxNodeModuleJsDepth":2,"allowSyntheticDefaultImports":true,"skipLibCheck":true,"noEmit":true,"configFilePath":"/jsconfig.json","allowNonTsExtensions":true},"typeAcquisition":{"enable":true,"include":[],"exclude":[]},"unresolvedImports":[],"projectRootPath":"/","cachePath":"/a/data/","kind":"discover"}
|
||||
TI:: [00:00:52.000] Request specifies cache path '/a/data/', loading cached information...
|
||||
TI:: [00:00:53.000] Processing cache location '/a/data/'
|
||||
TI:: [00:00:54.000] Cache location was already processed...
|
||||
TI:: [00:00:55.000] Failed to load safelist from types map file '/typesMap.json'
|
||||
TI:: [00:00:56.000] Explicitly included types: []
|
||||
TI:: [00:00:57.000] Inferred typings from unresolved imports: []
|
||||
TI:: [00:00:58.000] Result: {"cachedTypingPaths":[],"newTypingNames":[],"filesToWatch":["/bower_components","/node_modules"]}
|
||||
TI:: [00:00:59.000] Finished typings discovery: {"cachedTypingPaths":[],"newTypingNames":[],"filesToWatch":["/bower_components","/node_modules"]}
|
||||
TI:: [00:01:00.000] DirectoryWatcher:: Added:: WatchInfo: /bower_components
|
||||
TI:: [00:01:01.000] DirectoryWatcher:: Added:: WatchInfo: /bower_components 1 undefined Project: /jsconfig.json watcher already invoked: false
|
||||
TI:: [00:01:02.000] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /bower_components 1 undefined Project: /jsconfig.json watcher already invoked: false
|
||||
TI:: [00:01:03.000] DirectoryWatcher:: Added:: WatchInfo: /node_modules
|
||||
TI:: [00:01:04.000] DirectoryWatcher:: Added:: WatchInfo: /node_modules 1 undefined Project: /jsconfig.json watcher already invoked: false
|
||||
TI:: [00:01:05.000] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /node_modules 1 undefined Project: /jsconfig.json watcher already invoked: false
|
||||
TI:: [00:01:06.000] Sending response:
|
||||
{"projectName":"/jsconfig.json","typeAcquisition":{"enable":true,"include":[],"exclude":[]},"compilerOptions":{"allowJs":true,"maxNodeModuleJsDepth":2,"allowSyntheticDefaultImports":true,"skipLibCheck":true,"noEmit":true,"configFilePath":"/jsconfig.json","allowNonTsExtensions":true},"typings":[],"unresolvedImports":[],"kind":"action::set"}
|
||||
TI:: [00:01:07.000] No new typings were requested as a result of typings discovery
|
||||
Info 21 [00:01:08.000] Starting updateGraphWorker: Project: /dev/null/inferredProject1*
|
||||
Info 22 [00:01:09.000] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /dev/null/inferredProject1* WatchType: Missing file
|
||||
Info 23 [00:01:10.000] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
|
||||
Info 24 [00:01:11.000] Project '/dev/null/inferredProject1*' (Inferred)
|
||||
Info 25 [00:01:12.000] Files (1)
|
||||
/file2.js SVC-1-0 "class C {}"
|
||||
|
||||
|
||||
file2.js
|
||||
Root file specified for compilation
|
||||
|
||||
Info 26 [00:01:13.000] -----------------------------------------------
|
||||
TI:: [00:01:14.000] Got install request {"projectName":"/dev/null/inferredProject1*","fileNames":["/file2.js"],"compilerOptions":{"target":1,"jsx":1,"allowNonTsExtensions":true,"allowJs":true,"noEmitForJsFiles":true,"maxNodeModuleJsDepth":2},"typeAcquisition":{"enable":true,"include":[],"exclude":[]},"unresolvedImports":[],"projectRootPath":"/","cachePath":"/a/data/","kind":"discover"}
|
||||
TI:: [00:01:15.000] Request specifies cache path '/a/data/', loading cached information...
|
||||
TI:: [00:01:16.000] Processing cache location '/a/data/'
|
||||
TI:: [00:01:17.000] Cache location was already processed...
|
||||
TI:: [00:01:18.000] Explicitly included types: []
|
||||
TI:: [00:01:19.000] Inferred typings from unresolved imports: []
|
||||
TI:: [00:01:20.000] Result: {"cachedTypingPaths":[],"newTypingNames":[],"filesToWatch":["/bower_components","/node_modules"]}
|
||||
TI:: [00:01:21.000] Finished typings discovery: {"cachedTypingPaths":[],"newTypingNames":[],"filesToWatch":["/bower_components","/node_modules"]}
|
||||
TI:: [00:01:22.000] DirectoryWatcher:: Added:: WatchInfo: /bower_components
|
||||
TI:: [00:01:23.000] DirectoryWatcher:: Added:: WatchInfo: /bower_components 1 undefined Project: /dev/null/inferredProject1* watcher already invoked: false
|
||||
TI:: [00:01:24.000] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /bower_components 1 undefined Project: /dev/null/inferredProject1* watcher already invoked: false
|
||||
TI:: [00:01:25.000] DirectoryWatcher:: Added:: WatchInfo: /node_modules
|
||||
TI:: [00:01:26.000] DirectoryWatcher:: Added:: WatchInfo: /node_modules 1 undefined Project: /dev/null/inferredProject1* watcher already invoked: false
|
||||
TI:: [00:01:27.000] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /node_modules 1 undefined Project: /dev/null/inferredProject1* watcher already invoked: false
|
||||
TI:: [00:01:28.000] Sending response:
|
||||
{"projectName":"/dev/null/inferredProject1*","typeAcquisition":{"enable":true,"include":[],"exclude":[]},"compilerOptions":{"target":1,"jsx":1,"allowNonTsExtensions":true,"allowJs":true,"noEmitForJsFiles":true,"maxNodeModuleJsDepth":2},"typings":[],"unresolvedImports":[],"kind":"action::set"}
|
||||
TI:: [00:01:29.000] No new typings were requested as a result of typings discovery
|
||||
Info 27 [00:01:30.000] Project '/jsconfig.json' (Configured)
|
||||
Info 27 [00:01:31.000] Files (1)
|
||||
|
||||
Info 27 [00:01:32.000] -----------------------------------------------
|
||||
Info 27 [00:01:33.000] Project '/dev/null/inferredProject1*' (Inferred)
|
||||
Info 27 [00:01:34.000] Files (1)
|
||||
|
||||
Info 27 [00:01:35.000] -----------------------------------------------
|
||||
Info 27 [00:01:36.000] Open files:
|
||||
Info 27 [00:01:37.000] FileName: /file2.js ProjectRootPath: undefined
|
||||
Info 27 [00:01:38.000] Projects: /dev/null/inferredProject1*
|
||||
Info 27 [00:01:39.000] response:
|
||||
{
|
||||
"responseRequired": false
|
||||
}
|
||||
After request
|
||||
|
||||
PolledWatches::
|
||||
/file.js:
|
||||
{"pollingInterval":500}
|
||||
/a/lib/lib.d.ts:
|
||||
{"pollingInterval":500}
|
||||
/bower_components: *new*
|
||||
{"pollingInterval":500}
|
||||
/node_modules: *new*
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
/jsconfig.json:
|
||||
{}
|
||||
/file1.js:
|
||||
{}
|
||||
/:
|
||||
{}
|
||||
|
||||
Before request
|
||||
|
||||
Info 28 [00:01:40.000] request:
|
||||
{
|
||||
"command": "getMoveToRefactoringFileSuggestions",
|
||||
"arguments": {
|
||||
"file": "/file2.js",
|
||||
"line": 1,
|
||||
"offset": 7
|
||||
},
|
||||
"seq": 2,
|
||||
"type": "request"
|
||||
}
|
||||
Info 29 [00:01:41.000] response:
|
||||
{
|
||||
"response": {
|
||||
"newFilename": "/C.js",
|
||||
"files": [
|
||||
"/file2.js"
|
||||
]
|
||||
},
|
||||
"responseRequired": true
|
||||
}
|
||||
After request
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
currentDirectory:: / useCaseSensitiveFileNames: false
|
||||
Info 0 [00:00:09.000] Provided types map file "/a/lib/typesMap.json" doesn't exist
|
||||
Before request
|
||||
//// [/file1.ts]
|
||||
import {} from "./file.ts";
|
||||
|
||||
//// [/file2.ts]
|
||||
interface ka {
|
||||
name: string;
|
||||
}
|
||||
|
||||
|
||||
//// [/tsconfig.json]
|
||||
{"files":["./file1.ts","./file.ts"]}
|
||||
|
||||
|
||||
Info 1 [00:00:10.000] request:
|
||||
{
|
||||
"command": "open",
|
||||
"arguments": {
|
||||
"file": "/file2.ts"
|
||||
},
|
||||
"seq": 1,
|
||||
"type": "request"
|
||||
}
|
||||
Info 2 [00:00:11.000] Search path: /
|
||||
Info 3 [00:00:12.000] For info: /file2.ts :: Config file name: /tsconfig.json
|
||||
Info 4 [00:00:13.000] Creating configuration project /tsconfig.json
|
||||
Info 5 [00:00:14.000] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file
|
||||
Info 6 [00:00:15.000] Config: /tsconfig.json : {
|
||||
"rootNames": [
|
||||
"/file1.ts",
|
||||
"/file.ts"
|
||||
],
|
||||
"options": {
|
||||
"configFilePath": "/tsconfig.json"
|
||||
}
|
||||
}
|
||||
Info 7 [00:00:16.000] FileWatcher:: Added:: WatchInfo: /file1.ts 500 undefined WatchType: Closed Script info
|
||||
Info 8 [00:00:17.000] Starting updateGraphWorker: Project: /tsconfig.json
|
||||
Info 9 [00:00:18.000] DirectoryWatcher:: Added:: WatchInfo: /file.ts 1 undefined Project: /tsconfig.json WatchType: Failed Lookup Locations
|
||||
Info 10 [00:00:19.000] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /file.ts 1 undefined Project: /tsconfig.json WatchType: Failed Lookup Locations
|
||||
Info 11 [00:00:20.000] DirectoryWatcher:: Added:: WatchInfo: 0 undefined Project: /tsconfig.json WatchType: Failed Lookup Locations
|
||||
Info 12 [00:00:21.000] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: 0 undefined Project: /tsconfig.json WatchType: Failed Lookup Locations
|
||||
Info 13 [00:00:22.000] FileWatcher:: Added:: WatchInfo: /file.ts 500 undefined Project: /tsconfig.json WatchType: Missing file
|
||||
Info 14 [00:00:23.000] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /tsconfig.json WatchType: Missing file
|
||||
Info 15 [00:00:24.000] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
|
||||
Info 16 [00:00:25.000] Project '/tsconfig.json' (Configured)
|
||||
Info 17 [00:00:26.000] Files (1)
|
||||
/file1.ts Text-1 "import {} from \"./file.ts\";"
|
||||
|
||||
|
||||
file1.ts
|
||||
Part of 'files' list in tsconfig.json
|
||||
|
||||
Info 18 [00:00:27.000] -----------------------------------------------
|
||||
Info 19 [00:00:28.000] Starting updateGraphWorker: Project: /dev/null/inferredProject1*
|
||||
Info 20 [00:00:29.000] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /dev/null/inferredProject1* WatchType: Missing file
|
||||
Info 21 [00:00:30.000] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
|
||||
Info 22 [00:00:31.000] Project '/dev/null/inferredProject1*' (Inferred)
|
||||
Info 23 [00:00:32.000] Files (1)
|
||||
/file2.ts SVC-1-0 "interface ka {\n name: string;\n }\n "
|
||||
|
||||
|
||||
file2.ts
|
||||
Root file specified for compilation
|
||||
|
||||
Info 24 [00:00:33.000] -----------------------------------------------
|
||||
Info 25 [00:00:34.000] Project '/tsconfig.json' (Configured)
|
||||
Info 25 [00:00:35.000] Files (1)
|
||||
|
||||
Info 25 [00:00:36.000] -----------------------------------------------
|
||||
Info 25 [00:00:37.000] Project '/dev/null/inferredProject1*' (Inferred)
|
||||
Info 25 [00:00:38.000] Files (1)
|
||||
|
||||
Info 25 [00:00:39.000] -----------------------------------------------
|
||||
Info 25 [00:00:40.000] Open files:
|
||||
Info 25 [00:00:41.000] FileName: /file2.ts ProjectRootPath: undefined
|
||||
Info 25 [00:00:42.000] Projects: /dev/null/inferredProject1*
|
||||
Info 25 [00:00:43.000] response:
|
||||
{
|
||||
"responseRequired": false
|
||||
}
|
||||
After request
|
||||
|
||||
PolledWatches::
|
||||
/file.ts: *new*
|
||||
{"pollingInterval":500}
|
||||
/a/lib/lib.d.ts: *new*
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
/tsconfig.json: *new*
|
||||
{}
|
||||
/file1.ts: *new*
|
||||
{}
|
||||
/: *new*
|
||||
{}
|
||||
|
||||
Before request
|
||||
|
||||
Info 26 [00:00:44.000] request:
|
||||
{
|
||||
"command": "getMoveToRefactoringFileSuggestions",
|
||||
"arguments": {
|
||||
"file": "/file2.ts",
|
||||
"line": 1,
|
||||
"offset": 11
|
||||
},
|
||||
"seq": 2,
|
||||
"type": "request"
|
||||
}
|
||||
Info 27 [00:00:45.000] response:
|
||||
{
|
||||
"response": {
|
||||
"newFilename": "/ka.ts",
|
||||
"files": [
|
||||
"/file2.ts"
|
||||
]
|
||||
},
|
||||
"responseRequired": true
|
||||
}
|
||||
After request
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
currentDirectory:: / useCaseSensitiveFileNames: false
|
||||
Info 0 [00:00:17.000] Provided types map file "/a/lib/typesMap.json" doesn't exist
|
||||
Before request
|
||||
//// [/file1.ts]
|
||||
interface ka {
|
||||
name: string;
|
||||
}
|
||||
|
||||
|
||||
//// [/file2.tsx]
|
||||
|
||||
|
||||
//// [/file3.mts]
|
||||
|
||||
|
||||
//// [/file4.cts]
|
||||
|
||||
|
||||
//// [/file5.js]
|
||||
|
||||
|
||||
//// [/file6.d.ts]
|
||||
|
||||
|
||||
//// [/tsconfig.json]
|
||||
{"files":["./file1.ts","./file2.tsx","./file3.mts","./file4.cts","./file5.js","./file6.d.ts"]}
|
||||
|
||||
|
||||
Info 1 [00:00:18.000] request:
|
||||
{
|
||||
"command": "open",
|
||||
"arguments": {
|
||||
"file": "/file1.ts"
|
||||
},
|
||||
"seq": 1,
|
||||
"type": "request"
|
||||
}
|
||||
Info 2 [00:00:19.000] Search path: /
|
||||
Info 3 [00:00:20.000] For info: /file1.ts :: Config file name: /tsconfig.json
|
||||
Info 4 [00:00:21.000] Creating configuration project /tsconfig.json
|
||||
Info 5 [00:00:22.000] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file
|
||||
Info 6 [00:00:23.000] Config: /tsconfig.json : {
|
||||
"rootNames": [
|
||||
"/file1.ts",
|
||||
"/file2.tsx",
|
||||
"/file3.mts",
|
||||
"/file4.cts",
|
||||
"/file5.js",
|
||||
"/file6.d.ts"
|
||||
],
|
||||
"options": {
|
||||
"configFilePath": "/tsconfig.json"
|
||||
}
|
||||
}
|
||||
Info 7 [00:00:24.000] FileWatcher:: Added:: WatchInfo: /file2.tsx 500 undefined WatchType: Closed Script info
|
||||
Info 8 [00:00:25.000] FileWatcher:: Added:: WatchInfo: /file3.mts 500 undefined WatchType: Closed Script info
|
||||
Info 9 [00:00:26.000] FileWatcher:: Added:: WatchInfo: /file4.cts 500 undefined WatchType: Closed Script info
|
||||
Info 10 [00:00:27.000] FileWatcher:: Added:: WatchInfo: /file5.js 500 undefined WatchType: Closed Script info
|
||||
Info 11 [00:00:28.000] FileWatcher:: Added:: WatchInfo: /file6.d.ts 500 undefined WatchType: Closed Script info
|
||||
Info 12 [00:00:29.000] Starting updateGraphWorker: Project: /tsconfig.json
|
||||
Info 13 [00:00:30.000] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /tsconfig.json WatchType: Missing file
|
||||
Info 14 [00:00:31.000] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
|
||||
Info 15 [00:00:32.000] Project '/tsconfig.json' (Configured)
|
||||
Info 16 [00:00:33.000] Files (6)
|
||||
/file1.ts SVC-1-0 "interface ka {\n name: string;\n }\n "
|
||||
/file2.tsx Text-1 ""
|
||||
/file3.mts Text-1 ""
|
||||
/file4.cts Text-1 ""
|
||||
/file5.js Text-1 ""
|
||||
/file6.d.ts Text-1 ""
|
||||
|
||||
|
||||
file1.ts
|
||||
Part of 'files' list in tsconfig.json
|
||||
file2.tsx
|
||||
Part of 'files' list in tsconfig.json
|
||||
file3.mts
|
||||
Part of 'files' list in tsconfig.json
|
||||
file4.cts
|
||||
Part of 'files' list in tsconfig.json
|
||||
file5.js
|
||||
Part of 'files' list in tsconfig.json
|
||||
file6.d.ts
|
||||
Part of 'files' list in tsconfig.json
|
||||
|
||||
Info 17 [00:00:34.000] -----------------------------------------------
|
||||
Info 18 [00:00:35.000] Project '/tsconfig.json' (Configured)
|
||||
Info 18 [00:00:36.000] Files (6)
|
||||
|
||||
Info 18 [00:00:37.000] -----------------------------------------------
|
||||
Info 18 [00:00:38.000] Open files:
|
||||
Info 18 [00:00:39.000] FileName: /file1.ts ProjectRootPath: undefined
|
||||
Info 18 [00:00:40.000] Projects: /tsconfig.json
|
||||
Info 18 [00:00:41.000] response:
|
||||
{
|
||||
"responseRequired": false
|
||||
}
|
||||
After request
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts: *new*
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
/tsconfig.json: *new*
|
||||
{}
|
||||
/file2.tsx: *new*
|
||||
{}
|
||||
/file3.mts: *new*
|
||||
{}
|
||||
/file4.cts: *new*
|
||||
{}
|
||||
/file5.js: *new*
|
||||
{}
|
||||
/file6.d.ts: *new*
|
||||
{}
|
||||
|
||||
Before request
|
||||
|
||||
Info 19 [00:00:42.000] request:
|
||||
{
|
||||
"command": "getMoveToRefactoringFileSuggestions",
|
||||
"arguments": {
|
||||
"file": "/file1.ts",
|
||||
"line": 1,
|
||||
"offset": 11
|
||||
},
|
||||
"seq": 2,
|
||||
"type": "request"
|
||||
}
|
||||
Info 20 [00:00:43.000] response:
|
||||
{
|
||||
"response": {
|
||||
"newFilename": "/ka.ts",
|
||||
"files": [
|
||||
"/file1.ts",
|
||||
"/file2.tsx",
|
||||
"/file3.mts",
|
||||
"/file4.cts",
|
||||
"/file6.d.ts"
|
||||
]
|
||||
},
|
||||
"responseRequired": true
|
||||
}
|
||||
After request
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
currentDirectory:: / useCaseSensitiveFileNames: false
|
||||
Info 0 [00:00:15.000] Provided types map file "/a/lib/typesMap.json" doesn't exist
|
||||
Before request
|
||||
//// [/file1.js]
|
||||
class C {}
|
||||
|
||||
//// [/file2.js]
|
||||
|
||||
|
||||
//// [/file3.mts]
|
||||
|
||||
|
||||
//// [/file4.ts]
|
||||
|
||||
|
||||
//// [/file5.js]
|
||||
|
||||
|
||||
//// [/tsconfig.json]
|
||||
{"files":["./file1.js","./file2.js","./file3.mts","./file4.ts","./file5.js"]}
|
||||
|
||||
|
||||
Info 1 [00:00:16.000] request:
|
||||
{
|
||||
"command": "open",
|
||||
"arguments": {
|
||||
"file": "/file1.js"
|
||||
},
|
||||
"seq": 1,
|
||||
"type": "request"
|
||||
}
|
||||
Info 2 [00:00:17.000] Search path: /
|
||||
Info 3 [00:00:18.000] For info: /file1.js :: Config file name: /tsconfig.json
|
||||
Info 4 [00:00:19.000] Creating configuration project /tsconfig.json
|
||||
Info 5 [00:00:20.000] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file
|
||||
Info 6 [00:00:21.000] Config: /tsconfig.json : {
|
||||
"rootNames": [
|
||||
"/file1.js",
|
||||
"/file2.js",
|
||||
"/file3.mts",
|
||||
"/file4.ts",
|
||||
"/file5.js"
|
||||
],
|
||||
"options": {
|
||||
"configFilePath": "/tsconfig.json"
|
||||
}
|
||||
}
|
||||
Info 7 [00:00:22.000] FileWatcher:: Added:: WatchInfo: /file2.js 500 undefined WatchType: Closed Script info
|
||||
Info 8 [00:00:23.000] FileWatcher:: Added:: WatchInfo: /file3.mts 500 undefined WatchType: Closed Script info
|
||||
Info 9 [00:00:24.000] FileWatcher:: Added:: WatchInfo: /file4.ts 500 undefined WatchType: Closed Script info
|
||||
Info 10 [00:00:25.000] FileWatcher:: Added:: WatchInfo: /file5.js 500 undefined WatchType: Closed Script info
|
||||
Info 11 [00:00:26.000] Starting updateGraphWorker: Project: /tsconfig.json
|
||||
Info 12 [00:00:27.000] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /tsconfig.json WatchType: Missing file
|
||||
Info 13 [00:00:28.000] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
|
||||
Info 14 [00:00:29.000] Project '/tsconfig.json' (Configured)
|
||||
Info 15 [00:00:30.000] Files (5)
|
||||
/file1.js SVC-1-0 "class C {}"
|
||||
/file2.js Text-1 ""
|
||||
/file3.mts Text-1 ""
|
||||
/file4.ts Text-1 ""
|
||||
/file5.js Text-1 ""
|
||||
|
||||
|
||||
file1.js
|
||||
Part of 'files' list in tsconfig.json
|
||||
file2.js
|
||||
Part of 'files' list in tsconfig.json
|
||||
file3.mts
|
||||
Part of 'files' list in tsconfig.json
|
||||
file4.ts
|
||||
Part of 'files' list in tsconfig.json
|
||||
file5.js
|
||||
Part of 'files' list in tsconfig.json
|
||||
|
||||
Info 16 [00:00:31.000] -----------------------------------------------
|
||||
Info 17 [00:00:32.000] Project '/tsconfig.json' (Configured)
|
||||
Info 17 [00:00:33.000] Files (5)
|
||||
|
||||
Info 17 [00:00:34.000] -----------------------------------------------
|
||||
Info 17 [00:00:35.000] Open files:
|
||||
Info 17 [00:00:36.000] FileName: /file1.js ProjectRootPath: undefined
|
||||
Info 17 [00:00:37.000] Projects: /tsconfig.json
|
||||
Info 17 [00:00:38.000] response:
|
||||
{
|
||||
"responseRequired": false
|
||||
}
|
||||
After request
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts: *new*
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
/tsconfig.json: *new*
|
||||
{}
|
||||
/file2.js: *new*
|
||||
{}
|
||||
/file3.mts: *new*
|
||||
{}
|
||||
/file4.ts: *new*
|
||||
{}
|
||||
/file5.js: *new*
|
||||
{}
|
||||
|
||||
Before request
|
||||
|
||||
Info 18 [00:00:39.000] request:
|
||||
{
|
||||
"command": "getMoveToRefactoringFileSuggestions",
|
||||
"arguments": {
|
||||
"file": "/file1.js",
|
||||
"line": 1,
|
||||
"offset": 7
|
||||
},
|
||||
"seq": 2,
|
||||
"type": "request"
|
||||
}
|
||||
Info 19 [00:00:40.000] response:
|
||||
{
|
||||
"response": {
|
||||
"newFilename": "/C.js",
|
||||
"files": [
|
||||
"/file1.js",
|
||||
"/file2.js",
|
||||
"/file5.js"
|
||||
]
|
||||
},
|
||||
"responseRequired": true
|
||||
}
|
||||
After request
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
currentDirectory:: / useCaseSensitiveFileNames: false
|
||||
Info seq [hh:mm:ss:mss] Provided types map file "/a/lib/typesMap.json" doesn't exist
|
||||
Before request
|
||||
//// [/Foo/a.ts]
|
||||
const x = 0;
|
||||
|
||||
//// [/Foo/b.ts]
|
||||
import {} from "./bar";
|
||||
const a = 1;
|
||||
|
||||
//// [/Foo/tsconfig.json]
|
||||
{ "files": ["./a.ts", "./b.ts"] }
|
||||
|
||||
|
||||
Info seq [hh:mm:ss:mss] request:
|
||||
{
|
||||
"command": "open",
|
||||
"arguments": {
|
||||
"file": "/Foo/a.ts"
|
||||
},
|
||||
"seq": 1,
|
||||
"type": "request"
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] Search path: /Foo
|
||||
Info seq [hh:mm:ss:mss] For info: /Foo/a.ts :: Config file name: /Foo/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] Creating configuration project /Foo/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /Foo/tsconfig.json 2000 undefined Project: /Foo/tsconfig.json WatchType: Config file
|
||||
Info seq [hh:mm:ss:mss] Config: /Foo/tsconfig.json : {
|
||||
"rootNames": [
|
||||
"/Foo/a.ts",
|
||||
"/Foo/b.ts"
|
||||
],
|
||||
"options": {
|
||||
"configFilePath": "/Foo/tsconfig.json"
|
||||
}
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /Foo/b.ts 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /Foo/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /Foo/tsconfig.json WatchType: Missing file
|
||||
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /Foo/tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
|
||||
Info seq [hh:mm:ss:mss] Project '/Foo/tsconfig.json' (Configured)
|
||||
Info seq [hh:mm:ss:mss] Files (2)
|
||||
/Foo/a.ts SVC-1-0 "const x = 0;"
|
||||
/Foo/b.ts Text-1 "import {} from \"./bar\";\nconst a = 1;"
|
||||
|
||||
|
||||
a.ts
|
||||
Part of 'files' list in tsconfig.json
|
||||
b.ts
|
||||
Part of 'files' list in tsconfig.json
|
||||
|
||||
Info seq [hh:mm:ss:mss] -----------------------------------------------
|
||||
Info seq [hh:mm:ss:mss] Project '/Foo/tsconfig.json' (Configured)
|
||||
Info seq [hh:mm:ss:mss] Files (2)
|
||||
|
||||
Info seq [hh:mm:ss:mss] -----------------------------------------------
|
||||
Info seq [hh:mm:ss:mss] Open files:
|
||||
Info seq [hh:mm:ss:mss] FileName: /Foo/a.ts ProjectRootPath: undefined
|
||||
Info seq [hh:mm:ss:mss] Projects: /Foo/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] response:
|
||||
{
|
||||
"responseRequired": false
|
||||
}
|
||||
After request
|
||||
|
||||
PolledWatches::
|
||||
/a/lib/lib.d.ts: *new*
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
/foo/tsconfig.json: *new*
|
||||
{}
|
||||
/foo/b.ts: *new*
|
||||
{}
|
||||
|
||||
Before request
|
||||
|
||||
Info seq [hh:mm:ss:mss] request:
|
||||
{
|
||||
"command": "getEditsForRefactor",
|
||||
"arguments": {
|
||||
"file": "/Foo/a.ts",
|
||||
"startLine": 1,
|
||||
"startOffset": 1,
|
||||
"endLine": 2,
|
||||
"endOffset": 12,
|
||||
"refactor": "Move to file",
|
||||
"action": "Move to file",
|
||||
"interactiveRefactorArguments": {
|
||||
"targetFile": "/Foo/b.ts"
|
||||
}
|
||||
},
|
||||
"seq": 2,
|
||||
"type": "request"
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] response:
|
||||
{
|
||||
"response": {
|
||||
"edits": [
|
||||
{
|
||||
"fileName": "/Foo/a.ts",
|
||||
"textChanges": [
|
||||
{
|
||||
"start": {
|
||||
"line": 1,
|
||||
"offset": 1
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"offset": 13
|
||||
},
|
||||
"newText": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"fileName": "/Foo/b.ts",
|
||||
"textChanges": [
|
||||
{
|
||||
"start": {
|
||||
"line": 2,
|
||||
"offset": 13
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"offset": 13
|
||||
},
|
||||
"newText": "\nconst x = 0;\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"responseRequired": true
|
||||
}
|
||||
After request
|
||||
@@ -198,6 +198,9 @@ declare namespace FourSlashInterface {
|
||||
readonly semicolons?: ts.SemicolonPreference;
|
||||
readonly indentSwitchCase?: boolean;
|
||||
}
|
||||
interface InteractiveRefactorArguments {
|
||||
targetFile: string;
|
||||
}
|
||||
interface Range {
|
||||
fileName: string;
|
||||
pos: number;
|
||||
@@ -431,7 +434,11 @@ declare namespace FourSlashInterface {
|
||||
readonly preferences?: UserPreferences;
|
||||
}): void;
|
||||
noMoveToNewFile(): void;
|
||||
|
||||
moveToFile(options: {
|
||||
readonly newFileContents: { readonly [fileName: string]: string };
|
||||
readonly interactiveRefactorArguments: InteractiveRefactorArguments;
|
||||
readonly preferences?: UserPreferences;
|
||||
}): void;
|
||||
generateTypes(...options: GenerateTypesOptions[]): void;
|
||||
|
||||
organizeImports(newContent: string, mode?: ts.OrganizeImportsMode, preferences?: UserPreferences): void;
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//@Filename: /bar.ts
|
||||
////import './blah';
|
||||
////
|
||||
////const a = 2;
|
||||
|
||||
// @Filename: /a.ts
|
||||
////import { b } from './other';
|
||||
////
|
||||
////[|const y = b + 10;|]
|
||||
////y;
|
||||
|
||||
// @Filename: /other.ts
|
||||
////export const b = 1;
|
||||
|
||||
verify.moveToFile({
|
||||
newFileContents: {
|
||||
"/a.ts":
|
||||
`import { y } from './bar';
|
||||
|
||||
y;`,
|
||||
|
||||
"/bar.ts":
|
||||
`import './blah';
|
||||
import { b } from './other';
|
||||
|
||||
const a = 2;
|
||||
export const y = b + 10;
|
||||
`,
|
||||
},
|
||||
interactiveRefactorArguments: {targetFile: "/bar.ts"},
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /bar.ts
|
||||
//////
|
||||
|
||||
// @Filename: /a.ts
|
||||
////import { b } from './other';
|
||||
////const p = 0;
|
||||
////[|const y: Date = p + b;|]
|
||||
|
||||
// @Filename: /other.ts
|
||||
////export const b = 1;
|
||||
|
||||
verify.moveToFile({
|
||||
newFileContents: {
|
||||
"/a.ts":
|
||||
`export const p = 0;
|
||||
`,
|
||||
|
||||
"/bar.ts":
|
||||
`import { b } from './other';
|
||||
import { p } from './a';
|
||||
|
||||
const y: Date = p + b;
|
||||
`,
|
||||
},
|
||||
interactiveRefactorArguments: {targetFile: "/bar.ts"},
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @module: nodenext
|
||||
// @allowImportingTsExtensions: true
|
||||
// @noEmit: true
|
||||
|
||||
//@Filename: /src/dir2/bar.mts
|
||||
////import './blah.ts';
|
||||
////const a = 2;
|
||||
|
||||
// @Filename: /src/dir1/a.cts
|
||||
////import { b } from './other.cts';
|
||||
////const p = 0;
|
||||
////[|const y = p + b;|]
|
||||
////y;
|
||||
|
||||
// @Filename: /src/dir1/other.cts
|
||||
////export const b = 1;
|
||||
|
||||
verify.moveToFile({
|
||||
newFileContents: {
|
||||
"/src/dir1/a.cts":
|
||||
`import { y } from '../dir2/bar.mts';
|
||||
export const p = 0;
|
||||
y;`,
|
||||
|
||||
"/src/dir2/bar.mts":
|
||||
`import { p } from '../dir1/a.cts';
|
||||
import { b } from '../dir1/other.cts';
|
||||
import './blah.ts';
|
||||
const a = 2;
|
||||
export const y = p + b;
|
||||
`,
|
||||
},
|
||||
interactiveRefactorArguments: { targetFile: "/src/dir2/bar.mts" },
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//@moduleResolution: bundler
|
||||
//@module: esnext
|
||||
|
||||
// @Filename: /src/dir1/a.ts
|
||||
////import { b } from './other';
|
||||
////[|const y = b + 10;|]
|
||||
////y;
|
||||
|
||||
// @Filename: /src/dir1/other.ts
|
||||
////export const b = 1;
|
||||
|
||||
//@Filename: /src/dir2/bar.ts
|
||||
////import './blah';
|
||||
////const a = 2;
|
||||
|
||||
verify.moveToFile({
|
||||
newFileContents: {
|
||||
"/src/dir1/a.ts":
|
||||
`import { y } from '../dir2/bar';
|
||||
y;`,
|
||||
|
||||
"/src/dir2/bar.ts":
|
||||
`import { b } from '../dir1/other';
|
||||
import './blah';
|
||||
const a = 2;
|
||||
export const y = b + 10;
|
||||
`,
|
||||
},
|
||||
interactiveRefactorArguments: { targetFile: "/src/dir2/bar.ts" },
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//@moduleResolution: bundler
|
||||
//@module: esnext
|
||||
|
||||
// @Filename: /src/dir1/a.ts
|
||||
////import { b } from './other';
|
||||
////const a = 10;
|
||||
////[|const y = b + a;|]
|
||||
////y;
|
||||
|
||||
// @Filename: /src/dir1/other.ts
|
||||
////export const b = 1;
|
||||
|
||||
//@Filename: /src/dir2/bar.ts
|
||||
////
|
||||
|
||||
verify.moveToFile({
|
||||
newFileContents: {
|
||||
"/src/dir1/a.ts":
|
||||
`import { y } from '../dir2/bar';
|
||||
export const a = 10;
|
||||
y;`,
|
||||
|
||||
"/src/dir2/bar.ts":
|
||||
`import { b } from '../dir1/other';
|
||||
import { a } from '../dir1/a';
|
||||
|
||||
export const y = b + a;
|
||||
`,
|
||||
},
|
||||
interactiveRefactorArguments: { targetFile: "/src/dir2/bar.ts" }
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @module: nodenext
|
||||
|
||||
// @Filename: /bar.cts
|
||||
////const a = 2;
|
||||
|
||||
// @Filename: /node_modules/esm-only/package.json
|
||||
//// {
|
||||
//// "name": "esm-only",
|
||||
//// "version": "1.0.0",
|
||||
//// "type": "module",
|
||||
//// "exports": {
|
||||
//// ".": {
|
||||
//// "import": "./index.js"
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
|
||||
// @Filename: /node_modules/esm-only/index.d.ts
|
||||
//// export declare const esm: any;
|
||||
|
||||
// @Filename: /main.mts
|
||||
//// import { esm } from "esm-only";
|
||||
//// [|esm.ohno;|]
|
||||
|
||||
verify.moveToFile({
|
||||
newFileContents: {
|
||||
"/main.mts":``,
|
||||
|
||||
"/bar.cts":
|
||||
`const a = 2;
|
||||
esm.ohno;
|
||||
`,
|
||||
},
|
||||
interactiveRefactorArguments: { targetFile: "/bar.cts" }
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//@Filename: /bar.ts
|
||||
////import { } from './somefile';
|
||||
////const a = 12;
|
||||
|
||||
// @Filename: /a.ts
|
||||
////[|const q = 0;
|
||||
////const t = 2;
|
||||
////function f() {}
|
||||
////class C {}
|
||||
////enum E {}
|
||||
////namespace N { export const h = 0; }
|
||||
////type T = number;
|
||||
////interface I {}|]
|
||||
|
||||
verify.moveToFile({
|
||||
newFileContents: {
|
||||
"/a.ts":
|
||||
``,
|
||||
|
||||
"/bar.ts":
|
||||
`import { } from './somefile';
|
||||
const a = 12;
|
||||
const q = 0;
|
||||
const t = 2;
|
||||
function f() { }
|
||||
class C { }
|
||||
enum E { }
|
||||
namespace N { export const h = 0; }
|
||||
type T = number;
|
||||
interface I { }
|
||||
`,
|
||||
},
|
||||
interactiveRefactorArguments: { targetFile: "/bar.ts" }
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /bar.ts
|
||||
////const q = 0;
|
||||
|
||||
// @Filename: /a.ts
|
||||
////// header comment
|
||||
////
|
||||
////import { } from './other';
|
||||
////import type { } from './other';
|
||||
////
|
||||
////export const p = 0;
|
||||
////export const b = 1;
|
||||
////[|const y = p + b;|]
|
||||
|
||||
// @Filename: /other.ts
|
||||
////export const t = 2;
|
||||
|
||||
|
||||
verify.moveToFile({
|
||||
newFileContents: {
|
||||
"/a.ts":
|
||||
`// header comment
|
||||
|
||||
import { } from './other';
|
||||
import type { } from './other';
|
||||
|
||||
export const p = 0;
|
||||
export const b = 1;
|
||||
`,
|
||||
|
||||
"/bar.ts":
|
||||
`import { p, b } from './a';
|
||||
|
||||
const q = 0;
|
||||
const y = p + b;
|
||||
`,
|
||||
},
|
||||
interactiveRefactorArguments: { targetFile: "/bar.ts" },
|
||||
|
||||
preferences: {
|
||||
quotePreference: "single",
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////[|interface ka {
|
||||
//// name: string;
|
||||
////}|]
|
||||
|
||||
verify.moveToFile({
|
||||
newFileContents: {
|
||||
"/a.ts":
|
||||
``,
|
||||
|
||||
"/bar.ts":
|
||||
`interface ka {
|
||||
name: string;
|
||||
}
|
||||
`,
|
||||
},
|
||||
interactiveRefactorArguments: { targetFile: "/bar.ts" }
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//@Filename: /bar.ts
|
||||
////const q = "test";
|
||||
|
||||
// @Filename: /a.ts
|
||||
////const z = 1;
|
||||
////[|const y = z + 2;|]
|
||||
////const t = y + 1;
|
||||
|
||||
verify.moveToFile({
|
||||
newFileContents: {
|
||||
"/a.ts":
|
||||
`import { y } from "./bar";
|
||||
|
||||
export const z = 1;
|
||||
const t = y + 1;`,
|
||||
|
||||
"/bar.ts":
|
||||
`import { z } from "./a";
|
||||
|
||||
const q = "test";
|
||||
export const y = z + 2;
|
||||
`,
|
||||
},
|
||||
interactiveRefactorArguments: { targetFile: "/bar.ts" }
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//@Filename: /bar.ts
|
||||
////import './someFile';
|
||||
////
|
||||
////const q = 20;
|
||||
|
||||
// @Filename: /a.ts
|
||||
////import { b } from './other';
|
||||
////const p = 0;
|
||||
////[|const y: Date = p + b;|]
|
||||
|
||||
// @Filename: /other.ts
|
||||
////export const b = 2;
|
||||
|
||||
verify.moveToFile({
|
||||
newFileContents: {
|
||||
"/a.ts":
|
||||
`export const p = 0;
|
||||
`,
|
||||
|
||||
"/bar.ts":
|
||||
`import { p } from './a';
|
||||
import { b } from './other';
|
||||
import './someFile';
|
||||
|
||||
const q = 20;
|
||||
const y: Date = p + b;
|
||||
`,
|
||||
},
|
||||
interactiveRefactorArguments: { targetFile: "/bar.ts" }
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @module: commonjs
|
||||
// @allowJs: true
|
||||
|
||||
//@Filename: /bar.js
|
||||
////const x = 0;
|
||||
|
||||
//@Filename: /a.js
|
||||
////const { a, b } = require("./other");
|
||||
////const p = 0;
|
||||
////[|const y = p;
|
||||
////const z = 0;
|
||||
////exports.z = 0;|]
|
||||
////a; y; z;
|
||||
|
||||
//@Filename: /other.js
|
||||
////const a = 1;
|
||||
////exports.a = a;
|
||||
|
||||
//@Filename: /user.ts
|
||||
////const { x, y } = require("./a");
|
||||
|
||||
verify.moveToFile({
|
||||
newFileContents: {
|
||||
"/a.js":
|
||||
`const { y, z } = require("./bar");
|
||||
const { a, b } = require("./other");
|
||||
const p = 0;
|
||||
exports.p = p;
|
||||
a; y; z;`,
|
||||
|
||||
"/bar.js":
|
||||
`const { p } = require("./a");
|
||||
|
||||
const x = 0;
|
||||
const y = p;
|
||||
exports.y = y;
|
||||
const z = 0;
|
||||
exports.z = 0;
|
||||
`,
|
||||
},
|
||||
interactiveRefactorArguments: { targetFile: "/bar.js" }
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @verbatimModuleSyntax: true
|
||||
// @module: commonjs
|
||||
// @allowJs: true
|
||||
|
||||
//@Filename: /a.js
|
||||
////const { a, b } = require("./other");
|
||||
////const p = 0;
|
||||
////[|const y = p;
|
||||
////const z = 0;
|
||||
////exports.z = 0;|]
|
||||
////a; y; z;
|
||||
|
||||
//@Filename: /other.js
|
||||
////const a = 1;
|
||||
////exports.a = a;
|
||||
|
||||
//@Filename: /user.ts
|
||||
////const { x, y } = require("./a");
|
||||
|
||||
verify.moveToFile({
|
||||
newFileContents: {
|
||||
"/a.js":
|
||||
`const { y, z } = require("./bar");
|
||||
const { a, b } = require("./other");
|
||||
const p = 0;
|
||||
exports.p = p;
|
||||
a; y; z;`,
|
||||
|
||||
"/bar.js":
|
||||
`const { p } = require("./a");
|
||||
|
||||
const y = p;
|
||||
exports.y = y;
|
||||
const z = 0;
|
||||
exports.z = 0;
|
||||
`,
|
||||
},
|
||||
interactiveRefactorArguments: { targetFile: "/bar.js" }
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @verbatimModuleSyntax: true
|
||||
//@module: esnext
|
||||
//moduleResolution: bundler
|
||||
|
||||
// @Filename: /bar.ts
|
||||
////import {} from "./somefile";
|
||||
|
||||
// @Filename: /a.ts
|
||||
////import { type A } from "./other";
|
||||
////import type { B } from "./other";
|
||||
////[|function f(a: B) {}|]
|
||||
|
||||
// @Filename: /other.ts
|
||||
////export type B = {};
|
||||
////export interface A {
|
||||
//// x: number;
|
||||
////}
|
||||
|
||||
|
||||
verify.moveToFile({
|
||||
newFileContents: {
|
||||
"/a.ts":
|
||||
`import { type A } from "./other";
|
||||
`,
|
||||
"/bar.ts":
|
||||
`import type { B } from "./other";
|
||||
import {} from "./somefile";
|
||||
function f(a: B) { }
|
||||
`,
|
||||
},
|
||||
interactiveRefactorArguments: { targetFile: "/bar.ts" }
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /bar.ts
|
||||
////const a = 1;
|
||||
|
||||
// @Filename: /a.ts
|
||||
////import { a } from 'doesnt-exist';
|
||||
////[|a();|]
|
||||
|
||||
verify.moveToFile({
|
||||
newFileContents: {
|
||||
"/a.ts":
|
||||
``,
|
||||
|
||||
"/bar.ts":
|
||||
`import { a } from "doesnt-exist";
|
||||
|
||||
const a = 1;
|
||||
a();
|
||||
`,
|
||||
},
|
||||
interactiveRefactorArguments: { targetFile: "/bar.ts" }
|
||||
});
|
||||
Reference in New Issue
Block a user