mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Remove "generate types" code (#31075)
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
namespace ts.codefix {
|
||||
const fixName = "fixCannotFindModule";
|
||||
const fixIdInstallTypesPackage = "installTypesPackage";
|
||||
const fixIdGenerateTypes = "generateTypes";
|
||||
|
||||
const errorCodeCannotFindModule = Diagnostics.Cannot_find_module_0.code;
|
||||
const errorCodes = [
|
||||
@@ -17,13 +16,12 @@ namespace ts.codefix {
|
||||
if (packageName === undefined) return undefined;
|
||||
const typesPackageName = getTypesPackageNameToInstall(packageName, host, context.errorCode);
|
||||
return typesPackageName === undefined
|
||||
? singleElementArray(tryGetGenerateTypesAction(context, packageName))
|
||||
? []
|
||||
: [createCodeFixAction(fixName, /*changes*/ [], [Diagnostics.Install_0, typesPackageName], fixIdInstallTypesPackage, Diagnostics.Install_all_missing_types_packages, getInstallCommand(sourceFile.fileName, typesPackageName))];
|
||||
},
|
||||
fixIds: [fixIdInstallTypesPackage, fixIdGenerateTypes],
|
||||
fixIds: [fixIdInstallTypesPackage],
|
||||
getAllCodeActions: context => {
|
||||
let savedTypesDir: string | null | undefined = null; // tslint:disable-line no-null-keyword
|
||||
return codeFixAll(context, errorCodes, (changes, diag, commands) => {
|
||||
return codeFixAll(context, errorCodes, (_changes, diag, commands) => {
|
||||
const packageName = tryGetImportedPackageName(diag.file, diag.start);
|
||||
if (packageName === undefined) return undefined;
|
||||
switch (context.fixId) {
|
||||
@@ -34,12 +32,6 @@ namespace ts.codefix {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case fixIdGenerateTypes: {
|
||||
const typesDir = savedTypesDir !== null ? savedTypesDir : savedTypesDir = getOrCreateTypesDirectory(changes, context);
|
||||
const command = typesDir === undefined ? undefined : tryGenerateTypes(typesDir, packageName, context);
|
||||
if (command) commands.push(command);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Debug.fail(`Bad fixId: ${context.fixId}`);
|
||||
}
|
||||
@@ -47,88 +39,6 @@ namespace ts.codefix {
|
||||
},
|
||||
});
|
||||
|
||||
function tryGetGenerateTypesAction(context: CodeFixContextBase, packageName: string): CodeFixAction | undefined {
|
||||
let command: GenerateTypesAction | undefined;
|
||||
const changes = textChanges.ChangeTracker.with(context, t => {
|
||||
const typesDir = getOrCreateTypesDirectory(t, context);
|
||||
command = typesDir === undefined ? undefined : tryGenerateTypes(typesDir, packageName, context);
|
||||
});
|
||||
return command && createCodeFixAction(fixName, changes, [Diagnostics.Generate_types_for_0, packageName], fixIdGenerateTypes, Diagnostics.Generate_types_for_all_packages_without_types, command);
|
||||
}
|
||||
|
||||
function tryGenerateTypes(typesDir: string, packageName: string, context: CodeFixContextBase): GenerateTypesAction | undefined {
|
||||
const file = context.sourceFile.fileName;
|
||||
const fileToGenerateTypesFor = tryResolveJSModule(packageName, getDirectoryPath(file), context.host as ModuleResolutionHost); // TODO: GH#18217
|
||||
if (fileToGenerateTypesFor === undefined) return undefined;
|
||||
|
||||
const outputFileName = resolvePath(getDirectoryPath(context.program.getCompilerOptions().configFile!.fileName), typesDir, packageName + ".d.ts");
|
||||
if (context.host.fileExists!(outputFileName)) return undefined;
|
||||
return { type: "generate types", file, fileToGenerateTypesFor, outputFileName };
|
||||
}
|
||||
|
||||
// If no types directory exists yet, adds it to tsconfig.json
|
||||
function getOrCreateTypesDirectory(changes: textChanges.ChangeTracker, context: CodeFixContextBase): string | undefined {
|
||||
const { configFile } = context.program.getCompilerOptions();
|
||||
if (!configFile) return undefined;
|
||||
|
||||
const tsconfigObjectLiteral = getTsConfigObjectLiteralExpression(configFile);
|
||||
if (!tsconfigObjectLiteral) return undefined;
|
||||
|
||||
const compilerOptionsProperty = findJsonProperty(tsconfigObjectLiteral, "compilerOptions");
|
||||
if (!compilerOptionsProperty) {
|
||||
const newCompilerOptions = createObjectLiteral([makeDefaultBaseUrl(), makeDefaultPaths()]);
|
||||
changes.insertNodeAtObjectStart(configFile, tsconfigObjectLiteral, createJsonPropertyAssignment("compilerOptions", newCompilerOptions));
|
||||
return defaultTypesDirectoryName;
|
||||
}
|
||||
|
||||
const compilerOptions = compilerOptionsProperty.initializer;
|
||||
if (!isObjectLiteralExpression(compilerOptions)) return defaultTypesDirectoryName;
|
||||
|
||||
const baseUrl = getOrAddBaseUrl(changes, configFile, compilerOptions);
|
||||
const typesDirectoryFromPathMapping = getOrAddPathMapping(changes, configFile, compilerOptions);
|
||||
return combinePaths(baseUrl, typesDirectoryFromPathMapping);
|
||||
}
|
||||
|
||||
const defaultBaseUrl = ".";
|
||||
function makeDefaultBaseUrl(): PropertyAssignment {
|
||||
return createJsonPropertyAssignment("baseUrl", createStringLiteral(defaultBaseUrl));
|
||||
}
|
||||
function getOrAddBaseUrl(changes: textChanges.ChangeTracker, tsconfig: TsConfigSourceFile, compilerOptions: ObjectLiteralExpression): string {
|
||||
const baseUrlProp = findJsonProperty(compilerOptions, "baseUrl");
|
||||
if (baseUrlProp) {
|
||||
return isStringLiteral(baseUrlProp.initializer) ? baseUrlProp.initializer.text : defaultBaseUrl;
|
||||
}
|
||||
else {
|
||||
changes.insertNodeAtObjectStart(tsconfig, compilerOptions, makeDefaultBaseUrl());
|
||||
return defaultBaseUrl;
|
||||
}
|
||||
}
|
||||
|
||||
const defaultTypesDirectoryName = "types";
|
||||
function makeDefaultPathMapping(): PropertyAssignment {
|
||||
return createJsonPropertyAssignment("*", createArrayLiteral([createStringLiteral(`${defaultTypesDirectoryName}/*`)]));
|
||||
}
|
||||
function makeDefaultPaths(): PropertyAssignment {
|
||||
return createJsonPropertyAssignment("paths", createObjectLiteral([makeDefaultPathMapping()]));
|
||||
}
|
||||
function getOrAddPathMapping(changes: textChanges.ChangeTracker, tsconfig: TsConfigSourceFile, compilerOptions: ObjectLiteralExpression) {
|
||||
const paths = findJsonProperty(compilerOptions, "paths");
|
||||
if (!paths || !isObjectLiteralExpression(paths.initializer)) {
|
||||
changes.insertNodeAtObjectStart(tsconfig, compilerOptions, makeDefaultPaths());
|
||||
return defaultTypesDirectoryName;
|
||||
}
|
||||
|
||||
// Look for an existing path mapping. Should look like `"*": "foo/*"`.
|
||||
const existing = firstDefined(paths.initializer.properties, prop =>
|
||||
isPropertyAssignment(prop) && isStringLiteral(prop.name) && prop.name.text === "*" && isArrayLiteralExpression(prop.initializer)
|
||||
? firstDefined(prop.initializer.elements, value => isStringLiteral(value) ? tryRemoveSuffix(value.text, "/*") : undefined)
|
||||
: undefined);
|
||||
if (existing) return existing;
|
||||
|
||||
changes.insertNodeAtObjectStart(tsconfig, paths.initializer, makeDefaultPathMapping());
|
||||
return defaultTypesDirectoryName;
|
||||
}
|
||||
|
||||
function getInstallCommand(fileName: string, packageName: string): InstallPackageAction {
|
||||
return { type: "install package", file: fileName, packageName };
|
||||
}
|
||||
|
||||
@@ -1,252 +0,0 @@
|
||||
namespace ts {
|
||||
export function generateTypesForModule(name: string, moduleValue: unknown, formatSettings: FormatCodeSettings): string {
|
||||
return generateTypesForModuleOrGlobal(name, moduleValue, formatSettings, OutputKind.ExportEquals);
|
||||
}
|
||||
|
||||
export function generateTypesForGlobal(name: string, globalValue: unknown, formatSettings: FormatCodeSettings): string {
|
||||
return generateTypesForModuleOrGlobal(name, globalValue, formatSettings, OutputKind.Global);
|
||||
}
|
||||
|
||||
function generateTypesForModuleOrGlobal(name: string, globalValue: unknown, formatSettings: FormatCodeSettings, outputKind: OutputKind.ExportEquals | OutputKind.Global): string {
|
||||
return valueInfoToDeclarationFileText(inspectValue(name, globalValue), formatSettings, outputKind);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function valueInfoToDeclarationFileText(valueInfo: ValueInfo, formatSettings: FormatCodeSettings, outputKind: OutputKind.ExportEquals | OutputKind.Global = OutputKind.ExportEquals): string {
|
||||
return textChanges.getNewFileText(toStatements(valueInfo, outputKind), ScriptKind.TS, formatSettings.newLineCharacter || "\n", formatting.getFormatContext(formatSettings));
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
const enum OutputKind { ExportEquals, NamedExport, NamespaceMember, Global }
|
||||
function toNamespaceMemberStatements(info: ValueInfo): ReadonlyArray<Statement> {
|
||||
return toStatements(info, OutputKind.NamespaceMember);
|
||||
}
|
||||
function toStatements(info: ValueInfo, kind: OutputKind): ReadonlyArray<Statement> {
|
||||
const isDefault = info.name === InternalSymbolName.Default;
|
||||
const name = isDefault ? "_default" : info.name;
|
||||
if (!isValidIdentifier(name) || isDefault && kind !== OutputKind.NamedExport) return emptyArray;
|
||||
|
||||
const modifiers = isDefault && info.kind === ValueKind.FunctionOrClass ? [createModifier(SyntaxKind.ExportKeyword), createModifier(SyntaxKind.DefaultKeyword)]
|
||||
: kind === OutputKind.Global || kind === OutputKind.ExportEquals ? [createModifier(SyntaxKind.DeclareKeyword)]
|
||||
: kind === OutputKind.NamedExport ? [createModifier(SyntaxKind.ExportKeyword)]
|
||||
: undefined;
|
||||
const exportEquals = () => kind === OutputKind.ExportEquals ? [exportEqualsOrDefault(info.name, /*isExportEquals*/ true)] : emptyArray;
|
||||
const exportDefault = () => isDefault ? [exportEqualsOrDefault("_default", /*isExportEquals*/ false)] : emptyArray;
|
||||
|
||||
switch (info.kind) {
|
||||
case ValueKind.FunctionOrClass:
|
||||
return [...exportEquals(), ...functionOrClassToStatements(modifiers, name, info)];
|
||||
case ValueKind.Object:
|
||||
const { members, hasNontrivialPrototype } = info;
|
||||
if (!hasNontrivialPrototype) {
|
||||
if (kind === OutputKind.ExportEquals) {
|
||||
return flatMap(members, v => toStatements(v, OutputKind.NamedExport));
|
||||
}
|
||||
if (members.some(m => m.kind === ValueKind.FunctionOrClass)) {
|
||||
// If some member is a function, use a namespace so it gets a FunctionDeclaration or ClassDeclaration.
|
||||
return [...exportDefault(), createNamespace(modifiers, name, flatMap(members, toNamespaceMemberStatements))];
|
||||
}
|
||||
}
|
||||
// falls through
|
||||
case ValueKind.Const:
|
||||
case ValueKind.Array: {
|
||||
const comment = info.kind === ValueKind.Const ? info.comment : undefined;
|
||||
const constVar = createVariableStatement(modifiers, createVariableDeclarationList([createVariableDeclaration(name, toType(info))], NodeFlags.Const));
|
||||
return [...exportEquals(), ...exportDefault(), addComment(constVar, comment)];
|
||||
}
|
||||
default:
|
||||
return Debug.assertNever(info);
|
||||
}
|
||||
}
|
||||
function exportEqualsOrDefault(name: string, isExportEquals: boolean): ExportAssignment {
|
||||
return createExportAssignment(/*decorators*/ undefined, /*modifiers*/ undefined, isExportEquals, createIdentifier(name));
|
||||
}
|
||||
|
||||
function functionOrClassToStatements(modifiers: Modifiers, name: string, { source, prototypeMembers, namespaceMembers }: ValueInfoFunctionOrClass): ReadonlyArray<Statement> {
|
||||
const fnAst = parseClassOrFunctionBody(source);
|
||||
const { parameters, returnType } = fnAst === undefined ? { parameters: emptyArray, returnType: anyType() } : getParametersAndReturnType(fnAst);
|
||||
const protoOrInstanceMembers = createMap<MethodDeclaration | PropertyDeclaration>();
|
||||
if (typeof fnAst === "object") getConstructorFunctionInstanceProperties(fnAst, protoOrInstanceMembers);
|
||||
for (const p of prototypeMembers) {
|
||||
// ignore non-functions on the prototype
|
||||
if (p.kind === ValueKind.FunctionOrClass) {
|
||||
const m = tryGetMethod(p);
|
||||
if (m) {
|
||||
protoOrInstanceMembers.set(p.name, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const classStaticMembers: ClassElement[] | undefined =
|
||||
protoOrInstanceMembers.size !== 0 || fnAst === undefined || typeof fnAst !== "number" && fnAst.kind === SyntaxKind.Constructor ? [] : undefined;
|
||||
|
||||
const namespaceStatements = flatMap(namespaceMembers, info => {
|
||||
if (!isValidIdentifier(info.name)) return undefined;
|
||||
if (classStaticMembers) {
|
||||
switch (info.kind) {
|
||||
case ValueKind.Object:
|
||||
if (info.members.some(m => m.kind === ValueKind.FunctionOrClass)) {
|
||||
break;
|
||||
}
|
||||
// falls through
|
||||
case ValueKind.Array:
|
||||
case ValueKind.Const:
|
||||
classStaticMembers.push(
|
||||
addComment(
|
||||
createProperty(/*decorators*/ undefined, [createModifier(SyntaxKind.StaticKeyword)], info.name, /*questionOrExclamationToken*/ undefined, toType(info), /*initializer*/ undefined),
|
||||
info.kind === ValueKind.Const ? info.comment : undefined));
|
||||
return undefined;
|
||||
case ValueKind.FunctionOrClass:
|
||||
if (!info.namespaceMembers.length) { // Else, can't merge a static method with a namespace. Must make it a function on the namespace.
|
||||
const sig = tryGetMethod(info, [createModifier(SyntaxKind.StaticKeyword)]);
|
||||
if (sig) {
|
||||
classStaticMembers.push(sig);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Debug.assertNever(info);
|
||||
}
|
||||
}
|
||||
return toStatements(info, OutputKind.NamespaceMember);
|
||||
});
|
||||
|
||||
const decl = classStaticMembers
|
||||
? createClassDeclaration(
|
||||
/*decorators*/ undefined,
|
||||
modifiers,
|
||||
name,
|
||||
/*typeParameters*/ undefined,
|
||||
/*heritageClauses*/ undefined,
|
||||
[
|
||||
...classStaticMembers,
|
||||
...(parameters.length ? [createConstructor(/*decorators*/ undefined, /*modifiers*/ undefined, parameters, /*body*/ undefined)] : emptyArray),
|
||||
...arrayFrom(protoOrInstanceMembers.values()),
|
||||
])
|
||||
: createFunctionDeclaration(/*decorators*/ undefined, modifiers, /*asteriskToken*/ undefined, name, /*typeParameters*/ undefined, parameters, returnType, /*body*/ undefined);
|
||||
return [decl, ...(namespaceStatements.length === 0 ? emptyArray : [createNamespace(modifiers && modifiers.map(m => getSynthesizedDeepClone(m)), name, namespaceStatements)])];
|
||||
}
|
||||
|
||||
function tryGetMethod({ name, source }: ValueInfoFunctionOrClass, modifiers?: Modifiers): MethodDeclaration | undefined {
|
||||
if (!isValidIdentifier(name)) return undefined;
|
||||
const fnAst = parseClassOrFunctionBody(source);
|
||||
if (fnAst === undefined || (typeof fnAst !== "number" && fnAst.kind === SyntaxKind.Constructor)) return undefined;
|
||||
const sig = getParametersAndReturnType(fnAst);
|
||||
return sig && createMethod(
|
||||
/*decorators*/ undefined,
|
||||
modifiers,
|
||||
/*asteriskToken*/ undefined,
|
||||
name,
|
||||
/*questionToken*/ undefined,
|
||||
/*typeParameters*/ undefined,
|
||||
sig.parameters,
|
||||
sig.returnType,
|
||||
/*body*/ undefined);
|
||||
}
|
||||
|
||||
function toType(info: ValueInfo): TypeNode {
|
||||
switch (info.kind) {
|
||||
case ValueKind.Const:
|
||||
return createTypeReferenceNode(info.typeName, /*typeArguments*/ undefined);
|
||||
case ValueKind.Array:
|
||||
return createArrayTypeNode(toType(info.inner));
|
||||
case ValueKind.FunctionOrClass:
|
||||
return createTypeReferenceNode("Function", /*typeArguments*/ undefined); // Normally we create a FunctionDeclaration, but this can happen for a function in an array.
|
||||
case ValueKind.Object:
|
||||
return createTypeLiteralNode(info.members.map(m => createPropertySignature(/*modifiers*/ undefined, toPropertyName(m.name), /*questionToken*/ undefined, toType(m), /*initializer*/ undefined)));
|
||||
default:
|
||||
return Debug.assertNever(info);
|
||||
}
|
||||
}
|
||||
function toPropertyName(name: string): Identifier | StringLiteral {
|
||||
return isIdentifierText(name, ScriptTarget.ESNext) ? createIdentifier(name) : createStringLiteral(name);
|
||||
}
|
||||
|
||||
// Parses assignments to "this.x" in the constructor into class property declarations
|
||||
function getConstructorFunctionInstanceProperties(fnAst: FunctionOrConstructorNode, members: Map<MethodDeclaration | PropertyDeclaration>): void {
|
||||
forEachOwnNodeOfFunction(fnAst, node => {
|
||||
if (isAssignmentExpression(node, /*excludeCompoundAssignment*/ true) &&
|
||||
isPropertyAccessExpression(node.left) && node.left.expression.kind === SyntaxKind.ThisKeyword) {
|
||||
const name = node.left.name.text;
|
||||
if (!isJsPrivate(name)) {
|
||||
getOrUpdate(members, name, () => createProperty(/*decorators*/ undefined, /*modifiers*/ undefined, name, /*questionOrExclamationToken*/ undefined, anyType(), /*initializer*/ undefined));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
interface ParametersAndReturnType { readonly parameters: ReadonlyArray<ParameterDeclaration>; readonly returnType: TypeNode; }
|
||||
function getParametersAndReturnType(fnAst: FunctionOrConstructor): ParametersAndReturnType {
|
||||
if (typeof fnAst === "number") {
|
||||
return { parameters: fill(fnAst, i => makeParameter(`p${i}`, anyType())), returnType: anyType() };
|
||||
}
|
||||
let usedArguments = false, hasReturn = false;
|
||||
forEachOwnNodeOfFunction(fnAst, node => {
|
||||
usedArguments = usedArguments || isIdentifier(node) && node.text === "arguments";
|
||||
hasReturn = hasReturn || isReturnStatement(node) && !!node.expression && node.expression.kind !== SyntaxKind.VoidExpression;
|
||||
});
|
||||
const parameters = [
|
||||
...fnAst.parameters.map(p => makeParameter(`${p.name.getText()}`, inferParameterType(fnAst, p))),
|
||||
...(usedArguments ? [makeRestParameter()] : emptyArray),
|
||||
];
|
||||
return { parameters, returnType: hasReturn ? anyType() : createKeywordTypeNode(SyntaxKind.VoidKeyword) };
|
||||
}
|
||||
function makeParameter(name: string, type: TypeNode): ParameterDeclaration {
|
||||
return createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name, /*questionToken*/ undefined, type);
|
||||
}
|
||||
function makeRestParameter(): ParameterDeclaration {
|
||||
return createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, createToken(SyntaxKind.DotDotDotToken), "args", /*questionToken*/ undefined, createArrayTypeNode(anyType()));
|
||||
}
|
||||
|
||||
type FunctionOrConstructorNode = FunctionExpression | ArrowFunction | ConstructorDeclaration | MethodDeclaration;
|
||||
type FunctionOrConstructor = FunctionOrConstructorNode | number; // number is for native function
|
||||
/** Returns 'undefined' for class with no declared constructor */
|
||||
function parseClassOrFunctionBody(source: string | number): FunctionOrConstructor | undefined {
|
||||
if (typeof source === "number") return source;
|
||||
const classOrFunction = tryCast(parseExpression(source), (node): node is FunctionExpression | ArrowFunction | ClassExpression => isFunctionExpression(node) || isArrowFunction(node) || isClassExpression(node));
|
||||
return classOrFunction
|
||||
? isClassExpression(classOrFunction) ? find(classOrFunction.members, isConstructorDeclaration) : classOrFunction
|
||||
// If that didn't parse, it's a method `m() {}`. Parse again inside of an object literal.
|
||||
: cast(first(cast(parseExpression(`{ ${source} }`), isObjectLiteralExpression).properties), isMethodDeclaration);
|
||||
}
|
||||
|
||||
function parseExpression(expr: string): Expression {
|
||||
const text = `const _ = ${expr}`;
|
||||
const srcFile = createSourceFile("test.ts", text, ScriptTarget.Latest, /*setParentNodes*/ true);
|
||||
return first(cast(first(srcFile.statements), isVariableStatement).declarationList.declarations).initializer!;
|
||||
}
|
||||
|
||||
function inferParameterType(_fn: FunctionOrConstructor, _param: ParameterDeclaration): TypeNode {
|
||||
// TODO: Inspect function body for clues (see inferFromUsage.ts)
|
||||
return anyType();
|
||||
}
|
||||
|
||||
// Descends through all nodes in a function, but not in nested functions.
|
||||
function forEachOwnNodeOfFunction(fnAst: FunctionOrConstructorNode, cb: (node: Node) => void) {
|
||||
fnAst.body!.forEachChild(function recur(node) {
|
||||
cb(node);
|
||||
if (!isFunctionLike(node)) node.forEachChild(recur);
|
||||
});
|
||||
}
|
||||
|
||||
function isValidIdentifier(name: string): boolean {
|
||||
const keyword = stringToToken(name);
|
||||
return !(keyword && isNonContextualKeyword(keyword)) && isIdentifierText(name, ScriptTarget.ESNext);
|
||||
}
|
||||
|
||||
type Modifiers = ReadonlyArray<Modifier> | undefined;
|
||||
|
||||
function addComment<T extends Node>(node: T, comment: string | undefined): T {
|
||||
if (comment !== undefined) addSyntheticLeadingComment(node, SyntaxKind.SingleLineCommentTrivia, comment);
|
||||
return node;
|
||||
}
|
||||
|
||||
function anyType(): KeywordTypeNode {
|
||||
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
|
||||
}
|
||||
|
||||
function createNamespace(modifiers: Modifiers, name: string, statements: ReadonlyArray<Statement>): NamespaceDeclaration {
|
||||
return createModuleDeclaration(/*decorators*/ undefined, modifiers, createIdentifier(name), createModuleBlock(statements), NodeFlags.Namespace) as NamespaceDeclaration;
|
||||
}
|
||||
}
|
||||
@@ -1833,30 +1833,15 @@ namespace ts {
|
||||
function applyCodeActionCommand(fileName: Path, action: CodeActionCommand[]): Promise<ApplyCodeActionCommandResult[]>;
|
||||
function applyCodeActionCommand(fileName: Path | CodeActionCommand | CodeActionCommand[], actionOrFormatSettingsOrUndefined?: CodeActionCommand | CodeActionCommand[] | FormatCodeSettings): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]> {
|
||||
const action = typeof fileName === "string" ? actionOrFormatSettingsOrUndefined as CodeActionCommand | CodeActionCommand[] : fileName as CodeActionCommand[];
|
||||
const formatSettings = typeof fileName !== "string" ? actionOrFormatSettingsOrUndefined as FormatCodeSettings : undefined;
|
||||
return isArray(action) ? Promise.all(action.map(a => applySingleCodeActionCommand(a, formatSettings))) : applySingleCodeActionCommand(action, formatSettings);
|
||||
return isArray(action) ? Promise.all(action.map(a => applySingleCodeActionCommand(a))) : applySingleCodeActionCommand(action);
|
||||
}
|
||||
|
||||
function applySingleCodeActionCommand(action: CodeActionCommand, formatSettings: FormatCodeSettings | undefined): Promise<ApplyCodeActionCommandResult> {
|
||||
function applySingleCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult> {
|
||||
const getPath = (path: string): Path => toPath(path, currentDirectory, getCanonicalFileName);
|
||||
switch (action.type) {
|
||||
case "install package":
|
||||
return host.installPackage
|
||||
? host.installPackage({ fileName: getPath(action.file), packageName: action.packageName })
|
||||
: Promise.reject("Host does not implement `installPackage`");
|
||||
case "generate types": {
|
||||
const { fileToGenerateTypesFor, outputFileName } = action;
|
||||
if (!host.inspectValue) return Promise.reject("Host does not implement `installPackage`");
|
||||
const valueInfoPromise = host.inspectValue({ fileNameToRequire: fileToGenerateTypesFor });
|
||||
return valueInfoPromise.then(valueInfo => {
|
||||
const fullOut = getPath(outputFileName);
|
||||
host.writeFile!(fullOut, valueInfoToDeclarationFileText(valueInfo, formatSettings || testFormatSettings)); // TODO: GH#18217
|
||||
return { successMessage: `Wrote types to '${fullOut}'` };
|
||||
});
|
||||
}
|
||||
default:
|
||||
return Debug.assertNever(action);
|
||||
}
|
||||
Debug.assertEqual(action.type, "install package");
|
||||
return host.installPackage
|
||||
? host.installPackage({ fileName: getPath(action.file), packageName: action.packageName })
|
||||
: Promise.reject("Host does not implement `installPackage`");
|
||||
}
|
||||
|
||||
function getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion | undefined {
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
"codefixes/helpers.ts",
|
||||
"codefixes/fixInvalidImportSyntax.ts",
|
||||
"codefixes/fixStrictClassInitialization.ts",
|
||||
"codefixes/generateTypes.ts",
|
||||
"codefixes/requireInTs.ts",
|
||||
"codefixes/useDefaultImport.ts",
|
||||
"codefixes/fixAddModuleReferTypeMissingTypeof.ts",
|
||||
|
||||
+1
-12
@@ -230,7 +230,6 @@ namespace ts {
|
||||
|
||||
isKnownTypesPackageName?(name: string): boolean;
|
||||
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
|
||||
/* @internal */ inspectValue?(options: InspectValueOptions): Promise<ValueInfo>;
|
||||
writeFile?(fileName: string, content: string): void;
|
||||
|
||||
/* @internal */
|
||||
@@ -534,7 +533,7 @@ namespace ts {
|
||||
|
||||
// Publicly, this type is just `{}`. Internally it is a union of all the actions we use.
|
||||
// See `commands?: {}[]` in protocol.ts
|
||||
export type CodeActionCommand = InstallPackageAction | GenerateTypesAction;
|
||||
export type CodeActionCommand = InstallPackageAction;
|
||||
|
||||
export interface InstallPackageAction {
|
||||
/* @internal */ readonly type: "install package";
|
||||
@@ -542,16 +541,6 @@ namespace ts {
|
||||
/* @internal */ readonly packageName: string;
|
||||
}
|
||||
|
||||
export interface GenerateTypesAction extends GenerateTypesOptions {
|
||||
/* @internal */ readonly type: "generate types";
|
||||
}
|
||||
|
||||
export interface GenerateTypesOptions {
|
||||
readonly file: string; // File that was importing fileToGenerateTypesFor; used for formatting options.
|
||||
readonly fileToGenerateTypesFor: string;
|
||||
readonly outputFileName: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of one or more available refactoring actions, grouped under a parent refactoring.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user