mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-12-12 11:50:54 -06:00
Add codefix to generate types for untyped module (#26588)
This commit is contained in:
parent
7852cf7ed3
commit
c57ff087d6
@ -75,6 +75,7 @@
|
||||
"gulp-typescript": "latest",
|
||||
"istanbul": "latest",
|
||||
"jake": "latest",
|
||||
"lodash": "4.17.10",
|
||||
"merge2": "latest",
|
||||
"minimist": "latest",
|
||||
"mkdirp": "latest",
|
||||
|
||||
@ -1409,9 +1409,12 @@ namespace ts {
|
||||
/**
|
||||
* Tests whether a value is string
|
||||
*/
|
||||
export function isString(text: any): text is string {
|
||||
export function isString(text: unknown): text is string {
|
||||
return typeof text === "string";
|
||||
}
|
||||
export function isNumber(x: unknown): x is number {
|
||||
return typeof x === "number";
|
||||
}
|
||||
|
||||
export function tryCast<TOut extends TIn, TIn = any>(value: TIn | undefined, test: (value: TIn) => value is TOut): TOut | undefined;
|
||||
export function tryCast<T>(value: T, test: (value: T) => boolean): T | undefined;
|
||||
@ -1534,6 +1537,7 @@ namespace ts {
|
||||
* Every function should be assignable to this, but this should not be assignable to every function.
|
||||
*/
|
||||
export type AnyFunction = (...args: never[]) => void;
|
||||
export type AnyConstructor = new (...args: unknown[]) => unknown;
|
||||
|
||||
export namespace Debug {
|
||||
export let currentAssertionLevel = AssertionLevel.None;
|
||||
@ -2125,4 +2129,8 @@ namespace ts {
|
||||
deleted(oldItems[oldIndex++]);
|
||||
}
|
||||
}
|
||||
|
||||
export function fill<T>(length: number, cb: (index: number) => T): T[] {
|
||||
return new Array(length).fill(0).map((_, i) => cb(i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -4671,5 +4671,13 @@
|
||||
"Convert all to async functions": {
|
||||
"category": "Message",
|
||||
"code": 95066
|
||||
},
|
||||
"Generate types for '{0}'": {
|
||||
"category": "Message",
|
||||
"code": 95067
|
||||
},
|
||||
"Generate types for all packages without types": {
|
||||
"category": "Message",
|
||||
"code": 95068
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -235,7 +235,7 @@ namespace ts {
|
||||
|
||||
// Modifiers
|
||||
|
||||
export function createModifier<T extends Modifier["kind"]>(kind: T) {
|
||||
export function createModifier<T extends Modifier["kind"]>(kind: T): Token<T> {
|
||||
return createToken(kind);
|
||||
}
|
||||
|
||||
|
||||
159
src/compiler/inspectValue.ts
Normal file
159
src/compiler/inspectValue.ts
Normal file
@ -0,0 +1,159 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export interface InspectValueOptions {
|
||||
readonly fileNameToRequire: string;
|
||||
}
|
||||
|
||||
export const enum ValueKind { Const, Array, FunctionOrClass, Object }
|
||||
export interface ValueInfoBase {
|
||||
readonly name: string;
|
||||
}
|
||||
export type ValueInfo = ValueInfoSimple | ValueInfoArray | ValueInfoFunctionOrClass | ValueInfoObject;
|
||||
export interface ValueInfoSimple extends ValueInfoBase {
|
||||
readonly kind: ValueKind.Const;
|
||||
readonly typeName: string;
|
||||
readonly comment?: string | undefined;
|
||||
}
|
||||
export interface ValueInfoFunctionOrClass extends ValueInfoBase {
|
||||
readonly kind: ValueKind.FunctionOrClass;
|
||||
readonly source: string | number; // For a native function, this is the length.
|
||||
readonly prototypeMembers: ReadonlyArray<ValueInfo>;
|
||||
readonly namespaceMembers: ReadonlyArray<ValueInfo>;
|
||||
}
|
||||
export interface ValueInfoArray extends ValueInfoBase {
|
||||
readonly kind: ValueKind.Array;
|
||||
readonly inner: ValueInfo;
|
||||
}
|
||||
export interface ValueInfoObject extends ValueInfoBase {
|
||||
readonly kind: ValueKind.Object;
|
||||
readonly members: ReadonlyArray<ValueInfo>;
|
||||
}
|
||||
|
||||
export function inspectModule(fileNameToRequire: string): ValueInfo {
|
||||
return inspectValue(removeFileExtension(getBaseFileName(fileNameToRequire)), tryRequire(fileNameToRequire));
|
||||
}
|
||||
|
||||
export function inspectValue(name: string, value: unknown): ValueInfo {
|
||||
return getValueInfo(name, value, getRecurser());
|
||||
}
|
||||
|
||||
type Recurser = <T>(obj: unknown, name: string, cbOk: () => T, cbFail: (isCircularReference: boolean, keyStack: ReadonlyArray<string>) => T) => T;
|
||||
function getRecurser(): Recurser {
|
||||
const seen = new Set<unknown>();
|
||||
const nameStack: string[] = [];
|
||||
return (obj, name, cbOk, cbFail) => {
|
||||
if (seen.has(obj) || nameStack.length > 4) {
|
||||
return cbFail(seen.has(obj), nameStack);
|
||||
}
|
||||
|
||||
seen.add(obj);
|
||||
nameStack.push(name);
|
||||
const res = cbOk();
|
||||
nameStack.pop();
|
||||
seen.delete(obj);
|
||||
return res;
|
||||
};
|
||||
}
|
||||
|
||||
function getValueInfo(name: string, value: unknown, recurser: Recurser): ValueInfo {
|
||||
return recurser(value, name,
|
||||
(): ValueInfo => {
|
||||
if (typeof value === "function") return getFunctionOrClassInfo(value as AnyFunction, name, recurser);
|
||||
if (typeof value === "object") {
|
||||
const builtin = getBuiltinType(name, value as object, recurser);
|
||||
if (builtin !== undefined) return builtin;
|
||||
const entries = getEntriesOfObject(value as object);
|
||||
return { kind: ValueKind.Object, name, members: flatMap(entries, ({ key, value }) => getValueInfo(key, value, recurser)) };
|
||||
}
|
||||
return { kind: ValueKind.Const, name, typeName: isNullOrUndefined(value) ? "any" : typeof value };
|
||||
},
|
||||
(isCircularReference, keyStack) => anyValue(name, ` ${isCircularReference ? "Circular reference" : "Too-deep object hierarchy"} from ${keyStack.join(".")}`));
|
||||
}
|
||||
|
||||
function getFunctionOrClassInfo(fn: AnyFunction, name: string, recurser: Recurser): ValueInfoFunctionOrClass {
|
||||
const prototypeMembers = getPrototypeMembers(fn, recurser);
|
||||
const namespaceMembers = flatMap(getEntriesOfObject(fn), ({ key, value }) => getValueInfo(key, value, recurser));
|
||||
const toString = cast(Function.prototype.toString.call(fn), isString);
|
||||
const source = stringContains(toString, "{ [native code] }") ? getFunctionLength(fn) : toString;
|
||||
return { kind: ValueKind.FunctionOrClass, name, source, namespaceMembers, prototypeMembers };
|
||||
}
|
||||
|
||||
const builtins: () => ReadonlyMap<AnyConstructor> = memoize(() => {
|
||||
const map = createMap<AnyConstructor>();
|
||||
for (const { key, value } of getEntriesOfObject(global)) {
|
||||
if (typeof value === "function" && typeof value.prototype === "object" && value !== Object) {
|
||||
map.set(key, value as AnyConstructor);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
});
|
||||
function getBuiltinType(name: string, value: object, recurser: Recurser): ValueInfo | undefined {
|
||||
return isArray(value)
|
||||
? { name, kind: ValueKind.Array, inner: value.length && getValueInfo("element", first(value), recurser) || anyValue(name) }
|
||||
: forEachEntry(builtins(), (builtin, builtinName): ValueInfo | undefined =>
|
||||
value instanceof builtin ? { kind: ValueKind.Const, name, typeName: builtinName } : undefined);
|
||||
}
|
||||
|
||||
function getPrototypeMembers(fn: AnyFunction, recurser: Recurser): ReadonlyArray<ValueInfo> {
|
||||
const prototype = fn.prototype as unknown;
|
||||
// tslint:disable-next-line no-unnecessary-type-assertion (TODO: update LKG and it will really be unnecessary)
|
||||
return typeof prototype !== "object" || prototype === null ? emptyArray : mapDefined(getEntriesOfObject(prototype as object), ({ key, value }) =>
|
||||
key === "constructor" ? undefined : getValueInfo(key, value, recurser));
|
||||
}
|
||||
|
||||
const ignoredProperties: ReadonlySet<string> = new Set(["arguments", "caller", "constructor", "eval", "super_"]);
|
||||
const reservedFunctionProperties: ReadonlySet<string> = new Set(Object.getOwnPropertyNames(noop));
|
||||
interface ObjectEntry { readonly key: string; readonly value: unknown; }
|
||||
function getEntriesOfObject(obj: object): ReadonlyArray<ObjectEntry> {
|
||||
const seen = createMap<true>();
|
||||
const entries: ObjectEntry[] = [];
|
||||
let chain = obj;
|
||||
while (!isNullOrUndefined(chain) && chain !== Object.prototype && chain !== Function.prototype) {
|
||||
for (const key of Object.getOwnPropertyNames(chain)) {
|
||||
if (!isJsPrivate(key) &&
|
||||
!ignoredProperties.has(key) &&
|
||||
(typeof obj !== "function" || !reservedFunctionProperties.has(key)) &&
|
||||
// Don't add property from a higher prototype if it already exists in a lower one
|
||||
addToSeen(seen, key)) {
|
||||
const value = safeGetPropertyOfObject(chain, key);
|
||||
// Don't repeat "toString" that matches signature from Object.prototype
|
||||
if (!(key === "toString" && typeof value === "function" && value.length === 0)) {
|
||||
entries.push({ key, value });
|
||||
}
|
||||
}
|
||||
}
|
||||
chain = Object.getPrototypeOf(chain);
|
||||
}
|
||||
return entries.sort((e1, e2) => compareStringsCaseSensitive(e1.key, e2.key));
|
||||
}
|
||||
|
||||
function getFunctionLength(fn: AnyFunction): number {
|
||||
return tryCast(safeGetPropertyOfObject(fn, "length"), isNumber) || 0;
|
||||
}
|
||||
|
||||
function safeGetPropertyOfObject(obj: object, key: string): unknown {
|
||||
const desc = Object.getOwnPropertyDescriptor(obj, key);
|
||||
return desc && desc.value;
|
||||
}
|
||||
|
||||
function isNullOrUndefined(value: unknown): value is null | undefined {
|
||||
return value == null; // tslint:disable-line
|
||||
}
|
||||
|
||||
function anyValue(name: string, comment?: string): ValueInfo {
|
||||
return { kind: ValueKind.Const, name, typeName: "any", comment };
|
||||
}
|
||||
|
||||
export function isJsPrivate(name: string): boolean {
|
||||
return name.startsWith("_");
|
||||
}
|
||||
|
||||
function tryRequire(fileNameToRequire: string): unknown {
|
||||
try {
|
||||
return require(fileNameToRequire);
|
||||
}
|
||||
catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -779,14 +779,23 @@ namespace ts {
|
||||
*/
|
||||
/* @internal */
|
||||
export function resolveJSModule(moduleName: string, initialDir: string, host: ModuleResolutionHost): string {
|
||||
const { resolvedModule, failedLookupLocations } =
|
||||
nodeModuleNameResolverWorker(moduleName, initialDir, { moduleResolution: ModuleResolutionKind.NodeJs, allowJs: true }, host, /*cache*/ undefined, /*jsOnly*/ true);
|
||||
const { resolvedModule, failedLookupLocations } = tryResolveJSModuleWorker(moduleName, initialDir, host);
|
||||
if (!resolvedModule) {
|
||||
throw new Error(`Could not resolve JS module '${moduleName}' starting at '${initialDir}'. Looked in: ${failedLookupLocations.join(", ")}`);
|
||||
}
|
||||
return resolvedModule.resolvedFileName;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function tryResolveJSModule(moduleName: string, initialDir: string, host: ModuleResolutionHost): string | undefined {
|
||||
const { resolvedModule } = tryResolveJSModuleWorker(moduleName, initialDir, host);
|
||||
return resolvedModule && resolvedModule.resolvedFileName;
|
||||
}
|
||||
|
||||
function tryResolveJSModuleWorker(moduleName: string, initialDir: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
|
||||
return nodeModuleNameResolverWorker(moduleName, initialDir, { moduleResolution: ModuleResolutionKind.NodeJs, allowJs: true }, host, /*cache*/ undefined, /*jsOnly*/ true);
|
||||
}
|
||||
|
||||
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache): ResolvedModuleWithFailedLookupLocations {
|
||||
return nodeModuleNameResolverWorker(moduleName, getDirectoryPath(containingFile), compilerOptions, host, cache, /*jsOnly*/ false);
|
||||
}
|
||||
|
||||
@ -52,6 +52,7 @@
|
||||
"resolutionCache.ts",
|
||||
"moduleSpecifiers.ts",
|
||||
"watch.ts",
|
||||
"tsbuild.ts"
|
||||
"tsbuild.ts",
|
||||
"inspectValue.ts",
|
||||
]
|
||||
}
|
||||
|
||||
@ -2502,9 +2502,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
|
||||
const { changes, commands } = this.languageService.getCombinedCodeFix({ type: "file", fileName: this.activeFile.fileName }, fixId, this.formatCodeSettings, ts.emptyOptions);
|
||||
assert.deepEqual<ReadonlyArray<{}> | undefined>(commands, expectedCommands);
|
||||
assert(changes.every(c => c.fileName === this.activeFile.fileName), "TODO: support testing codefixes that touch multiple files");
|
||||
this.applyChanges(changes);
|
||||
this.verifyCurrentFileContent(newFileContent);
|
||||
this.verifyNewContent({ newFileContent }, changes);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3389,6 +3387,19 @@ Actual: ${stringify(fullActual)}`);
|
||||
private getApplicableRefactorsWorker(positionOrRange: number | ts.TextRange, fileName: string, preferences = ts.emptyOptions): ReadonlyArray<ts.ApplicableRefactorInfo> {
|
||||
return this.languageService.getApplicableRefactors(fileName, positionOrRange, preferences) || ts.emptyArray;
|
||||
}
|
||||
|
||||
public generateTypes(examples: ReadonlyArray<FourSlashInterface.GenerateTypesOptions>): void {
|
||||
for (const { name = "example", value, output, outputBaseline } of examples) {
|
||||
const actual = ts.generateTypesForModule(name, value, this.formatCodeSettings);
|
||||
if (outputBaseline) {
|
||||
if (actual === undefined) throw ts.Debug.fail();
|
||||
Harness.Baseline.runBaseline(ts.combinePaths("generateTypes", outputBaseline + ts.Extension.Dts), actual);
|
||||
}
|
||||
else {
|
||||
assert.equal(actual, output, `generateTypes output for ${name} does not match`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateTextRangeForTextChanges({ pos, end }: ts.TextRange, textChanges: ReadonlyArray<ts.TextChange>): ts.TextRange {
|
||||
@ -3442,7 +3453,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
// Parse out the files and their metadata
|
||||
const testData = parseTestData(absoluteBasePath, content, absoluteFileName);
|
||||
const state = new TestState(absoluteBasePath, testType, testData);
|
||||
const output = ts.transpileModule(content, { reportDiagnostics: true });
|
||||
const output = ts.transpileModule(content, { reportDiagnostics: true, compilerOptions: { target: ts.ScriptTarget.ES2015 } });
|
||||
if (output.diagnostics!.length > 0) {
|
||||
throw new Error(`Syntax error in ${absoluteBasePath}: ${output.diagnostics![0].messageText}`);
|
||||
}
|
||||
@ -4512,6 +4523,18 @@ namespace FourSlashInterface {
|
||||
public noMoveToNewFile(): void {
|
||||
this.state.noMoveToNewFile();
|
||||
}
|
||||
|
||||
public generateTypes(...options: GenerateTypesOptions[]): void {
|
||||
this.state.generateTypes(options);
|
||||
}
|
||||
}
|
||||
|
||||
export interface GenerateTypesOptions {
|
||||
readonly name?: string;
|
||||
readonly value: unknown;
|
||||
// Exactly one of these should be set:
|
||||
readonly output?: string;
|
||||
readonly outputBaseline?: string;
|
||||
}
|
||||
|
||||
export class Edit {
|
||||
@ -4901,7 +4924,7 @@ namespace FourSlashInterface {
|
||||
export interface VerifyCodeFixAllOptions {
|
||||
fixId: string;
|
||||
fixAllDescription: string;
|
||||
newFileContent: string;
|
||||
newFileContent: NewFileContent;
|
||||
commands: ReadonlyArray<{}>;
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ namespace ts.server {
|
||||
export const ActionSet: ActionSet = "action::set";
|
||||
export const ActionInvalidate: ActionInvalidate = "action::invalidate";
|
||||
export const ActionPackageInstalled: ActionPackageInstalled = "action::packageInstalled";
|
||||
export const ActionValueInspected: ActionValueInspected = "action::valueInspected";
|
||||
export const EventTypesRegistry: EventTypesRegistry = "event::typesRegistry";
|
||||
export const EventBeginInstallTypes: EventBeginInstallTypes = "event::beginInstallTypes";
|
||||
export const EventEndInstallTypes: EventEndInstallTypes = "event::endInstallTypes";
|
||||
|
||||
@ -2,6 +2,7 @@ declare namespace ts.server {
|
||||
export type ActionSet = "action::set";
|
||||
export type ActionInvalidate = "action::invalidate";
|
||||
export type ActionPackageInstalled = "action::packageInstalled";
|
||||
export type ActionValueInspected = "action::valueInspected";
|
||||
export type EventTypesRegistry = "event::typesRegistry";
|
||||
export type EventBeginInstallTypes = "event::beginInstallTypes";
|
||||
export type EventEndInstallTypes = "event::endInstallTypes";
|
||||
@ -12,7 +13,7 @@ declare namespace ts.server {
|
||||
}
|
||||
|
||||
export interface TypingInstallerResponse {
|
||||
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
|
||||
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | ActionValueInspected | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
|
||||
}
|
||||
|
||||
export interface TypingInstallerRequestWithProjectName {
|
||||
@ -20,7 +21,7 @@ declare namespace ts.server {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export type TypingInstallerRequestUnion = DiscoverTypings | CloseProject | TypesRegistryRequest | InstallPackageRequest;
|
||||
export type TypingInstallerRequestUnion = DiscoverTypings | CloseProject | TypesRegistryRequest | InstallPackageRequest | InspectValueRequest;
|
||||
|
||||
export interface DiscoverTypings extends TypingInstallerRequestWithProjectName {
|
||||
readonly fileNames: string[];
|
||||
@ -47,6 +48,12 @@ declare namespace ts.server {
|
||||
readonly projectRootPath: Path;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface InspectValueRequest {
|
||||
readonly kind: "inspectValue";
|
||||
readonly options: InspectValueOptions;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface TypesRegistryResponse extends TypingInstallerResponse {
|
||||
readonly kind: EventTypesRegistry;
|
||||
@ -59,6 +66,12 @@ declare namespace ts.server {
|
||||
readonly message: string;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface InspectValueResponse {
|
||||
readonly kind: ActionValueInspected;
|
||||
readonly result: ValueInfo;
|
||||
}
|
||||
|
||||
export interface InitializationFailedResponse extends TypingInstallerResponse {
|
||||
readonly kind: EventInitializationFailed;
|
||||
readonly message: string;
|
||||
@ -106,5 +119,5 @@ declare namespace ts.server {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export type TypingInstallerResponseUnion = SetTypings | InvalidateCachedTypings | TypesRegistryResponse | PackageInstalledResponse | InstallTypes | InitializationFailedResponse;
|
||||
export type TypingInstallerResponseUnion = SetTypings | InvalidateCachedTypings | TypesRegistryResponse | PackageInstalledResponse | InspectValueResponse | InstallTypes | InitializationFailedResponse;
|
||||
}
|
||||
|
||||
@ -254,6 +254,11 @@ namespace ts.server {
|
||||
installPackage(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult> {
|
||||
return this.typingsCache.installPackage({ ...options, projectName: this.projectName, projectRootPath: this.toPath(this.currentDirectory) });
|
||||
}
|
||||
/* @internal */
|
||||
inspectValue(options: InspectValueOptions): Promise<ValueInfo> {
|
||||
return this.typingsCache.inspectValue(options);
|
||||
}
|
||||
|
||||
private get typingsCache(): TypingsCache {
|
||||
return this.projectService.typingsCache;
|
||||
}
|
||||
@ -352,6 +357,10 @@ namespace ts.server {
|
||||
return this.projectService.host.readFile(fileName);
|
||||
}
|
||||
|
||||
writeFile(fileName: string, content: string): void {
|
||||
return this.projectService.host.writeFile(fileName, content);
|
||||
}
|
||||
|
||||
fileExists(file: string): boolean {
|
||||
// As an optimization, don't hit the disks for files we already know don't exist
|
||||
// (because we're watching for their creation).
|
||||
|
||||
@ -1829,8 +1829,8 @@ namespace ts.server {
|
||||
private applyCodeActionCommand(args: protocol.ApplyCodeActionCommandRequestArgs): {} {
|
||||
const commands = args.command as CodeActionCommand | CodeActionCommand[]; // They should be sending back the command we sent them.
|
||||
for (const command of toArray(commands)) {
|
||||
const { project } = this.getFileAndProject(command);
|
||||
project.getLanguageService().applyCodeActionCommand(command).then(
|
||||
const { file, project } = this.getFileAndProject(command);
|
||||
project.getLanguageService().applyCodeActionCommand(command, this.getFormatOptions(file)).then(
|
||||
_result => { /* TODO: GH#20447 report success message? */ },
|
||||
_error => { /* TODO: GH#20447 report errors */ });
|
||||
}
|
||||
|
||||
@ -8,6 +8,8 @@ namespace ts.server {
|
||||
export interface ITypingsInstaller {
|
||||
isKnownTypesPackageName(name: string): boolean;
|
||||
installPackage(options: InstallPackageOptionsWithProject): Promise<ApplyCodeActionCommandResult>;
|
||||
/* @internal */
|
||||
inspectValue(options: InspectValueOptions): Promise<ValueInfo>;
|
||||
enqueueInstallTypingsRequest(p: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray<string> | undefined): void;
|
||||
attach(projectService: ProjectService): void;
|
||||
onProjectClosed(p: Project): void;
|
||||
@ -18,6 +20,7 @@ namespace ts.server {
|
||||
isKnownTypesPackageName: returnFalse,
|
||||
// Should never be called because we never provide a types registry.
|
||||
installPackage: notImplemented,
|
||||
inspectValue: notImplemented,
|
||||
enqueueInstallTypingsRequest: noop,
|
||||
attach: noop,
|
||||
onProjectClosed: noop,
|
||||
@ -95,6 +98,10 @@ namespace ts.server {
|
||||
return this.installer.installPackage(options);
|
||||
}
|
||||
|
||||
inspectValue(options: InspectValueOptions): Promise<ValueInfo> {
|
||||
return this.installer.inspectValue(options);
|
||||
}
|
||||
|
||||
enqueueInstallTypingsForProject(project: Project, unresolvedImports: SortedReadonlyArray<string> | undefined, forceRefresh: boolean) {
|
||||
const typeAcquisition = project.getTypeAcquisition();
|
||||
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
const fixId = "fixCannotFindModule";
|
||||
const fixName = "fixCannotFindModule";
|
||||
const fixIdInstallTypesPackage = "installTypesPackage";
|
||||
const fixIdGenerateTypes = "generateTypes";
|
||||
|
||||
const errorCodeCannotFindModule = Diagnostics.Cannot_find_module_0.code;
|
||||
const errorCodes = [
|
||||
errorCodeCannotFindModule,
|
||||
@ -10,26 +13,141 @@ namespace ts.codefix {
|
||||
errorCodes,
|
||||
getCodeActions: context => {
|
||||
const { host, sourceFile, span: { start } } = context;
|
||||
const packageName = getTypesPackageNameToInstall(host, sourceFile, start, context.errorCode);
|
||||
return packageName === undefined ? []
|
||||
: [createCodeFixAction(fixId, /*changes*/ [], [Diagnostics.Install_0, packageName], fixId, Diagnostics.Install_all_missing_types_packages, getCommand(sourceFile.fileName, packageName))];
|
||||
const packageName = tryGetImportedPackageName(sourceFile, start);
|
||||
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],
|
||||
getAllCodeActions: context => {
|
||||
let savedTypesDir: string | null | undefined = null; // tslint:disable-line no-null-keyword
|
||||
return codeFixAll(context, errorCodes, (changes, diag, commands) => {
|
||||
const packageName = tryGetImportedPackageName(diag.file, diag.start);
|
||||
if (packageName === undefined) return undefined;
|
||||
switch (context.fixId) {
|
||||
case fixIdInstallTypesPackage: {
|
||||
const pkg = getTypesPackageNameToInstall(packageName, context.host, diag.code);
|
||||
if (pkg) {
|
||||
commands.push(getInstallCommand(diag.file.fileName, pkg));
|
||||
}
|
||||
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}`);
|
||||
}
|
||||
});
|
||||
},
|
||||
fixIds: [fixId],
|
||||
getAllCodeActions: context => codeFixAll(context, errorCodes, (_, diag, commands) => {
|
||||
const pkg = getTypesPackageNameToInstall(context.host, diag.file, diag.start, diag.code);
|
||||
if (pkg) {
|
||||
commands.push(getCommand(diag.file.fileName, pkg));
|
||||
}
|
||||
}),
|
||||
});
|
||||
|
||||
function getCommand(fileName: string, packageName: string): InstallPackageAction {
|
||||
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 = findProperty(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 = findProperty(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 = findProperty(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 createJsonPropertyAssignment(name: string, initializer: Expression) {
|
||||
return createPropertyAssignment(createStringLiteral(name), initializer);
|
||||
}
|
||||
|
||||
function findProperty(obj: ObjectLiteralExpression, name: string): PropertyAssignment | undefined {
|
||||
return find(obj.properties, (p): p is PropertyAssignment => isPropertyAssignment(p) && !!p.name && isStringLiteral(p.name) && p.name.text === name);
|
||||
}
|
||||
|
||||
function getInstallCommand(fileName: string, packageName: string): InstallPackageAction {
|
||||
return { type: "install package", file: fileName, packageName };
|
||||
}
|
||||
|
||||
function getTypesPackageNameToInstall(host: LanguageServiceHost, sourceFile: SourceFile, pos: number, diagCode: number): string | undefined {
|
||||
function tryGetImportedPackageName(sourceFile: SourceFile, pos: number): string | undefined {
|
||||
const moduleName = cast(getTokenAtPosition(sourceFile, pos), isStringLiteral).text;
|
||||
const { packageName } = parsePackageName(moduleName);
|
||||
return isExternalModuleNameRelative(packageName) ? undefined : packageName;
|
||||
}
|
||||
|
||||
function getTypesPackageNameToInstall(packageName: string, host: LanguageServiceHost, diagCode: number): string | undefined {
|
||||
return diagCode === errorCodeCannotFindModule
|
||||
? (JsTyping.nodeCoreModules.has(packageName) ? "@types/node" : undefined)
|
||||
: (host.isKnownTypesPackageName!(packageName) ? getTypesPackageName(packageName) : undefined); // TODO: GH#18217
|
||||
|
||||
227
src/services/codefixes/generateTypes.ts
Normal file
227
src/services/codefixes/generateTypes.ts
Normal file
@ -0,0 +1,227 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export function generateTypesForModule(name: string, moduleValue: unknown, formatSettings: FormatCodeSettings): string {
|
||||
return valueInfoToDeclarationFileText(inspectValue(name, moduleValue), formatSettings);
|
||||
}
|
||||
|
||||
export function valueInfoToDeclarationFileText(valueInfo: ValueInfo, formatSettings: FormatCodeSettings): string {
|
||||
return textChanges.getNewFileText(toStatements(valueInfo, OutputKind.ExportEquals), ScriptKind.TS, "\n", formatting.getFormatContext(formatSettings));
|
||||
}
|
||||
|
||||
const enum OutputKind { ExportEquals, NamedExport, NamespaceMember }
|
||||
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.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 } = info;
|
||||
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 instanceProperties = typeof fnAst === "object" ? getConstructorFunctionInstanceProperties(fnAst) : emptyArray;
|
||||
|
||||
const classStaticMembers: ClassElement[] | undefined =
|
||||
instanceProperties.length !== 0 || prototypeMembers.length !== 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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),
|
||||
...instanceProperties,
|
||||
// ignore non-functions on the prototype
|
||||
...mapDefined(prototypeMembers, info => info.kind === ValueKind.FunctionOrClass ? tryGetMethod(info) : undefined),
|
||||
])
|
||||
: 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, m.name, /*questionToken*/ undefined, toType(m), /*initializer*/ undefined)));
|
||||
default:
|
||||
return Debug.assertNever(info);
|
||||
}
|
||||
}
|
||||
|
||||
// Parses assignments to "this.x" in the constructor into class property declarations
|
||||
function getConstructorFunctionInstanceProperties(fnAst: FunctionOrConstructorNode): ReadonlyArray<PropertyDeclaration> {
|
||||
const members: PropertyDeclaration[] = [];
|
||||
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)) members.push(createProperty(/*decorators*/ undefined, /*modifiers*/ undefined, name, /*questionOrExclamationToken*/ undefined, anyType(), /*initializer*/ undefined));
|
||||
}
|
||||
});
|
||||
return members;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -1808,25 +1808,36 @@ namespace ts {
|
||||
return ts.getEditsForFileRename(getProgram()!, oldFilePath, newFilePath, host, formatting.getFormatContext(formatOptions), preferences, sourceMapper);
|
||||
}
|
||||
|
||||
function applyCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
|
||||
function applyCodeActionCommand(action: CodeActionCommand[]): Promise<ApplyCodeActionCommandResult[]>;
|
||||
function applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[]): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
|
||||
function applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult>;
|
||||
function applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult[]>;
|
||||
function applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
|
||||
function applyCodeActionCommand(fileName: Path, action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
|
||||
function applyCodeActionCommand(fileName: Path, action: CodeActionCommand[]): Promise<ApplyCodeActionCommandResult[]>;
|
||||
function applyCodeActionCommand(fileName: Path | CodeActionCommand | CodeActionCommand[], actionOrUndefined?: CodeActionCommand | CodeActionCommand[]): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]> {
|
||||
const action = typeof fileName === "string" ? actionOrUndefined! : fileName as CodeActionCommand[];
|
||||
return isArray(action) ? Promise.all(action.map(applySingleCodeActionCommand)) : applySingleCodeActionCommand(action);
|
||||
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);
|
||||
}
|
||||
|
||||
function applySingleCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult> {
|
||||
function applySingleCodeActionCommand(action: CodeActionCommand, formatSettings: FormatCodeSettings | undefined): Promise<ApplyCodeActionCommandResult> {
|
||||
const getPath = (path: string): Path => toPath(path, currentDirectory, getCanonicalFileName);
|
||||
switch (action.type) {
|
||||
case "install package":
|
||||
return host.installPackage
|
||||
? host.installPackage({ fileName: toPath(action.file, currentDirectory, getCanonicalFileName), packageName: action.packageName })
|
||||
? 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.fail();
|
||||
// TODO: Debug.assertNever(action); will only work if there is more than one type.
|
||||
return Debug.assertNever(action);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -211,8 +211,8 @@ namespace ts.textChanges {
|
||||
|
||||
export class ChangeTracker {
|
||||
private readonly changes: Change[] = [];
|
||||
private readonly newFiles: { readonly oldFile: SourceFile, readonly fileName: string, readonly statements: ReadonlyArray<Statement> }[] = [];
|
||||
private readonly classesWithNodesInsertedAtStart = createMap<ClassDeclaration>(); // Set<ClassDeclaration> implemented as Map<node id, ClassDeclaration>
|
||||
private readonly newFiles: { readonly oldFile: SourceFile | undefined, readonly fileName: string, readonly statements: ReadonlyArray<Statement> }[] = [];
|
||||
private readonly classesWithNodesInsertedAtStart = createMap<{ readonly node: ClassDeclaration | InterfaceDeclaration | ObjectLiteralExpression, readonly sourceFile: SourceFile }>(); // Set<ClassDeclaration> implemented as Map<node id, ClassDeclaration>
|
||||
private readonly deletedNodes: { readonly sourceFile: SourceFile, readonly node: Node | NodeArray<TypeParameterDeclaration> }[] = [];
|
||||
|
||||
public static fromContext(context: TextChangesContext): ChangeTracker {
|
||||
@ -410,25 +410,33 @@ namespace ts.textChanges {
|
||||
}
|
||||
|
||||
public insertNodeAtClassStart(sourceFile: SourceFile, cls: ClassLikeDeclaration | InterfaceDeclaration, newElement: ClassElement): void {
|
||||
this.insertNodeAtStartWorker(sourceFile, cls, newElement);
|
||||
}
|
||||
public insertNodeAtObjectStart(sourceFile: SourceFile, obj: ObjectLiteralExpression, newElement: ObjectLiteralElementLike): void {
|
||||
this.insertNodeAtStartWorker(sourceFile, obj, newElement);
|
||||
}
|
||||
|
||||
private insertNodeAtStartWorker(sourceFile: SourceFile, cls: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression, newElement: ClassElement | ObjectLiteralElementLike): void {
|
||||
const clsStart = cls.getStart(sourceFile);
|
||||
const indentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(getLineStartPositionForPosition(clsStart, sourceFile), clsStart, sourceFile, this.formatContext.options)
|
||||
+ this.formatContext.options.indentSize!;
|
||||
this.insertNodeAt(sourceFile, cls.members.pos, newElement, { indentation, ...this.getInsertNodeAtClassStartPrefixSuffix(sourceFile, cls) });
|
||||
this.insertNodeAt(sourceFile, getMembersOrProperties(cls).pos, newElement, { indentation, ...this.getInsertNodeAtStartPrefixSuffix(sourceFile, cls) });
|
||||
}
|
||||
|
||||
private getInsertNodeAtClassStartPrefixSuffix(sourceFile: SourceFile, cls: ClassLikeDeclaration | InterfaceDeclaration): { prefix: string, suffix: string } {
|
||||
if (cls.members.length === 0) {
|
||||
if (addToSeen(this.classesWithNodesInsertedAtStart, getNodeId(cls), cls)) {
|
||||
private getInsertNodeAtStartPrefixSuffix(sourceFile: SourceFile, cls: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression): { prefix: string, suffix: string } {
|
||||
const comma = isObjectLiteralExpression(cls) ? "," : "";
|
||||
if (getMembersOrProperties(cls).length === 0) {
|
||||
if (addToSeen(this.classesWithNodesInsertedAtStart, getNodeId(cls), { node: cls, sourceFile })) {
|
||||
// For `class C {\n}`, don't add the trailing "\n"
|
||||
const shouldSuffix = (positionsAreOnSameLine as any)(...getClassBraceEnds(cls, sourceFile), sourceFile); // TODO: GH#4130 remove 'as any'
|
||||
return { prefix: this.newLineCharacter, suffix: shouldSuffix ? this.newLineCharacter : "" };
|
||||
const shouldSuffix = (positionsAreOnSameLine as any)(...getClassOrObjectBraceEnds(cls, sourceFile), sourceFile); // TODO: GH#4130 remove 'as any'
|
||||
return { prefix: this.newLineCharacter, suffix: comma + (shouldSuffix ? this.newLineCharacter : "") };
|
||||
}
|
||||
else {
|
||||
return { prefix: "", suffix: this.newLineCharacter };
|
||||
return { prefix: "", suffix: comma + this.newLineCharacter };
|
||||
}
|
||||
}
|
||||
else {
|
||||
return { prefix: this.newLineCharacter, suffix: "" };
|
||||
return { prefix: this.newLineCharacter, suffix: comma };
|
||||
}
|
||||
}
|
||||
|
||||
@ -647,9 +655,8 @@ namespace ts.textChanges {
|
||||
}
|
||||
|
||||
private finishClassesWithNodesInsertedAtStart(): void {
|
||||
this.classesWithNodesInsertedAtStart.forEach(cls => {
|
||||
const sourceFile = cls.getSourceFile();
|
||||
const [openBraceEnd, closeBraceEnd] = getClassBraceEnds(cls, sourceFile);
|
||||
this.classesWithNodesInsertedAtStart.forEach(({ node, sourceFile }) => {
|
||||
const [openBraceEnd, closeBraceEnd] = getClassOrObjectBraceEnds(node, sourceFile);
|
||||
// For `class C { }` remove the whitespace inside the braces.
|
||||
if (positionsAreOnSameLine(openBraceEnd, closeBraceEnd, sourceFile) && openBraceEnd !== closeBraceEnd - 1) {
|
||||
this.deleteRange(sourceFile, createRange(openBraceEnd, closeBraceEnd - 1));
|
||||
@ -698,7 +705,7 @@ namespace ts.textChanges {
|
||||
return changes;
|
||||
}
|
||||
|
||||
public createNewFile(oldFile: SourceFile, fileName: string, statements: ReadonlyArray<Statement>) {
|
||||
public createNewFile(oldFile: SourceFile | undefined, fileName: string, statements: ReadonlyArray<Statement>) {
|
||||
this.newFiles.push({ oldFile, fileName, statements });
|
||||
}
|
||||
}
|
||||
@ -708,12 +715,19 @@ namespace ts.textChanges {
|
||||
return skipTrivia(sourceFile.text, getAdjustedStartPosition(sourceFile, node, {}, Position.FullStart), /*stopAfterLineBreak*/ false, /*stopAtComments*/ true);
|
||||
}
|
||||
|
||||
function getClassBraceEnds(cls: ClassLikeDeclaration | InterfaceDeclaration, sourceFile: SourceFile): [number, number] {
|
||||
function getClassOrObjectBraceEnds(cls: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression, sourceFile: SourceFile): [number, number] {
|
||||
return [findChildOfKind(cls, SyntaxKind.OpenBraceToken, sourceFile)!.end, findChildOfKind(cls, SyntaxKind.CloseBraceToken, sourceFile)!.end];
|
||||
}
|
||||
function getMembersOrProperties(cls: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression): NodeArray<Node> {
|
||||
return isObjectLiteralExpression(cls) ? cls.properties : cls.members;
|
||||
}
|
||||
|
||||
export type ValidateNonFormattedText = (node: Node, text: string) => void;
|
||||
|
||||
export function getNewFileText(statements: ReadonlyArray<Statement>, scriptKind: ScriptKind, newLineCharacter: string, formatContext: formatting.FormatContext): string {
|
||||
return changesToText.newFileChangesWorker(/*oldFile*/ undefined, scriptKind, statements, newLineCharacter, formatContext);
|
||||
}
|
||||
|
||||
namespace changesToText {
|
||||
export function getTextChangesFromChanges(changes: ReadonlyArray<Change>, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): FileTextChanges[] {
|
||||
return group(changes, c => c.sourceFile.path).map(changesInFile => {
|
||||
@ -732,13 +746,17 @@ namespace ts.textChanges {
|
||||
});
|
||||
}
|
||||
|
||||
export function newFileChanges(oldFile: SourceFile, fileName: string, statements: ReadonlyArray<Statement>, newLineCharacter: string, formatContext: formatting.FormatContext): FileTextChanges {
|
||||
export function newFileChanges(oldFile: SourceFile | undefined, fileName: string, statements: ReadonlyArray<Statement>, newLineCharacter: string, formatContext: formatting.FormatContext): FileTextChanges {
|
||||
const text = newFileChangesWorker(oldFile, getScriptKindFromFileName(fileName), statements, newLineCharacter, formatContext);
|
||||
return { fileName, textChanges: [createTextChange(createTextSpan(0, 0), text)], isNewFile: true };
|
||||
}
|
||||
|
||||
export function newFileChangesWorker(oldFile: SourceFile | undefined, scriptKind: ScriptKind, statements: ReadonlyArray<Statement>, 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 => getNonformattedText(s, oldFile, newLineCharacter).text).join(newLineCharacter);
|
||||
const sourceFile = createSourceFile(fileName, nonFormattedText, ScriptTarget.ESNext, /*setParentNodes*/ true);
|
||||
const sourceFile = createSourceFile("any file name", nonFormattedText, ScriptTarget.ESNext, /*setParentNodes*/ true, scriptKind);
|
||||
const changes = formatting.formatDocument(sourceFile, formatContext);
|
||||
const text = applyChanges(nonFormattedText, changes);
|
||||
return { fileName, textChanges: [createTextChange(createTextSpan(0, 0), text)], isNewFile: true };
|
||||
return applyChanges(nonFormattedText, changes);
|
||||
}
|
||||
|
||||
function computeNewText(change: Change, sourceFile: SourceFile, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): string {
|
||||
|
||||
@ -69,6 +69,7 @@
|
||||
"codefixes/inferFromUsage.ts",
|
||||
"codefixes/fixInvalidImportSyntax.ts",
|
||||
"codefixes/fixStrictClassInitialization.ts",
|
||||
"codefixes/generateTypes.ts",
|
||||
"codefixes/requireInTs.ts",
|
||||
"codefixes/useDefaultImport.ts",
|
||||
"codefixes/fixAddModuleReferTypeMissingTypeof.ts",
|
||||
@ -82,6 +83,6 @@
|
||||
"services.ts",
|
||||
"breakpoints.ts",
|
||||
"transform.ts",
|
||||
"shims.ts"
|
||||
"shims.ts",
|
||||
]
|
||||
}
|
||||
|
||||
@ -231,6 +231,8 @@ namespace ts {
|
||||
|
||||
isKnownTypesPackageName?(name: string): boolean;
|
||||
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
|
||||
/* @internal */ inspectValue?(options: InspectValueOptions): Promise<ValueInfo>;
|
||||
writeFile?(fileName: string, content: string): void;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@ -331,9 +333,9 @@ namespace ts {
|
||||
|
||||
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: ReadonlyArray<number>, formatOptions: FormatCodeSettings, preferences: UserPreferences): ReadonlyArray<CodeFixAction>;
|
||||
getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions;
|
||||
applyCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
|
||||
applyCodeActionCommand(action: CodeActionCommand[]): Promise<ApplyCodeActionCommandResult[]>;
|
||||
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[]): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
|
||||
applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult>;
|
||||
applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult[]>;
|
||||
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
|
||||
/** @deprecated `fileName` will be ignored */
|
||||
applyCodeActionCommand(fileName: string, action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
|
||||
/** @deprecated `fileName` will be ignored */
|
||||
@ -526,12 +528,22 @@ 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;
|
||||
export type CodeActionCommand = InstallPackageAction | GenerateTypesAction;
|
||||
|
||||
export interface InstallPackageAction {
|
||||
/* @internal */ file: string;
|
||||
/* @internal */ type: "install package";
|
||||
/* @internal */ packageName: string;
|
||||
/* @internal */ readonly type: "install package";
|
||||
/* @internal */ readonly file: string;
|
||||
/* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -717,6 +729,31 @@ namespace ts {
|
||||
indentMultiLineObjectLiteralBeginningOnBlankLine?: boolean;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export const testFormatSettings: FormatCodeSettings = {
|
||||
baseIndentSize: 0,
|
||||
indentSize: 4,
|
||||
tabSize: 4,
|
||||
newLineCharacter: "\n",
|
||||
convertTabsToSpaces: true,
|
||||
indentStyle: IndentStyle.Smart,
|
||||
insertSpaceAfterCommaDelimiter: true,
|
||||
insertSpaceAfterSemicolonInForStatements: true,
|
||||
insertSpaceBeforeAndAfterBinaryOperators: true,
|
||||
insertSpaceAfterConstructor: false,
|
||||
insertSpaceAfterKeywordsInControlFlowStatements: true,
|
||||
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
|
||||
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
|
||||
insertSpaceAfterTypeAssertion: false,
|
||||
placeOpenBraceOnNewLineForFunctions: false,
|
||||
placeOpenBraceOnNewLineForControlBlocks: false,
|
||||
insertSpaceBeforeTypeAnnotation: false
|
||||
};
|
||||
|
||||
export interface DefinitionInfo extends DocumentSpan {
|
||||
kind: ScriptElementKind;
|
||||
name: string;
|
||||
|
||||
@ -292,7 +292,7 @@ interface Array<T> {}`
|
||||
cancellationToken: { throwIfCancellationRequested: noop, isCancellationRequested: returnFalse },
|
||||
preferences: emptyOptions,
|
||||
host: notImplementedHost,
|
||||
formatContext: formatting.getFormatContext(testFormatOptions)
|
||||
formatContext: formatting.getFormatContext(testFormatSettings)
|
||||
};
|
||||
|
||||
const diagnostics = languageService.getSuggestionDiagnostics(f.path);
|
||||
|
||||
@ -64,27 +64,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
export const newLineCharacter = "\n";
|
||||
export const testFormatOptions: FormatCodeSettings = {
|
||||
indentSize: 4,
|
||||
tabSize: 4,
|
||||
newLineCharacter,
|
||||
convertTabsToSpaces: true,
|
||||
indentStyle: IndentStyle.Smart,
|
||||
insertSpaceAfterConstructor: false,
|
||||
insertSpaceAfterCommaDelimiter: true,
|
||||
insertSpaceAfterSemicolonInForStatements: true,
|
||||
insertSpaceBeforeAndAfterBinaryOperators: true,
|
||||
insertSpaceAfterKeywordsInControlFlowStatements: true,
|
||||
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
|
||||
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
|
||||
insertSpaceBeforeFunctionParenthesis: false,
|
||||
placeOpenBraceOnNewLineForFunctions: false,
|
||||
placeOpenBraceOnNewLineForControlBlocks: false,
|
||||
};
|
||||
|
||||
export const notImplementedHost: LanguageServiceHost = {
|
||||
getCompilationSettings: notImplemented,
|
||||
@ -123,7 +102,7 @@ namespace ts {
|
||||
startPosition: selectionRange.pos,
|
||||
endPosition: selectionRange.end,
|
||||
host: notImplementedHost,
|
||||
formatContext: formatting.getFormatContext(testFormatOptions),
|
||||
formatContext: formatting.getFormatContext(testFormatSettings),
|
||||
preferences: emptyOptions,
|
||||
};
|
||||
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromRange(selectionRange));
|
||||
@ -185,7 +164,7 @@ namespace ts {
|
||||
startPosition: selectionRange.pos,
|
||||
endPosition: selectionRange.end,
|
||||
host: notImplementedHost,
|
||||
formatContext: formatting.getFormatContext(testFormatOptions),
|
||||
formatContext: formatting.getFormatContext(testFormatSettings),
|
||||
preferences: emptyOptions,
|
||||
};
|
||||
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromRange(selectionRange));
|
||||
|
||||
@ -270,7 +270,7 @@ export const Other = 1;
|
||||
content: "function F() { }",
|
||||
};
|
||||
const languageService = makeLanguageService(testFile);
|
||||
const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, testFormatOptions, emptyOptions);
|
||||
const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, testFormatSettings, emptyOptions);
|
||||
assert.isEmpty(changes);
|
||||
});
|
||||
|
||||
@ -741,7 +741,7 @@ export * from "lib";
|
||||
function runBaseline(baselinePath: string, testFile: TestFSWithWatch.File, ...otherFiles: TestFSWithWatch.File[]) {
|
||||
const { path: testPath, content: testContent } = testFile;
|
||||
const languageService = makeLanguageService(testFile, ...otherFiles);
|
||||
const changes = languageService.organizeImports({ type: "file", fileName: testPath }, testFormatOptions, emptyOptions);
|
||||
const changes = languageService.organizeImports({ type: "file", fileName: testPath }, testFormatSettings, emptyOptions);
|
||||
assert.equal(changes.length, 1);
|
||||
assert.equal(changes[0].fileName, testPath);
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ namespace ts {
|
||||
const newLineCharacter = getNewLineCharacter(printerOptions);
|
||||
|
||||
function getRuleProvider(placeOpenBraceOnNewLineForFunctions: boolean): formatting.FormatContext {
|
||||
return formatting.getFormatContext(placeOpenBraceOnNewLineForFunctions ? { ...testFormatOptions, placeOpenBraceOnNewLineForFunctions: true } : testFormatOptions);
|
||||
return formatting.getFormatContext(placeOpenBraceOnNewLineForFunctions ? { ...testFormatSettings, placeOpenBraceOnNewLineForFunctions: true } : testFormatSettings);
|
||||
}
|
||||
|
||||
// validate that positions that were recovered from the printed text actually match positions that will be created if the same text is parsed.
|
||||
|
||||
@ -85,6 +85,7 @@ namespace ts.projectSystem {
|
||||
|
||||
isKnownTypesPackageName = notImplemented;
|
||||
installPackage = notImplemented;
|
||||
inspectValue = notImplemented;
|
||||
|
||||
executePendingCommands() {
|
||||
const actionsToRun = this.postExecActions;
|
||||
@ -9092,7 +9093,7 @@ export const x = 10;`
|
||||
|
||||
Debug.assert(!!project.resolveModuleNames);
|
||||
|
||||
const edits = project.getLanguageService().getEditsForFileRename("/old.ts", "/new.ts", testFormatOptions, emptyOptions);
|
||||
const edits = project.getLanguageService().getEditsForFileRename("/old.ts", "/new.ts", testFormatSettings, emptyOptions);
|
||||
assert.deepEqual<ReadonlyArray<FileTextChanges>>(edits, [{
|
||||
fileName: "/user.ts",
|
||||
textChanges: [{
|
||||
|
||||
@ -231,7 +231,8 @@ namespace ts.server {
|
||||
// buffer, but we have yet to find a way to retrieve that value.
|
||||
private static readonly maxActiveRequestCount = 10;
|
||||
private static readonly requestDelayMillis = 100;
|
||||
private packageInstalledPromise: { resolve(value: ApplyCodeActionCommandResult): void, reject(reason: any): void } | undefined;
|
||||
private packageInstalledPromise: { resolve(value: ApplyCodeActionCommandResult): void, reject(reason: unknown): void } | undefined;
|
||||
private inspectValuePromise: { resolve(value: ValueInfo): void } | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly telemetryEnabled: boolean,
|
||||
@ -261,14 +262,19 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
installPackage(options: InstallPackageOptionsWithProject): Promise<ApplyCodeActionCommandResult> {
|
||||
const rq: InstallPackageRequest = { kind: "installPackage", ...options };
|
||||
this.send(rq);
|
||||
this.send<InstallPackageRequest>({ kind: "installPackage", ...options });
|
||||
Debug.assert(this.packageInstalledPromise === undefined);
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<ApplyCodeActionCommandResult>((resolve, reject) => {
|
||||
this.packageInstalledPromise = { resolve, reject };
|
||||
});
|
||||
}
|
||||
|
||||
inspectValue(options: InspectValueOptions): Promise<ValueInfo> {
|
||||
this.send<InspectValueRequest>({ kind: "inspectValue", options });
|
||||
Debug.assert(this.inspectValuePromise === undefined);
|
||||
return new Promise<ValueInfo>(resolve => { this.inspectValuePromise = { resolve }; });
|
||||
}
|
||||
|
||||
attach(projectService: ProjectService) {
|
||||
this.projectService = projectService;
|
||||
if (this.logger.hasLevel(LogLevel.requestTime)) {
|
||||
@ -320,7 +326,7 @@ namespace ts.server {
|
||||
this.send({ projectName: p.getProjectName(), kind: "closeProject" });
|
||||
}
|
||||
|
||||
private send(rq: TypingInstallerRequestUnion): void {
|
||||
private send<T extends TypingInstallerRequestUnion>(rq: T): void {
|
||||
this.installer.send(rq);
|
||||
}
|
||||
|
||||
@ -353,7 +359,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
private handleMessage(response: TypesRegistryResponse | PackageInstalledResponse | SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes | InitializationFailedResponse) {
|
||||
private handleMessage(response: TypesRegistryResponse | PackageInstalledResponse | InspectValueResponse | SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes | InitializationFailedResponse) {
|
||||
if (this.logger.hasLevel(LogLevel.verbose)) {
|
||||
this.logger.info(`Received response:${stringifyIndented(response)}`);
|
||||
}
|
||||
@ -378,6 +384,10 @@ namespace ts.server {
|
||||
this.event(response, "setTypings");
|
||||
break;
|
||||
}
|
||||
case ActionValueInspected:
|
||||
this.inspectValuePromise!.resolve(response.result);
|
||||
this.inspectValuePromise = undefined;
|
||||
break;
|
||||
case EventInitializationFailed:
|
||||
{
|
||||
const body: protocol.TypesInstallerInitializationFailedEventBody = {
|
||||
|
||||
@ -164,6 +164,11 @@ namespace ts.server.typingsInstaller {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "inspectValue": {
|
||||
const response: InspectValueResponse = { kind: ActionValueInspected, result: inspectModule(req.options.fileNameToRequire) };
|
||||
this.sendResponse(response);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Debug.assertNever(req);
|
||||
}
|
||||
|
||||
@ -4445,6 +4445,7 @@ declare namespace ts.server {
|
||||
type ActionSet = "action::set";
|
||||
type ActionInvalidate = "action::invalidate";
|
||||
type ActionPackageInstalled = "action::packageInstalled";
|
||||
type ActionValueInspected = "action::valueInspected";
|
||||
type EventTypesRegistry = "event::typesRegistry";
|
||||
type EventBeginInstallTypes = "event::beginInstallTypes";
|
||||
type EventEndInstallTypes = "event::endInstallTypes";
|
||||
@ -4453,7 +4454,7 @@ declare namespace ts.server {
|
||||
" __sortedArrayBrand": any;
|
||||
}
|
||||
interface TypingInstallerResponse {
|
||||
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
|
||||
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | ActionValueInspected | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
|
||||
}
|
||||
interface TypingInstallerRequestWithProjectName {
|
||||
readonly projectName: string;
|
||||
@ -4661,6 +4662,7 @@ declare namespace ts {
|
||||
getCustomTransformers?(): CustomTransformers | undefined;
|
||||
isKnownTypesPackageName?(name: string): boolean;
|
||||
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
|
||||
writeFile?(fileName: string, content: string): void;
|
||||
}
|
||||
interface LanguageService {
|
||||
cleanupSemanticCache(): void;
|
||||
@ -4718,9 +4720,9 @@ declare namespace ts {
|
||||
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
|
||||
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: ReadonlyArray<number>, formatOptions: FormatCodeSettings, preferences: UserPreferences): ReadonlyArray<CodeFixAction>;
|
||||
getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions;
|
||||
applyCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
|
||||
applyCodeActionCommand(action: CodeActionCommand[]): Promise<ApplyCodeActionCommandResult[]>;
|
||||
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[]): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
|
||||
applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult>;
|
||||
applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult[]>;
|
||||
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
|
||||
/** @deprecated `fileName` will be ignored */
|
||||
applyCodeActionCommand(fileName: string, action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
|
||||
/** @deprecated `fileName` will be ignored */
|
||||
@ -4882,9 +4884,16 @@ declare namespace ts {
|
||||
changes: ReadonlyArray<FileTextChanges>;
|
||||
commands?: ReadonlyArray<CodeActionCommand>;
|
||||
}
|
||||
type CodeActionCommand = InstallPackageAction;
|
||||
type CodeActionCommand = InstallPackageAction | GenerateTypesAction;
|
||||
interface InstallPackageAction {
|
||||
}
|
||||
interface GenerateTypesAction extends GenerateTypesOptions {
|
||||
}
|
||||
interface GenerateTypesOptions {
|
||||
readonly file: string;
|
||||
readonly fileToGenerateTypesFor: string;
|
||||
readonly outputFileName: string;
|
||||
}
|
||||
/**
|
||||
* A set of one or more available refactoring actions, grouped under a parent refactoring.
|
||||
*/
|
||||
@ -8102,6 +8111,7 @@ declare namespace ts.server {
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
|
||||
readFile(fileName: string): string | undefined;
|
||||
writeFile(fileName: string, content: string): void;
|
||||
fileExists(file: string): boolean;
|
||||
resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModuleFull[];
|
||||
getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): ResolvedModuleWithFailedLookupLocations | undefined;
|
||||
|
||||
19
tests/baselines/reference/api/typescript.d.ts
vendored
19
tests/baselines/reference/api/typescript.d.ts
vendored
@ -4445,6 +4445,7 @@ declare namespace ts.server {
|
||||
type ActionSet = "action::set";
|
||||
type ActionInvalidate = "action::invalidate";
|
||||
type ActionPackageInstalled = "action::packageInstalled";
|
||||
type ActionValueInspected = "action::valueInspected";
|
||||
type EventTypesRegistry = "event::typesRegistry";
|
||||
type EventBeginInstallTypes = "event::beginInstallTypes";
|
||||
type EventEndInstallTypes = "event::endInstallTypes";
|
||||
@ -4453,7 +4454,7 @@ declare namespace ts.server {
|
||||
" __sortedArrayBrand": any;
|
||||
}
|
||||
interface TypingInstallerResponse {
|
||||
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
|
||||
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | ActionValueInspected | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
|
||||
}
|
||||
interface TypingInstallerRequestWithProjectName {
|
||||
readonly projectName: string;
|
||||
@ -4661,6 +4662,7 @@ declare namespace ts {
|
||||
getCustomTransformers?(): CustomTransformers | undefined;
|
||||
isKnownTypesPackageName?(name: string): boolean;
|
||||
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
|
||||
writeFile?(fileName: string, content: string): void;
|
||||
}
|
||||
interface LanguageService {
|
||||
cleanupSemanticCache(): void;
|
||||
@ -4718,9 +4720,9 @@ declare namespace ts {
|
||||
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
|
||||
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: ReadonlyArray<number>, formatOptions: FormatCodeSettings, preferences: UserPreferences): ReadonlyArray<CodeFixAction>;
|
||||
getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions;
|
||||
applyCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
|
||||
applyCodeActionCommand(action: CodeActionCommand[]): Promise<ApplyCodeActionCommandResult[]>;
|
||||
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[]): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
|
||||
applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult>;
|
||||
applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult[]>;
|
||||
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
|
||||
/** @deprecated `fileName` will be ignored */
|
||||
applyCodeActionCommand(fileName: string, action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
|
||||
/** @deprecated `fileName` will be ignored */
|
||||
@ -4882,9 +4884,16 @@ declare namespace ts {
|
||||
changes: ReadonlyArray<FileTextChanges>;
|
||||
commands?: ReadonlyArray<CodeActionCommand>;
|
||||
}
|
||||
type CodeActionCommand = InstallPackageAction;
|
||||
type CodeActionCommand = InstallPackageAction | GenerateTypesAction;
|
||||
interface InstallPackageAction {
|
||||
}
|
||||
interface GenerateTypesAction extends GenerateTypesOptions {
|
||||
}
|
||||
interface GenerateTypesOptions {
|
||||
readonly file: string;
|
||||
readonly fileToGenerateTypesFor: string;
|
||||
readonly outputFileName: string;
|
||||
}
|
||||
/**
|
||||
* A set of one or more available refactoring actions, grouped under a parent refactoring.
|
||||
*/
|
||||
|
||||
236
tests/baselines/reference/generateTypes/global.d.ts
vendored
Normal file
236
tests/baselines/reference/generateTypes/global.d.ts
vendored
Normal file
@ -0,0 +1,236 @@
|
||||
export class Array {
|
||||
static from(p0: any): any;
|
||||
static isArray(p0: any): any;
|
||||
static of(): any;
|
||||
concat(p0: any): any;
|
||||
copyWithin(p0: any, p1: any): any;
|
||||
entries(): any;
|
||||
every(p0: any): any;
|
||||
fill(p0: any): any;
|
||||
filter(p0: any): any;
|
||||
find(p0: any): any;
|
||||
findIndex(p0: any): any;
|
||||
forEach(p0: any): any;
|
||||
includes(p0: any): any;
|
||||
indexOf(p0: any): any;
|
||||
join(p0: any): any;
|
||||
keys(): any;
|
||||
lastIndexOf(p0: any): any;
|
||||
map(p0: any): any;
|
||||
pop(): any;
|
||||
push(p0: any): any;
|
||||
reduce(p0: any): any;
|
||||
reduceRight(p0: any): any;
|
||||
reverse(): any;
|
||||
shift(): any;
|
||||
slice(p0: any, p1: any): any;
|
||||
some(p0: any): any;
|
||||
sort(p0: any): any;
|
||||
splice(p0: any, p1: any): any;
|
||||
toLocaleString(): any;
|
||||
unshift(p0: any): any;
|
||||
}
|
||||
export class Boolean {
|
||||
constructor(p0: any);
|
||||
valueOf(): any;
|
||||
}
|
||||
export class Date {
|
||||
static UTC(p0: any, p1: any, p2: any, p3: any, p4: any, p5: any, p6: any): any;
|
||||
static now(): any;
|
||||
static parse(p0: any): any;
|
||||
constructor(p0: any, p1: any, p2: any, p3: any, p4: any, p5: any, p6: any);
|
||||
getDate(): any;
|
||||
getDay(): any;
|
||||
getFullYear(): any;
|
||||
getHours(): any;
|
||||
getMilliseconds(): any;
|
||||
getMinutes(): any;
|
||||
getMonth(): any;
|
||||
getSeconds(): any;
|
||||
getTime(): any;
|
||||
getTimezoneOffset(): any;
|
||||
getUTCDate(): any;
|
||||
getUTCDay(): any;
|
||||
getUTCFullYear(): any;
|
||||
getUTCHours(): any;
|
||||
getUTCMilliseconds(): any;
|
||||
getUTCMinutes(): any;
|
||||
getUTCMonth(): any;
|
||||
getUTCSeconds(): any;
|
||||
getYear(): any;
|
||||
setDate(p0: any): any;
|
||||
setFullYear(p0: any, p1: any, p2: any): any;
|
||||
setHours(p0: any, p1: any, p2: any, p3: any): any;
|
||||
setMilliseconds(p0: any): any;
|
||||
setMinutes(p0: any, p1: any, p2: any): any;
|
||||
setMonth(p0: any, p1: any): any;
|
||||
setSeconds(p0: any, p1: any): any;
|
||||
setTime(p0: any): any;
|
||||
setUTCDate(p0: any): any;
|
||||
setUTCFullYear(p0: any, p1: any, p2: any): any;
|
||||
setUTCHours(p0: any, p1: any, p2: any, p3: any): any;
|
||||
setUTCMilliseconds(p0: any): any;
|
||||
setUTCMinutes(p0: any, p1: any, p2: any): any;
|
||||
setUTCMonth(p0: any, p1: any): any;
|
||||
setUTCSeconds(p0: any, p1: any): any;
|
||||
setYear(p0: any): any;
|
||||
toDateString(): any;
|
||||
toGMTString(): any;
|
||||
toISOString(): any;
|
||||
toJSON(p0: any): any;
|
||||
toLocaleDateString(): any;
|
||||
toLocaleString(): any;
|
||||
toLocaleTimeString(): any;
|
||||
toTimeString(): any;
|
||||
toUTCString(): any;
|
||||
valueOf(): any;
|
||||
}
|
||||
export namespace Math {
|
||||
const E: number;
|
||||
const LN10: number;
|
||||
const LN2: number;
|
||||
const LOG10E: number;
|
||||
const LOG2E: number;
|
||||
const PI: number;
|
||||
const SQRT1_2: number;
|
||||
const SQRT2: number;
|
||||
function abs(p0: any): any;
|
||||
function acos(p0: any): any;
|
||||
function acosh(p0: any): any;
|
||||
function asin(p0: any): any;
|
||||
function asinh(p0: any): any;
|
||||
function atan(p0: any): any;
|
||||
function atan2(p0: any, p1: any): any;
|
||||
function atanh(p0: any): any;
|
||||
function cbrt(p0: any): any;
|
||||
function ceil(p0: any): any;
|
||||
function clz32(p0: any): any;
|
||||
function cos(p0: any): any;
|
||||
function cosh(p0: any): any;
|
||||
function exp(p0: any): any;
|
||||
function expm1(p0: any): any;
|
||||
function floor(p0: any): any;
|
||||
function fround(p0: any): any;
|
||||
function hypot(p0: any, p1: any): any;
|
||||
function imul(p0: any, p1: any): any;
|
||||
function log(p0: any): any;
|
||||
function log10(p0: any): any;
|
||||
function log1p(p0: any): any;
|
||||
function log2(p0: any): any;
|
||||
function max(p0: any, p1: any): any;
|
||||
function min(p0: any, p1: any): any;
|
||||
function pow(p0: any, p1: any): any;
|
||||
function random(): any;
|
||||
function round(p0: any): any;
|
||||
function sign(p0: any): any;
|
||||
function sin(p0: any): any;
|
||||
function sinh(p0: any): any;
|
||||
function sqrt(p0: any): any;
|
||||
function tan(p0: any): any;
|
||||
function tanh(p0: any): any;
|
||||
function trunc(p0: any): any;
|
||||
}
|
||||
export class Number {
|
||||
static EPSILON: number;
|
||||
static MAX_SAFE_INTEGER: number;
|
||||
static MAX_VALUE: number;
|
||||
static MIN_SAFE_INTEGER: number;
|
||||
static MIN_VALUE: number;
|
||||
static NEGATIVE_INFINITY: number;
|
||||
static NaN: number;
|
||||
static POSITIVE_INFINITY: number;
|
||||
static isFinite(p0: any): any;
|
||||
static isInteger(p0: any): any;
|
||||
static isNaN(p0: any): any;
|
||||
static isSafeInteger(p0: any): any;
|
||||
static parseFloat(p0: any): any;
|
||||
static parseInt(p0: any, p1: any): any;
|
||||
constructor(p0: any);
|
||||
toExponential(p0: any): any;
|
||||
toFixed(p0: any): any;
|
||||
toLocaleString(): any;
|
||||
toPrecision(p0: any): any;
|
||||
toString(p0: any): any;
|
||||
valueOf(): any;
|
||||
}
|
||||
export class RegExp {
|
||||
static $1: any;
|
||||
static $2: any;
|
||||
static $3: any;
|
||||
static $4: any;
|
||||
static $5: any;
|
||||
static $6: any;
|
||||
static $7: any;
|
||||
static $8: any;
|
||||
static $9: any;
|
||||
static $_: any;
|
||||
static input: any;
|
||||
static lastMatch: any;
|
||||
static lastParen: any;
|
||||
static leftContext: any;
|
||||
static rightContext: any;
|
||||
constructor(p0: any, p1: any);
|
||||
compile(p0: any, p1: any): any;
|
||||
exec(p0: any): any;
|
||||
test(p0: any): any;
|
||||
}
|
||||
export class String {
|
||||
static fromCharCode(p0: any): any;
|
||||
static fromCodePoint(p0: any): any;
|
||||
static raw(p0: any): any;
|
||||
anchor(p0: any): any;
|
||||
big(): any;
|
||||
blink(): any;
|
||||
bold(): any;
|
||||
charAt(p0: any): any;
|
||||
charCodeAt(p0: any): any;
|
||||
codePointAt(p0: any): any;
|
||||
concat(p0: any): any;
|
||||
endsWith(p0: any): any;
|
||||
fixed(): any;
|
||||
fontcolor(p0: any): any;
|
||||
fontsize(p0: any): any;
|
||||
includes(p0: any): any;
|
||||
indexOf(p0: any): any;
|
||||
italics(): any;
|
||||
lastIndexOf(p0: any): any;
|
||||
link(p0: any): any;
|
||||
localeCompare(p0: any): any;
|
||||
match(p0: any): any;
|
||||
normalize(): any;
|
||||
repeat(p0: any): any;
|
||||
replace(p0: any, p1: any): any;
|
||||
search(p0: any): any;
|
||||
slice(p0: any, p1: any): any;
|
||||
small(): any;
|
||||
split(p0: any, p1: any): any;
|
||||
startsWith(p0: any): any;
|
||||
strike(): any;
|
||||
sub(): any;
|
||||
substr(p0: any, p1: any): any;
|
||||
substring(p0: any, p1: any): any;
|
||||
sup(): any;
|
||||
toLocaleLowerCase(): any;
|
||||
toLocaleUpperCase(): any;
|
||||
toLowerCase(): any;
|
||||
toUpperCase(): any;
|
||||
trim(): any;
|
||||
trimLeft(): any;
|
||||
trimRight(): any;
|
||||
valueOf(): any;
|
||||
}
|
||||
export class Symbol {
|
||||
static hasInstance: symbol;
|
||||
static isConcatSpreadable: symbol;
|
||||
static iterator: symbol;
|
||||
static keyFor(p0: any): any;
|
||||
static match: symbol;
|
||||
static replace: symbol;
|
||||
static search: symbol;
|
||||
static species: symbol;
|
||||
static split: symbol;
|
||||
static toPrimitive: symbol;
|
||||
static toStringTag: symbol;
|
||||
static unscopables: symbol;
|
||||
valueOf(): any;
|
||||
}
|
||||
668
tests/baselines/reference/generateTypes/lodash.d.ts
vendored
Normal file
668
tests/baselines/reference/generateTypes/lodash.d.ts
vendored
Normal file
@ -0,0 +1,668 @@
|
||||
export = example;
|
||||
declare class example {
|
||||
static VERSION: string;
|
||||
static add(value: any, other: any): any;
|
||||
static after(n: any, func: any): any;
|
||||
static ary(func: any, n: any, guard: any): any;
|
||||
static assign(...args: any[]): any;
|
||||
static assignIn(...args: any[]): any;
|
||||
static assignInWith(...args: any[]): any;
|
||||
static assignWith(...args: any[]): any;
|
||||
static at(...args: any[]): any;
|
||||
static attempt(...args: any[]): any;
|
||||
static before(n: any, func: any): any;
|
||||
static bindAll(...args: any[]): any;
|
||||
static camelCase(string: any): any;
|
||||
static capitalize(string: any): any;
|
||||
static castArray(...args: any[]): any;
|
||||
static ceil(number: any, precision: any): any;
|
||||
static chain(value: any): any;
|
||||
static chunk(array: any, size: any, guard: any): any;
|
||||
static clamp(number: any, lower: any, upper: any): any;
|
||||
static clone(value: any): any;
|
||||
static cloneDeep(value: any): any;
|
||||
static cloneDeepWith(value: any, customizer: any): any;
|
||||
static cloneWith(value: any, customizer: any): any;
|
||||
static compact(array: any): any;
|
||||
static concat(...args: any[]): any;
|
||||
static cond(pairs: any): any;
|
||||
static conforms(source: any): any;
|
||||
static conformsTo(object: any, source: any): any;
|
||||
static constant(value: any): any;
|
||||
static countBy(collection: any, iteratee: any): any;
|
||||
static create(prototype: any, properties: any): any;
|
||||
static debounce(func: any, wait: any, options: any): any;
|
||||
static deburr(string: any): any;
|
||||
static defaultTo(value: any, defaultValue: any): any;
|
||||
static defaults(...args: any[]): any;
|
||||
static defaultsDeep(...args: any[]): any;
|
||||
static defer(...args: any[]): any;
|
||||
static delay(...args: any[]): any;
|
||||
static difference(...args: any[]): any;
|
||||
static differenceBy(...args: any[]): any;
|
||||
static differenceWith(...args: any[]): any;
|
||||
static divide(value: any, other: any): any;
|
||||
static drop(array: any, n: any, guard: any): any;
|
||||
static dropRight(array: any, n: any, guard: any): any;
|
||||
static dropRightWhile(array: any, predicate: any): any;
|
||||
static dropWhile(array: any, predicate: any): any;
|
||||
static each(collection: any, iteratee: any): any;
|
||||
static eachRight(collection: any, iteratee: any): any;
|
||||
static endsWith(string: any, target: any, position: any): any;
|
||||
static entries(object: any): any;
|
||||
static entriesIn(object: any): any;
|
||||
static eq(value: any, other: any): any;
|
||||
static escape(string: any): any;
|
||||
static escapeRegExp(string: any): any;
|
||||
static every(collection: any, predicate: any, guard: any): any;
|
||||
static extend(...args: any[]): any;
|
||||
static extendWith(...args: any[]): any;
|
||||
static fill(array: any, value: any, start: any, end: any): any;
|
||||
static filter(collection: any, predicate: any): any;
|
||||
static find(collection: any, predicate: any, fromIndex: any): any;
|
||||
static findIndex(array: any, predicate: any, fromIndex: any): any;
|
||||
static findKey(object: any, predicate: any): any;
|
||||
static findLast(collection: any, predicate: any, fromIndex: any): any;
|
||||
static findLastIndex(array: any, predicate: any, fromIndex: any): any;
|
||||
static findLastKey(object: any, predicate: any): any;
|
||||
static first(array: any): any;
|
||||
static flatMap(collection: any, iteratee: any): any;
|
||||
static flatMapDeep(collection: any, iteratee: any): any;
|
||||
static flatMapDepth(collection: any, iteratee: any, depth: any): any;
|
||||
static flatten(array: any): any;
|
||||
static flattenDeep(array: any): any;
|
||||
static flattenDepth(array: any, depth: any): any;
|
||||
static flip(func: any): any;
|
||||
static floor(number: any, precision: any): any;
|
||||
static flow(...args: any[]): any;
|
||||
static flowRight(...args: any[]): any;
|
||||
static forEach(collection: any, iteratee: any): any;
|
||||
static forEachRight(collection: any, iteratee: any): any;
|
||||
static forIn(object: any, iteratee: any): any;
|
||||
static forInRight(object: any, iteratee: any): any;
|
||||
static forOwn(object: any, iteratee: any): any;
|
||||
static forOwnRight(object: any, iteratee: any): any;
|
||||
static fromPairs(pairs: any): any;
|
||||
static functions(object: any): any;
|
||||
static functionsIn(object: any): any;
|
||||
static get(object: any, path: any, defaultValue: any): any;
|
||||
static groupBy(collection: any, iteratee: any): any;
|
||||
static gt(value: any, other: any): any;
|
||||
static gte(value: any, other: any): any;
|
||||
static has(object: any, path: any): any;
|
||||
static hasIn(object: any, path: any): any;
|
||||
static head(array: any): any;
|
||||
static identity(value: any): any;
|
||||
static inRange(number: any, start: any, end: any): any;
|
||||
static includes(collection: any, value: any, fromIndex: any, guard: any): any;
|
||||
static indexOf(array: any, value: any, fromIndex: any): any;
|
||||
static initial(array: any): any;
|
||||
static intersection(...args: any[]): any;
|
||||
static intersectionBy(...args: any[]): any;
|
||||
static intersectionWith(...args: any[]): any;
|
||||
static invert(object: any, iteratee: any): any;
|
||||
static invertBy(object: any, iteratee: any): any;
|
||||
static invoke(...args: any[]): any;
|
||||
static invokeMap(...args: any[]): any;
|
||||
static isArguments(value: any): any;
|
||||
static isArray(p0: any): any;
|
||||
static isArrayBuffer(value: any): any;
|
||||
static isArrayLike(value: any): any;
|
||||
static isArrayLikeObject(value: any): any;
|
||||
static isBoolean(value: any): any;
|
||||
static isBuffer(b: any): any;
|
||||
static isDate(value: any): any;
|
||||
static isElement(value: any): any;
|
||||
static isEmpty(value: any): any;
|
||||
static isEqual(value: any, other: any): any;
|
||||
static isEqualWith(value: any, other: any, customizer: any): any;
|
||||
static isError(value: any): any;
|
||||
static isFinite(value: any): any;
|
||||
static isFunction(value: any): any;
|
||||
static isInteger(value: any): any;
|
||||
static isLength(value: any): any;
|
||||
static isMap(value: any): any;
|
||||
static isMatch(object: any, source: any): any;
|
||||
static isMatchWith(object: any, source: any, customizer: any): any;
|
||||
static isNaN(value: any): any;
|
||||
static isNative(value: any): any;
|
||||
static isNil(value: any): any;
|
||||
static isNull(value: any): any;
|
||||
static isNumber(value: any): any;
|
||||
static isObject(value: any): any;
|
||||
static isObjectLike(value: any): any;
|
||||
static isPlainObject(value: any): any;
|
||||
static isRegExp(value: any): any;
|
||||
static isSafeInteger(value: any): any;
|
||||
static isSet(value: any): any;
|
||||
static isString(value: any): any;
|
||||
static isSymbol(value: any): any;
|
||||
static isTypedArray(value: any): any;
|
||||
static isUndefined(value: any): any;
|
||||
static isWeakMap(value: any): any;
|
||||
static isWeakSet(value: any): any;
|
||||
static iteratee(func: any): any;
|
||||
static join(array: any, separator: any): any;
|
||||
static kebabCase(string: any): any;
|
||||
static keyBy(collection: any, iteratee: any): any;
|
||||
static keys(object: any): any;
|
||||
static keysIn(object: any): any;
|
||||
static last(array: any): any;
|
||||
static lastIndexOf(array: any, value: any, fromIndex: any): any;
|
||||
static lowerCase(string: any): any;
|
||||
static lowerFirst(string: any): any;
|
||||
static lt(value: any, other: any): any;
|
||||
static lte(value: any, other: any): any;
|
||||
static map(collection: any, iteratee: any): any;
|
||||
static mapKeys(object: any, iteratee: any): any;
|
||||
static mapValues(object: any, iteratee: any): any;
|
||||
static matches(source: any): any;
|
||||
static matchesProperty(path: any, srcValue: any): any;
|
||||
static max(array: any): any;
|
||||
static maxBy(array: any, iteratee: any): any;
|
||||
static mean(array: any): any;
|
||||
static meanBy(array: any, iteratee: any): any;
|
||||
static merge(...args: any[]): any;
|
||||
static mergeWith(...args: any[]): any;
|
||||
static method(...args: any[]): any;
|
||||
static methodOf(...args: any[]): any;
|
||||
static min(array: any): any;
|
||||
static minBy(array: any, iteratee: any): any;
|
||||
static mixin(object: any, source: any, options: any): any;
|
||||
static multiply(value: any, other: any): any;
|
||||
static negate(predicate: any): any;
|
||||
static noConflict(): any;
|
||||
static noop(): void;
|
||||
static now(): any;
|
||||
static nth(array: any, n: any): any;
|
||||
static nthArg(n: any): any;
|
||||
static omit(...args: any[]): any;
|
||||
static omitBy(object: any, predicate: any): any;
|
||||
static once(func: any): any;
|
||||
static orderBy(collection: any, iteratees: any, orders: any, guard: any): any;
|
||||
static over(...args: any[]): any;
|
||||
static overArgs(...args: any[]): any;
|
||||
static overEvery(...args: any[]): any;
|
||||
static overSome(...args: any[]): any;
|
||||
static pad(string: any, length: any, chars: any): any;
|
||||
static padEnd(string: any, length: any, chars: any): any;
|
||||
static padStart(string: any, length: any, chars: any): any;
|
||||
static parseInt(string: any, radix: any, guard: any): any;
|
||||
static partition(collection: any, iteratee: any): any;
|
||||
static pick(...args: any[]): any;
|
||||
static pickBy(object: any, predicate: any): any;
|
||||
static property(path: any): any;
|
||||
static propertyOf(object: any): any;
|
||||
static pull(...args: any[]): any;
|
||||
static pullAll(array: any, values: any): any;
|
||||
static pullAllBy(array: any, values: any, iteratee: any): any;
|
||||
static pullAllWith(array: any, values: any, comparator: any): any;
|
||||
static pullAt(...args: any[]): any;
|
||||
static random(lower: any, upper: any, floating: any): any;
|
||||
static range(start: any, end: any, step: any): any;
|
||||
static rangeRight(start: any, end: any, step: any): any;
|
||||
static rearg(...args: any[]): any;
|
||||
static reduce(collection: any, iteratee: any, accumulator: any, ...args: any[]): any;
|
||||
static reduceRight(collection: any, iteratee: any, accumulator: any, ...args: any[]): any;
|
||||
static reject(collection: any, predicate: any): any;
|
||||
static remove(array: any, predicate: any): any;
|
||||
static repeat(string: any, n: any, guard: any): any;
|
||||
static replace(...args: any[]): any;
|
||||
static rest(func: any, start: any): any;
|
||||
static result(object: any, path: any, defaultValue: any): any;
|
||||
static reverse(array: any): any;
|
||||
static round(number: any, precision: any): any;
|
||||
static runInContext(context: any): any;
|
||||
static sample(collection: any): any;
|
||||
static sampleSize(collection: any, n: any, guard: any): any;
|
||||
static set(object: any, path: any, value: any): any;
|
||||
static setWith(object: any, path: any, value: any, customizer: any): any;
|
||||
static shuffle(collection: any): any;
|
||||
static size(collection: any): any;
|
||||
static slice(array: any, start: any, end: any): any;
|
||||
static snakeCase(string: any): any;
|
||||
static some(collection: any, predicate: any, guard: any): any;
|
||||
static sortBy(...args: any[]): any;
|
||||
static sortedIndex(array: any, value: any): any;
|
||||
static sortedIndexBy(array: any, value: any, iteratee: any): any;
|
||||
static sortedIndexOf(array: any, value: any): any;
|
||||
static sortedLastIndex(array: any, value: any): any;
|
||||
static sortedLastIndexBy(array: any, value: any, iteratee: any): any;
|
||||
static sortedLastIndexOf(array: any, value: any): any;
|
||||
static sortedUniq(array: any): any;
|
||||
static sortedUniqBy(array: any, iteratee: any): any;
|
||||
static split(string: any, separator: any, limit: any): any;
|
||||
static spread(func: any, start: any): any;
|
||||
static startCase(string: any): any;
|
||||
static startsWith(string: any, target: any, position: any): any;
|
||||
static stubArray(): any;
|
||||
static stubFalse(): any;
|
||||
static stubObject(): any;
|
||||
static stubString(): any;
|
||||
static stubTrue(): any;
|
||||
static subtract(value: any, other: any): any;
|
||||
static sum(array: any): any;
|
||||
static sumBy(array: any, iteratee: any): any;
|
||||
static tail(array: any): any;
|
||||
static take(array: any, n: any, guard: any): any;
|
||||
static takeRight(array: any, n: any, guard: any): any;
|
||||
static takeRightWhile(array: any, predicate: any): any;
|
||||
static takeWhile(array: any, predicate: any): any;
|
||||
static tap(value: any, interceptor: any): any;
|
||||
static template(string: any, options: any, guard: any): any;
|
||||
static templateSettings: {
|
||||
escape: RegExp;
|
||||
evaluate: RegExp;
|
||||
imports: {};
|
||||
interpolate: RegExp;
|
||||
variable: string;
|
||||
};
|
||||
static throttle(func: any, wait: any, options: any): any;
|
||||
static thru(value: any, interceptor: any): any;
|
||||
static times(n: any, iteratee: any): any;
|
||||
static toArray(value: any): any;
|
||||
static toFinite(value: any): any;
|
||||
static toInteger(value: any): any;
|
||||
static toLength(value: any): any;
|
||||
static toLower(value: any): any;
|
||||
static toNumber(value: any): any;
|
||||
static toPairs(object: any): any;
|
||||
static toPairsIn(object: any): any;
|
||||
static toPath(value: any): any;
|
||||
static toPlainObject(value: any): any;
|
||||
static toSafeInteger(value: any): any;
|
||||
static toString(value: any): any;
|
||||
static toUpper(value: any): any;
|
||||
static transform(object: any, iteratee: any, accumulator: any): any;
|
||||
static trim(string: any, chars: any, guard: any): any;
|
||||
static trimEnd(string: any, chars: any, guard: any): any;
|
||||
static trimStart(string: any, chars: any, guard: any): any;
|
||||
static truncate(string: any, options: any): any;
|
||||
static unary(func: any): any;
|
||||
static unescape(string: any): any;
|
||||
static union(...args: any[]): any;
|
||||
static unionBy(...args: any[]): any;
|
||||
static unionWith(...args: any[]): any;
|
||||
static uniq(array: any): any;
|
||||
static uniqBy(array: any, iteratee: any): any;
|
||||
static uniqWith(array: any, comparator: any): any;
|
||||
static uniqueId(prefix: any): any;
|
||||
static unset(object: any, path: any): any;
|
||||
static unzip(array: any): any;
|
||||
static unzipWith(array: any, iteratee: any): any;
|
||||
static update(object: any, path: any, updater: any): any;
|
||||
static updateWith(object: any, path: any, updater: any, customizer: any): any;
|
||||
static upperCase(string: any): any;
|
||||
static upperFirst(string: any): any;
|
||||
static values(object: any): any;
|
||||
static valuesIn(object: any): any;
|
||||
static without(...args: any[]): any;
|
||||
static words(string: any, pattern: any, guard: any): any;
|
||||
static wrap(value: any, wrapper: any): any;
|
||||
static xor(...args: any[]): any;
|
||||
static xorBy(...args: any[]): any;
|
||||
static xorWith(...args: any[]): any;
|
||||
static zip(...args: any[]): any;
|
||||
static zipObject(props: any, values: any): any;
|
||||
static zipObjectDeep(props: any, values: any): any;
|
||||
static zipWith(...args: any[]): any;
|
||||
constructor(value: any);
|
||||
add(...args: any[]): any;
|
||||
after(...args: any[]): any;
|
||||
ary(...args: any[]): any;
|
||||
assign(...args: any[]): any;
|
||||
assignIn(...args: any[]): any;
|
||||
assignInWith(...args: any[]): any;
|
||||
assignWith(...args: any[]): any;
|
||||
at(...args: any[]): any;
|
||||
attempt(...args: any[]): any;
|
||||
before(...args: any[]): any;
|
||||
bind(...args: any[]): any;
|
||||
bindAll(...args: any[]): any;
|
||||
bindKey(...args: any[]): any;
|
||||
camelCase(...args: any[]): any;
|
||||
capitalize(...args: any[]): any;
|
||||
castArray(...args: any[]): any;
|
||||
ceil(...args: any[]): any;
|
||||
chain(): any;
|
||||
chunk(...args: any[]): any;
|
||||
clamp(...args: any[]): any;
|
||||
clone(...args: any[]): any;
|
||||
cloneDeep(...args: any[]): any;
|
||||
cloneDeepWith(...args: any[]): any;
|
||||
cloneWith(...args: any[]): any;
|
||||
commit(): any;
|
||||
compact(...args: any[]): any;
|
||||
concat(...args: any[]): any;
|
||||
cond(...args: any[]): any;
|
||||
conforms(...args: any[]): any;
|
||||
conformsTo(...args: any[]): any;
|
||||
constant(...args: any[]): any;
|
||||
countBy(...args: any[]): any;
|
||||
create(...args: any[]): any;
|
||||
curry(...args: any[]): any;
|
||||
curryRight(...args: any[]): any;
|
||||
debounce(...args: any[]): any;
|
||||
deburr(...args: any[]): any;
|
||||
defaultTo(...args: any[]): any;
|
||||
defaults(...args: any[]): any;
|
||||
defaultsDeep(...args: any[]): any;
|
||||
defer(...args: any[]): any;
|
||||
delay(...args: any[]): any;
|
||||
difference(...args: any[]): any;
|
||||
differenceBy(...args: any[]): any;
|
||||
differenceWith(...args: any[]): any;
|
||||
divide(...args: any[]): any;
|
||||
drop(...args: any[]): any;
|
||||
dropRight(...args: any[]): any;
|
||||
dropRightWhile(...args: any[]): any;
|
||||
dropWhile(...args: any[]): any;
|
||||
each(...args: any[]): any;
|
||||
eachRight(...args: any[]): any;
|
||||
endsWith(...args: any[]): any;
|
||||
entries(...args: any[]): any;
|
||||
entriesIn(...args: any[]): any;
|
||||
eq(...args: any[]): any;
|
||||
escape(...args: any[]): any;
|
||||
escapeRegExp(...args: any[]): any;
|
||||
every(...args: any[]): any;
|
||||
extend(...args: any[]): any;
|
||||
extendWith(...args: any[]): any;
|
||||
fill(...args: any[]): any;
|
||||
filter(...args: any[]): any;
|
||||
find(...args: any[]): any;
|
||||
findIndex(...args: any[]): any;
|
||||
findKey(...args: any[]): any;
|
||||
findLast(...args: any[]): any;
|
||||
findLastIndex(...args: any[]): any;
|
||||
findLastKey(...args: any[]): any;
|
||||
first(...args: any[]): any;
|
||||
flatMap(...args: any[]): any;
|
||||
flatMapDeep(...args: any[]): any;
|
||||
flatMapDepth(...args: any[]): any;
|
||||
flatten(...args: any[]): any;
|
||||
flattenDeep(...args: any[]): any;
|
||||
flattenDepth(...args: any[]): any;
|
||||
flip(...args: any[]): any;
|
||||
floor(...args: any[]): any;
|
||||
flow(...args: any[]): any;
|
||||
flowRight(...args: any[]): any;
|
||||
forEach(...args: any[]): any;
|
||||
forEachRight(...args: any[]): any;
|
||||
forIn(...args: any[]): any;
|
||||
forInRight(...args: any[]): any;
|
||||
forOwn(...args: any[]): any;
|
||||
forOwnRight(...args: any[]): any;
|
||||
fromPairs(...args: any[]): any;
|
||||
functions(...args: any[]): any;
|
||||
functionsIn(...args: any[]): any;
|
||||
get(...args: any[]): any;
|
||||
groupBy(...args: any[]): any;
|
||||
gt(...args: any[]): any;
|
||||
gte(...args: any[]): any;
|
||||
has(...args: any[]): any;
|
||||
hasIn(...args: any[]): any;
|
||||
head(...args: any[]): any;
|
||||
identity(...args: any[]): any;
|
||||
inRange(...args: any[]): any;
|
||||
includes(...args: any[]): any;
|
||||
indexOf(...args: any[]): any;
|
||||
initial(...args: any[]): any;
|
||||
intersection(...args: any[]): any;
|
||||
intersectionBy(...args: any[]): any;
|
||||
intersectionWith(...args: any[]): any;
|
||||
invert(...args: any[]): any;
|
||||
invertBy(...args: any[]): any;
|
||||
invoke(...args: any[]): any;
|
||||
invokeMap(...args: any[]): any;
|
||||
isArguments(...args: any[]): any;
|
||||
isArray(...args: any[]): any;
|
||||
isArrayBuffer(...args: any[]): any;
|
||||
isArrayLike(...args: any[]): any;
|
||||
isArrayLikeObject(...args: any[]): any;
|
||||
isBoolean(...args: any[]): any;
|
||||
isBuffer(...args: any[]): any;
|
||||
isDate(...args: any[]): any;
|
||||
isElement(...args: any[]): any;
|
||||
isEmpty(...args: any[]): any;
|
||||
isEqual(...args: any[]): any;
|
||||
isEqualWith(...args: any[]): any;
|
||||
isError(...args: any[]): any;
|
||||
isFinite(...args: any[]): any;
|
||||
isFunction(...args: any[]): any;
|
||||
isInteger(...args: any[]): any;
|
||||
isLength(...args: any[]): any;
|
||||
isMap(...args: any[]): any;
|
||||
isMatch(...args: any[]): any;
|
||||
isMatchWith(...args: any[]): any;
|
||||
isNaN(...args: any[]): any;
|
||||
isNative(...args: any[]): any;
|
||||
isNil(...args: any[]): any;
|
||||
isNull(...args: any[]): any;
|
||||
isNumber(...args: any[]): any;
|
||||
isObject(...args: any[]): any;
|
||||
isObjectLike(...args: any[]): any;
|
||||
isPlainObject(...args: any[]): any;
|
||||
isRegExp(...args: any[]): any;
|
||||
isSafeInteger(...args: any[]): any;
|
||||
isSet(...args: any[]): any;
|
||||
isString(...args: any[]): any;
|
||||
isSymbol(...args: any[]): any;
|
||||
isTypedArray(...args: any[]): any;
|
||||
isUndefined(...args: any[]): any;
|
||||
isWeakMap(...args: any[]): any;
|
||||
isWeakSet(...args: any[]): any;
|
||||
iteratee(...args: any[]): any;
|
||||
join(...args: any[]): any;
|
||||
kebabCase(...args: any[]): any;
|
||||
keyBy(...args: any[]): any;
|
||||
keys(...args: any[]): any;
|
||||
keysIn(...args: any[]): any;
|
||||
last(...args: any[]): any;
|
||||
lastIndexOf(...args: any[]): any;
|
||||
lowerCase(...args: any[]): any;
|
||||
lowerFirst(...args: any[]): any;
|
||||
lt(...args: any[]): any;
|
||||
lte(...args: any[]): any;
|
||||
map(...args: any[]): any;
|
||||
mapKeys(...args: any[]): any;
|
||||
mapValues(...args: any[]): any;
|
||||
matches(...args: any[]): any;
|
||||
matchesProperty(...args: any[]): any;
|
||||
max(...args: any[]): any;
|
||||
maxBy(...args: any[]): any;
|
||||
mean(...args: any[]): any;
|
||||
meanBy(...args: any[]): any;
|
||||
memoize(...args: any[]): any;
|
||||
merge(...args: any[]): any;
|
||||
mergeWith(...args: any[]): any;
|
||||
method(...args: any[]): any;
|
||||
methodOf(...args: any[]): any;
|
||||
min(...args: any[]): any;
|
||||
minBy(...args: any[]): any;
|
||||
mixin(...args: any[]): any;
|
||||
multiply(...args: any[]): any;
|
||||
negate(...args: any[]): any;
|
||||
next(): any;
|
||||
noConflict(...args: any[]): any;
|
||||
noop(...args: any[]): any;
|
||||
now(...args: any[]): any;
|
||||
nth(...args: any[]): any;
|
||||
nthArg(...args: any[]): any;
|
||||
omit(...args: any[]): any;
|
||||
omitBy(...args: any[]): any;
|
||||
once(...args: any[]): any;
|
||||
orderBy(...args: any[]): any;
|
||||
over(...args: any[]): any;
|
||||
overArgs(...args: any[]): any;
|
||||
overEvery(...args: any[]): any;
|
||||
overSome(...args: any[]): any;
|
||||
pad(...args: any[]): any;
|
||||
padEnd(...args: any[]): any;
|
||||
padStart(...args: any[]): any;
|
||||
parseInt(...args: any[]): any;
|
||||
partial(...args: any[]): any;
|
||||
partialRight(...args: any[]): any;
|
||||
partition(...args: any[]): any;
|
||||
pick(...args: any[]): any;
|
||||
pickBy(...args: any[]): any;
|
||||
plant(value: any): any;
|
||||
pop(...args: any[]): any;
|
||||
property(...args: any[]): any;
|
||||
propertyOf(...args: any[]): any;
|
||||
pull(...args: any[]): any;
|
||||
pullAll(...args: any[]): any;
|
||||
pullAllBy(...args: any[]): any;
|
||||
pullAllWith(...args: any[]): any;
|
||||
pullAt(...args: any[]): any;
|
||||
push(...args: any[]): any;
|
||||
random(...args: any[]): any;
|
||||
range(...args: any[]): any;
|
||||
rangeRight(...args: any[]): any;
|
||||
rearg(...args: any[]): any;
|
||||
reduce(...args: any[]): any;
|
||||
reduceRight(...args: any[]): any;
|
||||
reject(...args: any[]): any;
|
||||
remove(...args: any[]): any;
|
||||
repeat(...args: any[]): any;
|
||||
replace(...args: any[]): any;
|
||||
rest(...args: any[]): any;
|
||||
result(...args: any[]): any;
|
||||
reverse(): any;
|
||||
round(...args: any[]): any;
|
||||
runInContext(...args: any[]): any;
|
||||
sample(...args: any[]): any;
|
||||
sampleSize(...args: any[]): any;
|
||||
set(...args: any[]): any;
|
||||
setWith(...args: any[]): any;
|
||||
shift(...args: any[]): any;
|
||||
shuffle(...args: any[]): any;
|
||||
size(...args: any[]): any;
|
||||
slice(...args: any[]): any;
|
||||
snakeCase(...args: any[]): any;
|
||||
some(...args: any[]): any;
|
||||
sort(...args: any[]): any;
|
||||
sortBy(...args: any[]): any;
|
||||
sortedIndex(...args: any[]): any;
|
||||
sortedIndexBy(...args: any[]): any;
|
||||
sortedIndexOf(...args: any[]): any;
|
||||
sortedLastIndex(...args: any[]): any;
|
||||
sortedLastIndexBy(...args: any[]): any;
|
||||
sortedLastIndexOf(...args: any[]): any;
|
||||
sortedUniq(...args: any[]): any;
|
||||
sortedUniqBy(...args: any[]): any;
|
||||
splice(...args: any[]): any;
|
||||
split(...args: any[]): any;
|
||||
spread(...args: any[]): any;
|
||||
startCase(...args: any[]): any;
|
||||
startsWith(...args: any[]): any;
|
||||
stubArray(...args: any[]): any;
|
||||
stubFalse(...args: any[]): any;
|
||||
stubObject(...args: any[]): any;
|
||||
stubString(...args: any[]): any;
|
||||
stubTrue(...args: any[]): any;
|
||||
subtract(...args: any[]): any;
|
||||
sum(...args: any[]): any;
|
||||
sumBy(...args: any[]): any;
|
||||
tail(...args: any[]): any;
|
||||
take(...args: any[]): any;
|
||||
takeRight(...args: any[]): any;
|
||||
takeRightWhile(...args: any[]): any;
|
||||
takeWhile(...args: any[]): any;
|
||||
tap(...args: any[]): any;
|
||||
template(...args: any[]): any;
|
||||
throttle(...args: any[]): any;
|
||||
thru(...args: any[]): any;
|
||||
times(...args: any[]): any;
|
||||
toArray(...args: any[]): any;
|
||||
toFinite(...args: any[]): any;
|
||||
toInteger(...args: any[]): any;
|
||||
toJSON(): any;
|
||||
toLength(...args: any[]): any;
|
||||
toLower(...args: any[]): any;
|
||||
toNumber(...args: any[]): any;
|
||||
toPairs(...args: any[]): any;
|
||||
toPairsIn(...args: any[]): any;
|
||||
toPath(...args: any[]): any;
|
||||
toPlainObject(...args: any[]): any;
|
||||
toSafeInteger(...args: any[]): any;
|
||||
toUpper(...args: any[]): any;
|
||||
transform(...args: any[]): any;
|
||||
trim(...args: any[]): any;
|
||||
trimEnd(...args: any[]): any;
|
||||
trimStart(...args: any[]): any;
|
||||
truncate(...args: any[]): any;
|
||||
unary(...args: any[]): any;
|
||||
unescape(...args: any[]): any;
|
||||
union(...args: any[]): any;
|
||||
unionBy(...args: any[]): any;
|
||||
unionWith(...args: any[]): any;
|
||||
uniq(...args: any[]): any;
|
||||
uniqBy(...args: any[]): any;
|
||||
uniqWith(...args: any[]): any;
|
||||
uniqueId(...args: any[]): any;
|
||||
unset(...args: any[]): any;
|
||||
unshift(...args: any[]): any;
|
||||
unzip(...args: any[]): any;
|
||||
unzipWith(...args: any[]): any;
|
||||
update(...args: any[]): any;
|
||||
updateWith(...args: any[]): any;
|
||||
upperCase(...args: any[]): any;
|
||||
upperFirst(...args: any[]): any;
|
||||
value(): any;
|
||||
valueOf(): any;
|
||||
values(...args: any[]): any;
|
||||
valuesIn(...args: any[]): any;
|
||||
without(...args: any[]): any;
|
||||
words(...args: any[]): any;
|
||||
wrap(...args: any[]): any;
|
||||
xor(...args: any[]): any;
|
||||
xorBy(...args: any[]): any;
|
||||
xorWith(...args: any[]): any;
|
||||
zip(...args: any[]): any;
|
||||
zipObject(...args: any[]): any;
|
||||
zipObjectDeep(...args: any[]): any;
|
||||
zipWith(...args: any[]): any;
|
||||
}
|
||||
declare namespace example {
|
||||
function bind(...args: any[]): any;
|
||||
namespace bind {
|
||||
// Circular reference from example.bind
|
||||
const placeholder: any;
|
||||
}
|
||||
function bindKey(...args: any[]): any;
|
||||
namespace bindKey {
|
||||
// Circular reference from example.bindKey
|
||||
const placeholder: any;
|
||||
}
|
||||
function curry(func: any, arity: any, guard: any): any;
|
||||
namespace curry {
|
||||
// Circular reference from example.curry
|
||||
const placeholder: any;
|
||||
}
|
||||
function curryRight(func: any, arity: any, guard: any): any;
|
||||
namespace curryRight {
|
||||
// Circular reference from example.curryRight
|
||||
const placeholder: any;
|
||||
}
|
||||
function memoize(func: any, resolver: any): any;
|
||||
namespace memoize {
|
||||
class Cache {
|
||||
constructor(entries: any);
|
||||
clear(): void;
|
||||
get(key: any): any;
|
||||
has(key: any): any;
|
||||
set(key: any, value: any): any;
|
||||
}
|
||||
}
|
||||
function partial(...args: any[]): any;
|
||||
namespace partial {
|
||||
// Circular reference from example.partial
|
||||
const placeholder: any;
|
||||
}
|
||||
function partialRight(...args: any[]): any;
|
||||
namespace partialRight {
|
||||
// Circular reference from example.partialRight
|
||||
const placeholder: any;
|
||||
}
|
||||
}
|
||||
@ -21,12 +21,11 @@ test.setTypesRegistry({
|
||||
goTo.marker();
|
||||
|
||||
verify.codeFixAll({
|
||||
fixId: "fixCannotFindModule",
|
||||
fixId: "installTypesPackage",
|
||||
fixAllDescription: "Install all missing types packages",
|
||||
newFileContent: {}, // no changes
|
||||
commands: [
|
||||
{ packageName: "@types/abs", file: "/a.ts", type: "install package" },
|
||||
{ packageName: "@types/zap", file: "/a.ts", type: "install package" },
|
||||
],
|
||||
newFileContent: `import * as abs from "abs";
|
||||
import * as zap from "zap";` // unchanged
|
||||
});
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /dir/node_modules/plus/index.js
|
||||
////module.exports = function plus(x, y) { return x + y; };
|
||||
|
||||
// @Filename: /dir/a.ts
|
||||
////import plus = require("plus");
|
||||
////plus;
|
||||
|
||||
// @Filename: /dir/tsconfig.json
|
||||
////{
|
||||
//// "compilerOptions": {
|
||||
//// "paths": {
|
||||
//// "nota": ["valid_pathmapping"],
|
||||
//// dontCrash: 37,
|
||||
//// "*": ["abc123"],
|
||||
//// }
|
||||
//// }
|
||||
////}
|
||||
|
||||
goTo.file("/dir/a.ts");
|
||||
verify.codeFix({
|
||||
description: "Generate types for 'plus'",
|
||||
newFileContent: {
|
||||
"/dir/tsconfig.json":
|
||||
`{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"*": ["types/*"],
|
||||
"nota": ["valid_pathmapping"],
|
||||
dontCrash: 37,
|
||||
"*": ["abc123"],
|
||||
}
|
||||
}
|
||||
}`,
|
||||
},
|
||||
commands: [{
|
||||
type: "generate types",
|
||||
file: "/dir/a.ts",
|
||||
fileToGenerateTypesFor: "/dir/node_modules/plus/index.js",
|
||||
outputFileName: "/dir/types/plus.d.ts",
|
||||
}],
|
||||
});
|
||||
@ -0,0 +1,47 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /dir/node_modules/plus/index.js
|
||||
////module.exports = function plus(x, y) { return x + y; };
|
||||
|
||||
// @Filename: /dir/node_modules/times/index.js
|
||||
////module.exports = function times(x, y) { return x * y; };
|
||||
|
||||
// @Filename: /dir/a.ts
|
||||
////import plus = require("plus");
|
||||
////import times = require("times");
|
||||
////plus;
|
||||
|
||||
// @Filename: /dir/tsconfig.json
|
||||
////{
|
||||
//// "compilerOptions": {}
|
||||
////}
|
||||
|
||||
goTo.file("/dir/a.ts");
|
||||
verify.codeFixAll({
|
||||
fixAllDescription: "Generate types for all packages without types",
|
||||
fixId: "generateTypes",
|
||||
newFileContent: {
|
||||
"/dir/tsconfig.json":
|
||||
// TODO: GH#26618
|
||||
`{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": { "*": ["types/*"] },
|
||||
}
|
||||
}`,
|
||||
},
|
||||
commands: [
|
||||
{
|
||||
type: "generate types",
|
||||
file: "/dir/a.ts",
|
||||
fileToGenerateTypesFor: "/dir/node_modules/plus/index.js",
|
||||
outputFileName: "/dir/types/plus.d.ts",
|
||||
},
|
||||
{
|
||||
type: "generate types",
|
||||
file: "/dir/a.ts",
|
||||
fileToGenerateTypesFor: "/dir/node_modules/times/index.js",
|
||||
outputFileName: "/dir/types/times.d.ts",
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -0,0 +1,28 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /dir/node_modules/plus/index.js
|
||||
////module.exports = function plus(x, y) { return x * y; };
|
||||
|
||||
// @Filename: /dir/a.ts
|
||||
////import plus = require("plus");
|
||||
////plus;
|
||||
|
||||
// @Filename: /dir/tsconfig.json
|
||||
////{}
|
||||
|
||||
goTo.file("/dir/a.ts");
|
||||
verify.codeFix({
|
||||
description: "Generate types for 'plus'",
|
||||
newFileContent: {
|
||||
"/dir/tsconfig.json":
|
||||
`{
|
||||
"compilerOptions": { "baseUrl": ".", "paths": { "*": ["types/*"] } },
|
||||
}`,
|
||||
},
|
||||
commands: [{
|
||||
type: "generate types",
|
||||
file: "/dir/a.ts",
|
||||
fileToGenerateTypesFor: "/dir/node_modules/plus/index.js",
|
||||
outputFileName: "/dir/types/plus.d.ts",
|
||||
}],
|
||||
});
|
||||
@ -0,0 +1,13 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////import plus = require("plus");
|
||||
////plus;
|
||||
|
||||
// @Filename: /tsconfig.json
|
||||
////{
|
||||
//// "compilerOptions": {}
|
||||
////}
|
||||
|
||||
goTo.file("/a.ts");
|
||||
verify.codeFixAvailable([]);
|
||||
@ -0,0 +1,30 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /dir/node_modules/plus/index.js
|
||||
////module.exports = function plus(x, y) { return x * y; };
|
||||
|
||||
// @Filename: /dir/a.ts
|
||||
////import plus = require("plus");
|
||||
////plus;
|
||||
|
||||
// @Filename: /dir/tsconfig.json
|
||||
////{
|
||||
//// "compilerOptions": {
|
||||
//// "baseUrl": "base",
|
||||
//// "paths": {
|
||||
//// "*": ["myTypes/*"],
|
||||
//// },
|
||||
//// },
|
||||
////}
|
||||
|
||||
goTo.file("/dir/a.ts");
|
||||
verify.codeFix({
|
||||
description: "Generate types for 'plus'",
|
||||
newFileContent: {}, // no change
|
||||
commands: [{
|
||||
type: "generate types",
|
||||
file: "/dir/a.ts",
|
||||
fileToGenerateTypesFor: "/dir/node_modules/plus/index.js",
|
||||
outputFileName: "/dir/base/myTypes/plus.d.ts",
|
||||
}],
|
||||
});
|
||||
9
tests/cases/fourslash/codeFixGenerateDefinitions.ts
Normal file
9
tests/cases/fourslash/codeFixGenerateDefinitions.ts
Normal file
@ -0,0 +1,9 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /node_modules/foo/index.d.ts
|
||||
////module.exports = 0;
|
||||
|
||||
// @Filename: /a.ts
|
||||
////import * as foo from "foo";
|
||||
|
||||
verify.not.codeFixAvailable();
|
||||
@ -28,5 +28,5 @@ verify.codeFix({
|
||||
foo1(arg0: () => number, arg1: () => string, arg2: () => boolean): any {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`
|
||||
`,
|
||||
});
|
||||
|
||||
@ -13,4 +13,4 @@ format.document();
|
||||
verify.currentFileContentIs(
|
||||
`const foo = [
|
||||
1
|
||||
];`);
|
||||
];`);
|
||||
|
||||
@ -284,7 +284,7 @@ declare namespace FourSlashInterface {
|
||||
docCommentTemplateAt(markerName: string | FourSlashInterface.Marker, expectedOffset: number, expectedText: string): void;
|
||||
noDocCommentTemplateAt(markerName: string | FourSlashInterface.Marker): void;
|
||||
rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number): void;
|
||||
codeFixAll(options: { fixId: string, fixAllDescription: string, newFileContent: string, commands?: {}[] }): void;
|
||||
codeFixAll(options: { fixId: string, fixAllDescription: string, newFileContent: NewFileContent, commands?: {}[] }): void;
|
||||
fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, actionName: string, formattingOptions?: FormatCodeOptions): void;
|
||||
rangeIs(expectedText: string, includeWhiteSpace?: boolean): void;
|
||||
fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, formattingOptions?: FormatCodeOptions): void;
|
||||
@ -348,6 +348,8 @@ declare namespace FourSlashInterface {
|
||||
readonly preferences?: UserPreferences;
|
||||
}): void;
|
||||
noMoveToNewFile(): void;
|
||||
|
||||
generateTypes(...options: GenerateTypesOptions[]): void;
|
||||
}
|
||||
class edit {
|
||||
backspace(count?: number): void;
|
||||
@ -637,6 +639,13 @@ declare namespace FourSlashInterface {
|
||||
readonly text: string | undefined;
|
||||
}
|
||||
|
||||
interface GenerateTypesOptions {
|
||||
readonly name?: string;
|
||||
readonly value: unknown;
|
||||
readonly output?: string | undefined;
|
||||
readonly outputBaseline?: string;
|
||||
}
|
||||
|
||||
type ArrayOrSingle<T> = T | ReadonlyArray<T>;
|
||||
type NewFileContent = string | { readonly [fileName: string]: string };
|
||||
}
|
||||
|
||||
109
tests/cases/fourslash/generateTypes.ts
Normal file
109
tests/cases/fourslash/generateTypes.ts
Normal file
@ -0,0 +1,109 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////dummy text
|
||||
|
||||
verify.generateTypes(
|
||||
{
|
||||
value: 0,
|
||||
output:
|
||||
`export = example;
|
||||
declare const example: number;`,
|
||||
},
|
||||
{
|
||||
value: (x, y) => x + y,
|
||||
output:
|
||||
`export = example;
|
||||
declare function example(x: any, y: any): void;`,
|
||||
},
|
||||
{
|
||||
// non-arrow functions have different toString(), so important to test
|
||||
value: function(x, y) {
|
||||
return x * y;
|
||||
function inner() {
|
||||
arguments; // Should not affect type inference
|
||||
}
|
||||
},
|
||||
output:
|
||||
`export = example;
|
||||
declare function example(x: any, y: any): any;`,
|
||||
},
|
||||
{
|
||||
value: function(x) { arguments; },
|
||||
output:
|
||||
`export = example;
|
||||
declare function example(x: any, ...args: any[]): void;`,
|
||||
},
|
||||
|
||||
{
|
||||
value: ({ default() {} }),
|
||||
output:
|
||||
`export default function _default(): void;`,
|
||||
},
|
||||
|
||||
{
|
||||
value: ({ default: class {} }),
|
||||
output:
|
||||
`export default class _default {
|
||||
}`,
|
||||
},
|
||||
|
||||
{
|
||||
value: new Date(),
|
||||
output:
|
||||
`export = example;
|
||||
declare const example: Date;`,
|
||||
},
|
||||
|
||||
{
|
||||
value: [0],
|
||||
output:
|
||||
`export = example;
|
||||
declare const example: number[];`,
|
||||
},
|
||||
{
|
||||
value: [() => 0, () => ""],
|
||||
output:
|
||||
`export = example;
|
||||
declare const example: Function[];`,
|
||||
},
|
||||
{
|
||||
value: (() => {
|
||||
const a = [];
|
||||
a.push(a);
|
||||
return a;
|
||||
})(),
|
||||
output:
|
||||
`export = example;
|
||||
declare const example: any[];`,
|
||||
},
|
||||
{
|
||||
value: (() => {
|
||||
const o = {
|
||||
default: 0,
|
||||
a: 0,
|
||||
b: "",
|
||||
self: null,
|
||||
fn: x => x,
|
||||
ns1: { x: 0, default: 0 },
|
||||
ns2: { fn: x => x, default: 0 },
|
||||
};
|
||||
o.self = o;
|
||||
return o;
|
||||
})(),
|
||||
output:
|
||||
`export const a: number;
|
||||
export const b: string;
|
||||
export default _default;
|
||||
export const _default: number;
|
||||
export function fn(x: any): void;
|
||||
export const ns1: {
|
||||
default: number;
|
||||
x: number;
|
||||
};
|
||||
export namespace ns2 {
|
||||
function fn(x: any): void;
|
||||
}
|
||||
// Circular reference from example
|
||||
export const self: any;`,
|
||||
},
|
||||
);
|
||||
35
tests/cases/fourslash/generateTypes_baselines.ts
Normal file
35
tests/cases/fourslash/generateTypes_baselines.ts
Normal file
@ -0,0 +1,35 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////dummy text
|
||||
|
||||
verify.generateTypes(
|
||||
// would like to test against the real "global" but that may vary between node versions.
|
||||
{
|
||||
value: {
|
||||
Array: ignore(Array, ["values"]),
|
||||
Boolean,
|
||||
Date,
|
||||
Math,
|
||||
Number,
|
||||
RegExp,
|
||||
String: ignore(String, ["padStart", "padEnd", "trimStart", "trimEnd"]),
|
||||
Symbol: ignore(Symbol, ["asyncIterator"]),
|
||||
},
|
||||
outputBaseline: "global",
|
||||
},
|
||||
{ value: require("lodash"), outputBaseline: "lodash" },
|
||||
);
|
||||
|
||||
// Ignore properties only present in newer versions of node.
|
||||
function ignore(Cls: Function, ignored: ReadonlyArray<string>): Function {
|
||||
class Copy {}
|
||||
for (const name of Object.getOwnPropertyNames(Cls)) {
|
||||
if (ignored.includes(name) || name === "arguments" || name === "caller" || name === "name" || name === "length" || name === "prototype") continue;
|
||||
Copy[name] = Cls[name];
|
||||
}
|
||||
for (const name of Object.getOwnPropertyNames(Cls.prototype)) {
|
||||
if (ignored.includes(name)) continue;
|
||||
Copy.prototype[name] = Cls.prototype[name];
|
||||
}
|
||||
return Copy;
|
||||
}
|
||||
109
tests/cases/fourslash/generateTypes_classes.ts
Normal file
109
tests/cases/fourslash/generateTypes_classes.ts
Normal file
@ -0,0 +1,109 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////dummy text
|
||||
|
||||
verify.generateTypes(
|
||||
{
|
||||
value: class {},
|
||||
output:
|
||||
`export = example;
|
||||
declare class example {
|
||||
}`,
|
||||
},
|
||||
|
||||
{
|
||||
value: class {
|
||||
constructor(x) {
|
||||
(this as any).x = x;
|
||||
// Code inside this function should be ignored
|
||||
function f(this: any) {
|
||||
this.y = 0;
|
||||
}
|
||||
// Same for this class
|
||||
class Other { constructor() { (this as any).z = 0; } }
|
||||
}
|
||||
},
|
||||
output:
|
||||
`export = example;
|
||||
declare class example {
|
||||
constructor(x: any);
|
||||
x: any;
|
||||
}`,
|
||||
},
|
||||
{
|
||||
value: { x: 0, export: 0 },
|
||||
output: `export const x: number;`,
|
||||
},
|
||||
{
|
||||
value: (() => {
|
||||
class Super {
|
||||
superField = 0; // TODO: climb to prototype.constructor and get instance fields?
|
||||
superMethod() {}
|
||||
static superStaticMethod() {}
|
||||
}
|
||||
class C extends Super {
|
||||
constructor() {
|
||||
super();
|
||||
(this as any)._privateField = 0;
|
||||
(this as any).field = 0;
|
||||
}
|
||||
|
||||
_privateMethod() {}
|
||||
method(_p) {
|
||||
(this as any).otherField = 0; // TODO: include this in output?
|
||||
}
|
||||
|
||||
static _privateStatic() {}
|
||||
static staticMethod(_s: any) {}
|
||||
static staticMethodWithNoNamespaceMembers(_p: any) {}
|
||||
|
||||
static _privateStaticField = 0;
|
||||
static staticField = 0;
|
||||
static innerClass = class {};
|
||||
}
|
||||
(C.prototype as any).prototypeNonFunction = 0; // ignored
|
||||
(C.staticMethod as any).staticMethodProperty = 0;
|
||||
(C.staticMethod as any)._staticFieldPrivateMember = 0;
|
||||
(C.prototype.method as any).methodMember = 0; // ignored
|
||||
// Non-identifier names should be ignored.
|
||||
(C as any)["&"] = function() {};
|
||||
(C.prototype as any)["&"] = function() {};
|
||||
return C;
|
||||
})(),
|
||||
output:
|
||||
`export = example;
|
||||
declare class example {
|
||||
static staticField: number;
|
||||
static staticMethodWithNoNamespaceMembers(_p: any): void;
|
||||
static superStaticMethod(): void;
|
||||
field: any;
|
||||
method(_p: any): void;
|
||||
superMethod(): void;
|
||||
}
|
||||
declare namespace example {
|
||||
class innerClass {
|
||||
}
|
||||
function staticMethod(_s: any): void;
|
||||
namespace staticMethod {
|
||||
const staticMethodProperty: number;
|
||||
}
|
||||
}`,
|
||||
},
|
||||
|
||||
{
|
||||
value: (() => {
|
||||
function F() { this.x = 0; }
|
||||
(F as any).staticMethod = function() {}
|
||||
F.prototype.method = function() { }
|
||||
return F;
|
||||
})(),
|
||||
output:
|
||||
`export = example;
|
||||
declare class example {
|
||||
static staticMethod(): void;
|
||||
x: any;
|
||||
method(): void;
|
||||
}`,
|
||||
},
|
||||
|
||||
);
|
||||
Loading…
x
Reference in New Issue
Block a user