From e0a6e80084c1e886b3f06835a01335c86c371cb5 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 29 Sep 2026 16:02:08 -0700 Subject: [PATCH 1/5] Ensure completion symbols returned to API always come from the current snapshot --- packages/typescript/src/api/async/api.ts | 1 + packages/typescript/src/api/async/types.ts | 3 + .../typescript/src/api/proto.generated.ts | 195 ++++++++++++ packages/typescript/src/api/sync/api.ts | 2 + packages/typescript/src/api/sync/types.ts | 3 + packages/typescript/test/async/api.test.ts | 50 +++ packages/typescript/test/sync/api.test.ts | 42 +++ tools/gen-proto/main.go | 49 ++- tools/gen-proto/main_test.go | 9 + tsc/internal/api/proto.go | 18 +- tsc/internal/api/session.go | 39 ++- tsc/internal/api/session_completion_test.go | 285 +++++++++++++++++- tsc/internal/ls/autoimport/registry.go | 28 +- tsc/internal/ls/languageservice.go | 4 + tsc/internal/ls/lsutil/userpreferences.go | 108 ++++--- .../ls/lsutil/userpreferences_test.go | 11 + tsc/internal/project/snapshot.go | 19 +- tsc/internal/project/snapshothost.go | 5 + 18 files changed, 800 insertions(+), 71 deletions(-) diff --git a/packages/typescript/src/api/async/api.ts b/packages/typescript/src/api/async/api.ts index d767720351e95..0c9ca9cb64b47 100644 --- a/packages/typescript/src/api/async/api.ts +++ b/packages/typescript/src/api/async/api.ts @@ -1533,6 +1533,7 @@ export class LanguageService { position, triggerCharacter: options?.triggerCharacter, includeSymbol: options?.includeSymbol, + preferences: options?.preferences, }); if (!data) return undefined; return { diff --git a/packages/typescript/src/api/async/types.ts b/packages/typescript/src/api/async/types.ts index 0844a354223f2..4910895f63c5f 100644 --- a/packages/typescript/src/api/async/types.ts +++ b/packages/typescript/src/api/async/types.ts @@ -9,6 +9,7 @@ import type { ParameterDeclaration, } from "../../ast/ast.ts"; import type { + CompletionPreferences, Diagnostic, RequestFileSystem, } from "../proto.ts"; @@ -388,6 +389,8 @@ export interface CompletionOptions { triggerCharacter?: string | undefined; /** Include a `symbol` property on each completion entry. Only populated for symbol-based completions (not keywords or literals). */ includeSymbol?: boolean | undefined; + /** Overrides the snapshot preferences used to produce this completion list. */ + preferences?: CompletionPreferences | undefined; } /** A single completion item returned by {@link LanguageService.getCompletionsAtPosition}. */ diff --git a/packages/typescript/src/api/proto.generated.ts b/packages/typescript/src/api/proto.generated.ts index 4dccbe902202c..0bfcb2f9e5e8a 100644 --- a/packages/typescript/src/api/proto.generated.ts +++ b/packages/typescript/src/api/proto.generated.ts @@ -233,6 +233,10 @@ export interface InitializeResponse { /** CreateSnapshotParams are the parameters for creating a new independent snapshot. */ export interface CreateSnapshotParams extends SnapshotRequestChangesParams { + /** UserPreferences configures language service behavior in the new snapshot. */ + userPreferences?: UserPreferences | undefined; + /** PrepareAutoImports identifies the file whose auto-import indexes should be ready in the new snapshot. */ + prepareAutoImports?: DocumentIdentifier | undefined; /** FileNotifications describes host file system changes to invalidate while creating the snapshot. */ fileNotifications?: FileNotifications | undefined; /** @@ -951,6 +955,7 @@ export interface GetCompletionsAtPositionParams { position: number; triggerCharacter?: string | undefined; includeSymbol?: boolean | undefined; + preferences?: CompletionPreferences | undefined; } /** CompletionInfoResponse wraps a list of completion entries. */ @@ -1472,6 +1477,113 @@ export interface SnapshotRequestChangesParams { ensurePrograms?: EnsurePrograms | undefined; } +/** UserPreferences represents TypeScript language service preferences. */ +export interface UserPreferences extends FormatCodeSettings, CompletionPreferences, InlayHintsPreferences, CodeLensUserPreferences { + quotePreference?: "auto" | "double" | "single" | undefined; + lazyConfiguredProjectsFromExternalProject?: boolean | undefined; + /** + * A positive integer indicating the maximum length of a hover text before it is truncated. + * + * Default: `500` + */ + maximumHoverLength?: number | undefined; + autoClosingTags?: boolean | undefined; + completeJSDocs?: boolean | undefined; + generateReturnInDocTemplate?: boolean | undefined; + importModuleSpecifierPreference?: "shortest" | "project-relative" | "relative" | "non-relative" | undefined; + /** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */ + importModuleSpecifierEnding?: "auto" | "minimal" | "index" | "js" | undefined; + autoImportSpecifierExcludeRegexes?: string[] | undefined; + autoImportFileExcludePatterns?: string[] | undefined; + autoImportEntrypointDirectorySearch?: boolean | undefined; + preferTypeOnlyAutoImports?: boolean | undefined; + /** + * Indicates which deterministic preset should be used to sort imports. + * "auto" detects the existing ordinal case sensitivity where possible. + */ + organizeImportsSort?: "auto" | "ordinal" | "ordinalIgnoreCase" | "natural" | "naturalIgnoreCase" | undefined; + /** + * Indicates whether imports should be organized in a case-insensitive manner. + * + * Default: TSUnknown ("auto" in strada), will perform detection + */ + organizeImportsIgnoreCase?: boolean | undefined; + /** + * Indicates whether imports should be organized via an "ordinal" (binary) comparison using the numeric value of their + * code points, or via "unicode" natural sorting. This implementation is locale-agnostic and approximates the practical + * import-sorting behavior rather than the full Unicode Collation Algorithm. + * + * Default: Ordinal + */ + organizeImportsCollation?: "ordinal" | "unicode" | undefined; + /** + * Indicates the locale to use for "unicode" collation in legacy clients. This is accepted for compatibility, but + * currently ignored because organize-import sorting is deterministic and locale-agnostic. + * + * This preference is ignored if organizeImportsCollation is not `unicode`. + * + * Default: `"en"` + */ + organizeImportsLocale?: string | undefined; + /** + * Indicates whether numeric collation should be used for digit sequences in strings. When `true`, will collate + * strings such that `a1z < a2z < a100z`. When `false`, will collate strings such that `a1z < a100z < a2z`. + * + * This preference is ignored if organizeImportsCollation is not `unicode`. + * + * Default: `false` + */ + organizeImportsNumericCollation?: boolean | undefined; + /** + * Indicates whether accents and other diacritic marks are considered unequal for the purpose of sorting. + * + * This preference is ignored if organizeImportsCollation is not `unicode`. + * + * Default: `true` + */ + organizeImportsAccentCollation?: boolean | undefined; + /** + * Indicates whether upper case or lower case should sort first. + * + * This permission is ignored if: + * - organizeImportsCollation is not `unicode` + * - organizeImportsIgnoreCase is `true` + * - organizeImportsIgnoreCase is `auto` and the auto-detected case sensitivity is case-insensitive. + * + * Default: `false` + */ + organizeImportsCaseFirst?: "default" | "lower" | "upper" | undefined; + /** + * Indicates where named type-only imports should sort. "inline" sorts named imports without regard to if the import is type-only. + * + * Default: `auto`, which defaults to `last` + */ + organizeImportsTypeOrder?: "auto" | "last" | "inline" | "first" | undefined; + allowTextChangesInNewFiles?: boolean | undefined; + providePrefixAndSuffixTextForRename?: boolean | undefined; + allowRenameOfImportPath?: boolean | undefined; + provideRefactorNotApplicableReason?: boolean | undefined; + preferGoToSourceDefinition?: boolean | undefined; + excludeLibrarySymbolsInNavTo?: boolean | undefined; + workspaceSymbolsScope?: "allOpenProjects" | "currentProject" | undefined; + formatEnabled?: boolean | undefined; + validateEnabled?: boolean | undefined; + disableSuggestions?: boolean | undefined; + disableLineTextInReferences?: boolean | undefined; + displayPartsForJSDoc?: boolean | undefined; + reportStyleChecksAsWarnings?: boolean | undefined; + locale?: string | undefined; + /** DisableAutomaticTypeAcquisition is the deprecated setting from typescript.disableAutomaticTypeAcquisition. */ + disableAutomaticTypeAcquisition?: boolean | undefined; + /** + * AutomaticTypeAcquisitionEnabled is the unified setting from tsserver.automaticTypeAcquisition.enabled under the js/ts section. + * When set, it takes precedence over DisableAutomaticTypeAcquisition. + */ + automaticTypeAcquisitionEnabled?: boolean | undefined; + /** CustomConfigFileName specifies a custom config file name to use before defaulting to tsconfig.json/jsconfig.json. */ + customConfigFileName?: string | undefined; +} + /** * FileNotifications describes changes to files that have occurred on the host * file system, used to notify the session to reload cached files and reevaluate @@ -1705,6 +1817,37 @@ export interface ImportAdderAction { isValidTypeOnlyUseSite?: boolean | undefined; } +/** CompletionPreferences contains preferences used while producing completions. */ +export interface CompletionPreferences { + /** + * If enabled, TypeScript will search through all external modules' exports and add them to the completions list. + * This affects lone identifier completions but not completions on the right hand side of `obj.`. + */ + includeCompletionsForModuleExports?: boolean | undefined; + /** + * Enables auto-import-style completions on partially-typed import statements. E.g., allows + * `import write|` to be completed to `import { writeFile } from "fs"`. + */ + includeCompletionsForImportStatements?: boolean | undefined; + /** + * Unless this option is `false`, member completion lists triggered with `.` will include entries + * on potentially-null and potentially-undefined values, with insertion text to replace + * preceding `.` tokens with `?.`. + */ + includeAutomaticOptionalChainCompletions?: boolean | undefined; + /** + * If enabled, completions for class members (e.g. methods and properties) will include + * a whole declaration for the member. + */ + includeCompletionsWithClassMemberSnippets?: boolean | undefined; + /** + * If enabled, object literal methods will have a method declaration completion entry in addition + * to the regular completion entry containing just the method name. + */ + includeCompletionsWithObjectLiteralMethodSnippets?: boolean | undefined; + jsxAttributeCompletionStyle?: "auto" | "braces" | "none" | undefined; +} + /** CompletionEntryResponse represents a single completion item. */ export interface CompletionEntryResponse { name: string; @@ -1746,6 +1889,48 @@ export interface ReconfigureSnapshotProgramParams { options?: CreateProgramOptions | undefined; } +export interface FormatCodeSettings extends EditorSettings { + insertSpaceAfterCommaDelimiter?: boolean | undefined; + insertSpaceAfterSemicolonInForStatements?: boolean | undefined; + insertSpaceBeforeAndAfterBinaryOperators?: boolean | undefined; + insertSpaceAfterConstructor?: boolean | undefined; + insertSpaceAfterKeywordsInControlFlowStatements?: boolean | undefined; + insertSpaceAfterFunctionKeywordForAnonymousFunctions?: boolean | undefined; + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis?: boolean | undefined; + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets?: boolean | undefined; + insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces?: boolean | undefined; + insertSpaceAfterOpeningAndBeforeClosingEmptyBraces?: boolean | undefined; + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces?: boolean | undefined; + insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean | undefined; + insertSpaceAfterTypeAssertion?: boolean | undefined; + insertSpaceBeforeFunctionParenthesis?: boolean | undefined; + placeOpenBraceOnNewLineForFunctions?: boolean | undefined; + placeOpenBraceOnNewLineForControlBlocks?: boolean | undefined; + insertSpaceBeforeTypeAnnotation?: boolean | undefined; + indentMultiLineObjectLiteralBeginningOnBlankLine?: boolean | undefined; + semicolons?: "ignore" | "insert" | "remove" | undefined; + indentSwitchCase?: boolean | undefined; +} + +export interface InlayHintsPreferences { + includeInlayParameterNameHints?: "none" | "literals" | "all" | undefined; + includeInlayParameterNameHintsWhenArgumentMatchesName?: boolean | undefined; + includeInlayFunctionParameterTypeHints?: boolean | undefined; + includeInlayVariableTypeHints?: boolean | undefined; + includeInlayVariableTypeHintsWhenTypeMatchesName?: boolean | undefined; + includeInlayPropertyDeclarationTypeHints?: boolean | undefined; + includeInlayFunctionLikeReturnTypeHints?: boolean | undefined; + includeInlayEnumMemberValueHints?: boolean | undefined; +} + +export interface CodeLensUserPreferences { + referencesCodeLensEnabled?: boolean | undefined; + implementationsCodeLensEnabled?: boolean | undefined; + referencesCodeLensShowOnAllFunctions?: boolean | undefined; + implementationsCodeLensShowOnInterfaceMethods?: boolean | undefined; + implementationsCodeLensShowOnAllClassMethods?: boolean | undefined; +} + /** * RequestDirectoryEntries is a cached directory listing. Entry names are * relative to the directory, matching vfs.GetAccessibleEntries. @@ -1804,6 +1989,16 @@ export interface CreateProgramOptions { moduleResolver?: number | undefined; } +export interface EditorSettings { + baseIndentSize?: number | undefined; + indentSize?: number | undefined; + tabSize?: number | undefined; + newLineCharacter?: string | undefined; + convertTabsToSpaces?: boolean | undefined; + indentStyle?: "none" | "block" | "smart" | undefined; + trimTrailingWhitespace?: boolean | undefined; +} + export interface StaticModuleResolution { resolvedFileName?: DocumentIdentifier | undefined; originalPath?: DocumentIdentifier | undefined; diff --git a/packages/typescript/src/api/sync/api.ts b/packages/typescript/src/api/sync/api.ts index dcd00e40ee58d..d34525f067eb7 100644 --- a/packages/typescript/src/api/sync/api.ts +++ b/packages/typescript/src/api/sync/api.ts @@ -2666,6 +2666,7 @@ export class LanguageService { position, triggerCharacter: options?.triggerCharacter, includeSymbol: options?.includeSymbol, + preferences: options?.preferences, }); if (!data) return undefined; return { @@ -2684,6 +2685,7 @@ export class LanguageService { position, triggerCharacter: options?.triggerCharacter, includeSymbol: options?.includeSymbol, + preferences: options?.preferences, }); if (!data) return undefined; return { diff --git a/packages/typescript/src/api/sync/types.ts b/packages/typescript/src/api/sync/types.ts index a6a0e7b1c310d..1eec5b22902e1 100644 --- a/packages/typescript/src/api/sync/types.ts +++ b/packages/typescript/src/api/sync/types.ts @@ -22,6 +22,7 @@ import type { ParameterDeclaration, } from "../../ast/ast.ts"; import type { + CompletionPreferences, Diagnostic, RequestFileSystem, } from "../proto.ts"; @@ -527,6 +528,8 @@ export interface CompletionOptions { triggerCharacter?: string | undefined; /** Include a `symbol` property on each completion entry. Only populated for symbol-based completions (not keywords or literals). */ includeSymbol?: boolean | undefined; + /** Overrides the snapshot preferences used to produce this completion list. */ + preferences?: CompletionPreferences | undefined; } /** A single completion item returned by {@link LanguageService.getCompletionsAtPosition}. */ diff --git a/packages/typescript/test/async/api.test.ts b/packages/typescript/test/async/api.test.ts index 28d42215faeda..796607b04513f 100644 --- a/packages/typescript/test/async/api.test.ts +++ b/packages/typescript/test/async/api.test.ts @@ -2082,6 +2082,56 @@ describe("LanguageService - getCompletionsAtPosition", { concurrency }, () => { assert.ok(nameEntry.symbol, "Expected symbol to be set on 'name' entry when includeSymbol: true"); assert.equal(nameEntry.symbol.name, "name", "Symbol name should match completion name"); }); + + test("auto-import completions with symbols require a prepared snapshot", async () => { + const src = "someV"; + await using api = spawnAPI({ + "/tsconfig.json": `{ "compilerOptions": { "module": "esnext", "target": "esnext" }, "include": ["src"] }`, + "/src/export.ts": "export const someValue = 1;", + "/src/main.ts": src, + }); + + const unprepared = await api.createSnapshot({ + openProject: "/tsconfig.json", + userPreferences: { includeCompletionsForModuleExports: true }, + }); + const unpreparedProject = unprepared.getConfiguredProject("/tsconfig.json")!; + // @sync-skip-block-start + await assert.rejects( + unpreparedProject.languageService.getCompletionsAtPosition("/src/main.ts", src.length, { includeSymbol: true }), + /snapshot is not prepared for auto-imports/, + ); + // @sync-skip-block-end + // @sync-only-start + // assert.throws(() => unpreparedProject.languageService.getCompletionsAtPosition("/src/main.ts", src.length, { includeSymbol: true }), /snapshot is not prepared for auto-imports/); + // @sync-only-end + + const prepared = await unprepared.update({ prepareAutoImports: "/src/main.ts" }); + const preparedProject = prepared.getConfiguredProject("/tsconfig.json")!; + const completions = await preparedProject.languageService.getCompletionsAtPosition("/src/main.ts", src.length, { includeSymbol: true }); + assert.ok(completions?.entries.some(entry => entry.name === "someValue")); + }); + + test("completion preferences override snapshot preferences", async () => { + const src = "someV"; + await using api = spawnAPI({ + "/tsconfig.json": `{ "compilerOptions": { "module": "esnext", "target": "esnext" }, "include": ["src"] }`, + "/src/export.ts": "export const someValue = 1;", + "/src/main.ts": src, + }); + + const snapshot = await api.createSnapshot({ + openProject: "/tsconfig.json", + prepareAutoImports: "/src/main.ts", + userPreferences: { includeCompletionsForModuleExports: true }, + }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const completions = await project.languageService.getCompletionsAtPosition("/src/main.ts", src.length, { + preferences: { includeCompletionsForModuleExports: false }, + }); + assert.ok(completions); + assert.ok(!completions.entries.some(entry => entry.name === "someValue")); + }); }); describe("LanguageService - getReferencedSymbolsForNode", { concurrency }, () => { diff --git a/packages/typescript/test/sync/api.test.ts b/packages/typescript/test/sync/api.test.ts index b39a98fc94c10..3fd5ef0e775b8 100644 --- a/packages/typescript/test/sync/api.test.ts +++ b/packages/typescript/test/sync/api.test.ts @@ -1949,6 +1949,48 @@ describe("LanguageService - getCompletionsAtPosition", { concurrency }, () => { assert.ok(nameEntry.symbol, "Expected symbol to be set on 'name' entry when includeSymbol: true"); assert.equal(nameEntry.symbol.name, "name", "Symbol name should match completion name"); }); + + test("auto-import completions with symbols require a prepared snapshot", () => { + const src = "someV"; + using api = spawnAPI({ + "/tsconfig.json": `{ "compilerOptions": { "module": "esnext", "target": "esnext" }, "include": ["src"] }`, + "/src/export.ts": "export const someValue = 1;", + "/src/main.ts": src, + }); + + const unprepared = api.createSnapshot({ + openProject: "/tsconfig.json", + userPreferences: { includeCompletionsForModuleExports: true }, + }); + const unpreparedProject = unprepared.getConfiguredProject("/tsconfig.json")!; + assert.throws(() => unpreparedProject.languageService.getCompletionsAtPosition("/src/main.ts", src.length, { includeSymbol: true }), /snapshot is not prepared for auto-imports/); + + const prepared = unprepared.update({ prepareAutoImports: "/src/main.ts" }); + const preparedProject = prepared.getConfiguredProject("/tsconfig.json")!; + const completions = preparedProject.languageService.getCompletionsAtPosition("/src/main.ts", src.length, { includeSymbol: true }); + assert.ok(completions?.entries.some(entry => entry.name === "someValue")); + }); + + test("completion preferences override snapshot preferences", () => { + const src = "someV"; + using api = spawnAPI({ + "/tsconfig.json": `{ "compilerOptions": { "module": "esnext", "target": "esnext" }, "include": ["src"] }`, + "/src/export.ts": "export const someValue = 1;", + "/src/main.ts": src, + }); + + const snapshot = api.createSnapshot({ + openProject: "/tsconfig.json", + prepareAutoImports: "/src/main.ts", + userPreferences: { includeCompletionsForModuleExports: true }, + }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const completions = project.languageService.getCompletionsAtPosition("/src/main.ts", src.length, { + preferences: { includeCompletionsForModuleExports: false }, + }); + assert.ok(completions); + assert.ok(!completions.entries.some(entry => entry.name === "someValue")); + }); }); describe("LanguageService - getReferencedSymbolsForNode", { concurrency }, () => { diff --git a/tools/gen-proto/main.go b/tools/gen-proto/main.go index c2541415b255f..7936e3c257131 100644 --- a/tools/gen-proto/main.go +++ b/tools/gen-proto/main.go @@ -403,7 +403,10 @@ func (r *typeRenderer) indexPackage(pkg *packages.Package) { func (r *typeRenderer) recordDoc(obj types.Object, doc *ast.CommentGroup) { if obj != nil && doc != nil { - r.docs[obj] = strings.TrimSpace(doc.Text()) + text := strings.TrimSpace(doc.Text()) + if text != "!!!" { + r.docs[obj] = text + } } } @@ -513,6 +516,22 @@ func (r *typeRenderer) namedType(named *types.Named) string { return "unknown" case "github.com/microsoft/TypeScript/tsc/internal/core.Tristate": return "boolean" + case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.IndentStyle": + return `"none" | "block" | "smart"` + case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.QuotePreference": + return `"auto" | "double" | "single"` + case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.JsxAttributeCompletionStyle": + return `"auto" | "braces" | "none"` + case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.IncludeInlayParameterNameHints": + return `"none" | "literals" | "all"` + case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.OrganizeImportsSort": + return `"auto" | "ordinal" | "ordinalIgnoreCase" | "natural" | "naturalIgnoreCase"` + case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.OrganizeImportsCollation": + return `"ordinal" | "unicode"` + case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.OrganizeImportsCaseFirst": + return `"default" | "lower" | "upper"` + case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.OrganizeImportsTypeOrder": + return `"auto" | "last" | "inline" | "first"` case "github.com/microsoft/TypeScript/tsc/internal/core.JsxEmit": return r.importType("JsxEmit", "#enums/jsxEmit") case "github.com/microsoft/TypeScript/tsc/internal/core.ModuleDetectionKind": @@ -527,6 +546,10 @@ func (r *typeRenderer) namedType(named *types.Named) string { return r.importType("ScriptTarget", "#enums/scriptTarget") case "github.com/microsoft/TypeScript/tsc/internal/core.ScriptKind": return r.importType("ScriptKind", "#enums/scriptKind") + case "github.com/microsoft/TypeScript/tsc/internal/modulespecifiers.ImportModuleSpecifierPreference": + return `"shortest" | "project-relative" | "relative" | "non-relative"` + case "github.com/microsoft/TypeScript/tsc/internal/modulespecifiers.ImportModuleSpecifierEndingPreference": + return `"auto" | "minimal" | "index" | "js"` case "github.com/microsoft/TypeScript/tsc/internal/collections.OrderedMap": if named.TypeArgs().Len() != 2 { return "Record" @@ -629,6 +652,10 @@ func (r *typeRenderer) declarations() (string, error) { for field := range structType.Fields() { if field.Embedded() { embedded = append(embedded, r.typeString(field.Type(), false)) + } else if named.Obj().Pkg().Path() == "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil" && + named.Obj().Name() == "UserPreferences" && + (field.Name() == "InlayHints" || field.Name() == "CodeLens") { + embedded = append(embedded, r.typeString(field.Type(), false)) } } fmt.Fprintf(&out, "export interface %s", exportedName(named.Obj().Name())) @@ -637,7 +664,11 @@ func (r *typeRenderer) declarations() (string, error) { } out.WriteString(" {\n") for i := range structType.NumFields() { - if structType.Field(i).Embedded() { + fieldName := structType.Field(i).Name() + if structType.Field(i).Embedded() || + named.Obj().Pkg().Path() == "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil" && + named.Obj().Name() == "UserPreferences" && + (fieldName == "InlayHints" || fieldName == "CodeLens") { continue } field, include, optional, nonnil, deprecated, internal := jsonField(structType, i) @@ -742,7 +773,9 @@ func jsonField(structType *types.Struct, index int) (name string, include bool, if !field.Exported() { return "", false, false, false, false, false } - tag := reflect.StructTag(structType.Tag(index)).Get("json") + structTag := reflect.StructTag(structType.Tag(index)) + tag := structTag.Get("json") + rawTag := structTag.Get("raw") noniltag := reflect.StructTag(structType.Tag(index)).Get("nonnil") deprecatedtag := reflect.StructTag(structType.Tag(index)).Get("deprecated") internaltag := reflect.StructTag(structType.Tag(index)).Get("internal") @@ -752,7 +785,15 @@ func jsonField(structType *types.Struct, index int) (name string, include bool, return "", false, false, noniltag == "true", deprecatedtag == "true", internaltag == "true" } if name == "" { - name = field.Name() + if rawName, _, ok := strings.Cut(rawTag, ","); ok { + name = rawName + optional = true + } else if rawTag != "" { + name = rawTag + optional = true + } else { + name = field.Name() + } } for _, option := range parts[1:] { if option == "omitempty" || option == "omitzero" { diff --git a/tools/gen-proto/main_test.go b/tools/gen-proto/main_test.go index d2d433ff6107c..5bc4c276b7a5d 100644 --- a/tools/gen-proto/main_test.go +++ b/tools/gen-proto/main_test.go @@ -33,6 +33,11 @@ func TestGenerate(t *testing.T) { `export interface UpdateSnapshotParams`, `export interface CreateSnapshotParams extends SnapshotRequestChangesParams`, `export interface LanguageServerSnapshotChanges extends SnapshotRequestChangesParams`, + `export interface UserPreferences extends FormatCodeSettings, CompletionPreferences, InlayHintsPreferences, CodeLensUserPreferences`, + `userPreferences?: UserPreferences | undefined;`, + `prepareAutoImports?: DocumentIdentifier | undefined;`, + `includeCompletionsForModuleExports?: boolean | undefined;`, + `quotePreference?: "auto" | "double" | "single" | undefined;`, `openProjects?: readonly DocumentIdentifier[] | undefined;`, `export type EnsurePrograms = true | readonly ProjectId[];`, `export type InferredProjectId = string & { __inferredProjectIdBrand: any; };`, @@ -98,6 +103,10 @@ export interface CompilerOptions`, if strings.Contains(generated, "projects: readonly ProjectResponse[];") { t.Error("response array fields must remain mutable") } + languageServerChanges := generated[strings.Index(generated, "export interface LanguageServerSnapshotChanges"):strings.Index(generated, "export interface BuildOptions")] + if strings.Contains(languageServerChanges, "userPreferences") || strings.Contains(languageServerChanges, "prepareAutoImports") { + t.Error("language server snapshot changes must not configure independent snapshot state") + } err = generate(input, output) if err != nil { diff --git a/tsc/internal/api/proto.go b/tsc/internal/api/proto.go index 818ce96e35816..79b281837093a 100644 --- a/tsc/internal/api/proto.go +++ b/tsc/internal/api/proto.go @@ -19,6 +19,7 @@ import ( "github.com/microsoft/TypeScript/tsc/internal/json" "github.com/microsoft/TypeScript/tsc/internal/locale" "github.com/microsoft/TypeScript/tsc/internal/ls/lsconv" + "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil" "github.com/microsoft/TypeScript/tsc/internal/lsp/lsproto" "github.com/microsoft/TypeScript/tsc/internal/module" "github.com/microsoft/TypeScript/tsc/internal/packagejson" @@ -420,6 +421,10 @@ func (e *EnsurePrograms) UnmarshalJSONFrom(dec *json.Decoder) error { // CreateSnapshotParams are the parameters for creating a new independent snapshot. type CreateSnapshotParams struct { SnapshotRequestChangesParams + // UserPreferences configures language service behavior in the new snapshot. + UserPreferences *lsutil.UserPreferences `json:"userPreferences,omitempty"` + // PrepareAutoImports identifies the file whose auto-import indexes should be ready in the new snapshot. + PrepareAutoImports *DocumentIdentifier `json:"prepareAutoImports,omitempty"` // FileNotifications describes host file system changes to invalidate while creating the snapshot. FileNotifications *FileNotifications `json:"fileNotifications,omitempty"` // FileSystem supplies file contents and directory listings for the new snapshot. @@ -1538,12 +1543,13 @@ type SignatureUsageResponse struct { // GetCompletionsAtPositionParams are the parameters for the getCompletionsAtPosition method. type GetCompletionsAtPositionParams struct { - Snapshot SnapshotID `json:"snapshot"` - Project project.ID `json:"project"` - File DocumentIdentifier `json:"file"` - Position uint32 `json:"position"` - TriggerCharacter *string `json:"triggerCharacter,omitempty"` - IncludeSymbol bool `json:"includeSymbol,omitempty"` + Snapshot SnapshotID `json:"snapshot"` + Project project.ID `json:"project"` + File DocumentIdentifier `json:"file"` + Position uint32 `json:"position"` + TriggerCharacter *string `json:"triggerCharacter,omitempty"` + IncludeSymbol bool `json:"includeSymbol,omitempty"` + Preferences *lsutil.CompletionPreferences `json:"preferences,omitempty"` } // CompletionEntryLabelDetailsResponse holds additional label display text for a completion entry. diff --git a/tsc/internal/api/session.go b/tsc/internal/api/session.go index a70119ca47883..361b49411760a 100644 --- a/tsc/internal/api/session.go +++ b/tsc/internal/api/session.go @@ -102,7 +102,6 @@ func (sd *snapshotData) getProgram(projectHandle project.ID) (*compiler.Program, if err != nil { return nil, err } - program := proj.GetProgram() if program == nil { return nil, fmt.Errorf("%w: project has no program", ErrClientError) @@ -1228,6 +1227,10 @@ func (s *Session) handleCreateSnapshot(ctx context.Context, params *CreateSnapsh if err != nil { return nil, err } + apiRequest.UserPreferences = params.UserPreferences + if params.PrepareAutoImports != nil { + apiRequest.PrepareAutoImports = params.PrepareAutoImports.ToURI(s.GetCurrentDirectory()) + } openState := s.reconcileSnapshotOpens(apiRequest, snapshotOpenState{}) fileChanges := s.toFileChangeSummary(params.FileNotifications) @@ -1248,6 +1251,10 @@ func (s *Session) handleCreateSnapshot(ctx context.Context, params *CreateSnapsh snapshot.Deref() return nil, fmt.Errorf("%w: failed to create snapshot: %w", ErrClientError, err) } + if err := s.validatePreparedAutoImports(ctx, snapshot, params.PrepareAutoImports); err != nil { + snapshot.Deref() + return nil, err + } if err := moduleResolutionError(snapshot); err != nil { snapshot.Deref() return nil, err @@ -1273,6 +1280,10 @@ func (s *Session) handleUpdateSnapshot(ctx context.Context, params *UpdateSnapsh if err != nil { return nil, err } + apiRequest.UserPreferences = changes.UserPreferences + if changes.PrepareAutoImports != nil { + apiRequest.PrepareAutoImports = changes.PrepareAutoImports.ToURI(s.GetCurrentDirectory()) + } openState := s.reconcileSnapshotOpens(apiRequest, snapshotOpenState{openProjects: baseSD.openProjects, openFiles: baseSD.openFiles}) fileChanges := s.toFileChangeSummary(changes.FileNotifications) snapshotFileSystem := baseSD.fileSystem @@ -1296,6 +1307,10 @@ func (s *Session) handleUpdateSnapshot(ctx context.Context, params *UpdateSnapsh snapshot.Deref() return nil, fmt.Errorf("%w: failed to update snapshot: %w", ErrClientError, err) } + if err := s.validatePreparedAutoImports(ctx, snapshot, changes.PrepareAutoImports); err != nil { + snapshot.Deref() + return nil, err + } if err := moduleResolutionError(snapshot); err != nil { snapshot.Deref() return nil, err @@ -1435,6 +1450,22 @@ func (s *Session) toAPISnapshotRequest(ctx context.Context, changes *SnapshotReq return apiRequest, nil } +func (s *Session) validatePreparedAutoImports(ctx context.Context, snapshot *project.Snapshot, file *DocumentIdentifier) error { + if file == nil { + return nil + } + if err := ctx.Err(); err != nil { + return err + } + uri := file.ToURI(s.GetCurrentDirectory()) + proj := snapshot.GetDefaultProject(uri) + if proj == nil || snapshot.AutoImportRegistry() == nil || + !snapshot.AutoImportRegistry().IsPreparedForImportingFile(uri.FileName(), proj.ID(), snapshot.UserPreferences()) { + return fmt.Errorf("%w: could not prepare auto-imports for %s", ErrClientError, file) + } + return nil +} + type languageServerSnapshotUpdate struct { request *project.APISnapshotRequest openState snapshotOpenState @@ -5001,6 +5032,9 @@ func (s *Session) handleGetCompletionsAtPosition(ctx context.Context, params *Ge if e != nil { return nil, e } + if params.Preferences != nil { + langSvc.SetUserPreferences(langSvc.UserPreferences().WithCompletionPreferences(*params.Preferences)) + } internalPos := sourceFile.GetPositionMap().UTF16ToUTF8(int(params.Position)) return langSvc.GetCompletionsAtPosition(ctx, sourceFile, internalPos, params.TriggerCharacter, params.IncludeSymbol) } @@ -5011,6 +5045,9 @@ func (s *Session) handleGetCompletionsAtPosition(ctx context.Context, params *Ge } result, err := run(sd.snapshot, program) if errors.Is(err, ls.ErrNeedsAutoImports) { + if params.IncludeSymbol { + return nil, fmt.Errorf("%w: snapshot is not prepared for auto-imports for %s", ErrClientError, params.File) + } preparedSnapshot := s.snapshotHost.CloneSnapshotWithAutoImports(ctx, sd.snapshot, params.File.ToURI(s.GetCurrentDirectory()), nil) if s.projectSession != nil { s.projectSession.TryAdoptSnapshotInBackground(sd.snapshot, preparedSnapshot) diff --git a/tsc/internal/api/session_completion_test.go b/tsc/internal/api/session_completion_test.go index 1596cff1a198c..3d97b9150ded0 100644 --- a/tsc/internal/api/session_completion_test.go +++ b/tsc/internal/api/session_completion_test.go @@ -7,6 +7,8 @@ import ( "github.com/microsoft/TypeScript/tsc/internal/bundled" "github.com/microsoft/TypeScript/tsc/internal/core" "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil" + "github.com/microsoft/TypeScript/tsc/internal/lsp/lsproto" + "github.com/microsoft/TypeScript/tsc/internal/testutil" "github.com/microsoft/TypeScript/tsc/internal/testutil/projecttestutil" "gotest.tools/v3/assert" ) @@ -187,6 +189,286 @@ func TestCompletionRetriesWithAutoImports(t *testing.T) { t.Fatal("expected auto-import completion for someValue") } +func TestCompletionWithSymbolsRequiresPreparedAutoImports(t *testing.T) { + t.Parallel() + if !bundled.Embedded { + t.Skip("bundled files are not embedded") + } + + const fileName = "/home/projects/p/src/index.ts" + const content = "someV" + projectSession, _ := projecttestutil.Setup(map[string]any{ + "/home/projects/p/tsconfig.json": `{ "compilerOptions": { "module": "esnext", "target": "esnext" } }`, + "/home/projects/p/src/export.ts": "export const someValue = 1;", + fileName: content, + }) + defer projectSession.Close() + + session := NewLSPSession(projectSession, nil) + defer session.Close() + + snapshotResp, err := session.handleCreateSnapshot(t.Context(), &CreateSnapshotParams{ + OpenFiles: []DocumentIdentifier{{FileName: fileName}}, + UserPreferences: &lsutil.UserPreferences{ + IncludeCompletionsForModuleExports: core.TSTrue, + }, + }) + assert.NilError(t, err) + proj, err := session.handleGetDefaultProjectForFile(t.Context(), &GetDefaultProjectForFileParams{ + Snapshot: snapshotResp.Snapshot, + File: DocumentIdentifier{FileName: fileName}, + }) + assert.NilError(t, err) + + _, err = session.handleGetCompletionsAtPosition(t.Context(), &GetCompletionsAtPositionParams{ + Snapshot: snapshotResp.Snapshot, + Project: proj.Id, + File: DocumentIdentifier{FileName: fileName}, + Position: uint32(len(content)), + IncludeSymbol: true, + }) + assert.ErrorContains(t, err, "snapshot is not prepared for auto-imports") +} + +func TestCompletionWithSymbolsUsesPreparedSnapshot(t *testing.T) { + t.Parallel() + if !bundled.Embedded { + t.Skip("bundled files are not embedded") + } + + const fileName = "/home/projects/p/src/index.ts" + const content = "someV" + projectSession, _ := projecttestutil.Setup(map[string]any{ + "/home/projects/p/tsconfig.json": `{ "compilerOptions": { "module": "esnext", "target": "esnext" } }`, + "/home/projects/p/src/export.ts": "export const someValue = 1;", + fileName: content, + }) + defer projectSession.Close() + + session := NewLSPSession(projectSession, nil) + defer session.Close() + + snapshotResp, err := session.handleCreateSnapshot(t.Context(), &CreateSnapshotParams{ + OpenFiles: []DocumentIdentifier{{FileName: fileName}}, + PrepareAutoImports: &DocumentIdentifier{FileName: fileName}, + UserPreferences: &lsutil.UserPreferences{ + IncludeCompletionsForModuleExports: core.TSTrue, + }, + }) + assert.NilError(t, err) + proj, err := session.handleGetDefaultProjectForFile(t.Context(), &GetDefaultProjectForFileParams{ + Snapshot: snapshotResp.Snapshot, + File: DocumentIdentifier{FileName: fileName}, + }) + assert.NilError(t, err) + + completions, err := session.handleGetCompletionsAtPosition(t.Context(), &GetCompletionsAtPositionParams{ + Snapshot: snapshotResp.Snapshot, + Project: proj.Id, + File: DocumentIdentifier{FileName: fileName}, + Position: uint32(len(content)), + IncludeSymbol: true, + }) + assert.NilError(t, err) + assert.Assert(t, completions != nil) + for _, entry := range completions.Entries { + if entry.Name == "someValue" { + return + } + } + t.Fatal("expected auto-import completion for someValue") +} + +func TestCompletionPreferencesOverrideSnapshot(t *testing.T) { + t.Parallel() + if !bundled.Embedded { + t.Skip("bundled files are not embedded") + } + + const fileName = "/home/projects/p/src/index.ts" + const content = "someV" + projectSession, _ := projecttestutil.Setup(map[string]any{ + "/home/projects/p/tsconfig.json": `{ "compilerOptions": { "module": "esnext", "target": "esnext" } }`, + "/home/projects/p/src/export.ts": "export const someValue = 1;", + fileName: content, + }) + defer projectSession.Close() + + session := NewLSPSession(projectSession, nil) + defer session.Close() + + snapshotResp, err := session.handleCreateSnapshot(t.Context(), &CreateSnapshotParams{ + OpenFiles: []DocumentIdentifier{{FileName: fileName}}, + PrepareAutoImports: &DocumentIdentifier{FileName: fileName}, + UserPreferences: &lsutil.UserPreferences{ + IncludeCompletionsForModuleExports: core.TSTrue, + }, + }) + assert.NilError(t, err) + proj, err := session.handleGetDefaultProjectForFile(t.Context(), &GetDefaultProjectForFileParams{ + Snapshot: snapshotResp.Snapshot, + File: DocumentIdentifier{FileName: fileName}, + }) + assert.NilError(t, err) + + completions, err := session.handleGetCompletionsAtPosition(t.Context(), &GetCompletionsAtPositionParams{ + Snapshot: snapshotResp.Snapshot, + Project: proj.Id, + File: DocumentIdentifier{FileName: fileName}, + Position: uint32(len(content)), + Preferences: &lsutil.CompletionPreferences{ + IncludeCompletionsForModuleExports: core.TSFalse, + }, + }) + assert.NilError(t, err) + assert.Assert(t, completions != nil) + for _, entry := range completions.Entries { + assert.Assert(t, entry.Name != "someValue", "per-call preferences should disable auto-import completions") + } +} + +func TestSnapshotCreatesProgramsAndPreparesAutoImportsInOneClone(t *testing.T) { + t.Parallel() + for _, update := range []bool{false, true} { + t.Run(map[bool]string{false: "create", true: "update"}[update], func(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "snapshot creation panicked") + const fileName = "/home/projects/p/index.ts" + projectSession, _ := projecttestutil.Setup(map[string]any{ + "/home/projects/p/tsconfig.json": "{}", + fileName: "someV", + "/home/projects/p/export.ts": "export const someValue = 1;", + "/home/projects/synthetic.ts": "export const x = 1;", + }) + defer projectSession.Close() + session := NewLSPSession(projectSession, nil) + defer session.Close() + params := &CreateSnapshotParams{ + OpenProjects: []DocumentIdentifier{{FileName: "/home/projects/p/tsconfig.json"}}, + PrepareAutoImports: &DocumentIdentifier{FileName: fileName}, + CreatePrograms: []*CreateSnapshotProgramParams{{ + RootFiles: []DocumentIdentifier{{FileName: "/home/projects/synthetic.ts"}}, + CompilerOptions: core.CompilerOptions{NoLib: core.TSTrue}, + }}, + } + var response *CreateSnapshotResponse + var err error + expectedID := SnapshotID(1) + if update { + base, e := session.handleCreateSnapshot(t.Context(), &CreateSnapshotParams{}) + assert.NilError(t, e) + expectedID = base.Snapshot + 1 + response, err = session.handleUpdateSnapshot(t.Context(), &UpdateSnapshotParams{ + Snapshot: base.Snapshot, + Changes: params, + }) + } else { + response, err = session.handleCreateSnapshot(t.Context(), params) + } + assert.NilError(t, err) + assert.Equal(t, response.Snapshot, expectedID) + assert.Equal(t, len(*response.Operation.CreatedPrograms), 1) + snapshot := session.snapshots[response.Snapshot].snapshot + proj := snapshot.GetDefaultProject("file:///home/projects/p/index.ts") + assert.Assert(t, snapshot.AutoImportRegistry().IsPreparedForImportingFile(fileName, proj.ID(), snapshot.UserPreferences())) + }) + } +} + +func TestPreparedIndependentSnapshotPreservesLSPOverlays(t *testing.T) { + t.Parallel() + const fileName = "/home/projects/p/index.ts" + projectSession, _ := projecttestutil.Setup(map[string]any{ + "/home/projects/p/tsconfig.json": "{}", + fileName: "diskOnly", + "/home/projects/p/package.json": `{"dependencies":{"my-pkg":"1.0.0"}}`, + "/home/projects/p/node_modules/my-pkg/package.json": `{"name":"my-pkg","version":"1.0.0","types":"index.d.ts"}`, + "/home/projects/p/node_modules/my-pkg/index.d.ts": "export declare const packageValue: number;", + }) + defer projectSession.Close() + projectSession.DidOpenFile(t.Context(), "file:///home/projects/p/index.ts", 1, "packageV", lsproto.LanguageKindTypeScript) + session := NewLSPSession(projectSession, nil) + defer session.Close() + base, err := session.handleGetCurrentLanguageServerSnapshot(t.Context(), &GetCurrentLanguageServerSnapshotParams{}) + assert.NilError(t, err) + prepared, err := session.handleUpdateSnapshot(t.Context(), &UpdateSnapshotParams{ + Snapshot: base.Snapshot, + Changes: &CreateSnapshotParams{ + PrepareAutoImports: &DocumentIdentifier{FileName: fileName}, + }, + }) + assert.NilError(t, err) + snapshot := session.snapshots[prepared.Snapshot].snapshot + content, ok := snapshot.ReadFile(fileName) + assert.Assert(t, ok) + assert.Equal(t, content, "packageV") + proj := snapshot.GetDefaultProject("file:///home/projects/p/index.ts") + assert.Equal(t, proj.GetProgram().GetSourceFile(fileName).Text(), "packageV") + completions, err := session.handleGetCompletionsAtPosition(t.Context(), &GetCompletionsAtPositionParams{ + Snapshot: prepared.Snapshot, + Project: proj.ID(), + File: DocumentIdentifier{FileName: fileName}, + Position: 8, + IncludeSymbol: true, + }) + assert.NilError(t, err) + for _, entry := range completions.Entries { + if entry.Name == "packageValue" { + return + } + } + t.Fatal("expected dependency auto-import completion from an LSP-derived snapshot") +} + +func TestFreshSnapshotIncludesDependencyAutoImports(t *testing.T) { + t.Parallel() + for _, prepare := range []bool{false, true} { + t.Run(map[bool]string{false: "retry", true: "prepared"}[prepare], func(t *testing.T) { + t.Parallel() + const fileName = "/home/projects/MixedCase/index.ts" + projectSession, _ := projecttestutil.Setup(map[string]any{ + "/home/projects/MixedCase/tsconfig.json": "{}", + fileName: "packageV", + "/home/projects/MixedCase/package.json": `{"dependencies":{"my-pkg":"1.0.0"}}`, + "/home/projects/MixedCase/node_modules/my-pkg/package.json": `{"name":"my-pkg","version":"1.0.0","types":"index.d.ts"}`, + "/home/projects/MixedCase/node_modules/my-pkg/index.d.ts": "export declare const packageValue: number;", + }) + defer projectSession.Close() + projectSession.DidOpenFile(t.Context(), "file:///home/projects/MixedCase/index.ts", 1, "editorOnly", lsproto.LanguageKindTypeScript) + session := NewLSPSession(projectSession, nil) + defer session.Close() + params := &CreateSnapshotParams{ + OpenProjects: []DocumentIdentifier{{FileName: "/home/projects/MixedCase/tsconfig.json"}}, + } + if prepare { + params.PrepareAutoImports = &DocumentIdentifier{FileName: fileName} + } + response, err := session.handleCreateSnapshot(t.Context(), params) + assert.NilError(t, err) + snapshot := session.snapshots[response.Snapshot].snapshot + content, ok := snapshot.ReadFile(fileName) + assert.Assert(t, ok) + assert.Equal(t, content, "packageV") + proj := snapshot.GetDefaultProject("file:///home/projects/MixedCase/index.ts") + completions, err := session.handleGetCompletionsAtPosition(t.Context(), &GetCompletionsAtPositionParams{ + Snapshot: response.Snapshot, + Project: proj.ID(), + File: DocumentIdentifier{FileName: fileName}, + Position: 8, + IncludeSymbol: prepare, + }) + assert.NilError(t, err) + assert.Assert(t, completions != nil) + for _, entry := range completions.Entries { + if entry.Name == "packageValue" { + return + } + } + t.Fatal("expected dependency auto-import completion from a fresh API snapshot") + }) + } +} + func TestCompletionWithSymbolsAndExistingImportDoesNotDeadlock(t *testing.T) { t.Parallel() if !bundled.Embedded { @@ -210,7 +492,8 @@ func TestCompletionWithSymbolsAndExistingImportDoesNotDeadlock(t *testing.T) { defer session.Close() snapshotResp, err := session.handleCreateSnapshot(t.Context(), &CreateSnapshotParams{ - OpenFiles: []DocumentIdentifier{{FileName: fileName}}, + OpenFiles: []DocumentIdentifier{{FileName: fileName}}, + PrepareAutoImports: &DocumentIdentifier{FileName: fileName}, }) assert.NilError(t, err) proj, err := session.handleGetDefaultProjectForFile(t.Context(), &GetDefaultProjectForFileParams{ diff --git a/tsc/internal/ls/autoimport/registry.go b/tsc/internal/ls/autoimport/registry.go index a6c2f256afba3..9a5e27349337c 100644 --- a/tsc/internal/ls/autoimport/registry.go +++ b/tsc/internal/ls/autoimport/registry.go @@ -485,11 +485,12 @@ func (r *Registry) GetCacheStats() *CacheStats { } type RegistryChange struct { - RequestedFile tspath.Path - OpenFiles map[tspath.Path]string - Changed collections.Set[lsproto.DocumentUri] - Created collections.Set[lsproto.DocumentUri] - Deleted collections.Set[lsproto.DocumentUri] + RequestedFile tspath.Path + RequestedFileName string + OpenFiles map[tspath.Path]string + Changed collections.Set[lsproto.DocumentUri] + Created collections.Set[lsproto.DocumentUri] + Deleted collections.Set[lsproto.DocumentUri] // RebuiltPrograms maps from project ID to: // - true: the program was rebuilt with a different set of file names // - false: the program was rebuilt but the set of file names is unchanged @@ -554,12 +555,9 @@ func (b *registryBuilder) updateBucketAndDirectoryExistence(change RegistryChang start := time.Now() neededProjects := make(map[ProjectID]struct{}) neededDirectories := make(map[tspath.Path]string) - for path, fileName := range change.OpenFiles { - if projectID, _ := b.host.GetDefaultProject(path); projectID != nil { - neededProjects[projectID] = struct{}{} - } + addNeededDirectories := func(path tspath.Path, fileName string) { if tspath.IsDynamicFileName(fileName) { - continue + return } dir := fileName dirPath := path @@ -575,6 +573,15 @@ func (b *registryBuilder) updateBucketAndDirectoryExistence(change RegistryChang } neededDirectories[dirPath] = dir } + } + for path, fileName := range change.OpenFiles { + if projectID, _ := b.host.GetDefaultProject(path); projectID != nil { + neededProjects[projectID] = struct{}{} + } + if tspath.IsDynamicFileName(fileName) { + continue + } + addNeededDirectories(path, fileName) if !b.specifierCache.Has(path) { b.specifierCache.Set(path, &collections.SyncMap[tspath.Path, string]{}) @@ -582,6 +589,7 @@ func (b *registryBuilder) updateBucketAndDirectoryExistence(change RegistryChang } if change.RequestedFile != "" { + addNeededDirectories(change.RequestedFile, change.RequestedFileName) if projectID, _ := b.host.GetDefaultProject(change.RequestedFile); projectID != nil { neededProjects[projectID] = struct{}{} } diff --git a/tsc/internal/ls/languageservice.go b/tsc/internal/ls/languageservice.go index b88ed55a4bca0..cf28be37b5a4b 100644 --- a/tsc/internal/ls/languageservice.go +++ b/tsc/internal/ls/languageservice.go @@ -50,6 +50,10 @@ func (l *LanguageService) UserPreferences() lsutil.UserPreferences { return l.activeConfig } +func (l *LanguageService) SetUserPreferences(preferences lsutil.UserPreferences) { + l.activeConfig = preferences +} + func (l *LanguageService) FormatOptions() lsutil.FormatCodeSettings { return l.activeConfig.FormatCodeSettings } diff --git a/tsc/internal/ls/lsutil/userpreferences.go b/tsc/internal/ls/lsutil/userpreferences.go index bf9273b7ad760..2c3a3a006975d 100644 --- a/tsc/internal/ls/lsutil/userpreferences.go +++ b/tsc/internal/ls/lsutil/userpreferences.go @@ -14,14 +14,12 @@ import ( ) func NewDefaultUserPreferences() UserPreferences { - return UserPreferences{ + preferences := UserPreferences{ FormatCodeSettings: GetDefaultFormatCodeSettings(), - IncludeCompletionsForModuleExports: core.TSTrue, - IncludeCompletionsForImportStatements: core.TSTrue, - EnableAutoClosingTags: core.TSTrue, - EnableJSDocCompletions: core.TSTrue, - GenerateReturnInDocTemplate: core.TSTrue, + EnableAutoClosingTags: core.TSTrue, + EnableJSDocCompletions: core.TSTrue, + GenerateReturnInDocTemplate: core.TSTrue, AllowRenameOfImportPath: core.TSTrue, ProvideRefactorNotApplicableReason: core.TSTrue, @@ -33,19 +31,16 @@ func NewDefaultUserPreferences() UserPreferences { ExcludeLibrarySymbolsInNavTo: core.TSTrue, WorkspaceSymbolsScope: WorkspaceSymbolsScopeAllOpenProjects, + + IncludeCompletionsForModuleExports: core.TSTrue, + IncludeCompletionsForImportStatements: core.TSTrue, } + return preferences } // UserPreferences represents TypeScript language service preferences. -// -// Fields are populated using two tags: -// - `raw:"name"` or `raw:"name,invert"` - TypeScript/raw name for unstable section lookup -// - `config:"path.to.setting"` or `config:"path.to.setting,invert"` - VS Code nested config path -// -// At least one tag must be present on each preference field. -// The `,invert` modifier inverts boolean values (e.g., VS Code's "suppress" -> our "include"). type UserPreferences struct { - FormatCodeSettings FormatCodeSettings + FormatCodeSettings QuotePreference QuotePreference `raw:"quotePreference" config:"preferences.quoteStyle"` LazyConfiguredProjectsFromExternalProject core.Tristate `raw:"lazyConfiguredProjectsFromExternalProject"` // !!! @@ -55,32 +50,10 @@ type UserPreferences struct { // Default: `500` MaximumHoverLength int `raw:"maximumHoverLength"` // !!! - // ------- Completions ------- - - // If enabled, TypeScript will search through all external modules' exports and add them to the completions list. - // This affects lone identifier completions but not completions on the right hand side of `obj.`. - IncludeCompletionsForModuleExports core.Tristate `raw:"includeCompletionsForModuleExports" config:"suggest.autoImports"` - // Enables auto-import-style completions on partially-typed import statements. E.g., allows - // `import write|` to be completed to `import { writeFile } from "fs"`. - IncludeCompletionsForImportStatements core.Tristate `raw:"includeCompletionsForImportStatements" config:"suggest.includeCompletionsForImportStatements"` - // Unless this option is `false`, member completion lists triggered with `.` will include entries - // on potentially-null and potentially-undefined values, with insertion text to replace - // preceding `.` tokens with `?.`. - IncludeAutomaticOptionalChainCompletions core.Tristate `raw:"includeAutomaticOptionalChainCompletions" config:"suggest.includeAutomaticOptionalChainCompletions"` - // If enabled, completions for class members (e.g. methods and properties) will include - // a whole declaration for the member. - // E.g., `class A { f| }` could be completed to `class A { foo(): number {} }`, instead of - // `class A { foo }`. - IncludeCompletionsWithClassMemberSnippets core.Tristate `raw:"includeCompletionsWithClassMemberSnippets" config:"suggest.classMemberSnippets.enabled"` - // If enabled, object literal methods will have a method declaration completion entry in addition - // to the regular completion entry containing just the method name. - // E.g., `const objectLiteral: T = { f| }` could be completed to `const objectLiteral: T = { foo(): void {} }`, - // in addition to `const objectLiteral: T = { foo }`. - IncludeCompletionsWithObjectLiteralMethodSnippets core.Tristate `raw:"includeCompletionsWithObjectLiteralMethodSnippets" config:"suggest.objectLiteralMethodSnippets.enabled"` - JsxAttributeCompletionStyle JsxAttributeCompletionStyle `raw:"jsxAttributeCompletionStyle" config:"preferences.jsxAttributeCompletionStyle"` - EnableAutoClosingTags core.Tristate `raw:"autoClosingTags" config:"autoClosingTags.enabled" fallbackConfig:"autoClosingTags"` - EnableJSDocCompletions core.Tristate `raw:"completeJSDocs" config:"suggest.jsdoc.enabled" fallbackConfig:"suggest.completeJSDocs"` - GenerateReturnInDocTemplate core.Tristate `raw:"generateReturnInDocTemplate" config:"suggest.jsdoc.generateReturns"` + CompletionPreferences + EnableAutoClosingTags core.Tristate `raw:"autoClosingTags" config:"autoClosingTags.enabled" fallbackConfig:"autoClosingTags"` + EnableJSDocCompletions core.Tristate `raw:"completeJSDocs" config:"suggest.jsdoc.enabled" fallbackConfig:"suggest.completeJSDocs"` + GenerateReturnInDocTemplate core.Tristate `raw:"generateReturnInDocTemplate" config:"suggest.jsdoc.generateReturns"` // ------- AutoImports -------- @@ -169,7 +142,7 @@ type UserPreferences struct { // ------- Symbols ------- ExcludeLibrarySymbolsInNavTo core.Tristate `raw:"excludeLibrarySymbolsInNavTo" config:"workspaceSymbols.excludeLibrarySymbols"` - WorkspaceSymbolsScope WorkspaceSymbolsScope `config:"workspaceSymbols.scope"` + WorkspaceSymbolsScope WorkspaceSymbolsScope `raw:"workspaceSymbolsScope" config:"workspaceSymbols.scope"` // ------- Misc ------- @@ -179,7 +152,7 @@ type UserPreferences struct { DisableLineTextInReferences core.Tristate `raw:"disableLineTextInReferences"` // !!! DisplayPartsForJSDoc core.Tristate `raw:"displayPartsForJSDoc"` // !!! ReportStyleChecksAsWarnings core.Tristate `raw:"reportStyleChecksAsWarnings" config:"reportStyleChecksAsWarnings"` - Locale string `config:"locale"` + Locale string `raw:"locale" config:"locale"` // ------- ATA ------- @@ -196,6 +169,57 @@ type UserPreferences struct { CustomConfigFileName string `raw:"customConfigFileName" config:"customConfigFileName"` } +// CompletionPreferences contains preferences used while producing completions. +type CompletionPreferences struct { + // If enabled, TypeScript will search through all external modules' exports and add them to the completions list. + // This affects lone identifier completions but not completions on the right hand side of `obj.`. + IncludeCompletionsForModuleExports core.Tristate `json:"includeCompletionsForModuleExports,omitempty" raw:"includeCompletionsForModuleExports" config:"suggest.autoImports"` + // Enables auto-import-style completions on partially-typed import statements. E.g., allows + // `import write|` to be completed to `import { writeFile } from "fs"`. + IncludeCompletionsForImportStatements core.Tristate `json:"includeCompletionsForImportStatements,omitempty" raw:"includeCompletionsForImportStatements" config:"suggest.includeCompletionsForImportStatements"` + // Unless this option is `false`, member completion lists triggered with `.` will include entries + // on potentially-null and potentially-undefined values, with insertion text to replace + // preceding `.` tokens with `?.`. + IncludeAutomaticOptionalChainCompletions core.Tristate `json:"includeAutomaticOptionalChainCompletions,omitempty" raw:"includeAutomaticOptionalChainCompletions" config:"suggest.includeAutomaticOptionalChainCompletions"` + // If enabled, completions for class members (e.g. methods and properties) will include + // a whole declaration for the member. + IncludeCompletionsWithClassMemberSnippets core.Tristate `json:"includeCompletionsWithClassMemberSnippets,omitempty" raw:"includeCompletionsWithClassMemberSnippets" config:"suggest.classMemberSnippets.enabled"` + // If enabled, object literal methods will have a method declaration completion entry in addition + // to the regular completion entry containing just the method name. + IncludeCompletionsWithObjectLiteralMethodSnippets core.Tristate `json:"includeCompletionsWithObjectLiteralMethodSnippets,omitempty" raw:"includeCompletionsWithObjectLiteralMethodSnippets" config:"suggest.objectLiteralMethodSnippets.enabled"` + JsxAttributeCompletionStyle JsxAttributeCompletionStyle `json:"jsxAttributeCompletionStyle,omitempty" raw:"jsxAttributeCompletionStyle" config:"preferences.jsxAttributeCompletionStyle"` +} + +func (p *CompletionPreferences) UnmarshalJSONFrom(dec *json.Decoder) error { + var values map[string]any + if err := json.UnmarshalDecode(dec, &values); err != nil { + return err + } + v := reflect.ValueOf(p).Elem() + for _, info := range collectFieldInfos(reflect.TypeFor[CompletionPreferences](), nil) { + if value, ok := values[info.rawName]; ok { + setFieldFromValue(getFieldByPath(v, info.fieldPath), value) + } + } + return nil +} + +func (p UserPreferences) WithCompletionPreferences(overrides CompletionPreferences) UserPreferences { + source := reflect.ValueOf(overrides) + target := reflect.ValueOf(&p).Elem() + userPreferenceFields := fieldInfoCache() + userPreferenceIndex := unstableNameIndex() + for _, info := range collectFieldInfos(reflect.TypeFor[CompletionPreferences](), nil) { + sourceField := getFieldByPath(source, info.fieldPath) + if serializeField(sourceField) == nil { + continue + } + targetInfo := userPreferenceFields[userPreferenceIndex[info.rawName]] + getFieldByPath(target, targetInfo.fieldPath).Set(sourceField) + } + return p +} + // IsATADisabled returns whether Automatic Type Acquisition is disabled based on user preferences. // It checks the unified setting (tsserver.automaticTypeAcquisition.enabled) first, // then falls back to the deprecated setting (disableAutomaticTypeAcquisition). diff --git a/tsc/internal/ls/lsutil/userpreferences_test.go b/tsc/internal/ls/lsutil/userpreferences_test.go index 26653cfbc9b97..0ff3cb7bff647 100644 --- a/tsc/internal/ls/lsutil/userpreferences_test.go +++ b/tsc/internal/ls/lsutil/userpreferences_test.go @@ -10,6 +10,17 @@ import ( "gotest.tools/v3/assert" ) +func TestCompletionPreferencesUnmarshal(t *testing.T) { + t.Parallel() + var preferences CompletionPreferences + assert.NilError(t, json.Unmarshal([]byte(`{"includeCompletionsForModuleExports":false}`), &preferences)) + assert.Equal(t, preferences.IncludeCompletionsForModuleExports, core.TSFalse) + + userPreferences := NewDefaultUserPreferences().WithCompletionPreferences(preferences) + assert.Equal(t, userPreferences.IncludeCompletionsForModuleExports, core.TSFalse) + assert.Equal(t, userPreferences.IncludeCompletionsForImportStatements, core.TSTrue) +} + func fillNonZeroValues(v reflect.Value) { t := v.Type() for i := range t.NumField() { diff --git a/tsc/internal/project/snapshot.go b/tsc/internal/project/snapshot.go index ab9d2645e01f3..9bb3aaf8136ab 100644 --- a/tsc/internal/project/snapshot.go +++ b/tsc/internal/project/snapshot.go @@ -338,6 +338,8 @@ type APIReconfigureProgramRequest struct { } type APISnapshotRequest struct { + UserPreferences *lsutil.UserPreferences + PrepareAutoImports lsproto.DocumentUri OpenProjects *collections.Set[string] CloseProjects *collections.Set[tspath.Path] OpenFiles map[tspath.Path]string @@ -651,8 +653,10 @@ func (s *Snapshot) Clone( openFiles[path] = overlay.FileName() } prepareAutoImports := tspath.Path("") + prepareAutoImportsFileName := "" if change.ResourceRequest.AutoImports != "" { prepareAutoImports = change.ResourceRequest.AutoImports.Path(s.UseCaseSensitiveFileNames()) + prepareAutoImportsFileName = change.ResourceRequest.AutoImports.FileName() } oldAutoImports := s.AutoImports if oldAutoImports == nil { @@ -660,13 +664,14 @@ func (s *Snapshot) Clone( } var autoImportsWatch *WatchedFiles[map[tspath.Path]string] autoImports, err := oldAutoImports.Clone(ctx, autoimport.RegistryChange{ - RequestedFile: prepareAutoImports, - OpenFiles: openFiles, - Changed: change.fileChanges.Changed, - Created: change.fileChanges.Created, - Deleted: change.fileChanges.Deleted, - RebuiltPrograms: projectsWithNewProgramStructure, - UserPreferences: change.newConfig, + RequestedFile: prepareAutoImports, + RequestedFileName: prepareAutoImportsFileName, + OpenFiles: openFiles, + Changed: change.fileChanges.Changed, + Created: change.fileChanges.Created, + Deleted: change.fileChanges.Deleted, + RebuiltPrograms: projectsWithNewProgramStructure, + UserPreferences: change.newConfig, }, autoImportHost, logger.Fork("UpdateAutoImports")) if err == nil { autoImportsWatch = s.autoImportsWatch.Clone(autoImports.NodeModulesDirectories()) diff --git a/tsc/internal/project/snapshothost.go b/tsc/internal/project/snapshothost.go index 6659133490421..e93e48ef22d42 100644 --- a/tsc/internal/project/snapshothost.go +++ b/tsc/internal/project/snapshothost.go @@ -115,6 +115,11 @@ func (s *SnapshotHost) CloneSnapshot( change.fs = apiRequest.FileSystem change.fileSystemOverride = apiRequest.FileSystem != nil change.replaceFileSystem = apiRequest.ReplaceFileSystem + change.newConfig = apiRequest.UserPreferences + if apiRequest.PrepareAutoImports != "" { + change.ResourceRequest = baseSnapshot.resourceRequestForDocument(apiRequest.PrepareAutoImports) + change.AutoImports = apiRequest.PrepareAutoImports + } } snapshot := s.update(ctx, baseSnapshot, change) return snapshot, snapshot.apiError From c4cb92cb290b403f99e33e1fec3a8efb8453748d Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 30 Sep 2026 08:22:31 -0700 Subject: [PATCH 2/5] Generate UserPreferences from schema --- Herebyfile.mjs | 21 + .../typescript/src/api/proto.generated.ts | 194 +-- packages/typescript/src/api/proto.ts | 1 + .../src/api/userPreferences.generated.ts | 201 +++ tools/gen-preferences/main.go | 329 ++++ tools/gen-preferences/main_test.go | 80 + tools/gen-preferences/methods.go | 318 ++++ tools/gen-proto/main.go | 52 +- tools/gen-proto/main_test.go | 4 +- tools/userPreferences.schema.json | 494 ++++++ tsc/internal/fourslash/fourslash.go | 4 +- .../codeLensFunctionExpressions01_test.go | 14 +- .../codeLensFunctionsAndConstants01_test.go | 14 +- .../tests/codeLensInterface01_test.go | 14 +- .../tests/codeLensOverloads01_test.go | 14 +- .../codeLensShowOnAllClassMethods_test.go | 6 +- .../tests/codeLensShowOnAllFunctions_test.go | 6 +- .../codeLensShowOnInterfaceMethods_test.go | 6 +- .../tests/contentMapperEditSafety_test.go | 16 +- .../findAllRefsPrefixSuffixPreference_test.go | 8 +- ...indAllRefsReExportsUseInImportType_test.go | 2 +- .../fourslash/tests/inlayHintsCrash1_test.go | 2 +- .../tests/inlayHintsElementAccess_test.go | 4 +- .../tests/inlayHintsEnumMemberValue_test.go | 2 +- .../inlayHintsFunctionParameterTypes1_test.go | 2 +- .../inlayHintsFunctionParameterTypes2_test.go | 2 +- .../inlayHintsFunctionParameterTypes3_test.go | 2 +- .../inlayHintsFunctionParameterTypes4_test.go | 2 +- .../inlayHintsFunctionParameterTypes5_test.go | 2 +- .../inlayHintsIdentifierLocation_test.go | 2 +- .../tests/inlayHintsImportType1_test.go | 2 +- .../tests/inlayHintsImportType2_test.go | 2 +- .../inlayHintsInferredTypePredicate1_test.go | 2 +- ...inlayHintsInteractiveAnyParameter1_test.go | 2 +- ...inlayHintsInteractiveAnyParameter2_test.go | 2 +- ...InteractiveFunctionParameterTypes1_test.go | 2 +- ...InteractiveFunctionParameterTypes2_test.go | 2 +- ...InteractiveFunctionParameterTypes3_test.go | 2 +- ...InteractiveFunctionParameterTypes4_test.go | 2 +- ...InteractiveFunctionParameterTypes5_test.go | 2 +- .../inlayHintsInteractiveImportType1_test.go | 2 +- .../inlayHintsInteractiveImportType2_test.go | 2 +- ...sInteractiveInferredTypePredicate1_test.go | 2 +- ...intsInteractiveJsDocParameterNames_test.go | 2 +- .../inlayHintsInteractiveMultifile1_test.go | 2 +- ...sInteractiveMultifileFunctionCalls_test.go | 2 +- .../inlayHintsInteractiveOverloadCall_test.go | 2 +- ...tsInteractiveParameterNamesInSpan1_test.go | 4 +- ...tsInteractiveParameterNamesInSpan2_test.go | 4 +- ...eractiveParameterNamesWithComments_test.go | 2 +- ...nlayHintsInteractiveParameterNames_test.go | 2 +- ...layHintsInteractiveRestParameters1_test.go | 2 +- ...layHintsInteractiveRestParameters2_test.go | 2 +- ...layHintsInteractiveRestParameters3_test.go | 2 +- .../inlayHintsInteractiveReturnType_test.go | 2 +- ...ntsInteractiveTemplateLiteralTypes_test.go | 2 +- ...nlayHintsInteractiveVariableTypes1_test.go | 2 +- ...nlayHintsInteractiveVariableTypes2_test.go | 2 +- .../inlayHintsInteractiveWithClosures_test.go | 2 +- .../inlayHintsJsDocParameterNames_test.go | 2 +- .../tests/inlayHintsMultifile1_test.go | 2 +- ...HintsNoHintWhenArgumentMatchesName_test.go | 2 +- .../tests/inlayHintsNoParameterHints_test.go | 2 +- .../inlayHintsNoVariableTypeHints_test.go | 2 +- .../tests/inlayHintsOverloadCall1_test.go | 2 +- .../tests/inlayHintsOverloadCall2_test.go | 2 +- .../tests/inlayHintsParameterNames_test.go | 2 +- ...tsPropertyDeclarationComputedName1_test.go | 4 +- .../inlayHintsPropertyDeclarations2_test.go | 2 +- .../inlayHintsPropertyDeclarations_test.go | 2 +- .../tests/inlayHintsQuotePreference1_test.go | 2 +- .../tests/inlayHintsQuotePreference2_test.go | 2 +- .../tests/inlayHintsReparsedNodeCrash_test.go | 4 +- .../tests/inlayHintsRestParameters1_test.go | 2 +- .../tests/inlayHintsRestParameters2_test.go | 2 +- .../tests/inlayHintsReturnType_test.go | 2 +- .../tests/inlayHintsThisParameter_test.go | 2 +- .../tests/inlayHintsTupleTypeCrash_test.go | 4 +- .../tests/inlayHintsTypeMatchesName_test.go | 2 +- .../inlayHintsTypeParameterModifiers1_test.go | 2 +- .../fourslash/tests/inlayHintsUsing_test.go | 4 +- .../tests/inlayHintsVariableTypes1_test.go | 2 +- .../tests/inlayHintsVariableTypes2_test.go | 2 +- .../tests/inlayHintsVariableTypes3_test.go | 2 +- .../tests/inlayHintsWithClosures_test.go | 2 +- .../tests/jsdocSnippetCompletion_test.go | 2 +- .../tests/renameExportSpecifier2_test.go | 2 +- .../tests/renameExportSpecifier_test.go | 2 +- .../tests/renameFromNodeModulesDep1_test.go | 4 +- .../tests/renameFromNodeModulesDep2_test.go | 4 +- .../tests/renameFromNodeModulesDep3_test.go | 4 +- .../tests/renameFromNodeModulesDep4_test.go | 16 +- .../renameModuleExportsProperties1_test.go | 2 +- .../renameModuleExportsProperties3_test.go | 2 +- ...ameNamedImportUseAliasesForRenames_test.go | 8 +- .../fourslash/tests/renameNamedImport_test.go | 2 +- .../tests/renameRestBindingElement_test.go | 2 +- .../fourslash/tests/statecodelens_test.go | 16 +- tsc/internal/ls/autoinsert.go | 2 +- tsc/internal/ls/codelens.go | 2 +- tsc/internal/ls/diagnostics.go | 2 +- tsc/internal/ls/findallreferences.go | 2 +- tsc/internal/ls/format.go | 6 +- tsc/internal/ls/inlay_hints.go | 2 +- tsc/internal/ls/jsdoc_snippet.go | 2 +- tsc/internal/ls/lsutil/formatcodeoptions.go | 69 - tsc/internal/ls/lsutil/userpreferences.go | 817 +--------- .../ls/lsutil/userpreferences_generated.go | 1348 +++++++++++++++++ .../ls/lsutil/userpreferences_test.go | 140 +- tsc/internal/ls/rename.go | 4 +- tsc/internal/project/project_test.go | 4 +- tsc/internal/project/session.go | 14 +- tsc/internal/project/session_test.go | 12 +- 113 files changed, 3148 insertions(+), 1284 deletions(-) create mode 100644 packages/typescript/src/api/userPreferences.generated.ts create mode 100644 tools/gen-preferences/main.go create mode 100644 tools/gen-preferences/main_test.go create mode 100644 tools/gen-preferences/methods.go create mode 100644 tools/userPreferences.schema.json create mode 100644 tsc/internal/ls/lsutil/userpreferences_generated.go diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 3298ed9ec6d83..6e31858a0b645 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -655,7 +655,28 @@ export const generateSync = task({ run: runGenerateSync, }); +async function runGeneratePreferences() { + await runGoGenerator("generate:preferences", { + file: "tsc/internal/ls/lsutil/userpreferences.go", + cwd: __dirname, + inputs: ["tools/userPreferences.schema.json", "tools/gen-preferences/*.go"], + exclude: ["**/*_test.go"], + envInputs: [], + outputs: [ + "tsc/internal/ls/lsutil/userpreferences_generated.go", + "packages/typescript/src/api/userPreferences.generated.ts", + ], + commands: [ + ["go", "-C", "./tools", "run", "./gen-preferences", "./userPreferences.schema.json", "../tsc/internal/ls/lsutil/userpreferences_generated.go", "../packages/typescript/src/api/userPreferences.generated.ts"], + ["dprint", "fmt", "tsc/internal/ls/lsutil/userpreferences_generated.go", "packages/typescript/src/api/userPreferences.generated.ts"], + ], + }); +} + +export const generatePreferences = goGenerateTask("generate:preferences", runGeneratePreferences); + async function runGenerateAPI() { + await runGeneratePreferences(); await runGoGenerator("generate:api", { file: "tsc/internal/api/proto.go", cwd: __dirname, diff --git a/packages/typescript/src/api/proto.generated.ts b/packages/typescript/src/api/proto.generated.ts index 0bfcb2f9e5e8a..3b1a2a26b22d3 100644 --- a/packages/typescript/src/api/proto.generated.ts +++ b/packages/typescript/src/api/proto.generated.ts @@ -8,6 +8,10 @@ import { NewLineKind } from "#enums/newLineKind"; import { ScriptKind } from "#enums/scriptKind"; import { ScriptTarget } from "#enums/scriptTarget"; import type { Path } from "../ast/index.ts"; +import type { + CompletionPreferences, + UserPreferences, +} from "./userPreferences.generated.ts"; export { JsxEmit } from "#enums/jsxEmit"; export { ModuleDetectionKind } from "#enums/moduleDetectionKind"; @@ -1477,113 +1481,6 @@ export interface SnapshotRequestChangesParams { ensurePrograms?: EnsurePrograms | undefined; } -/** UserPreferences represents TypeScript language service preferences. */ -export interface UserPreferences extends FormatCodeSettings, CompletionPreferences, InlayHintsPreferences, CodeLensUserPreferences { - quotePreference?: "auto" | "double" | "single" | undefined; - lazyConfiguredProjectsFromExternalProject?: boolean | undefined; - /** - * A positive integer indicating the maximum length of a hover text before it is truncated. - * - * Default: `500` - */ - maximumHoverLength?: number | undefined; - autoClosingTags?: boolean | undefined; - completeJSDocs?: boolean | undefined; - generateReturnInDocTemplate?: boolean | undefined; - importModuleSpecifierPreference?: "shortest" | "project-relative" | "relative" | "non-relative" | undefined; - /** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */ - importModuleSpecifierEnding?: "auto" | "minimal" | "index" | "js" | undefined; - autoImportSpecifierExcludeRegexes?: string[] | undefined; - autoImportFileExcludePatterns?: string[] | undefined; - autoImportEntrypointDirectorySearch?: boolean | undefined; - preferTypeOnlyAutoImports?: boolean | undefined; - /** - * Indicates which deterministic preset should be used to sort imports. - * "auto" detects the existing ordinal case sensitivity where possible. - */ - organizeImportsSort?: "auto" | "ordinal" | "ordinalIgnoreCase" | "natural" | "naturalIgnoreCase" | undefined; - /** - * Indicates whether imports should be organized in a case-insensitive manner. - * - * Default: TSUnknown ("auto" in strada), will perform detection - */ - organizeImportsIgnoreCase?: boolean | undefined; - /** - * Indicates whether imports should be organized via an "ordinal" (binary) comparison using the numeric value of their - * code points, or via "unicode" natural sorting. This implementation is locale-agnostic and approximates the practical - * import-sorting behavior rather than the full Unicode Collation Algorithm. - * - * Default: Ordinal - */ - organizeImportsCollation?: "ordinal" | "unicode" | undefined; - /** - * Indicates the locale to use for "unicode" collation in legacy clients. This is accepted for compatibility, but - * currently ignored because organize-import sorting is deterministic and locale-agnostic. - * - * This preference is ignored if organizeImportsCollation is not `unicode`. - * - * Default: `"en"` - */ - organizeImportsLocale?: string | undefined; - /** - * Indicates whether numeric collation should be used for digit sequences in strings. When `true`, will collate - * strings such that `a1z < a2z < a100z`. When `false`, will collate strings such that `a1z < a100z < a2z`. - * - * This preference is ignored if organizeImportsCollation is not `unicode`. - * - * Default: `false` - */ - organizeImportsNumericCollation?: boolean | undefined; - /** - * Indicates whether accents and other diacritic marks are considered unequal for the purpose of sorting. - * - * This preference is ignored if organizeImportsCollation is not `unicode`. - * - * Default: `true` - */ - organizeImportsAccentCollation?: boolean | undefined; - /** - * Indicates whether upper case or lower case should sort first. - * - * This permission is ignored if: - * - organizeImportsCollation is not `unicode` - * - organizeImportsIgnoreCase is `true` - * - organizeImportsIgnoreCase is `auto` and the auto-detected case sensitivity is case-insensitive. - * - * Default: `false` - */ - organizeImportsCaseFirst?: "default" | "lower" | "upper" | undefined; - /** - * Indicates where named type-only imports should sort. "inline" sorts named imports without regard to if the import is type-only. - * - * Default: `auto`, which defaults to `last` - */ - organizeImportsTypeOrder?: "auto" | "last" | "inline" | "first" | undefined; - allowTextChangesInNewFiles?: boolean | undefined; - providePrefixAndSuffixTextForRename?: boolean | undefined; - allowRenameOfImportPath?: boolean | undefined; - provideRefactorNotApplicableReason?: boolean | undefined; - preferGoToSourceDefinition?: boolean | undefined; - excludeLibrarySymbolsInNavTo?: boolean | undefined; - workspaceSymbolsScope?: "allOpenProjects" | "currentProject" | undefined; - formatEnabled?: boolean | undefined; - validateEnabled?: boolean | undefined; - disableSuggestions?: boolean | undefined; - disableLineTextInReferences?: boolean | undefined; - displayPartsForJSDoc?: boolean | undefined; - reportStyleChecksAsWarnings?: boolean | undefined; - locale?: string | undefined; - /** DisableAutomaticTypeAcquisition is the deprecated setting from typescript.disableAutomaticTypeAcquisition. */ - disableAutomaticTypeAcquisition?: boolean | undefined; - /** - * AutomaticTypeAcquisitionEnabled is the unified setting from tsserver.automaticTypeAcquisition.enabled under the js/ts section. - * When set, it takes precedence over DisableAutomaticTypeAcquisition. - */ - automaticTypeAcquisitionEnabled?: boolean | undefined; - /** CustomConfigFileName specifies a custom config file name to use before defaulting to tsconfig.json/jsconfig.json. */ - customConfigFileName?: string | undefined; -} - /** * FileNotifications describes changes to files that have occurred on the host * file system, used to notify the session to reload cached files and reevaluate @@ -1817,37 +1714,6 @@ export interface ImportAdderAction { isValidTypeOnlyUseSite?: boolean | undefined; } -/** CompletionPreferences contains preferences used while producing completions. */ -export interface CompletionPreferences { - /** - * If enabled, TypeScript will search through all external modules' exports and add them to the completions list. - * This affects lone identifier completions but not completions on the right hand side of `obj.`. - */ - includeCompletionsForModuleExports?: boolean | undefined; - /** - * Enables auto-import-style completions on partially-typed import statements. E.g., allows - * `import write|` to be completed to `import { writeFile } from "fs"`. - */ - includeCompletionsForImportStatements?: boolean | undefined; - /** - * Unless this option is `false`, member completion lists triggered with `.` will include entries - * on potentially-null and potentially-undefined values, with insertion text to replace - * preceding `.` tokens with `?.`. - */ - includeAutomaticOptionalChainCompletions?: boolean | undefined; - /** - * If enabled, completions for class members (e.g. methods and properties) will include - * a whole declaration for the member. - */ - includeCompletionsWithClassMemberSnippets?: boolean | undefined; - /** - * If enabled, object literal methods will have a method declaration completion entry in addition - * to the regular completion entry containing just the method name. - */ - includeCompletionsWithObjectLiteralMethodSnippets?: boolean | undefined; - jsxAttributeCompletionStyle?: "auto" | "braces" | "none" | undefined; -} - /** CompletionEntryResponse represents a single completion item. */ export interface CompletionEntryResponse { name: string; @@ -1889,48 +1755,6 @@ export interface ReconfigureSnapshotProgramParams { options?: CreateProgramOptions | undefined; } -export interface FormatCodeSettings extends EditorSettings { - insertSpaceAfterCommaDelimiter?: boolean | undefined; - insertSpaceAfterSemicolonInForStatements?: boolean | undefined; - insertSpaceBeforeAndAfterBinaryOperators?: boolean | undefined; - insertSpaceAfterConstructor?: boolean | undefined; - insertSpaceAfterKeywordsInControlFlowStatements?: boolean | undefined; - insertSpaceAfterFunctionKeywordForAnonymousFunctions?: boolean | undefined; - insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis?: boolean | undefined; - insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets?: boolean | undefined; - insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces?: boolean | undefined; - insertSpaceAfterOpeningAndBeforeClosingEmptyBraces?: boolean | undefined; - insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces?: boolean | undefined; - insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean | undefined; - insertSpaceAfterTypeAssertion?: boolean | undefined; - insertSpaceBeforeFunctionParenthesis?: boolean | undefined; - placeOpenBraceOnNewLineForFunctions?: boolean | undefined; - placeOpenBraceOnNewLineForControlBlocks?: boolean | undefined; - insertSpaceBeforeTypeAnnotation?: boolean | undefined; - indentMultiLineObjectLiteralBeginningOnBlankLine?: boolean | undefined; - semicolons?: "ignore" | "insert" | "remove" | undefined; - indentSwitchCase?: boolean | undefined; -} - -export interface InlayHintsPreferences { - includeInlayParameterNameHints?: "none" | "literals" | "all" | undefined; - includeInlayParameterNameHintsWhenArgumentMatchesName?: boolean | undefined; - includeInlayFunctionParameterTypeHints?: boolean | undefined; - includeInlayVariableTypeHints?: boolean | undefined; - includeInlayVariableTypeHintsWhenTypeMatchesName?: boolean | undefined; - includeInlayPropertyDeclarationTypeHints?: boolean | undefined; - includeInlayFunctionLikeReturnTypeHints?: boolean | undefined; - includeInlayEnumMemberValueHints?: boolean | undefined; -} - -export interface CodeLensUserPreferences { - referencesCodeLensEnabled?: boolean | undefined; - implementationsCodeLensEnabled?: boolean | undefined; - referencesCodeLensShowOnAllFunctions?: boolean | undefined; - implementationsCodeLensShowOnInterfaceMethods?: boolean | undefined; - implementationsCodeLensShowOnAllClassMethods?: boolean | undefined; -} - /** * RequestDirectoryEntries is a cached directory listing. Entry names are * relative to the directory, matching vfs.GetAccessibleEntries. @@ -1989,16 +1813,6 @@ export interface CreateProgramOptions { moduleResolver?: number | undefined; } -export interface EditorSettings { - baseIndentSize?: number | undefined; - indentSize?: number | undefined; - tabSize?: number | undefined; - newLineCharacter?: string | undefined; - convertTabsToSpaces?: boolean | undefined; - indentStyle?: "none" | "block" | "smart" | undefined; - trimTrailingWhitespace?: boolean | undefined; -} - export interface StaticModuleResolution { resolvedFileName?: DocumentIdentifier | undefined; originalPath?: DocumentIdentifier | undefined; diff --git a/packages/typescript/src/api/proto.ts b/packages/typescript/src/api/proto.ts index f45bc1f2caedc..14e17599ac432 100644 --- a/packages/typescript/src/api/proto.ts +++ b/packages/typescript/src/api/proto.ts @@ -14,6 +14,7 @@ import type { export type { ConfigFileResponse as ParsedCommandLine, DiagnosticResponse as Diagnostic } from "./proto.generated.ts"; export * from "./proto.generated.ts"; +export * from "./userPreferences.generated.ts"; export type APIMethodsReturning = { [K in keyof APIMethodInfo]: [T] extends [NonNullable] ? [NonNullable] extends [T] ? K : never : never; }[keyof APIMethodInfo]; diff --git a/packages/typescript/src/api/userPreferences.generated.ts b/packages/typescript/src/api/userPreferences.generated.ts new file mode 100644 index 0000000000000..bea3f03d426de --- /dev/null +++ b/packages/typescript/src/api/userPreferences.generated.ts @@ -0,0 +1,201 @@ +// Code generated by gen-preferences from tools/userPreferences.schema.json; DO NOT EDIT. + +export interface CodeLensUserPreferences { + implementationsCodeLensEnabled?: boolean | undefined; + implementationsCodeLensShowOnAllClassMethods?: boolean | undefined; + implementationsCodeLensShowOnInterfaceMethods?: boolean | undefined; + referencesCodeLensEnabled?: boolean | undefined; + referencesCodeLensShowOnAllFunctions?: boolean | undefined; +} + +/** + * CompletionPreferences contains preferences used while producing completions. + */ +export interface CompletionPreferences { + /** + * Unless this option is `false`, member completion lists triggered with `.` will include entries + * on potentially-null and potentially-undefined values, with insertion text to replace + * preceding `.` tokens with `?.`. + */ + includeAutomaticOptionalChainCompletions?: boolean | undefined; + /** + * Enables auto-import-style completions on partially-typed import statements. E.g., allows + * `import write|` to be completed to `import { writeFile } from "fs"`. + */ + includeCompletionsForImportStatements?: boolean | undefined; + /** + * If enabled, TypeScript will search through all external modules' exports and add them to the completions list. + * This affects lone identifier completions but not completions on the right hand side of `obj.`. + */ + includeCompletionsForModuleExports?: boolean | undefined; + /** + * If enabled, completions for class members (e.g. methods and properties) will include + * a whole declaration for the member. + */ + includeCompletionsWithClassMemberSnippets?: boolean | undefined; + /** + * If enabled, object literal methods will have a method declaration completion entry in addition + * to the regular completion entry containing just the method name. + */ + includeCompletionsWithObjectLiteralMethodSnippets?: boolean | undefined; + jsxAttributeCompletionStyle?: "auto" | "braces" | "none" | undefined; +} + +export interface EditorSettings { + baseIndentSize?: number | undefined; + convertTabsToSpaces?: boolean | undefined; + indentSize?: number | undefined; + indentStyle?: "none" | "block" | "smart" | undefined; + newLineCharacter?: string | undefined; + tabSize?: number | undefined; + trimTrailingWhitespace?: boolean | undefined; +} + +export interface FormatCodeSettings extends EditorSettings { + indentMultiLineObjectLiteralBeginningOnBlankLine?: boolean | undefined; + indentSwitchCase?: boolean | undefined; + insertSpaceAfterCommaDelimiter?: boolean | undefined; + insertSpaceAfterConstructor?: boolean | undefined; + insertSpaceAfterFunctionKeywordForAnonymousFunctions?: boolean | undefined; + insertSpaceAfterKeywordsInControlFlowStatements?: boolean | undefined; + insertSpaceAfterOpeningAndBeforeClosingEmptyBraces?: boolean | undefined; + insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean | undefined; + insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces?: boolean | undefined; + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets?: boolean | undefined; + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis?: boolean | undefined; + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces?: boolean | undefined; + insertSpaceAfterSemicolonInForStatements?: boolean | undefined; + insertSpaceAfterTypeAssertion?: boolean | undefined; + insertSpaceBeforeAndAfterBinaryOperators?: boolean | undefined; + insertSpaceBeforeFunctionParenthesis?: boolean | undefined; + insertSpaceBeforeTypeAnnotation?: boolean | undefined; + placeOpenBraceOnNewLineForControlBlocks?: boolean | undefined; + placeOpenBraceOnNewLineForFunctions?: boolean | undefined; + semicolons?: "ignore" | "insert" | "remove" | undefined; +} + +export interface InlayHintsPreferences { + includeInlayEnumMemberValueHints?: boolean | undefined; + includeInlayFunctionLikeReturnTypeHints?: boolean | undefined; + includeInlayFunctionParameterTypeHints?: boolean | undefined; + includeInlayParameterNameHints?: "none" | "literals" | "all" | undefined; + includeInlayParameterNameHintsWhenArgumentMatchesName?: boolean | undefined; + includeInlayPropertyDeclarationTypeHints?: boolean | undefined; + includeInlayVariableTypeHints?: boolean | undefined; + includeInlayVariableTypeHintsWhenTypeMatchesName?: boolean | undefined; +} + +/** + * UserPreferences represents TypeScript language service preferences. + */ +export interface UserPreferences extends FormatCodeSettings, CompletionPreferences, InlayHintsPreferences, CodeLensUserPreferences { + allowRenameOfImportPath?: boolean | undefined; + allowTextChangesInNewFiles?: boolean | undefined; + autoClosingTags?: boolean | undefined; + autoImportEntrypointDirectorySearch?: boolean | undefined; + autoImportFileExcludePatterns?: string[] | undefined; + autoImportSpecifierExcludeRegexes?: string[] | undefined; + /** + * AutomaticTypeAcquisitionEnabled is the unified setting from tsserver.automaticTypeAcquisition.enabled under the js/ts section. + * When set, it takes precedence over DisableAutomaticTypeAcquisition. + */ + automaticTypeAcquisitionEnabled?: boolean | undefined; + completeJSDocs?: boolean | undefined; + /** + * CustomConfigFileName specifies a custom config file name to use before defaulting to tsconfig.json/jsconfig.json. + */ + customConfigFileName?: string | undefined; + /** + * DisableAutomaticTypeAcquisition is the deprecated setting from typescript.disableAutomaticTypeAcquisition. + */ + disableAutomaticTypeAcquisition?: boolean | undefined; + disableLineTextInReferences?: boolean | undefined; + disableSuggestions?: boolean | undefined; + displayPartsForJSDoc?: boolean | undefined; + excludeLibrarySymbolsInNavTo?: boolean | undefined; + formatEnabled?: boolean | undefined; + generateReturnInDocTemplate?: boolean | undefined; + /** + * Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" + */ + importModuleSpecifierEnding?: "auto" | "minimal" | "index" | "js" | undefined; + importModuleSpecifierPreference?: "shortest" | "project-relative" | "relative" | "non-relative" | undefined; + lazyConfiguredProjectsFromExternalProject?: boolean | undefined; + locale?: string | undefined; + /** + * A positive integer indicating the maximum length of a hover text before it is truncated. + * + * Default: `500` + */ + maximumHoverLength?: number | undefined; + /** + * Indicates whether accents and other diacritic marks are considered unequal for the purpose of sorting. + * + * This preference is ignored if organizeImportsCollation is not `unicode`. + * + * Default: `true` + */ + organizeImportsAccentCollation?: boolean | undefined; + /** + * Indicates whether upper case or lower case should sort first. + * + * This permission is ignored if: + * - organizeImportsCollation is not `unicode` + * - organizeImportsIgnoreCase is `true` + * - organizeImportsIgnoreCase is `auto` and the auto-detected case sensitivity is case-insensitive. + * + * Default: `false` + */ + organizeImportsCaseFirst?: "default" | "lower" | "upper" | undefined; + /** + * Indicates whether imports should be organized via an "ordinal" (binary) comparison using the numeric value of their + * code points, or via "unicode" natural sorting. This implementation is locale-agnostic and approximates the practical + * import-sorting behavior rather than the full Unicode Collation Algorithm. + * + * Default: Ordinal + */ + organizeImportsCollation?: "ordinal" | "unicode" | undefined; + /** + * Indicates whether imports should be organized in a case-insensitive manner. + * + * If unspecified, case sensitivity is detected. + */ + organizeImportsIgnoreCase?: boolean | undefined; + /** + * Indicates the locale to use for "unicode" collation in legacy clients. This is accepted for compatibility, but + * currently ignored because organize-import sorting is deterministic and locale-agnostic. + * + * This preference is ignored if organizeImportsCollation is not `unicode`. + * + * Default: `"en"` + */ + organizeImportsLocale?: string | undefined; + /** + * Indicates whether numeric collation should be used for digit sequences in strings. When `true`, will collate + * strings such that `a1z < a2z < a100z`. When `false`, will collate strings such that `a1z < a100z < a2z`. + * + * This preference is ignored if organizeImportsCollation is not `unicode`. + * + * Default: `false` + */ + organizeImportsNumericCollation?: boolean | undefined; + /** + * Indicates which deterministic preset should be used to sort imports. + * "auto" detects the existing ordinal case sensitivity where possible. + */ + organizeImportsSort?: "auto" | "ordinal" | "ordinalIgnoreCase" | "natural" | "naturalIgnoreCase" | undefined; + /** + * Indicates where named type-only imports should sort. "inline" sorts named imports without regard to if the import is type-only. + * + * Default: `auto`, which defaults to `last` + */ + organizeImportsTypeOrder?: "auto" | "last" | "inline" | "first" | undefined; + preferGoToSourceDefinition?: boolean | undefined; + preferTypeOnlyAutoImports?: boolean | undefined; + providePrefixAndSuffixTextForRename?: boolean | undefined; + provideRefactorNotApplicableReason?: boolean | undefined; + quotePreference?: "auto" | "double" | "single" | undefined; + reportStyleChecksAsWarnings?: boolean | undefined; + validateEnabled?: boolean | undefined; + workspaceSymbolsScope?: "allOpenProjects" | "currentProject" | undefined; +} diff --git a/tools/gen-preferences/main.go b/tools/gen-preferences/main.go new file mode 100644 index 0000000000000..69471a7f4389b --- /dev/null +++ b/tools/gen-preferences/main.go @@ -0,0 +1,329 @@ +package main + +import ( + "bytes" + "encoding/json" //nolint:depguard // The tools module cannot import tsc/internal/json. + "errors" + "fmt" + "go/format" + "go/token" + "io" + "os" + "slices" + "strconv" + "strings" +) + +type schema struct { + Schema string `json:"$schema"` + Ref string `json:"$ref"` + Comment string `json:"$comment"` + Defs map[string]definition `json:"$defs"` +} + +type definition struct { + Type string `json:"type"` + Description string `json:"description"` + AllOf []reference `json:"allOf"` + Properties map[string]property `json:"properties"` +} + +type reference struct { + Ref string `json:"$ref"` +} + +type property struct { + Type string `json:"type"` + Description string `json:"description"` + Enum []string `json:"enum"` + Items *property `json:"items"` + GoType string `json:"x-go-type"` + Config string `json:"x-config"` + FallbackConfig string `json:"x-fallback-config"` + GoUnderlying string `json:"x-go-underlying"` + Default string `json:"default"` + AcceptNumber bool `json:"x-accept-number"` + ConfigParser string `json:"x-config-parser"` + Validator string `json:"x-validator"` +} + +func main() { + if len(os.Args) != 4 { + fmt.Fprintln(os.Stderr, "Usage: gen-preferences .json .go .ts") + os.Exit(1) + } + goOutput, tsOutput, err := generate(os.Args[1]) + if err == nil { + err = os.WriteFile(os.Args[2], goOutput, 0o644) + } + if err == nil { + err = os.WriteFile(os.Args[3], tsOutput, 0o644) + } + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func generate(path string) ([]byte, []byte, error) { + input, err := os.ReadFile(path) + if err != nil { + return nil, nil, err + } + var model schema + decoder := json.NewDecoder(bytes.NewReader(input)) + decoder.DisallowUnknownFields() + if err := decoder.Decode(&model); err != nil { + return nil, nil, fmt.Errorf("decode preference schema: %w", err) + } + if err := decoder.Decode(new(any)); err != io.EOF { + return nil, nil, errors.New("preference schema must contain one JSON object") + } + for _, def := range model.Defs { + for name, prop := range def.Properties { + if len(prop.Enum) != 0 && prop.GoType == "" { + prop.GoType = goName(name) + def.Properties[name] = prop + } + } + } + if _, err := model.resolve(model.Ref); err != nil { + return nil, nil, err + } + names := sortedKeys(model.Defs) + for _, name := range names { + if _, err := model.fields(name, map[string]bool{}); err != nil { + return nil, nil, err + } + } + + var goOutput, tsOutput bytes.Buffer + goOutput.WriteString("// Code generated by gen-preferences from tools/userPreferences.schema.json; DO NOT EDIT.\n\npackage lsutil\n\n") + tsOutput.WriteString("// Code generated by gen-preferences from tools/userPreferences.schema.json; DO NOT EDIT.\n\n") + imports := map[string]string{} + var goTypes bytes.Buffer + for _, name := range names { + def := model.Defs[name] + writeDescription(&goTypes, def.Description, "// ") + fmt.Fprintf(&goTypes, "type %s struct {\n", name) + writeDescription(&tsOutput, def.Description, "") + fmt.Fprintf(&tsOutput, "export interface %s", name) + var bases []string + for _, ref := range def.AllOf { + base, _ := model.resolve(ref.Ref) + bases = append(bases, base) + fmt.Fprintf(&goTypes, "%s\n", base) + } + if len(bases) != 0 { + fmt.Fprintf(&tsOutput, " extends %s", strings.Join(bases, ", ")) + } + tsOutput.WriteString(" {\n") + for _, wireName := range sortedKeys(def.Properties) { + prop := def.Properties[wireName] + fieldName := goName(wireName) + goType, _ := prop.goType() + for alias, path := range map[string]string{ + "core": "github.com/microsoft/TypeScript/tsc/internal/core", + "modulespecifiers": "github.com/microsoft/TypeScript/tsc/internal/modulespecifiers", + } { + if strings.HasPrefix(goType, alias+".") { + imports[alias] = path + } + } + writeDescription(&goTypes, prop.Description, "// ") + fmt.Fprintf(&goTypes, "%s %s `json:%s", fieldName, goType, strconv.Quote(wireName+",omitempty")) + goTypes.WriteString("`\n") + writeDescription(&tsOutput, prop.Description, " ") + tsType, _ := prop.tsType() + fmt.Fprintf(&tsOutput, " %s?: %s | undefined;\n", wireName, tsType) + } + goTypes.WriteString("}\n\n") + tsOutput.WriteString("}\n\n") + } + if err := model.writePreferenceMethods(&goTypes, imports); err != nil { + return nil, nil, err + } + if len(imports) != 0 { + goOutput.WriteString("import (\n") + for _, alias := range sortedKeys(imports) { + fmt.Fprintf(&goOutput, "%q\n", imports[alias]) + } + goOutput.WriteString(")\n\n") + } + goOutput.Write(goTypes.Bytes()) + formatted, formatErr := format.Source(goOutput.Bytes()) + if formatErr != nil { + return nil, nil, fmt.Errorf("format generated preferences: %w", formatErr) + } + return formatted, tsOutput.Bytes(), nil +} + +func (s schema) resolve(ref string) (string, error) { + name, ok := strings.CutPrefix(ref, "#/$defs/") + if !ok { + return "", fmt.Errorf("unsupported preference schema reference %q", ref) + } + if _, ok := s.Defs[name]; !ok { + return "", fmt.Errorf("unknown preference schema reference %q", ref) + } + return name, nil +} + +func (s schema) fields(name string, visiting map[string]bool) (map[string]bool, error) { + if visiting[name] { + return nil, fmt.Errorf("cyclic preference inheritance at %s", name) + } + if !token.IsIdentifier(name) || !token.IsExported(name) { + return nil, fmt.Errorf("invalid preference definition name %q", name) + } + visiting[name] = true + defer delete(visiting, name) + def := s.Defs[name] + if def.Type != "object" { + return nil, fmt.Errorf("%s: preference definitions must be objects", name) + } + fields := map[string]bool{} + goFields := map[string]bool{} + for _, ref := range def.AllOf { + base, err := s.resolve(ref.Ref) + if err != nil { + return nil, err + } + goField := base + if !token.IsIdentifier(goField) || !token.IsExported(goField) || goFields[goField] { + return nil, fmt.Errorf("%s: invalid or duplicate Go field %q", name, goField) + } + goFields[goField] = true + inherited, err := s.fields(base, visiting) + if err != nil { + return nil, err + } + for field := range inherited { + if fields[field] { + return nil, fmt.Errorf("%s: duplicate inherited preference %q", name, field) + } + fields[field] = true + } + } + for _, field := range sortedKeys(def.Properties) { + prop := def.Properties[field] + if !token.IsIdentifier(field) { + return nil, fmt.Errorf("%s: invalid preference field %q", name, field) + } + fieldName := goName(field) + if !token.IsIdentifier(fieldName) || !token.IsExported(fieldName) || goFields[fieldName] { + return nil, fmt.Errorf("%s: invalid or duplicate preference field %q", name, field) + } + if fields[field] { + return nil, fmt.Errorf("%s: duplicate inherited preference %q", name, field) + } + if _, err := prop.goType(); err != nil { + return nil, fmt.Errorf("%s.%s: %w", name, field, err) + } + if _, err := prop.tsType(); err != nil { + return nil, fmt.Errorf("%s.%s: %w", name, field, err) + } + if err := prop.validateParsing(); err != nil { + return nil, fmt.Errorf("%s.%s: %w", name, field, err) + } + if strings.ContainsAny(prop.Config+prop.FallbackConfig, "`\r\n") { + return nil, fmt.Errorf("%s.%s: invalid configuration tag", name, field) + } + goFields[fieldName] = true + fields[field] = true + } + return fields, nil +} + +func goName(name string) string { + var result strings.Builder + for part := range strings.SplitSeq(name, "-") { + if part != "" { + result.WriteString(strings.ToUpper(part[:1])) + result.WriteString(part[1:]) + } + } + return result.String() +} + +func (p property) goType() (string, error) { + if p.GoType != "" { + parts := strings.Split(p.GoType, ".") + if len(parts) > 2 || len(parts) == 2 && parts[0] != "core" && parts[0] != "modulespecifiers" { + return "", fmt.Errorf("unsupported Go preference type %q", p.GoType) + } + for _, part := range parts { + if !token.IsIdentifier(part) { + return "", fmt.Errorf("invalid Go preference type %q", p.GoType) + } + } + return p.GoType, nil + } + switch p.Type { + case "boolean": + return "core.Tristate", nil + case "integer": + return "int", nil + case "string": + return "string", nil + case "array": + if p.Items != nil && p.Items.Type == "string" && len(p.Items.Enum) == 0 { + return "[]string", nil + } + } + return "", fmt.Errorf("unsupported Go preference type for %q", p.Type) +} + +func (p property) tsType() (string, error) { + if len(p.Enum) != 0 { + if p.Type != "string" { + return "", errors.New("preference enums must have string values") + } + var values []string + for _, value := range p.Enum { + quoted := strconv.Quote(value) + if slices.Contains(values, quoted) { + return "", fmt.Errorf("duplicate preference enum value %q", value) + } + values = append(values, quoted) + } + return strings.Join(values, " | "), nil + } + switch p.Type { + case "boolean", "string": + return p.Type, nil + case "integer": + return "number", nil + case "array": + if p.Items != nil && p.Items.Type == "string" && len(p.Items.Enum) == 0 { + return "string[]", nil + } + } + return "", fmt.Errorf("unsupported TypeScript preference type %q", p.Type) +} + +func writeDescription(out *bytes.Buffer, description, prefix string) { + if description == "" { + return + } + if prefix == "// " { + for line := range strings.SplitSeq(description, "\n") { + fmt.Fprintf(out, "// %s\n", line) + } + return + } + fmt.Fprintf(out, "%s/**\n", prefix) + for line := range strings.SplitSeq(description, "\n") { + fmt.Fprintf(out, "%s * %s\n", prefix, strings.ReplaceAll(line, "*/", "*\\/")) + } + fmt.Fprintf(out, "%s */\n", prefix) +} + +func sortedKeys[V any](values map[string]V) []string { + keys := make([]string, 0, len(values)) + for key := range values { + keys = append(keys, key) + } + slices.Sort(keys) + return keys +} diff --git a/tools/gen-preferences/main_test.go b/tools/gen-preferences/main_test.go new file mode 100644 index 0000000000000..4a4d72f2cc17e --- /dev/null +++ b/tools/gen-preferences/main_test.go @@ -0,0 +1,80 @@ +package main + +import ( + "bytes" + "go/parser" + "go/token" + "os" + "path/filepath" + "strings" + "testing" +) + +func TestGenerate(t *testing.T) { + t.Parallel() + path := filepath.Join("..", "userPreferences.schema.json") + goOutput, tsOutput, err := generate(path) + if err != nil { + t.Fatal(err) + } + if _, parseErr := parser.ParseFile(token.NewFileSet(), "userpreferences_generated.go", goOutput, parser.AllErrors); parseErr != nil { + t.Fatal(parseErr) + } + for _, expected := range []string{ + "type UserPreferences struct {", + "CompletionPreferences", + "InlayHintsPreferences", + `json:"includeCompletionsForModuleExports,omitempty"`, + `getPreferenceConfigValue(config, "suggest.autoImports")`, + `getPreferenceConfigValue(config, "suggest.jsdoc.enabled", "suggest.completeJSDocs")`, + "func (p UserPreferences) withConfig(config map[string]any) UserPreferences", + "func (p *UserPreferences) MarshalJSONTo(enc *json.Encoder) error", + "func (p UserPreferences) WithCompletionPreferences(overrides CompletionPreferences) UserPreferences", + } { + if !strings.Contains(strings.Join(strings.Fields(string(goOutput)), " "), expected) { + t.Errorf("Go output does not contain %q", expected) + } + } + for _, expected := range []string{ + "export interface UserPreferences extends FormatCodeSettings, CompletionPreferences, InlayHintsPreferences, CodeLensUserPreferences", + "includeCompletionsForModuleExports?: boolean | undefined;", + `quotePreference?: "auto" | "double" | "single" | undefined;`, + `importModuleSpecifierEnding?: "auto" | "minimal" | "index" | "js" | undefined;`, + } { + if !strings.Contains(string(tsOutput), expected) { + t.Errorf("TypeScript output does not contain %q", expected) + } + } + secondGo, secondTS, err := generate(path) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(goOutput, secondGo) || !bytes.Equal(tsOutput, secondTS) { + t.Error("generation is not deterministic") + } + if bytes.Contains(goOutput, []byte("reflect.")) { + t.Error("generated preferences must use typed field access") + } +} + +func TestInvalidSchema(t *testing.T) { + t.Parallel() + for name, input := range map[string]string{ + "unknown keyword": `{"$ref":"#/$defs/UserPreferences","$defs":{"UserPreferences":{"type":"object","properties":{"value":{"type":"boolean","x-confgi":"suggest.autoImports"}}}}}`, + "unknown reference": `{"$ref":"#/$defs/UserPreferences","$defs":{"UserPreferences":{"type":"object","allOf":[{"$ref":"#/$defs/Missing"}]}}}`, + "cycle": `{"$ref":"#/$defs/UserPreferences","$defs":{"UserPreferences":{"type":"object","allOf":[{"$ref":"#/$defs/UserPreferences"}]}}}`, + "unsupported type": `{"$ref":"#/$defs/UserPreferences","$defs":{"UserPreferences":{"type":"object","properties":{"value":{"type":"null"}}}}}`, + "duplicate inherited property": `{"$ref":"#/$defs/UserPreferences","$defs":{"UserPreferences":{"type":"object","allOf":[{"$ref":"#/$defs/Base"}],"properties":{"value":{"type":"boolean"}}},"Base":{"type":"object","properties":{"value":{"type":"boolean"}}}}}`, + } { + t.Run(name, func(t *testing.T) { + t.Parallel() + path := filepath.Join(t.TempDir(), "schema.json") + if err := os.WriteFile(path, []byte(input), 0o644); err != nil { + t.Fatal(err) + } + if _, _, err := generate(path); err == nil { + t.Fatal("expected schema validation error") + } + }) + } +} diff --git a/tools/gen-preferences/methods.go b/tools/gen-preferences/methods.go new file mode 100644 index 0000000000000..8126983236724 --- /dev/null +++ b/tools/gen-preferences/methods.go @@ -0,0 +1,318 @@ +package main + +import ( + "bytes" + "errors" + "fmt" + "go/token" + "slices" + "strconv" + "strings" +) + +type preferenceField struct { + name string + selector string + property +} + +func (s schema) flattenedFields(name, prefix string) []preferenceField { + def := s.Defs[name] + var fields []preferenceField + for _, ref := range def.AllOf { + base, _ := s.resolve(ref.Ref) + fields = append(fields, s.flattenedFields(base, prefix+base+".")...) + } + for _, name := range sortedKeys(def.Properties) { + prop := def.Properties[name] + fields = append(fields, preferenceField{ + name: name, selector: prefix + goName(name), property: prop, + }) + } + return fields +} + +func (s schema) writePreferenceMethods(out *bytes.Buffer, imports map[string]string) error { + root, _ := s.resolve(s.Ref) + if root != "UserPreferences" { + return errors.New("preference schema must define UserPreferences as its root") + } + if _, ok := s.Defs["CompletionPreferences"]; !ok { + return errors.New("preference schema must define CompletionPreferences") + } + imports["json"] = "github.com/microsoft/TypeScript/tsc/internal/json" + fields := s.flattenedFields(root, "") + enumTypes := map[string]property{} + for _, field := range fields { + if len(field.Enum) != 0 { + if previous, ok := enumTypes[field.GoType]; ok && + (!slices.Equal(previous.Enum, field.Enum) || + previous.Default != field.Default || + previous.AcceptNumber != field.AcceptNumber || + previous.GoUnderlying != field.GoUnderlying) { + return fmt.Errorf("inconsistent parsing metadata for %s", field.GoType) + } + enumTypes[field.GoType] = field.property + } + } + for _, name := range sortedKeys(enumTypes) { + prop := enumTypes[name] + writeEnumParser(out, prop) + imports["strings"] = "strings" + if prop.serializeEnum() { + writeEnumSerializer(out, prop) + } + } + + for _, name := range []string{root, "CompletionPreferences"} { + fmt.Fprintf(out, "func (p *%s) applyRawPreferences(settings map[string]any) {\n", name) + out.WriteString("for name, value := range settings {\nif value == nil { continue }\nswitch name {\n") + for _, field := range s.flattenedFields(name, "") { + fmt.Fprintf(out, "case %q:\n", field.name) + writeAssignment(out, "p."+field.selector, field.property) + } + out.WriteString("}\n}\n}\n\n") + } + + out.WriteString("func (p UserPreferences) withConfig(config map[string]any) UserPreferences {\n") + out.WriteString("p.applyRawPreferences(config)\nif unstable, ok := config[\"unstable\"].(map[string]any); ok { p.applyRawPreferences(unstable) }\n") + for _, field := range fields { + if field.Config == "" { + continue + } + fmt.Fprintf(out, "if value, ok := getPreferenceConfigValue(config, %q", field.Config) + if field.FallbackConfig != "" { + for fallback := range strings.SplitSeq(field.FallbackConfig, ";") { + fmt.Fprintf(out, ", %q", fallback) + } + } + out.WriteString("); ok {\n") + if field.ConfigParser != "" { + fmt.Fprintf(out, "p.%s = %s(value)\n", field.selector, field.ConfigParser) + } else { + out.WriteString("if value != nil {\n") + writeAssignment(out, "p."+field.selector, field.property) + out.WriteString("}\n") + } + out.WriteString("}\n") + } + for _, field := range fields { + if field.Validator != "" { + fmt.Fprintf(out, "p.%s = %s(p.%s)\n", field.selector, field.Validator, field.selector) + } + } + out.WriteString("return p\n}\n\n") + + out.WriteString("func (p *CompletionPreferences) UnmarshalJSONFrom(dec *json.Decoder) error {\nvar settings map[string]any\nif err := json.UnmarshalDecode(dec, &settings); err != nil { return err }\np.applyRawPreferences(settings)\nreturn nil\n}\n\n") + out.WriteString("func (p UserPreferences) WithCompletionPreferences(overrides CompletionPreferences) UserPreferences {\n") + for _, field := range s.flattenedFields("CompletionPreferences", "") { + rootFieldIndex := slices.IndexFunc(fields, func(candidate preferenceField) bool { return candidate.name == field.name }) + if rootFieldIndex < 0 { + return fmt.Errorf("completion preference %s is not inherited by UserPreferences", field.name) + } + fmt.Fprintf(out, "if %s {\np.%s = overrides.%s\n}\n", presentCondition("overrides."+field.selector, field.property), fields[rootFieldIndex].selector, field.selector) + } + out.WriteString("return p\n}\n\n") + + out.WriteString("func (p *UserPreferences) MarshalJSONTo(enc *json.Encoder) error {\nconfig := make(map[string]any)\n") + for _, field := range fields { + target := field.Config + if target == "" { + target = "unstable." + field.name + } + path, inverted := splitConfigTag(target) + value := "p." + field.selector + condition := presentCondition(value, field.property) + if condition != "true" { + fmt.Fprintf(out, "if %s {\n", condition) + } + goType, _ := field.goType() + serialized := value + switch { + case goType == "core.Tristate": + serialized += ".IsTrue()" + case field.serializeEnum(): + serialized = serializerName(field.GoType) + "(" + value + ")" + case field.goKind() == "string": + serialized = "string(" + value + ")" + case field.goKind() == "int": + serialized = "int(" + value + ")" + case field.goKind() == "array": + serialized = "slices.Clone(" + value + ")" + imports["slices"] = "slices" + } + if inverted { + serialized = "!(" + serialized + ")" + } + fmt.Fprintf(out, "setNestedValue(config, %q, %s)\n", path, serialized) + if condition != "true" { + out.WriteString("}\n") + } + } + out.WriteString("return json.MarshalEncode(enc, config, json.Deterministic(true))\n}\n\n") + return nil +} + +func writeAssignment(out *bytes.Buffer, target string, prop property) { + goType, _ := prop.goType() + switch { + case len(prop.Enum) != 0: + fmt.Fprintf(out, "%s = %s(value)\n", target, parserName(prop.GoType)) + case goType == "core.Tristate": + fmt.Fprintf(out, "%s = parsePreferenceTristate(value)\n", target) + case prop.goKind() == "int": + fmt.Fprintf(out, "switch value := value.(type) {\ncase int: %s = %s(value)\ncase float64: %s = %s(value)\n}\n", target, goType, target, goType) + case prop.goKind() == "array": + fmt.Fprintf(out, "if values, ok := value.([]any); ok {\nresult := make([]string, 0, len(values))\nfor _, value := range values { if value, ok := value.(string); ok { result = append(result, value) } }\n%s = result\n}\n", target) + default: + fmt.Fprintf(out, "if value, ok := value.(%s); ok { %s = %s(value) }\n", prop.goKind(), target, goType) + } +} + +func presentCondition(value string, prop property) string { + goType, _ := prop.goType() + if prop.serializeEnum() { + return "true" + } + if goType == "core.Tristate" { + return "(" + value + ".IsTrue() || " + value + ".IsFalse())" + } + switch prop.goKind() { + case "string": + return value + ` != ""` + case "int": + return value + " != 0" + case "array": + return value + " != nil" + default: + return "true" + } +} + +func (p property) goKind() string { + if p.GoUnderlying != "" { + return p.GoUnderlying + } + switch p.Type { + case "boolean": + return "bool" + case "integer": + return "int" + default: + return p.Type + } +} + +func parserName(goType string) string { + _, name, ok := strings.Cut(goType, ".") + if !ok { + name = goType + } + return "parsePreference" + name +} + +func serializerName(goType string) string { + return strings.Replace(parserName(goType), "parsePreference", "serializePreference", 1) +} + +func writeEnumParser(out *bytes.Buffer, prop property) { + fmt.Fprintf(out, "func %s(value any) %s {\n", parserName(prop.GoType), prop.GoType) + out.WriteString("if value, ok := value.(string); ok {\n") + out.WriteString("switch strings.ToLower(value) {\n") + for _, literal := range prop.Enum { + fmt.Fprintf(out, "case %q: return %s\n", strings.ToLower(literal), prop.enumConstant(literal)) + } + out.WriteString("}\n}\n") + if prop.AcceptNumber { + fmt.Fprintf(out, "switch value := value.(type) {\ncase int: return %s(value)\ncase float64: return %s(value)\n}\n", prop.GoType, prop.GoType) + } + fallback := prop.GoType + `("")` + if prop.Default != "" { + fallback = prop.enumConstant(prop.Default) + } + fmt.Fprintf(out, "return %s\n}\n\n", fallback) +} + +func writeEnumSerializer(out *bytes.Buffer, prop property) { + fmt.Fprintf(out, "func %s(value %s) string {\nswitch value {\n", serializerName(prop.GoType), prop.GoType) + for _, value := range prop.Enum { + fmt.Fprintf(out, "case %s: return %q\n", prop.enumConstant(value), value) + } + fmt.Fprintf(out, "default: return %q\n}\n}\n\n", prop.Default) +} + +func (p property) enumConstant(value string) string { + return p.GoType + goName(value) +} + +func (p property) serializeEnum() bool { + return len(p.Enum) != 0 && p.goKind() != "string" && !p.AcceptNumber +} + +func splitConfigTag(tag string) (string, bool) { + path, modifier, _ := strings.Cut(tag, ",") + return path, modifier == "invert" +} + +func (p property) validateParsing() error { + if p.GoUnderlying != "" && p.GoUnderlying != "string" && p.GoUnderlying != "int" && p.GoUnderlying != "bool" { + return fmt.Errorf("unsupported Go underlying type %q", p.GoUnderlying) + } + for _, name := range []string{p.ConfigParser, p.Validator} { + if name != "" && !token.IsIdentifier(name) { + return fmt.Errorf("invalid preference helper %q", name) + } + if p.FallbackConfig != "" && p.Config == "" { + return errors.New("fallback config paths require a primary config path") + } + } + if p.ConfigParser != "" && (p.Config == "" || p.FallbackConfig != "") { + return errors.New("custom config parsers require a primary path without fallback paths") + } + for _, tag := range append([]string{p.Config}, strings.Split(p.FallbackConfig, ";")...) { + if tag == "" { + continue + } + path, modifier, _ := strings.Cut(tag, ",") + if path == "" || modifier != "" && modifier != "invert" { + return fmt.Errorf("invalid configuration mapping %q", tag) + } + if modifier == "invert" && p.Type != "boolean" { + return errors.New("only boolean preferences can invert configuration values") + } + } + if len(p.Enum) == 0 { + if p.Default != "" || p.AcceptNumber { + return errors.New("enum parsing metadata requires enum values") + } + return nil + } + for _, value := range p.Enum { + if _, err := (property{GoType: p.enumConstant(value)}).goType(); err != nil { + return err + } + } + if p.AcceptNumber && p.goKind() != "int" { + return errors.New("numeric parsing is only supported for integer enums") + } + if p.Default != "" && !slices.Contains(p.Enum, p.Default) { + return errors.New("enum default must have a wire value") + } + if p.goKind() != "string" && p.Default == "" { + return errors.New("non-string Go enums require an explicit default") + } + values := map[string]bool{} + constants := map[string]bool{} + for _, value := range p.Enum { + if value == "" || constants[p.enumConstant(value)] { + return errors.New("enum values must have unique Go constant names") + } + constants[p.enumConstant(value)] = true + value = strings.ToLower(value) + if values[value] { + return fmt.Errorf("ambiguous case-insensitive enum value %s", strconv.Quote(value)) + } + values[value] = true + } + return nil +} diff --git a/tools/gen-proto/main.go b/tools/gen-proto/main.go index 7936e3c257131..a9373624ba587 100644 --- a/tools/gen-proto/main.go +++ b/tools/gen-proto/main.go @@ -403,10 +403,7 @@ func (r *typeRenderer) indexPackage(pkg *packages.Package) { func (r *typeRenderer) recordDoc(obj types.Object, doc *ast.CommentGroup) { if obj != nil && doc != nil { - text := strings.TrimSpace(doc.Text()) - if text != "!!!" { - r.docs[obj] = text - } + r.docs[obj] = strings.TrimSpace(doc.Text()) } } @@ -516,22 +513,9 @@ func (r *typeRenderer) namedType(named *types.Named) string { return "unknown" case "github.com/microsoft/TypeScript/tsc/internal/core.Tristate": return "boolean" - case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.IndentStyle": - return `"none" | "block" | "smart"` - case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.QuotePreference": - return `"auto" | "double" | "single"` - case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.JsxAttributeCompletionStyle": - return `"auto" | "braces" | "none"` - case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.IncludeInlayParameterNameHints": - return `"none" | "literals" | "all"` - case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.OrganizeImportsSort": - return `"auto" | "ordinal" | "ordinalIgnoreCase" | "natural" | "naturalIgnoreCase"` - case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.OrganizeImportsCollation": - return `"ordinal" | "unicode"` - case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.OrganizeImportsCaseFirst": - return `"default" | "lower" | "upper"` - case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.OrganizeImportsTypeOrder": - return `"auto" | "last" | "inline" | "first"` + case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.UserPreferences", + "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.CompletionPreferences": + return r.importTypeOnly(obj.Name(), "./userPreferences.generated.ts") case "github.com/microsoft/TypeScript/tsc/internal/core.JsxEmit": return r.importType("JsxEmit", "#enums/jsxEmit") case "github.com/microsoft/TypeScript/tsc/internal/core.ModuleDetectionKind": @@ -546,10 +530,6 @@ func (r *typeRenderer) namedType(named *types.Named) string { return r.importType("ScriptTarget", "#enums/scriptTarget") case "github.com/microsoft/TypeScript/tsc/internal/core.ScriptKind": return r.importType("ScriptKind", "#enums/scriptKind") - case "github.com/microsoft/TypeScript/tsc/internal/modulespecifiers.ImportModuleSpecifierPreference": - return `"shortest" | "project-relative" | "relative" | "non-relative"` - case "github.com/microsoft/TypeScript/tsc/internal/modulespecifiers.ImportModuleSpecifierEndingPreference": - return `"auto" | "minimal" | "index" | "js"` case "github.com/microsoft/TypeScript/tsc/internal/collections.OrderedMap": if named.TypeArgs().Len() != 2 { return "Record" @@ -652,10 +632,6 @@ func (r *typeRenderer) declarations() (string, error) { for field := range structType.Fields() { if field.Embedded() { embedded = append(embedded, r.typeString(field.Type(), false)) - } else if named.Obj().Pkg().Path() == "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil" && - named.Obj().Name() == "UserPreferences" && - (field.Name() == "InlayHints" || field.Name() == "CodeLens") { - embedded = append(embedded, r.typeString(field.Type(), false)) } } fmt.Fprintf(&out, "export interface %s", exportedName(named.Obj().Name())) @@ -664,11 +640,7 @@ func (r *typeRenderer) declarations() (string, error) { } out.WriteString(" {\n") for i := range structType.NumFields() { - fieldName := structType.Field(i).Name() - if structType.Field(i).Embedded() || - named.Obj().Pkg().Path() == "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil" && - named.Obj().Name() == "UserPreferences" && - (fieldName == "InlayHints" || fieldName == "CodeLens") { + if structType.Field(i).Embedded() { continue } field, include, optional, nonnil, deprecated, internal := jsonField(structType, i) @@ -773,9 +745,7 @@ func jsonField(structType *types.Struct, index int) (name string, include bool, if !field.Exported() { return "", false, false, false, false, false } - structTag := reflect.StructTag(structType.Tag(index)) - tag := structTag.Get("json") - rawTag := structTag.Get("raw") + tag := reflect.StructTag(structType.Tag(index)).Get("json") noniltag := reflect.StructTag(structType.Tag(index)).Get("nonnil") deprecatedtag := reflect.StructTag(structType.Tag(index)).Get("deprecated") internaltag := reflect.StructTag(structType.Tag(index)).Get("internal") @@ -785,15 +755,7 @@ func jsonField(structType *types.Struct, index int) (name string, include bool, return "", false, false, noniltag == "true", deprecatedtag == "true", internaltag == "true" } if name == "" { - if rawName, _, ok := strings.Cut(rawTag, ","); ok { - name = rawName - optional = true - } else if rawTag != "" { - name = rawTag - optional = true - } else { - name = field.Name() - } + name = field.Name() } for _, option := range parts[1:] { if option == "omitempty" || option == "omitzero" { diff --git a/tools/gen-proto/main_test.go b/tools/gen-proto/main_test.go index 5bc4c276b7a5d..533862d5bb0ca 100644 --- a/tools/gen-proto/main_test.go +++ b/tools/gen-proto/main_test.go @@ -33,11 +33,9 @@ func TestGenerate(t *testing.T) { `export interface UpdateSnapshotParams`, `export interface CreateSnapshotParams extends SnapshotRequestChangesParams`, `export interface LanguageServerSnapshotChanges extends SnapshotRequestChangesParams`, - `export interface UserPreferences extends FormatCodeSettings, CompletionPreferences, InlayHintsPreferences, CodeLensUserPreferences`, + `import type { CompletionPreferences, UserPreferences } from "./userPreferences.generated.ts";`, `userPreferences?: UserPreferences | undefined;`, `prepareAutoImports?: DocumentIdentifier | undefined;`, - `includeCompletionsForModuleExports?: boolean | undefined;`, - `quotePreference?: "auto" | "double" | "single" | undefined;`, `openProjects?: readonly DocumentIdentifier[] | undefined;`, `export type EnsurePrograms = true | readonly ProjectId[];`, `export type InferredProjectId = string & { __inferredProjectIdBrand: any; };`, diff --git a/tools/userPreferences.schema.json b/tools/userPreferences.schema.json new file mode 100644 index 0000000000000..bc1f6fa40fe77 --- /dev/null +++ b/tools/userPreferences.schema.json @@ -0,0 +1,494 @@ +{ + "$comment": "Edit this schema and run npx hereby generate:preferences to update Go/TypeScript definitions and typed Go parsing, overlays, and serialization. All properties are optional. Go field names capitalize the first letter of the wire name; allOf groups become embedded Go structs and inherited TypeScript interfaces. Enum type names follow the field-name rule, constant names append the capitalized wire value with hyphens removed, and parsing is case-insensitive. Standard default values specify enum parsing fallbacks. Booleans use core.Tristate unless x-go-type overrides the Go representation; x-go-type also references external Go enum types. x-go-underlying preserves existing non-string enum representations, and x-accept-number allows numeric input and serialization for numeric editor settings. x-config and x-fallback-config specify editor configuration mappings, including the invert modifier. x-config-parser and x-validator name typed helpers for specialized behavior. Preference defaults and existing Go enum declarations remain in lsutil.", + "$defs": { + "CodeLensUserPreferences": { + "properties": { + "implementationsCodeLensEnabled": { + "type": "boolean", + "x-config": "implementationsCodeLens.enabled" + }, + "implementationsCodeLensShowOnAllClassMethods": { + "type": "boolean", + "x-config": "implementationsCodeLens.showOnAllClassMethods" + }, + "implementationsCodeLensShowOnInterfaceMethods": { + "type": "boolean", + "x-config": "implementationsCodeLens.showOnInterfaceMethods" + }, + "referencesCodeLensEnabled": { + "type": "boolean", + "x-config": "referencesCodeLens.enabled" + }, + "referencesCodeLensShowOnAllFunctions": { + "type": "boolean", + "x-config": "referencesCodeLens.showOnAllFunctions" + } + }, + "type": "object" + }, + "CompletionPreferences": { + "description": "CompletionPreferences contains preferences used while producing completions.", + "properties": { + "includeAutomaticOptionalChainCompletions": { + "description": "Unless this option is `false`, member completion lists triggered with `.` will include entries\non potentially-null and potentially-undefined values, with insertion text to replace\npreceding `.` tokens with `?.`.", + "type": "boolean", + "x-config": "suggest.includeAutomaticOptionalChainCompletions" + }, + "includeCompletionsForImportStatements": { + "description": "Enables auto-import-style completions on partially-typed import statements. E.g., allows\n`import write|` to be completed to `import { writeFile } from \"fs\"`.", + "type": "boolean", + "x-config": "suggest.includeCompletionsForImportStatements" + }, + "includeCompletionsForModuleExports": { + "description": "If enabled, TypeScript will search through all external modules' exports and add them to the completions list.\nThis affects lone identifier completions but not completions on the right hand side of `obj.`.", + "type": "boolean", + "x-config": "suggest.autoImports" + }, + "includeCompletionsWithClassMemberSnippets": { + "description": "If enabled, completions for class members (e.g. methods and properties) will include\na whole declaration for the member.", + "type": "boolean", + "x-config": "suggest.classMemberSnippets.enabled" + }, + "includeCompletionsWithObjectLiteralMethodSnippets": { + "description": "If enabled, object literal methods will have a method declaration completion entry in addition\nto the regular completion entry containing just the method name.", + "type": "boolean", + "x-config": "suggest.objectLiteralMethodSnippets.enabled" + }, + "jsxAttributeCompletionStyle": { + "enum": [ + "auto", + "braces", + "none" + ], + "type": "string", + "x-config": "preferences.jsxAttributeCompletionStyle", + "default": "auto" + } + }, + "type": "object" + }, + "EditorSettings": { + "properties": { + "baseIndentSize": { + "type": "integer", + "x-config": "format.baseIndentSize" + }, + "convertTabsToSpaces": { + "type": "boolean", + "x-config": "format.convertTabsToSpaces" + }, + "indentSize": { + "type": "integer", + "x-config": "format.indentSize" + }, + "indentStyle": { + "enum": [ + "none", + "block", + "smart" + ], + "type": "string", + "x-config": "format.indentStyle", + "x-go-underlying": "int", + "x-accept-number": true, + "default": "smart" + }, + "newLineCharacter": { + "type": "string", + "x-config": "format.newLineCharacter" + }, + "tabSize": { + "type": "integer", + "x-config": "format.tabSize" + }, + "trimTrailingWhitespace": { + "type": "boolean", + "x-config": "format.trimTrailingWhitespace" + } + }, + "type": "object" + }, + "FormatCodeSettings": { + "allOf": [ + { + "$ref": "#/$defs/EditorSettings" + } + ], + "properties": { + "indentMultiLineObjectLiteralBeginningOnBlankLine": { + "type": "boolean", + "x-config": "format.indentMultiLineObjectLiteralBeginningOnBlankLine" + }, + "indentSwitchCase": { + "type": "boolean", + "x-config": "format.indentSwitchCase" + }, + "insertSpaceAfterCommaDelimiter": { + "type": "boolean", + "x-config": "format.insertSpaceAfterCommaDelimiter" + }, + "insertSpaceAfterConstructor": { + "type": "boolean", + "x-config": "format.insertSpaceAfterConstructor" + }, + "insertSpaceAfterFunctionKeywordForAnonymousFunctions": { + "type": "boolean", + "x-config": "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions" + }, + "insertSpaceAfterKeywordsInControlFlowStatements": { + "type": "boolean", + "x-config": "format.insertSpaceAfterKeywordsInControlFlowStatements" + }, + "insertSpaceAfterOpeningAndBeforeClosingEmptyBraces": { + "type": "boolean", + "x-config": "format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces" + }, + "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": { + "type": "boolean", + "x-config": "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces" + }, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": { + "type": "boolean", + "x-config": "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces" + }, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": { + "type": "boolean", + "x-config": "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets" + }, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": { + "type": "boolean", + "x-config": "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis" + }, + "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": { + "type": "boolean", + "x-config": "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces" + }, + "insertSpaceAfterSemicolonInForStatements": { + "type": "boolean", + "x-config": "format.insertSpaceAfterSemicolonInForStatements" + }, + "insertSpaceAfterTypeAssertion": { + "type": "boolean", + "x-config": "format.insertSpaceAfterTypeAssertion" + }, + "insertSpaceBeforeAndAfterBinaryOperators": { + "type": "boolean", + "x-config": "format.insertSpaceBeforeAndAfterBinaryOperators" + }, + "insertSpaceBeforeFunctionParenthesis": { + "type": "boolean", + "x-config": "format.insertSpaceBeforeFunctionParenthesis" + }, + "insertSpaceBeforeTypeAnnotation": { + "type": "boolean", + "x-config": "format.insertSpaceBeforeTypeAnnotation" + }, + "placeOpenBraceOnNewLineForControlBlocks": { + "type": "boolean", + "x-config": "format.placeOpenBraceOnNewLineForControlBlocks" + }, + "placeOpenBraceOnNewLineForFunctions": { + "type": "boolean", + "x-config": "format.placeOpenBraceOnNewLineForFunctions" + }, + "semicolons": { + "enum": [ + "ignore", + "insert", + "remove" + ], + "type": "string", + "x-config": "format.semicolons", + "x-go-type": "SemicolonPreference", + "default": "ignore" + } + }, + "type": "object" + }, + "InlayHintsPreferences": { + "properties": { + "includeInlayEnumMemberValueHints": { + "type": "boolean", + "x-config": "inlayHints.enumMemberValues.enabled" + }, + "includeInlayFunctionLikeReturnTypeHints": { + "type": "boolean", + "x-config": "inlayHints.functionLikeReturnTypes.enabled" + }, + "includeInlayFunctionParameterTypeHints": { + "type": "boolean", + "x-config": "inlayHints.parameterTypes.enabled" + }, + "includeInlayParameterNameHints": { + "enum": [ + "none", + "literals", + "all" + ], + "type": "string", + "x-config": "inlayHints.parameterNames.enabled", + "default": "none" + }, + "includeInlayParameterNameHintsWhenArgumentMatchesName": { + "type": "boolean", + "x-config": "inlayHints.parameterNames.suppressWhenArgumentMatchesName,invert" + }, + "includeInlayPropertyDeclarationTypeHints": { + "type": "boolean", + "x-config": "inlayHints.propertyDeclarationTypes.enabled" + }, + "includeInlayVariableTypeHints": { + "type": "boolean", + "x-config": "inlayHints.variableTypes.enabled" + }, + "includeInlayVariableTypeHintsWhenTypeMatchesName": { + "type": "boolean", + "x-config": "inlayHints.variableTypes.suppressWhenTypeMatchesName,invert" + } + }, + "type": "object" + }, + "UserPreferences": { + "allOf": [ + { + "$ref": "#/$defs/FormatCodeSettings" + }, + { + "$ref": "#/$defs/CompletionPreferences" + }, + { + "$ref": "#/$defs/InlayHintsPreferences" + }, + { + "$ref": "#/$defs/CodeLensUserPreferences" + } + ], + "description": "UserPreferences represents TypeScript language service preferences.", + "properties": { + "allowRenameOfImportPath": { + "type": "boolean" + }, + "allowTextChangesInNewFiles": { + "type": "boolean" + }, + "autoClosingTags": { + "type": "boolean", + "x-config": "autoClosingTags.enabled", + "x-fallback-config": "autoClosingTags" + }, + "autoImportEntrypointDirectorySearch": { + "type": "boolean", + "x-config": "preferences.autoImportEntrypointDirectorySearch" + }, + "autoImportFileExcludePatterns": { + "items": { + "type": "string" + }, + "type": "array", + "x-config": "preferences.autoImportFileExcludePatterns" + }, + "autoImportSpecifierExcludeRegexes": { + "items": { + "type": "string" + }, + "type": "array", + "x-config": "preferences.autoImportSpecifierExcludeRegexes" + }, + "automaticTypeAcquisitionEnabled": { + "description": "AutomaticTypeAcquisitionEnabled is the unified setting from tsserver.automaticTypeAcquisition.enabled under the js/ts section.\nWhen set, it takes precedence over DisableAutomaticTypeAcquisition.", + "type": "boolean", + "x-config": "tsserver.automaticTypeAcquisition.enabled" + }, + "completeJSDocs": { + "type": "boolean", + "x-config": "suggest.jsdoc.enabled", + "x-fallback-config": "suggest.completeJSDocs" + }, + "customConfigFileName": { + "description": "CustomConfigFileName specifies a custom config file name to use before defaulting to tsconfig.json/jsconfig.json.", + "type": "string", + "x-config": "customConfigFileName", + "x-validator": "normalizeCustomConfigFileName" + }, + "disableAutomaticTypeAcquisition": { + "description": "DisableAutomaticTypeAcquisition is the deprecated setting from typescript.disableAutomaticTypeAcquisition.", + "type": "boolean", + "x-config": "disableAutomaticTypeAcquisition" + }, + "disableLineTextInReferences": { + "type": "boolean" + }, + "disableSuggestions": { + "type": "boolean" + }, + "displayPartsForJSDoc": { + "type": "boolean" + }, + "excludeLibrarySymbolsInNavTo": { + "type": "boolean", + "x-config": "workspaceSymbols.excludeLibrarySymbols" + }, + "formatEnabled": { + "type": "boolean", + "x-config": "format.enabled", + "x-fallback-config": "format.enable" + }, + "generateReturnInDocTemplate": { + "type": "boolean", + "x-config": "suggest.jsdoc.generateReturns" + }, + "importModuleSpecifierEnding": { + "description": "Determines whether we import `foo/index.ts` as \"foo\", \"foo/index\", or \"foo/index.js\"", + "enum": [ + "auto", + "minimal", + "index", + "js" + ], + "type": "string", + "x-config": "preferences.importModuleSpecifierEnding", + "x-go-type": "modulespecifiers.ImportModuleSpecifierEndingPreference", + "default": "auto" + }, + "importModuleSpecifierPreference": { + "enum": [ + "shortest", + "project-relative", + "relative", + "non-relative" + ], + "type": "string", + "x-config": "preferences.importModuleSpecifier", + "x-go-type": "modulespecifiers.ImportModuleSpecifierPreference", + "default": "shortest" + }, + "lazyConfiguredProjectsFromExternalProject": { + "type": "boolean" + }, + "locale": { + "type": "string", + "x-config": "locale" + }, + "maximumHoverLength": { + "description": "A positive integer indicating the maximum length of a hover text before it is truncated.\n\nDefault: `500`", + "type": "integer" + }, + "organizeImportsAccentCollation": { + "description": "Indicates whether accents and other diacritic marks are considered unequal for the purpose of sorting.\n\nThis preference is ignored if organizeImportsCollation is not `unicode`.\n\nDefault: `true`", + "type": "boolean", + "x-config": "preferences.organizeImports.accentCollation" + }, + "organizeImportsCaseFirst": { + "description": "Indicates whether upper case or lower case should sort first.\n\nThis permission is ignored if:\n\t- organizeImportsCollation is not `unicode`\n\t- organizeImportsIgnoreCase is `true`\n\t- organizeImportsIgnoreCase is `auto` and the auto-detected case sensitivity is case-insensitive.\n\nDefault: `false`", + "enum": [ + "default", + "lower", + "upper" + ], + "type": "string", + "x-config": "preferences.organizeImports.caseFirst", + "x-go-underlying": "int", + "default": "default" + }, + "organizeImportsCollation": { + "description": "Indicates whether imports should be organized via an \"ordinal\" (binary) comparison using the numeric value of their\ncode points, or via \"unicode\" natural sorting. This implementation is locale-agnostic and approximates the practical\nimport-sorting behavior rather than the full Unicode Collation Algorithm.\n\nDefault: Ordinal", + "enum": [ + "ordinal", + "unicode" + ], + "type": "string", + "x-config": "preferences.organizeImports.unicodeCollation", + "x-go-underlying": "bool", + "default": "ordinal" + }, + "organizeImportsIgnoreCase": { + "description": "Indicates whether imports should be organized in a case-insensitive manner.\n\nIf unspecified, case sensitivity is detected.", + "type": "boolean", + "x-config": "preferences.organizeImports.caseSensitivity", + "x-config-parser": "parseOrganizeImportsCaseSensitivity" + }, + "organizeImportsLocale": { + "description": "Indicates the locale to use for \"unicode\" collation in legacy clients. This is accepted for compatibility, but\ncurrently ignored because organize-import sorting is deterministic and locale-agnostic.\n\nThis preference is ignored if organizeImportsCollation is not `unicode`.\n\nDefault: `\"en\"`", + "type": "string", + "x-config": "preferences.organizeImports.locale" + }, + "organizeImportsNumericCollation": { + "description": "Indicates whether numeric collation should be used for digit sequences in strings. When `true`, will collate\nstrings such that `a1z < a2z < a100z`. When `false`, will collate strings such that `a1z < a100z < a2z`.\n\nThis preference is ignored if organizeImportsCollation is not `unicode`.\n\nDefault: `false`", + "type": "boolean", + "x-config": "preferences.organizeImports.numericCollation" + }, + "organizeImportsSort": { + "description": "Indicates which deterministic preset should be used to sort imports.\n\"auto\" detects the existing ordinal case sensitivity where possible.", + "enum": [ + "auto", + "ordinal", + "ordinalIgnoreCase", + "natural", + "naturalIgnoreCase" + ], + "type": "string", + "x-config": "preferences.organizeImports.sort", + "x-go-underlying": "int", + "default": "auto" + }, + "organizeImportsTypeOrder": { + "description": "Indicates where named type-only imports should sort. \"inline\" sorts named imports without regard to if the import is type-only.\n\nDefault: `auto`, which defaults to `last`", + "enum": [ + "auto", + "last", + "inline", + "first" + ], + "type": "string", + "x-config": "preferences.organizeImports.typeOrder", + "x-go-underlying": "int", + "default": "auto" + }, + "preferGoToSourceDefinition": { + "type": "boolean", + "x-go-type": "bool" + }, + "preferTypeOnlyAutoImports": { + "type": "boolean", + "x-config": "preferences.preferTypeOnlyAutoImports" + }, + "providePrefixAndSuffixTextForRename": { + "type": "boolean", + "x-config": "preferences.useAliasesForRenames" + }, + "provideRefactorNotApplicableReason": { + "type": "boolean" + }, + "quotePreference": { + "enum": [ + "auto", + "double", + "single" + ], + "type": "string", + "x-config": "preferences.quoteStyle" + }, + "reportStyleChecksAsWarnings": { + "type": "boolean", + "x-config": "reportStyleChecksAsWarnings" + }, + "validateEnabled": { + "type": "boolean", + "x-config": "validate.enabled", + "x-fallback-config": "validate.enable" + }, + "workspaceSymbolsScope": { + "enum": [ + "allOpenProjects", + "currentProject" + ], + "type": "string", + "x-config": "workspaceSymbols.scope" + } + }, + "type": "object" + } + }, + "$ref": "#/$defs/UserPreferences", + "$schema": "https://json-schema.org/draft/2020-12/schema" +} diff --git a/tsc/internal/fourslash/fourslash.go b/tsc/internal/fourslash/fourslash.go index de4ae802e3f84..03c56bde3b6d8 100644 --- a/tsc/internal/fourslash/fourslash.go +++ b/tsc/internal/fourslash/fourslash.go @@ -4811,8 +4811,8 @@ func (f *FourslashTest) verifyBaselineRename( var renameOptions strings.Builder if preferences != nil { - if preferences.UseAliasesForRename != core.TSUnknown { - fmt.Fprintf(&renameOptions, "// @useAliasesForRename: %v\n", preferences.UseAliasesForRename.IsTrue()) + if preferences.ProvidePrefixAndSuffixTextForRename != core.TSUnknown { + fmt.Fprintf(&renameOptions, "// @useAliasesForRename: %v\n", preferences.ProvidePrefixAndSuffixTextForRename.IsTrue()) } if preferences.QuotePreference != lsutil.QuotePreferenceUnknown { fmt.Fprintf(&renameOptions, "// @quotePreference: %v\n", preferences.QuotePreference) diff --git a/tsc/internal/fourslash/tests/codeLensFunctionExpressions01_test.go b/tsc/internal/fourslash/tests/codeLensFunctionExpressions01_test.go index b2c2d99e276aa..c9ede411b735a 100644 --- a/tsc/internal/fourslash/tests/codeLensFunctionExpressions01_test.go +++ b/tsc/internal/fourslash/tests/codeLensFunctionExpressions01_test.go @@ -45,13 +45,11 @@ const namedFn4 = function namedFn4() {}; f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{ - CodeLens: lsutil.CodeLensUserPreferences{ - ReferencesCodeLensEnabled: core.TSTrue, - ReferencesCodeLensShowOnAllFunctions: core.TSTrue, - - ImplementationsCodeLensEnabled: core.TSTrue, - ImplementationsCodeLensShowOnInterfaceMethods: core.TSTrue, - ImplementationsCodeLensShowOnAllClassMethods: core.TSTrue, - }, + ReferencesCodeLensEnabled: core.TSTrue, + ReferencesCodeLensShowOnAllFunctions: core.TSTrue, + + ImplementationsCodeLensEnabled: core.TSTrue, + ImplementationsCodeLensShowOnInterfaceMethods: core.TSTrue, + ImplementationsCodeLensShowOnAllClassMethods: core.TSTrue, }) } diff --git a/tsc/internal/fourslash/tests/codeLensFunctionsAndConstants01_test.go b/tsc/internal/fourslash/tests/codeLensFunctionsAndConstants01_test.go index d7d7157802f33..36eb801984ecb 100644 --- a/tsc/internal/fourslash/tests/codeLensFunctionsAndConstants01_test.go +++ b/tsc/internal/fourslash/tests/codeLensFunctionsAndConstants01_test.go @@ -42,13 +42,11 @@ console.log(bar); f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{ - CodeLens: lsutil.CodeLensUserPreferences{ - ReferencesCodeLensEnabled: core.TSTrue, - ReferencesCodeLensShowOnAllFunctions: core.TSTrue, - - ImplementationsCodeLensEnabled: core.TSTrue, - ImplementationsCodeLensShowOnInterfaceMethods: core.TSTrue, - ImplementationsCodeLensShowOnAllClassMethods: core.TSTrue, - }, + ReferencesCodeLensEnabled: core.TSTrue, + ReferencesCodeLensShowOnAllFunctions: core.TSTrue, + + ImplementationsCodeLensEnabled: core.TSTrue, + ImplementationsCodeLensShowOnInterfaceMethods: core.TSTrue, + ImplementationsCodeLensShowOnAllClassMethods: core.TSTrue, }) } diff --git a/tsc/internal/fourslash/tests/codeLensInterface01_test.go b/tsc/internal/fourslash/tests/codeLensInterface01_test.go index e71ce9beb6dec..8ddc5cb57685d 100644 --- a/tsc/internal/fourslash/tests/codeLensInterface01_test.go +++ b/tsc/internal/fourslash/tests/codeLensInterface01_test.go @@ -51,13 +51,11 @@ const p: Pointable = { f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{ - CodeLens: lsutil.CodeLensUserPreferences{ - ReferencesCodeLensEnabled: core.TSTrue, - ReferencesCodeLensShowOnAllFunctions: core.TSTrue, - - ImplementationsCodeLensEnabled: core.TSTrue, - ImplementationsCodeLensShowOnInterfaceMethods: core.TSTrue, - ImplementationsCodeLensShowOnAllClassMethods: core.TSTrue, - }, + ReferencesCodeLensEnabled: core.TSTrue, + ReferencesCodeLensShowOnAllFunctions: core.TSTrue, + + ImplementationsCodeLensEnabled: core.TSTrue, + ImplementationsCodeLensShowOnInterfaceMethods: core.TSTrue, + ImplementationsCodeLensShowOnAllClassMethods: core.TSTrue, }) } diff --git a/tsc/internal/fourslash/tests/codeLensOverloads01_test.go b/tsc/internal/fourslash/tests/codeLensOverloads01_test.go index b05cb8166370a..0887adb712f00 100644 --- a/tsc/internal/fourslash/tests/codeLensOverloads01_test.go +++ b/tsc/internal/fourslash/tests/codeLensOverloads01_test.go @@ -31,13 +31,11 @@ foo(Math.random() ? 1 : "hello"); f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{ - CodeLens: lsutil.CodeLensUserPreferences{ - ReferencesCodeLensEnabled: core.TSTrue, - ReferencesCodeLensShowOnAllFunctions: core.TSTrue, - - ImplementationsCodeLensEnabled: core.TSTrue, - ImplementationsCodeLensShowOnInterfaceMethods: core.TSTrue, - ImplementationsCodeLensShowOnAllClassMethods: core.TSTrue, - }, + ReferencesCodeLensEnabled: core.TSTrue, + ReferencesCodeLensShowOnAllFunctions: core.TSTrue, + + ImplementationsCodeLensEnabled: core.TSTrue, + ImplementationsCodeLensShowOnInterfaceMethods: core.TSTrue, + ImplementationsCodeLensShowOnAllClassMethods: core.TSTrue, }) } diff --git a/tsc/internal/fourslash/tests/codeLensShowOnAllClassMethods_test.go b/tsc/internal/fourslash/tests/codeLensShowOnAllClassMethods_test.go index 8f2e494d25eaa..f2db6dc9f3306 100644 --- a/tsc/internal/fourslash/tests/codeLensShowOnAllClassMethods_test.go +++ b/tsc/internal/fourslash/tests/codeLensShowOnAllClassMethods_test.go @@ -37,10 +37,8 @@ export abstract class ABC { f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{ - CodeLens: lsutil.CodeLensUserPreferences{ - ImplementationsCodeLensEnabled: core.TSTrue, - ImplementationsCodeLensShowOnAllClassMethods: value, - }, + ImplementationsCodeLensEnabled: core.TSTrue, + ImplementationsCodeLensShowOnAllClassMethods: value, }) }) } diff --git a/tsc/internal/fourslash/tests/codeLensShowOnAllFunctions_test.go b/tsc/internal/fourslash/tests/codeLensShowOnAllFunctions_test.go index df45d87594ebb..38ba79b0e25c2 100644 --- a/tsc/internal/fourslash/tests/codeLensShowOnAllFunctions_test.go +++ b/tsc/internal/fourslash/tests/codeLensShowOnAllFunctions_test.go @@ -32,10 +32,8 @@ const f5 = function() {}; f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{ - CodeLens: lsutil.CodeLensUserPreferences{ - ReferencesCodeLensEnabled: core.TSTrue, - ReferencesCodeLensShowOnAllFunctions: value, - }, + ReferencesCodeLensEnabled: core.TSTrue, + ReferencesCodeLensShowOnAllFunctions: value, }) }) } diff --git a/tsc/internal/fourslash/tests/codeLensShowOnInterfaceMethods_test.go b/tsc/internal/fourslash/tests/codeLensShowOnInterfaceMethods_test.go index 7d0d8fb4753b7..306a5b07cf27a 100644 --- a/tsc/internal/fourslash/tests/codeLensShowOnInterfaceMethods_test.go +++ b/tsc/internal/fourslash/tests/codeLensShowOnInterfaceMethods_test.go @@ -46,10 +46,8 @@ class AbstractC implements J { f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{ - CodeLens: lsutil.CodeLensUserPreferences{ - ImplementationsCodeLensEnabled: core.TSTrue, - ImplementationsCodeLensShowOnInterfaceMethods: value, - }, + ImplementationsCodeLensEnabled: core.TSTrue, + ImplementationsCodeLensShowOnInterfaceMethods: value, }) }) } diff --git a/tsc/internal/fourslash/tests/contentMapperEditSafety_test.go b/tsc/internal/fourslash/tests/contentMapperEditSafety_test.go index 3e2fc6e5da017..d371a830eb598 100644 --- a/tsc/internal/fourslash/tests/contentMapperEditSafety_test.go +++ b/tsc/internal/fourslash/tests/contentMapperEditSafety_test.go @@ -180,10 +180,10 @@ outer(); `, contentmappertest.PrefixedSupplementalMapper, ".astro") defer done() - f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{CodeLens: lsutil.CodeLensUserPreferences{ + f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{ ReferencesCodeLensEnabled: core.TSTrue, ReferencesCodeLensShowOnAllFunctions: core.TSTrue, - }}) + }) } func TestContentMapperDisabledSupplementalCodeLens(t *testing.T) { @@ -204,10 +204,10 @@ outer(); `, contentmappertest.PrefixedSupplementalMapper, ".astro") defer done() - f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{CodeLens: lsutil.CodeLensUserPreferences{ + f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{ ReferencesCodeLensEnabled: core.TSTrue, ReferencesCodeLensShowOnAllFunctions: core.TSTrue, - }}) + }) } func TestContentMapperDeduplicatesProjectedCodeLens(t *testing.T) { @@ -228,10 +228,10 @@ outer(); `, contentmappertest.PrefixedSupplementalMapper, ".astro") defer done() - f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{CodeLens: lsutil.CodeLensUserPreferences{ + f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{ ReferencesCodeLensEnabled: core.TSTrue, ReferencesCodeLensShowOnAllFunctions: core.TSTrue, - }}) + }) } func TestContentMapperSupplementalImplementationCodeLens(t *testing.T) { @@ -255,9 +255,9 @@ class Impl implements Service { run() {} } `, contentmappertest.PrefixedSupplementalMapper, ".astro") defer done() - f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{CodeLens: lsutil.CodeLensUserPreferences{ + f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{ ImplementationsCodeLensEnabled: core.TSTrue, - }}) + }) } func TestContentMapperFormatsSupplementalVerbatimRange(t *testing.T) { diff --git a/tsc/internal/fourslash/tests/findAllRefsPrefixSuffixPreference_test.go b/tsc/internal/fourslash/tests/findAllRefsPrefixSuffixPreference_test.go index 20e7e1503a7e1..462d279a4e17f 100644 --- a/tsc/internal/fourslash/tests/findAllRefsPrefixSuffixPreference_test.go +++ b/tsc/internal/fourslash/tests/findAllRefsPrefixSuffixPreference_test.go @@ -29,8 +29,8 @@ log(/*q3*/[|q|] + 1);` defer done() f.VerifyNoErrors(t) f.VerifyBaselineFindAllReferences(t, "q0", "q1", "q2", "q3", "z0", "z1", "z2") - f.VerifyBaselineRename(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSTrue}, f.Ranges()[1], f.Ranges()[3], f.Ranges()[10], f.Ranges()[11]) - f.VerifyBaselineRename(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSFalse}, f.Ranges()[1], f.Ranges()[3], f.Ranges()[10], f.Ranges()[11]) - f.VerifyBaselineRename(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSTrue}, f.Ranges()[5], f.Ranges()[7], f.Ranges()[8]) - f.VerifyBaselineRename(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSFalse}, f.Ranges()[5], f.Ranges()[7], f.Ranges()[8]) + f.VerifyBaselineRename(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSTrue}, f.Ranges()[1], f.Ranges()[3], f.Ranges()[10], f.Ranges()[11]) + f.VerifyBaselineRename(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSFalse}, f.Ranges()[1], f.Ranges()[3], f.Ranges()[10], f.Ranges()[11]) + f.VerifyBaselineRename(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSTrue}, f.Ranges()[5], f.Ranges()[7], f.Ranges()[8]) + f.VerifyBaselineRename(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSFalse}, f.Ranges()[5], f.Ranges()[7], f.Ranges()[8]) } diff --git a/tsc/internal/fourslash/tests/findAllRefsReExportsUseInImportType_test.go b/tsc/internal/fourslash/tests/findAllRefsReExportsUseInImportType_test.go index 93fb735f84a9f..1244f07b7878c 100644 --- a/tsc/internal/fourslash/tests/findAllRefsReExportsUseInImportType_test.go +++ b/tsc/internal/fourslash/tests/findAllRefsReExportsUseInImportType_test.go @@ -30,5 +30,5 @@ type fullType2 = import('./foo/types')./*foo4*/[|foo|]./*full2*/[|Full|];` f.VerifyBaselineRename(t, nil /*preferences*/, f.Ranges()[3]) f.VerifyBaselineRename(t, nil /*preferences*/, f.Ranges()[5], f.Ranges()[10]) f.VerifyBaselineRename(t, nil /*preferences*/, f.Ranges()[7], f.Ranges()[8]) - f.VerifyBaselineRename(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSFalse}, f.Ranges()[7], f.Ranges()[8], f.Ranges()[10], f.Ranges()[3], f.Ranges()[5]) + f.VerifyBaselineRename(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSFalse}, f.Ranges()[7], f.Ranges()[8], f.Ranges()[10], f.Ranges()[3], f.Ranges()[5]) } diff --git a/tsc/internal/fourslash/tests/inlayHintsCrash1_test.go b/tsc/internal/fourslash/tests/inlayHintsCrash1_test.go index 63d26fb639b67..6fc1757492a6e 100644 --- a/tsc/internal/fourslash/tests/inlayHintsCrash1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsCrash1_test.go @@ -23,5 +23,5 @@ function doThing(f) { }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSTrue, IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayVariableTypeHints: core.TSTrue, IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsElementAccess_test.go b/tsc/internal/fourslash/tests/inlayHintsElementAccess_test.go index 9afeac8692d49..8160b1df3843b 100644 --- a/tsc/internal/fourslash/tests/inlayHintsElementAccess_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsElementAccess_test.go @@ -25,7 +25,7 @@ let foo = { ` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{ + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{ IncludeInlayVariableTypeHints: core.TSTrue, - }}) + }) } diff --git a/tsc/internal/fourslash/tests/inlayHintsEnumMemberValue_test.go b/tsc/internal/fourslash/tests/inlayHintsEnumMemberValue_test.go index 6d2c55f1e3dc3..5c9a5d1327f34 100644 --- a/tsc/internal/fourslash/tests/inlayHintsEnumMemberValue_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsEnumMemberValue_test.go @@ -21,5 +21,5 @@ func TestInlayHintsEnumMemberValue(t *testing.T) { }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayEnumMemberValueHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayEnumMemberValueHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes1_test.go b/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes1_test.go index 73813ee47569f..e58fbedc5da88 100644 --- a/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes1_test.go @@ -32,5 +32,5 @@ type F2 = (a: { const foo5: F2 = (a) => { }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes2_test.go b/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes2_test.go index 12f1ef409130f..a40d93e3e98a8 100644 --- a/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes2_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes2_test.go @@ -29,5 +29,5 @@ function f11(a = { a: 1, b: 1 }) {} function f12(a = ((({ a: 1, b: 1 })))) {}` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes3_test.go b/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes3_test.go index 1dce0bd861c99..50044486dbee4 100644 --- a/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes3_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes3_test.go @@ -28,5 +28,5 @@ class Foo { }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes4_test.go b/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes4_test.go index 0acd20bd8948d..94c90e75f9a50 100644 --- a/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes4_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes4_test.go @@ -25,5 +25,5 @@ class Foo { }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes5_test.go b/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes5_test.go index 2e179698f3e32..444c9bc2010d7 100644 --- a/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes5_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsFunctionParameterTypes5_test.go @@ -21,5 +21,5 @@ declare function test( test((state) => {});` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsIdentifierLocation_test.go b/tsc/internal/fourslash/tests/inlayHintsIdentifierLocation_test.go index 18f4902fe261b..d5610da2e30f1 100644 --- a/tsc/internal/fourslash/tests/inlayHintsIdentifierLocation_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsIdentifierLocation_test.go @@ -16,5 +16,5 @@ func TestInlayHintsIdentifierLocation(t *testing.T) { const p = (a: Foo[]) => a;` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayVariableTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsImportType1_test.go b/tsc/internal/fourslash/tests/inlayHintsImportType1_test.go index 0c21dc137c5bc..8f29eb6726279 100644 --- a/tsc/internal/fourslash/tests/inlayHintsImportType1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsImportType1_test.go @@ -21,5 +21,5 @@ const a = require('./a');` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.GoToFile(t, "/b.js") - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayVariableTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsImportType2_test.go b/tsc/internal/fourslash/tests/inlayHintsImportType2_test.go index 75ac5eff1ee30..d2d3a52a229d3 100644 --- a/tsc/internal/fourslash/tests/inlayHintsImportType2_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsImportType2_test.go @@ -24,5 +24,5 @@ const d = bar()` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.GoToFile(t, "/b.js") - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSTrue, IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayVariableTypeHints: core.TSTrue, IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInferredTypePredicate1_test.go b/tsc/internal/fourslash/tests/inlayHintsInferredTypePredicate1_test.go index 0c2bfefbd7d63..10669dac1b19b 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInferredTypePredicate1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInferredTypePredicate1_test.go @@ -18,5 +18,5 @@ function test(x: unknown) { }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveAnyParameter1_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveAnyParameter1_test.go index 9101223f8de21..8293f2f814625 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveAnyParameter1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveAnyParameter1_test.go @@ -20,5 +20,5 @@ foo((1)); foo(foo(1));` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveAnyParameter2_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveAnyParameter2_test.go index 3e56d1b35379f..4f8df2fd27c8e 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveAnyParameter2_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveAnyParameter2_test.go @@ -26,5 +26,5 @@ foo((1)); foo(foo(1));` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes1_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes1_test.go index 6b97c5e4b7ced..c3f208bf8b079 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes1_test.go @@ -51,5 +51,5 @@ foo4(p => {}) const foo5: F4 = (a) => { }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes2_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes2_test.go index 5065687717b58..1c1c612dd076f 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes2_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes2_test.go @@ -29,5 +29,5 @@ function f11(a = { a: 1, b: 1 }) {} function f12(a = ((({ a: 1, b: 1 })))) {}` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes3_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes3_test.go index e11b464855bbd..e404f9245c555 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes3_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes3_test.go @@ -28,5 +28,5 @@ class Foo { }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes4_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes4_test.go index ce8a4b83eb73e..d9ffb4b28529c 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes4_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes4_test.go @@ -25,5 +25,5 @@ class Foo { }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes5_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes5_test.go index 84307e0b8d0ec..29e585d601223 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes5_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveFunctionParameterTypes5_test.go @@ -16,5 +16,5 @@ func TestInlayHintsInteractiveFunctionParameterTypes5(t *testing.T) { export function fn(b = foo) {}` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveImportType1_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveImportType1_test.go index c0a1c6c56c770..05da5eb05c3f9 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveImportType1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveImportType1_test.go @@ -21,5 +21,5 @@ const a = require('./a');` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.GoToFile(t, "/b.js") - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayVariableTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveImportType2_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveImportType2_test.go index a8fa6539a9b34..ad0cc3113b196 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveImportType2_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveImportType2_test.go @@ -24,5 +24,5 @@ const d = bar()` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.GoToFile(t, "/b.js") - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSTrue, IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayVariableTypeHints: core.TSTrue, IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveInferredTypePredicate1_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveInferredTypePredicate1_test.go index ed79af702b919..7beb5ea188134 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveInferredTypePredicate1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveInferredTypePredicate1_test.go @@ -18,5 +18,5 @@ function test(x: unknown) { }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveJsDocParameterNames_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveJsDocParameterNames_test.go index cef91ee543c5f..ec3ee1964de5b 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveJsDocParameterNames_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveJsDocParameterNames_test.go @@ -28,5 +28,5 @@ var z = ""` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.GoToFile(t, "/a.js") - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveMultifile1_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveMultifile1_test.go index 88344443172b8..96b44f52ef04f 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveMultifile1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveMultifile1_test.go @@ -27,5 +27,5 @@ async function main () { f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.GoToFile(t, "/b.ts") - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSTrue, IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayVariableTypeHints: core.TSTrue, IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveMultifileFunctionCalls_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveMultifileFunctionCalls_test.go index 2b7f7790a28be..445a788a9964e 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveMultifileFunctionCalls_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveMultifileFunctionCalls_test.go @@ -26,5 +26,5 @@ export function helperC(cParam: string) {}` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.GoToFile(t, "./aaa.mts") - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveOverloadCall_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveOverloadCall_test.go index 72fd09b6f7b4c..38f1b3d7dc3b2 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveOverloadCall_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveOverloadCall_test.go @@ -34,5 +34,5 @@ new Class(1) new Class(1, 2)` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveParameterNamesInSpan1_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveParameterNamesInSpan1_test.go index 8a0bf006c582f..9b37abe0e4f95 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveParameterNamesInSpan1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveParameterNamesInSpan1_test.go @@ -32,8 +32,6 @@ function c6 () { foo6(/*k*/1, /*l*/2); }` end := f.MarkerByName(t, "h") span := &lsproto.Range{Start: start.LSPosition, End: end.LSPosition} f.VerifyBaselineInlayHints(t, span, &lsutil.UserPreferences{ - InlayHints: lsutil.InlayHintsPreferences{ - IncludeInlayParameterNameHints: "literals", - }, + IncludeInlayParameterNameHints: "literals", }) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveParameterNamesInSpan2_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveParameterNamesInSpan2_test.go index bf4610196a3ca..f2b46c3e0c7b0 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveParameterNamesInSpan2_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveParameterNamesInSpan2_test.go @@ -32,8 +32,6 @@ foo6(/*k*/1, /*l*/2);` end := f.MarkerByName(t, "h") span := &lsproto.Range{Start: start.LSPosition, End: end.LSPosition} f.VerifyBaselineInlayHints(t, span, &lsutil.UserPreferences{ - InlayHints: lsutil.InlayHintsPreferences{ - IncludeInlayParameterNameHints: "literals", - }, + IncludeInlayParameterNameHints: "literals", }) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveParameterNamesWithComments_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveParameterNamesWithComments_test.go index 874573b1e3d41..6b333d40bd4c4 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveParameterNamesWithComments_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveParameterNamesWithComments_test.go @@ -44,5 +44,5 @@ foo( )` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveParameterNames_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveParameterNames_test.go index 81007ae797ca1..522ce33a5b58c 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveParameterNames_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveParameterNames_test.go @@ -52,5 +52,5 @@ trace(` + "`" + `${1}` + "`" + `); trace(` + "`" + `` + "`" + `);` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveRestParameters1_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveRestParameters1_test.go index 2aafe994ed1b4..3a9c2d5ed8901 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveRestParameters1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveRestParameters1_test.go @@ -21,5 +21,5 @@ declare function foo3(c: number, ...args: Args3); foo3(1, 2, 3)` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveRestParameters2_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveRestParameters2_test.go index 0f159779b6ff9..5ff224cac0fcf 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveRestParameters2_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveRestParameters2_test.go @@ -29,5 +29,5 @@ function foo5(...x: [number, number]) { }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveRestParameters3_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveRestParameters3_test.go index 9bad4410a9d96..3f8ee657d8bb2 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveRestParameters3_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveRestParameters3_test.go @@ -18,5 +18,5 @@ const foo: [x: number, y: number] = [1, 2]; fn(...foo, 3, 4);` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveReturnType_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveReturnType_test.go index c7fa332c900ee..87d3aa7815f43 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveReturnType_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveReturnType_test.go @@ -32,5 +32,5 @@ const c = (b) => 1 const d = b => 1` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveTemplateLiteralTypes_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveTemplateLiteralTypes_test.go index 6dcb64543fc61..9b7a8005ab54b 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveTemplateLiteralTypes_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveTemplateLiteralTypes_test.go @@ -22,5 +22,5 @@ declare function getTemplateLiteral4(): ` + "`" + `${string}\` + "`" + `,${strin const lit4 = getTemplateLiteral4();` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayVariableTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveVariableTypes1_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveVariableTypes1_test.go index 8195fa3b400a4..36b350e76d3c8 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveVariableTypes1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveVariableTypes1_test.go @@ -34,5 +34,5 @@ const l = ((({ a: 1, b: 1 }))); const q = ({ a }: { a: Foo }) => a;` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayVariableTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveVariableTypes2_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveVariableTypes2_test.go index 56d640fc37219..37f0ba85566a3 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveVariableTypes2_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveVariableTypes2_test.go @@ -24,5 +24,5 @@ declare function foo(t: T): T const x = foo(1)` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayVariableTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsInteractiveWithClosures_test.go b/tsc/internal/fourslash/tests/inlayHintsInteractiveWithClosures_test.go index c9d134c9b8a8d..ee5cf92d4d39f 100644 --- a/tsc/internal/fourslash/tests/inlayHintsInteractiveWithClosures_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsInteractiveWithClosures_test.go @@ -23,5 +23,5 @@ function foo2(a: (b: number) => number) { foo2((c: number) => c + 1);` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsJsDocParameterNames_test.go b/tsc/internal/fourslash/tests/inlayHintsJsDocParameterNames_test.go index 6a3238fb311f4..3bb849498658d 100644 --- a/tsc/internal/fourslash/tests/inlayHintsJsDocParameterNames_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsJsDocParameterNames_test.go @@ -28,5 +28,5 @@ var z = ""` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.GoToFile(t, "/a.js") - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsMultifile1_test.go b/tsc/internal/fourslash/tests/inlayHintsMultifile1_test.go index 733030bbb3c36..f1f4802a9f9fa 100644 --- a/tsc/internal/fourslash/tests/inlayHintsMultifile1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsMultifile1_test.go @@ -26,5 +26,5 @@ async function main () { f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.GoToFile(t, "/b.ts") - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSTrue, IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayVariableTypeHints: core.TSTrue, IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsNoHintWhenArgumentMatchesName_test.go b/tsc/internal/fourslash/tests/inlayHintsNoHintWhenArgumentMatchesName_test.go index 3452ad726d868..63ea89059cd52 100644 --- a/tsc/internal/fourslash/tests/inlayHintsNoHintWhenArgumentMatchesName_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsNoHintWhenArgumentMatchesName_test.go @@ -21,5 +21,5 @@ foo(v.b, v.b); foo(v.c, v.c);` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll, IncludeInlayParameterNameHintsWhenArgumentMatchesName: core.TSFalse}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll, IncludeInlayParameterNameHintsWhenArgumentMatchesName: core.TSFalse}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsNoParameterHints_test.go b/tsc/internal/fourslash/tests/inlayHintsNoParameterHints_test.go index 727868bdf71d6..2ad8abc4779c8 100644 --- a/tsc/internal/fourslash/tests/inlayHintsNoParameterHints_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsNoParameterHints_test.go @@ -15,5 +15,5 @@ func TestInlayHintsNoParameterHints(t *testing.T) { foo(1, 2);` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsNone}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsNone}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsNoVariableTypeHints_test.go b/tsc/internal/fourslash/tests/inlayHintsNoVariableTypeHints_test.go index a60db6b0d3aa0..bd274e410e4ce 100644 --- a/tsc/internal/fourslash/tests/inlayHintsNoVariableTypeHints_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsNoVariableTypeHints_test.go @@ -15,5 +15,5 @@ func TestInlayHintsNoVariableTypeHints(t *testing.T) { const content = `const a = 123;` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSFalse}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayVariableTypeHints: core.TSFalse}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsOverloadCall1_test.go b/tsc/internal/fourslash/tests/inlayHintsOverloadCall1_test.go index 4c7221d1d3528..9c8316914fbb4 100644 --- a/tsc/internal/fourslash/tests/inlayHintsOverloadCall1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsOverloadCall1_test.go @@ -34,5 +34,5 @@ new Class(1) new Class(1, 2)` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsOverloadCall2_test.go b/tsc/internal/fourslash/tests/inlayHintsOverloadCall2_test.go index 4d6283cb0c675..1b7193b532119 100644 --- a/tsc/internal/fourslash/tests/inlayHintsOverloadCall2_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsOverloadCall2_test.go @@ -30,5 +30,5 @@ func( );` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsParameterNames_test.go b/tsc/internal/fourslash/tests/inlayHintsParameterNames_test.go index 16603576f64b2..e37f69fdb7101 100644 --- a/tsc/internal/fourslash/tests/inlayHintsParameterNames_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsParameterNames_test.go @@ -65,5 +65,5 @@ func( )` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsPropertyDeclarationComputedName1_test.go b/tsc/internal/fourslash/tests/inlayHintsPropertyDeclarationComputedName1_test.go index b072ff37f53bc..85f188d7a57a9 100644 --- a/tsc/internal/fourslash/tests/inlayHintsPropertyDeclarationComputedName1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsPropertyDeclarationComputedName1_test.go @@ -22,8 +22,6 @@ func TestInlayHintsPropertyDeclarationComputedName1(t *testing.T) { f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{ - InlayHints: lsutil.InlayHintsPreferences{ - IncludeInlayPropertyDeclarationTypeHints: core.TSTrue, - }, + IncludeInlayPropertyDeclarationTypeHints: core.TSTrue, }) } diff --git a/tsc/internal/fourslash/tests/inlayHintsPropertyDeclarations2_test.go b/tsc/internal/fourslash/tests/inlayHintsPropertyDeclarations2_test.go index 5ebf9b7a08e46..5adcfb7c2c037 100644 --- a/tsc/internal/fourslash/tests/inlayHintsPropertyDeclarations2_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsPropertyDeclarations2_test.go @@ -29,5 +29,5 @@ class C { }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayPropertyDeclarationTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayPropertyDeclarationTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsPropertyDeclarations_test.go b/tsc/internal/fourslash/tests/inlayHintsPropertyDeclarations_test.go index 155286f366474..542317fc7bf63 100644 --- a/tsc/internal/fourslash/tests/inlayHintsPropertyDeclarations_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsPropertyDeclarations_test.go @@ -28,5 +28,5 @@ class C { }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayPropertyDeclarationTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayPropertyDeclarationTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsQuotePreference1_test.go b/tsc/internal/fourslash/tests/inlayHintsQuotePreference1_test.go index 270fdccf47350..32c32527576ad 100644 --- a/tsc/internal/fourslash/tests/inlayHintsQuotePreference1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsQuotePreference1_test.go @@ -17,5 +17,5 @@ const b1: '\\' = '\\'; export function fn(a = a1, b = b1) {}` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{QuotePreference: lsutil.QuotePreference("double"), InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{QuotePreference: lsutil.QuotePreference("double"), IncludeInlayFunctionParameterTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsQuotePreference2_test.go b/tsc/internal/fourslash/tests/inlayHintsQuotePreference2_test.go index d0b07810c2f3a..a740b96c0e171 100644 --- a/tsc/internal/fourslash/tests/inlayHintsQuotePreference2_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsQuotePreference2_test.go @@ -17,5 +17,5 @@ const b1: "\\" = "\\"; export function fn(a = a1, b = b1) {}` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{QuotePreference: lsutil.QuotePreference("single"), InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{QuotePreference: lsutil.QuotePreference("single"), IncludeInlayFunctionParameterTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsReparsedNodeCrash_test.go b/tsc/internal/fourslash/tests/inlayHintsReparsedNodeCrash_test.go index 1d0f7e887cb26..f66efdb216f5c 100644 --- a/tsc/internal/fourslash/tests/inlayHintsReparsedNodeCrash_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsReparsedNodeCrash_test.go @@ -25,8 +25,8 @@ module.exports = function () { f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{ + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{ IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue, IncludeInlayFunctionParameterTypeHints: core.TSTrue, - }}) + }) } diff --git a/tsc/internal/fourslash/tests/inlayHintsRestParameters1_test.go b/tsc/internal/fourslash/tests/inlayHintsRestParameters1_test.go index 6775acbb89762..806d4e067ac78 100644 --- a/tsc/internal/fourslash/tests/inlayHintsRestParameters1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsRestParameters1_test.go @@ -21,5 +21,5 @@ declare function foo3(c: number, ...args: Args3); foo3(1, 2, 3)` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsLiterals}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsRestParameters2_test.go b/tsc/internal/fourslash/tests/inlayHintsRestParameters2_test.go index d187c11f960a8..d7deb9e45f16c 100644 --- a/tsc/internal/fourslash/tests/inlayHintsRestParameters2_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsRestParameters2_test.go @@ -29,5 +29,5 @@ function foo5(...x: [number, number]) { }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsReturnType_test.go b/tsc/internal/fourslash/tests/inlayHintsReturnType_test.go index 5448f5be2a619..4576891396b9f 100644 --- a/tsc/internal/fourslash/tests/inlayHintsReturnType_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsReturnType_test.go @@ -29,5 +29,5 @@ const c = (b) => 1 const d = b => 1` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsThisParameter_test.go b/tsc/internal/fourslash/tests/inlayHintsThisParameter_test.go index ceafadc139636..2e0921efdddb5 100644 --- a/tsc/internal/fourslash/tests/inlayHintsThisParameter_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsThisParameter_test.go @@ -25,5 +25,5 @@ fn(function (this, a, b) { }); fn(function (this: I, a, b) { });` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayFunctionParameterTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsTupleTypeCrash_test.go b/tsc/internal/fourslash/tests/inlayHintsTupleTypeCrash_test.go index eba0817e29966..90a30142c6a0b 100644 --- a/tsc/internal/fourslash/tests/inlayHintsTupleTypeCrash_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsTupleTypeCrash_test.go @@ -19,8 +19,6 @@ func TestInlayHintsTupleTypeCrash(t *testing.T) { f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{ - InlayHints: lsutil.InlayHintsPreferences{ - IncludeInlayFunctionParameterTypeHints: core.TSTrue, - }, + IncludeInlayFunctionParameterTypeHints: core.TSTrue, }) } diff --git a/tsc/internal/fourslash/tests/inlayHintsTypeMatchesName_test.go b/tsc/internal/fourslash/tests/inlayHintsTypeMatchesName_test.go index f4ae2afe12c91..c19accb980375 100644 --- a/tsc/internal/fourslash/tests/inlayHintsTypeMatchesName_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsTypeMatchesName_test.go @@ -17,5 +17,5 @@ function getClient(): Client { return {}; }; const client = getClient();` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSTrue, IncludeInlayVariableTypeHintsWhenTypeMatchesName: core.TSFalse}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayVariableTypeHints: core.TSTrue, IncludeInlayVariableTypeHintsWhenTypeMatchesName: core.TSFalse}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsTypeParameterModifiers1_test.go b/tsc/internal/fourslash/tests/inlayHintsTypeParameterModifiers1_test.go index 17b530cd86bfb..0bfbecc2d39a9 100644 --- a/tsc/internal/fourslash/tests/inlayHintsTypeParameterModifiers1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsTypeParameterModifiers1_test.go @@ -17,5 +17,5 @@ func TestInlayHintsTypeParameterModifiers1(t *testing.T) { }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayFunctionLikeReturnTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsUsing_test.go b/tsc/internal/fourslash/tests/inlayHintsUsing_test.go index b8e53342331f4..cc39ba711a062 100644 --- a/tsc/internal/fourslash/tests/inlayHintsUsing_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsUsing_test.go @@ -19,7 +19,7 @@ using _defer = { };` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{ + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{ IncludeInlayVariableTypeHints: core.TSTrue, - }}) + }) } diff --git a/tsc/internal/fourslash/tests/inlayHintsVariableTypes1_test.go b/tsc/internal/fourslash/tests/inlayHintsVariableTypes1_test.go index 369d08d9bd59d..b697e853569b6 100644 --- a/tsc/internal/fourslash/tests/inlayHintsVariableTypes1_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsVariableTypes1_test.go @@ -31,5 +31,5 @@ const l = ((({ a: 1, b: 1 }))); const n;` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayVariableTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsVariableTypes2_test.go b/tsc/internal/fourslash/tests/inlayHintsVariableTypes2_test.go index a7efb18d9e831..a4d149e6cfd27 100644 --- a/tsc/internal/fourslash/tests/inlayHintsVariableTypes2_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsVariableTypes2_test.go @@ -24,5 +24,5 @@ declare function foo(t: T): T const x = foo(1)` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayVariableTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsVariableTypes3_test.go b/tsc/internal/fourslash/tests/inlayHintsVariableTypes3_test.go index 0cb397e43aa68..8acebd8ec0a96 100644 --- a/tsc/internal/fourslash/tests/inlayHintsVariableTypes3_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsVariableTypes3_test.go @@ -26,5 +26,5 @@ declare function getCtor(tagName: K): ElementMap[K] const div = getCtor("div");` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSTrue}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayVariableTypeHints: core.TSTrue}) } diff --git a/tsc/internal/fourslash/tests/inlayHintsWithClosures_test.go b/tsc/internal/fourslash/tests/inlayHintsWithClosures_test.go index c6b514dc35599..9d28544a07d3c 100644 --- a/tsc/internal/fourslash/tests/inlayHintsWithClosures_test.go +++ b/tsc/internal/fourslash/tests/inlayHintsWithClosures_test.go @@ -23,5 +23,5 @@ function foo2(a: (b: number) => number) { foo2((c: number) => c + 1);` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}}) + f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{IncludeInlayParameterNameHints: lsutil.IncludeInlayParameterNameHintsAll}) } diff --git a/tsc/internal/fourslash/tests/jsdocSnippetCompletion_test.go b/tsc/internal/fourslash/tests/jsdocSnippetCompletion_test.go index ddc8cecda5c94..e3c7aadff064f 100644 --- a/tsc/internal/fourslash/tests/jsdocSnippetCompletion_test.go +++ b/tsc/internal/fourslash/tests/jsdocSnippetCompletion_test.go @@ -120,7 +120,7 @@ function abcdef(x) { } f.Insert(t, "/**") userPreferences := lsutil.NewDefaultUserPreferences() - userPreferences.EnableJSDocCompletions = core.TSFalse + userPreferences.CompleteJSDocs = core.TSFalse list := f.GetCompletions(t, &userPreferences) if list != nil { for _, item := range list.Items { diff --git a/tsc/internal/fourslash/tests/renameExportSpecifier2_test.go b/tsc/internal/fourslash/tests/renameExportSpecifier2_test.go index d5b83e67c55a9..718416ba61d7d 100644 --- a/tsc/internal/fourslash/tests/renameExportSpecifier2_test.go +++ b/tsc/internal/fourslash/tests/renameExportSpecifier2_test.go @@ -20,5 +20,5 @@ import { name } from './a'; const x = name.toString();` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineRename(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSFalse}, "") + f.VerifyBaselineRename(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSFalse}, "") } diff --git a/tsc/internal/fourslash/tests/renameExportSpecifier_test.go b/tsc/internal/fourslash/tests/renameExportSpecifier_test.go index f9248876bfbe7..4031e9d474bde 100644 --- a/tsc/internal/fourslash/tests/renameExportSpecifier_test.go +++ b/tsc/internal/fourslash/tests/renameExportSpecifier_test.go @@ -20,5 +20,5 @@ import { name } from './a'; const x = name.toString();` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineRename(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSFalse}, "") + f.VerifyBaselineRename(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSFalse}, "") } diff --git a/tsc/internal/fourslash/tests/renameFromNodeModulesDep1_test.go b/tsc/internal/fourslash/tests/renameFromNodeModulesDep1_test.go index d6f7777a3b04d..6fb7d9229035a 100644 --- a/tsc/internal/fourslash/tests/renameFromNodeModulesDep1_test.go +++ b/tsc/internal/fourslash/tests/renameFromNodeModulesDep1_test.go @@ -27,8 +27,8 @@ export interface Foo { f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.GoToMarker(t, "okWithAlias") - f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSTrue}) - f.VerifyRenameFailed(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSFalse}) + f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSTrue}) + f.VerifyRenameFailed(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSFalse}) f.GoToMarker(t, "notOk") f.VerifyRenameFailed(t, nil /*preferences*/) } diff --git a/tsc/internal/fourslash/tests/renameFromNodeModulesDep2_test.go b/tsc/internal/fourslash/tests/renameFromNodeModulesDep2_test.go index 901115747290c..426f5453c04f0 100644 --- a/tsc/internal/fourslash/tests/renameFromNodeModulesDep2_test.go +++ b/tsc/internal/fourslash/tests/renameFromNodeModulesDep2_test.go @@ -27,8 +27,8 @@ declare type FooBar = Foo[/*ok3*/"[|bar|]"];` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.GoToMarker(t, "okWithAlias") - f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSTrue}) - f.VerifyRenameFailed(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSFalse}) + f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSTrue}) + f.VerifyRenameFailed(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSFalse}) f.GoToMarker(t, "notOk") f.VerifyRenameFailed(t, nil /*preferences*/) f.GoToMarker(t, "ok2") diff --git a/tsc/internal/fourslash/tests/renameFromNodeModulesDep3_test.go b/tsc/internal/fourslash/tests/renameFromNodeModulesDep3_test.go index e850050cebd21..77f964a3ff9cc 100644 --- a/tsc/internal/fourslash/tests/renameFromNodeModulesDep3_test.go +++ b/tsc/internal/fourslash/tests/renameFromNodeModulesDep3_test.go @@ -25,8 +25,8 @@ export interface Foo { f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.GoToMarker(t, "ok") - f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSTrue}) - f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSFalse}) + f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSTrue}) + f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSFalse}) f.GoToMarker(t, "ok2") f.VerifyRenameSucceeded(t, nil /*preferences*/) f.GoToMarker(t, "ok3") diff --git a/tsc/internal/fourslash/tests/renameFromNodeModulesDep4_test.go b/tsc/internal/fourslash/tests/renameFromNodeModulesDep4_test.go index 7478fe60b2a19..d56e7c1acf844 100644 --- a/tsc/internal/fourslash/tests/renameFromNodeModulesDep4_test.go +++ b/tsc/internal/fourslash/tests/renameFromNodeModulesDep4_test.go @@ -28,15 +28,15 @@ export const h: string; f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.GoToMarker(t, "ok") - f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSTrue}) - f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSFalse}) + f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSTrue}) + f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSFalse}) f.GoToMarker(t, "ok2") - f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSTrue}) - f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSFalse}) + f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSTrue}) + f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSFalse}) f.GoToMarker(t, "notOk") - f.VerifyRenameFailed(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSTrue}) - f.VerifyRenameFailed(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSFalse}) + f.VerifyRenameFailed(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSTrue}) + f.VerifyRenameFailed(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSFalse}) f.GoToMarker(t, "okWithAlias") - f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSTrue}) - f.VerifyRenameFailed(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSFalse}) + f.VerifyRenameSucceeded(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSTrue}) + f.VerifyRenameFailed(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSFalse}) } diff --git a/tsc/internal/fourslash/tests/renameModuleExportsProperties1_test.go b/tsc/internal/fourslash/tests/renameModuleExportsProperties1_test.go index 4f047bc45cd26..e0846d7126833 100644 --- a/tsc/internal/fourslash/tests/renameModuleExportsProperties1_test.go +++ b/tsc/internal/fourslash/tests/renameModuleExportsProperties1_test.go @@ -16,5 +16,5 @@ func TestRenameModuleExportsProperties1(t *testing.T) { module.exports = { [|A|] }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineRename(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSTrue}, f.Ranges()[1], f.Ranges()[2]) + f.VerifyBaselineRename(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSTrue}, f.Ranges()[1], f.Ranges()[2]) } diff --git a/tsc/internal/fourslash/tests/renameModuleExportsProperties3_test.go b/tsc/internal/fourslash/tests/renameModuleExportsProperties3_test.go index 6dd3a319dd981..c9eef47f86d79 100644 --- a/tsc/internal/fourslash/tests/renameModuleExportsProperties3_test.go +++ b/tsc/internal/fourslash/tests/renameModuleExportsProperties3_test.go @@ -18,5 +18,5 @@ func TestRenameModuleExportsProperties3(t *testing.T) { module.exports = { [|A|] }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineRename(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSTrue}, f.Ranges()[1], f.Ranges()[2]) + f.VerifyBaselineRename(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSTrue}, f.Ranges()[1], f.Ranges()[2]) } diff --git a/tsc/internal/fourslash/tests/renameNamedImportUseAliasesForRenames_test.go b/tsc/internal/fourslash/tests/renameNamedImportUseAliasesForRenames_test.go index e95c9098dd130..be9c4567ca7c7 100644 --- a/tsc/internal/fourslash/tests/renameNamedImportUseAliasesForRenames_test.go +++ b/tsc/internal/fourslash/tests/renameNamedImportUseAliasesForRenames_test.go @@ -22,8 +22,8 @@ export interface MyTypeA { f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineRename(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSFalse}, "import") - f.VerifyBaselineRename(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSTrue}, "import") + f.VerifyBaselineRename(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSFalse}, "import") + f.VerifyBaselineRename(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSTrue}, "import") } func TestRenameNamedImportDefaultInNodeModules(t *testing.T) { @@ -44,7 +44,7 @@ export interface Foo { f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() f.VerifyBaselineRename(t, nil /*preferences*/, "fooImport") - f.VerifyBaselineRename(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSTrue}, "fooImport") + f.VerifyBaselineRename(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSTrue}, "fooImport") f.GoToMarker(t, "fooImport") - f.VerifyRenameFailed(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSFalse}) + f.VerifyRenameFailed(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSFalse}) } diff --git a/tsc/internal/fourslash/tests/renameNamedImport_test.go b/tsc/internal/fourslash/tests/renameNamedImport_test.go index a8cc09a29c78c..4d896dcd9ee3c 100644 --- a/tsc/internal/fourslash/tests/renameNamedImport_test.go +++ b/tsc/internal/fourslash/tests/renameNamedImport_test.go @@ -29,5 +29,5 @@ someExportedVariable; f.MarkTestAsStradaServer() f.GoToFile(t, "/home/src/workspaces/project/lib/index.ts") f.GoToFile(t, "/home/src/workspaces/project/src/index.ts") - f.VerifyBaselineRename(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSTrue}, "i") + f.VerifyBaselineRename(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSTrue}, "i") } diff --git a/tsc/internal/fourslash/tests/renameRestBindingElement_test.go b/tsc/internal/fourslash/tests/renameRestBindingElement_test.go index e7c374fdcab4f..e3657d33a74df 100644 --- a/tsc/internal/fourslash/tests/renameRestBindingElement_test.go +++ b/tsc/internal/fourslash/tests/renameRestBindingElement_test.go @@ -22,5 +22,5 @@ function foo([|{ a, ...[|{| "contextRangeIndex": 0 |}rest|] }: I|]) { }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) defer done() - f.VerifyBaselineRename(t, &lsutil.UserPreferences{UseAliasesForRename: core.TSTrue}, f.Ranges()[1]) + f.VerifyBaselineRename(t, &lsutil.UserPreferences{ProvidePrefixAndSuffixTextForRename: core.TSTrue}, f.Ranges()[1]) } diff --git a/tsc/internal/fourslash/tests/statecodelens_test.go b/tsc/internal/fourslash/tests/statecodelens_test.go index e1ebf917e0e16..2b762cde91675 100644 --- a/tsc/internal/fourslash/tests/statecodelens_test.go +++ b/tsc/internal/fourslash/tests/statecodelens_test.go @@ -119,14 +119,12 @@ class Point2 implements Pointable { // Ref projects are loaded after as part of this command f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{ - CodeLens: lsutil.CodeLensUserPreferences{ - ReferencesCodeLensEnabled: core.TSTrue, - ReferencesCodeLensShowOnAllFunctions: core.TSTrue, + ReferencesCodeLensEnabled: core.TSTrue, + ReferencesCodeLensShowOnAllFunctions: core.TSTrue, - ImplementationsCodeLensEnabled: core.TSTrue, - ImplementationsCodeLensShowOnInterfaceMethods: core.TSTrue, - ImplementationsCodeLensShowOnAllClassMethods: core.TSTrue, - }, + ImplementationsCodeLensEnabled: core.TSTrue, + ImplementationsCodeLensShowOnInterfaceMethods: core.TSTrue, + ImplementationsCodeLensShowOnAllClassMethods: core.TSTrue, }) // Open temp file and verify all projects alive @@ -180,8 +178,6 @@ foo.aaa(); defer done() f.VerifyBaselineCodeLens(t, &lsutil.UserPreferences{ - CodeLens: lsutil.CodeLensUserPreferences{ - ReferencesCodeLensEnabled: core.TSTrue, - }, + ReferencesCodeLensEnabled: core.TSTrue, }) } diff --git a/tsc/internal/ls/autoinsert.go b/tsc/internal/ls/autoinsert.go index f25ac95ef7f8c..e7c36d04ca492 100644 --- a/tsc/internal/ls/autoinsert.go +++ b/tsc/internal/ls/autoinsert.go @@ -11,7 +11,7 @@ import ( ) func (l *LanguageService) ProvideOnAutoInsert(ctx context.Context, params *lsproto.VSOnAutoInsertParams) (lsproto.VSOnAutoInsertResponse, error) { - if l.UserPreferences().EnableAutoClosingTags.IsFalse() { + if l.UserPreferences().AutoClosingTags.IsFalse() { return lsproto.VSOnAutoInsertResponse{}, nil } if params.VSCh != ">" { diff --git a/tsc/internal/ls/codelens.go b/tsc/internal/ls/codelens.go index 8142f1cad24b9..357cd1513278a 100644 --- a/tsc/internal/ls/codelens.go +++ b/tsc/internal/ls/codelens.go @@ -18,7 +18,7 @@ import ( func (l *LanguageService) ProvideCodeLenses(ctx context.Context, documentURI lsproto.DocumentUri) (lsproto.CodeLensResponse, error) { _, file := l.getProgramAndFile(documentURI) - userPrefs := l.UserPreferences().CodeLens + userPrefs := l.UserPreferences().CodeLensUserPreferences if !userPrefs.ReferencesCodeLensEnabled.IsTrue() && !userPrefs.ImplementationsCodeLensEnabled.IsTrue() { return lsproto.CodeLensResponse{}, nil } diff --git a/tsc/internal/ls/diagnostics.go b/tsc/internal/ls/diagnostics.go index 3638efdac813a..7275b2e7f00aa 100644 --- a/tsc/internal/ls/diagnostics.go +++ b/tsc/internal/ls/diagnostics.go @@ -32,7 +32,7 @@ func getAllDiagnostics(ctx context.Context, program *compiler.Program, file *ast func (l *LanguageService) ProvideDiagnostics(ctx context.Context, uri lsproto.DocumentUri) (lsproto.DocumentDiagnosticResponse, error) { program, file := l.getProgramAndFile(uri) - if l.UserPreferences().EnableValidation.IsFalse() { + if l.UserPreferences().ValidateEnabled.IsFalse() { diagnostics := []*lsproto.Diagnostic{} return lsproto.RelatedFullDocumentDiagnosticReportOrUnchangedDocumentDiagnosticReport{ FullDocumentDiagnosticReport: &lsproto.RelatedFullDocumentDiagnosticReport{ diff --git a/tsc/internal/ls/findallreferences.go b/tsc/internal/ls/findallreferences.go index a9ccd11270b81..1004364ef89b4 100644 --- a/tsc/internal/ls/findallreferences.go +++ b/tsc/internal/ls/findallreferences.go @@ -739,7 +739,7 @@ func (l *LanguageService) getSymbolAndEntries( } } else { options.use = referenceUseRename - options.useAliasesForRename = l.UserPreferences().UseAliasesForRename.IsTrueOrUnknown() + options.useAliasesForRename = l.UserPreferences().ProvidePrefixAndSuffixTextForRename.IsTrueOrUnknown() } return l.getReferencedSymbolsForNode(ctx, position, node, program, program.GetSourceFiles(), options) } diff --git a/tsc/internal/ls/format.go b/tsc/internal/ls/format.go index 2fc341ff7cf40..36027e5146ae0 100644 --- a/tsc/internal/ls/format.go +++ b/tsc/internal/ls/format.go @@ -36,7 +36,7 @@ func (l *LanguageService) ProvideFormatDocument( documentURI lsproto.DocumentUri, options *lsproto.FormattingOptions, ) (lsproto.DocumentFormattingResponse, error) { - if l.UserPreferences().EnableFormatting.IsFalse() { + if l.UserPreferences().FormatEnabled.IsFalse() { return lsproto.TextEditsOrNull{}, nil } _, file := l.getProgramAndFile(documentURI) @@ -154,7 +154,7 @@ func (l *LanguageService) ProvideFormatDocumentRange( options *lsproto.FormattingOptions, r lsproto.Range, ) (lsproto.DocumentRangeFormattingResponse, error) { - if l.UserPreferences().EnableFormatting.IsFalse() { + if l.UserPreferences().FormatEnabled.IsFalse() { return lsproto.TextEditsOrNull{}, nil } _, file := l.getProgramAndFile(documentURI) @@ -184,7 +184,7 @@ func (l *LanguageService) ProvideFormatDocumentOnType( position lsproto.Position, character string, ) (lsproto.DocumentOnTypeFormattingResponse, error) { - if l.UserPreferences().EnableFormatting.IsFalse() { + if l.UserPreferences().FormatEnabled.IsFalse() { return lsproto.TextEditsOrNull{}, nil } _, file := l.getProgramAndFile(documentURI) diff --git a/tsc/internal/ls/inlay_hints.go b/tsc/internal/ls/inlay_hints.go index 0864f8df361e7..1e7db5120c438 100644 --- a/tsc/internal/ls/inlay_hints.go +++ b/tsc/internal/ls/inlay_hints.go @@ -27,7 +27,7 @@ func (l *LanguageService) ProvideInlayHint( params *lsproto.InlayHintParams, ) (lsproto.InlayHintResponse, error) { userPreferences := l.UserPreferences() - inlayHintPreferences := userPreferences.InlayHints + inlayHintPreferences := userPreferences.InlayHintsPreferences if !isAnyInlayHintEnabled(inlayHintPreferences) { return lsproto.InlayHintsOrNull{InlayHints: nil}, nil } diff --git a/tsc/internal/ls/jsdoc_snippet.go b/tsc/internal/ls/jsdoc_snippet.go index ec042fc59c804..a436e085bfd56 100644 --- a/tsc/internal/ls/jsdoc_snippet.go +++ b/tsc/internal/ls/jsdoc_snippet.go @@ -27,7 +27,7 @@ type commentOwnerInfo struct { } func (l *LanguageService) getJSDocSnippetCompletion(ctx context.Context, file *ast.SourceFile, position int) *CompletionList { - if l.UserPreferences().EnableJSDocCompletions.IsFalse() { + if l.UserPreferences().CompleteJSDocs.IsFalse() { return nil } if !isPotentiallyValidJSDocSnippetCompletionPosition(file, position) { diff --git a/tsc/internal/ls/lsutil/formatcodeoptions.go b/tsc/internal/ls/lsutil/formatcodeoptions.go index fe39b21f4d1e6..bbfd79e98a4c3 100644 --- a/tsc/internal/ls/lsutil/formatcodeoptions.go +++ b/tsc/internal/ls/lsutil/formatcodeoptions.go @@ -1,8 +1,6 @@ package lsutil import ( - "strings" - "github.com/microsoft/TypeScript/tsc/internal/core" "github.com/microsoft/TypeScript/tsc/internal/lsp/lsproto" "github.com/microsoft/TypeScript/tsc/internal/printer" @@ -16,25 +14,6 @@ const ( IndentStyleSmart ) -func parseIndentStyle(v any) IndentStyle { - switch s := v.(type) { - case string: - switch strings.ToLower(s) { - case "none": - return IndentStyleNone - case "block": - return IndentStyleBlock - case "smart": - return IndentStyleSmart - } - case float64: - return IndentStyle(int(s)) - case int: - return IndentStyle(s) - } - return IndentStyleSmart -} - type SemicolonPreference string const ( @@ -43,54 +22,6 @@ const ( SemicolonPreferenceRemove SemicolonPreference = "remove" ) -func parseSemicolonPreference(v any) SemicolonPreference { - if s, ok := v.(string); ok { - switch strings.ToLower(s) { - case "ignore": - return SemicolonPreferenceIgnore - case "insert": - return SemicolonPreferenceInsert - case "remove": - return SemicolonPreferenceRemove - } - } - return SemicolonPreferenceIgnore -} - -type EditorSettings struct { - BaseIndentSize int `raw:"baseIndentSize" config:"format.baseIndentSize"` - IndentSize int `raw:"indentSize" config:"format.indentSize"` - TabSize int `raw:"tabSize" config:"format.tabSize"` - NewLineCharacter string `raw:"newLineCharacter" config:"format.newLineCharacter"` - ConvertTabsToSpaces core.Tristate `raw:"convertTabsToSpaces" config:"format.convertTabsToSpaces"` - IndentStyle IndentStyle `raw:"indentStyle" config:"format.indentStyle"` - TrimTrailingWhitespace core.Tristate `raw:"trimTrailingWhitespace" config:"format.trimTrailingWhitespace"` -} - -type FormatCodeSettings struct { - EditorSettings - InsertSpaceAfterCommaDelimiter core.Tristate `raw:"insertSpaceAfterCommaDelimiter" config:"format.insertSpaceAfterCommaDelimiter"` - InsertSpaceAfterSemicolonInForStatements core.Tristate `raw:"insertSpaceAfterSemicolonInForStatements" config:"format.insertSpaceAfterSemicolonInForStatements"` - InsertSpaceBeforeAndAfterBinaryOperators core.Tristate `raw:"insertSpaceBeforeAndAfterBinaryOperators" config:"format.insertSpaceBeforeAndAfterBinaryOperators"` - InsertSpaceAfterConstructor core.Tristate `raw:"insertSpaceAfterConstructor" config:"format.insertSpaceAfterConstructor"` - InsertSpaceAfterKeywordsInControlFlowStatements core.Tristate `raw:"insertSpaceAfterKeywordsInControlFlowStatements" config:"format.insertSpaceAfterKeywordsInControlFlowStatements"` - InsertSpaceAfterFunctionKeywordForAnonymousFunctions core.Tristate `raw:"insertSpaceAfterFunctionKeywordForAnonymousFunctions" config:"format.insertSpaceAfterFunctionKeywordForAnonymousFunctions"` - InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis core.Tristate `raw:"insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis" config:"format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"` - InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets core.Tristate `raw:"insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets" config:"format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"` - InsertSpaceAfterOpeningAndBeforeClosingNonemptyBraces core.Tristate `raw:"insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces" config:"format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"` - InsertSpaceAfterOpeningAndBeforeClosingEmptyBraces core.Tristate `raw:"insertSpaceAfterOpeningAndBeforeClosingEmptyBraces" config:"format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces"` - InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces core.Tristate `raw:"insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces" config:"format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"` - InsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces core.Tristate `raw:"insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces" config:"format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"` - InsertSpaceAfterTypeAssertion core.Tristate `raw:"insertSpaceAfterTypeAssertion" config:"format.insertSpaceAfterTypeAssertion"` - InsertSpaceBeforeFunctionParenthesis core.Tristate `raw:"insertSpaceBeforeFunctionParenthesis" config:"format.insertSpaceBeforeFunctionParenthesis"` - PlaceOpenBraceOnNewLineForFunctions core.Tristate `raw:"placeOpenBraceOnNewLineForFunctions" config:"format.placeOpenBraceOnNewLineForFunctions"` - PlaceOpenBraceOnNewLineForControlBlocks core.Tristate `raw:"placeOpenBraceOnNewLineForControlBlocks" config:"format.placeOpenBraceOnNewLineForControlBlocks"` - InsertSpaceBeforeTypeAnnotation core.Tristate `raw:"insertSpaceBeforeTypeAnnotation" config:"format.insertSpaceBeforeTypeAnnotation"` - IndentMultiLineObjectLiteralBeginningOnBlankLine core.Tristate `raw:"indentMultiLineObjectLiteralBeginningOnBlankLine" config:"format.indentMultiLineObjectLiteralBeginningOnBlankLine"` - Semicolons SemicolonPreference `raw:"semicolons" config:"format.semicolons"` - IndentSwitchCase core.Tristate `raw:"indentSwitchCase" config:"format.indentSwitchCase"` -} - func FromLSFormatOptions(f FormatCodeSettings, opt *lsproto.FormattingOptions) FormatCodeSettings { updatedSettings := f updatedSettings.TabSize = int(opt.TabSize) diff --git a/tsc/internal/ls/lsutil/userpreferences.go b/tsc/internal/ls/lsutil/userpreferences.go index 2c3a3a006975d..bf61c1103d8af 100644 --- a/tsc/internal/ls/lsutil/userpreferences.go +++ b/tsc/internal/ls/lsutil/userpreferences.go @@ -1,11 +1,10 @@ package lsutil +//go:generate npx hereby generate:preferences + import ( "maps" - "reflect" - "slices" "strings" - "sync" "github.com/microsoft/TypeScript/tsc/internal/core" "github.com/microsoft/TypeScript/tsc/internal/json" @@ -14,17 +13,17 @@ import ( ) func NewDefaultUserPreferences() UserPreferences { - preferences := UserPreferences{ + return UserPreferences{ FormatCodeSettings: GetDefaultFormatCodeSettings(), - EnableAutoClosingTags: core.TSTrue, - EnableJSDocCompletions: core.TSTrue, + AutoClosingTags: core.TSTrue, + CompleteJSDocs: core.TSTrue, GenerateReturnInDocTemplate: core.TSTrue, AllowRenameOfImportPath: core.TSTrue, ProvideRefactorNotApplicableReason: core.TSTrue, - EnableFormatting: core.TSTrue, - EnableValidation: core.TSTrue, + FormatEnabled: core.TSTrue, + ValidateEnabled: core.TSTrue, DisplayPartsForJSDoc: core.TSTrue, DisableLineTextInReferences: core.TSTrue, ReportStyleChecksAsWarnings: core.TSTrue, @@ -35,231 +34,10 @@ func NewDefaultUserPreferences() UserPreferences { IncludeCompletionsForModuleExports: core.TSTrue, IncludeCompletionsForImportStatements: core.TSTrue, } - return preferences -} - -// UserPreferences represents TypeScript language service preferences. -type UserPreferences struct { - FormatCodeSettings - - QuotePreference QuotePreference `raw:"quotePreference" config:"preferences.quoteStyle"` - LazyConfiguredProjectsFromExternalProject core.Tristate `raw:"lazyConfiguredProjectsFromExternalProject"` // !!! - - // A positive integer indicating the maximum length of a hover text before it is truncated. - // - // Default: `500` - MaximumHoverLength int `raw:"maximumHoverLength"` // !!! - - CompletionPreferences - EnableAutoClosingTags core.Tristate `raw:"autoClosingTags" config:"autoClosingTags.enabled" fallbackConfig:"autoClosingTags"` - EnableJSDocCompletions core.Tristate `raw:"completeJSDocs" config:"suggest.jsdoc.enabled" fallbackConfig:"suggest.completeJSDocs"` - GenerateReturnInDocTemplate core.Tristate `raw:"generateReturnInDocTemplate" config:"suggest.jsdoc.generateReturns"` - - // ------- AutoImports -------- - - ImportModuleSpecifierPreference modulespecifiers.ImportModuleSpecifierPreference `raw:"importModuleSpecifierPreference" config:"preferences.importModuleSpecifier"` // !!! - // Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" - ImportModuleSpecifierEnding modulespecifiers.ImportModuleSpecifierEndingPreference `raw:"importModuleSpecifierEnding" config:"preferences.importModuleSpecifierEnding"` // !!! - AutoImportSpecifierExcludeRegexes []string `raw:"autoImportSpecifierExcludeRegexes" config:"preferences.autoImportSpecifierExcludeRegexes"` // !!! - AutoImportFileExcludePatterns []string `raw:"autoImportFileExcludePatterns" config:"preferences.autoImportFileExcludePatterns"` - AutoImportEntrypointDirectorySearch core.Tristate `raw:"autoImportEntrypointDirectorySearch" config:"preferences.autoImportEntrypointDirectorySearch"` - PreferTypeOnlyAutoImports core.Tristate `raw:"preferTypeOnlyAutoImports" config:"preferences.preferTypeOnlyAutoImports"` - - // ------- OrganizeImports ------- - - // Indicates which deterministic preset should be used to sort imports. - // "auto" detects the existing ordinal case sensitivity where possible. - OrganizeImportsSort OrganizeImportsSort `raw:"organizeImportsSort" config:"preferences.organizeImports.sort"` // !!! - // Indicates whether imports should be organized in a case-insensitive manner. - // - // Default: TSUnknown ("auto" in strada), will perform detection - OrganizeImportsIgnoreCase core.Tristate `raw:"organizeImportsIgnoreCase" config:"preferences.organizeImports.caseSensitivity"` // !!! - // Indicates whether imports should be organized via an "ordinal" (binary) comparison using the numeric value of their - // code points, or via "unicode" natural sorting. This implementation is locale-agnostic and approximates the practical - // import-sorting behavior rather than the full Unicode Collation Algorithm. - // - // Default: Ordinal - OrganizeImportsCollation OrganizeImportsCollation `raw:"organizeImportsCollation" config:"preferences.organizeImports.unicodeCollation"` // !!! - // Indicates the locale to use for "unicode" collation in legacy clients. This is accepted for compatibility, but - // currently ignored because organize-import sorting is deterministic and locale-agnostic. - // - // This preference is ignored if organizeImportsCollation is not `unicode`. - // - // Default: `"en"` - OrganizeImportsLocale string `raw:"organizeImportsLocale" config:"preferences.organizeImports.locale"` // !!! - // Indicates whether numeric collation should be used for digit sequences in strings. When `true`, will collate - // strings such that `a1z < a2z < a100z`. When `false`, will collate strings such that `a1z < a100z < a2z`. - // - // This preference is ignored if organizeImportsCollation is not `unicode`. - // - // Default: `false` - OrganizeImportsNumericCollation core.Tristate `raw:"organizeImportsNumericCollation" config:"preferences.organizeImports.numericCollation"` // !!! - // Indicates whether accents and other diacritic marks are considered unequal for the purpose of sorting. - // - // This preference is ignored if organizeImportsCollation is not `unicode`. - // - // Default: `true` - OrganizeImportsAccentCollation core.Tristate `raw:"organizeImportsAccentCollation" config:"preferences.organizeImports.accentCollation"` // !!! - // Indicates whether upper case or lower case should sort first. - // - // This permission is ignored if: - // - organizeImportsCollation is not `unicode` - // - organizeImportsIgnoreCase is `true` - // - organizeImportsIgnoreCase is `auto` and the auto-detected case sensitivity is case-insensitive. - // - // Default: `false` - OrganizeImportsCaseFirst OrganizeImportsCaseFirst `raw:"organizeImportsCaseFirst" config:"preferences.organizeImports.caseFirst"` // !!! - // Indicates where named type-only imports should sort. "inline" sorts named imports without regard to if the import is type-only. - // - // Default: `auto`, which defaults to `last` - OrganizeImportsTypeOrder OrganizeImportsTypeOrder `raw:"organizeImportsTypeOrder" config:"preferences.organizeImports.typeOrder"` // !!! - - // ------- MoveToFile ------- - - AllowTextChangesInNewFiles core.Tristate `raw:"allowTextChangesInNewFiles"` // !!! - - // ------- Rename ------- - - UseAliasesForRename core.Tristate `raw:"providePrefixAndSuffixTextForRename" config:"preferences.useAliasesForRenames"` - AllowRenameOfImportPath core.Tristate `raw:"allowRenameOfImportPath"` - - // ------- CodeFixes/Refactors ------- - - ProvideRefactorNotApplicableReason core.Tristate `raw:"provideRefactorNotApplicableReason"` // !!! - - // ------- InlayHints ------- - - InlayHints InlayHintsPreferences - - // ------- CodeLens ------- - - CodeLens CodeLensUserPreferences - - // ------- Definition ------- - - PreferGoToSourceDefinition bool `raw:"preferGoToSourceDefinition"` - - // ------- Symbols ------- - - ExcludeLibrarySymbolsInNavTo core.Tristate `raw:"excludeLibrarySymbolsInNavTo" config:"workspaceSymbols.excludeLibrarySymbols"` - WorkspaceSymbolsScope WorkspaceSymbolsScope `raw:"workspaceSymbolsScope" config:"workspaceSymbols.scope"` - - // ------- Misc ------- - - EnableFormatting core.Tristate `raw:"formatEnabled" config:"format.enabled" fallbackConfig:"format.enable"` - EnableValidation core.Tristate `raw:"validateEnabled" config:"validate.enabled" fallbackConfig:"validate.enable"` - DisableSuggestions core.Tristate `raw:"disableSuggestions"` // !!! - DisableLineTextInReferences core.Tristate `raw:"disableLineTextInReferences"` // !!! - DisplayPartsForJSDoc core.Tristate `raw:"displayPartsForJSDoc"` // !!! - ReportStyleChecksAsWarnings core.Tristate `raw:"reportStyleChecksAsWarnings" config:"reportStyleChecksAsWarnings"` - Locale string `raw:"locale" config:"locale"` - - // ------- ATA ------- - - // DisableAutomaticTypeAcquisition is the deprecated setting from typescript.disableAutomaticTypeAcquisition. - DisableAutomaticTypeAcquisition core.Tristate `raw:"disableAutomaticTypeAcquisition" config:"disableAutomaticTypeAcquisition"` - // AutomaticTypeAcquisitionEnabled is the unified setting from tsserver.automaticTypeAcquisition.enabled under the js/ts section. - // When set, it takes precedence over DisableAutomaticTypeAcquisition. - AutomaticTypeAcquisitionEnabled core.Tristate `raw:"automaticTypeAcquisitionEnabled" config:"tsserver.automaticTypeAcquisition.enabled"` - // TODO: add tsserver.web.typeAcquisition.enabled under the js/ts section for the web variant when web support is implemented. - - // ------- Project Configuration ------- - - // CustomConfigFileName specifies a custom config file name to use before defaulting to tsconfig.json/jsconfig.json. - CustomConfigFileName string `raw:"customConfigFileName" config:"customConfigFileName"` -} - -// CompletionPreferences contains preferences used while producing completions. -type CompletionPreferences struct { - // If enabled, TypeScript will search through all external modules' exports and add them to the completions list. - // This affects lone identifier completions but not completions on the right hand side of `obj.`. - IncludeCompletionsForModuleExports core.Tristate `json:"includeCompletionsForModuleExports,omitempty" raw:"includeCompletionsForModuleExports" config:"suggest.autoImports"` - // Enables auto-import-style completions on partially-typed import statements. E.g., allows - // `import write|` to be completed to `import { writeFile } from "fs"`. - IncludeCompletionsForImportStatements core.Tristate `json:"includeCompletionsForImportStatements,omitempty" raw:"includeCompletionsForImportStatements" config:"suggest.includeCompletionsForImportStatements"` - // Unless this option is `false`, member completion lists triggered with `.` will include entries - // on potentially-null and potentially-undefined values, with insertion text to replace - // preceding `.` tokens with `?.`. - IncludeAutomaticOptionalChainCompletions core.Tristate `json:"includeAutomaticOptionalChainCompletions,omitempty" raw:"includeAutomaticOptionalChainCompletions" config:"suggest.includeAutomaticOptionalChainCompletions"` - // If enabled, completions for class members (e.g. methods and properties) will include - // a whole declaration for the member. - IncludeCompletionsWithClassMemberSnippets core.Tristate `json:"includeCompletionsWithClassMemberSnippets,omitempty" raw:"includeCompletionsWithClassMemberSnippets" config:"suggest.classMemberSnippets.enabled"` - // If enabled, object literal methods will have a method declaration completion entry in addition - // to the regular completion entry containing just the method name. - IncludeCompletionsWithObjectLiteralMethodSnippets core.Tristate `json:"includeCompletionsWithObjectLiteralMethodSnippets,omitempty" raw:"includeCompletionsWithObjectLiteralMethodSnippets" config:"suggest.objectLiteralMethodSnippets.enabled"` - JsxAttributeCompletionStyle JsxAttributeCompletionStyle `json:"jsxAttributeCompletionStyle,omitempty" raw:"jsxAttributeCompletionStyle" config:"preferences.jsxAttributeCompletionStyle"` -} - -func (p *CompletionPreferences) UnmarshalJSONFrom(dec *json.Decoder) error { - var values map[string]any - if err := json.UnmarshalDecode(dec, &values); err != nil { - return err - } - v := reflect.ValueOf(p).Elem() - for _, info := range collectFieldInfos(reflect.TypeFor[CompletionPreferences](), nil) { - if value, ok := values[info.rawName]; ok { - setFieldFromValue(getFieldByPath(v, info.fieldPath), value) - } - } - return nil -} - -func (p UserPreferences) WithCompletionPreferences(overrides CompletionPreferences) UserPreferences { - source := reflect.ValueOf(overrides) - target := reflect.ValueOf(&p).Elem() - userPreferenceFields := fieldInfoCache() - userPreferenceIndex := unstableNameIndex() - for _, info := range collectFieldInfos(reflect.TypeFor[CompletionPreferences](), nil) { - sourceField := getFieldByPath(source, info.fieldPath) - if serializeField(sourceField) == nil { - continue - } - targetInfo := userPreferenceFields[userPreferenceIndex[info.rawName]] - getFieldByPath(target, targetInfo.fieldPath).Set(sourceField) - } - return p -} - -// IsATADisabled returns whether Automatic Type Acquisition is disabled based on user preferences. -// It checks the unified setting (tsserver.automaticTypeAcquisition.enabled) first, -// then falls back to the deprecated setting (disableAutomaticTypeAcquisition). -func (p UserPreferences) IsATADisabled() bool { - if !p.AutomaticTypeAcquisitionEnabled.IsUnknown() { - return !p.AutomaticTypeAcquisitionEnabled.IsTrue() - } - return p.DisableAutomaticTypeAcquisition.IsTrue() -} - -type InlayHintsPreferences struct { - IncludeInlayParameterNameHints IncludeInlayParameterNameHints `raw:"includeInlayParameterNameHints" config:"inlayHints.parameterNames.enabled"` - IncludeInlayParameterNameHintsWhenArgumentMatchesName core.Tristate `raw:"includeInlayParameterNameHintsWhenArgumentMatchesName" config:"inlayHints.parameterNames.suppressWhenArgumentMatchesName,invert"` - IncludeInlayFunctionParameterTypeHints core.Tristate `raw:"includeInlayFunctionParameterTypeHints" config:"inlayHints.parameterTypes.enabled"` - IncludeInlayVariableTypeHints core.Tristate `raw:"includeInlayVariableTypeHints" config:"inlayHints.variableTypes.enabled"` - IncludeInlayVariableTypeHintsWhenTypeMatchesName core.Tristate `raw:"includeInlayVariableTypeHintsWhenTypeMatchesName" config:"inlayHints.variableTypes.suppressWhenTypeMatchesName,invert"` - IncludeInlayPropertyDeclarationTypeHints core.Tristate `raw:"includeInlayPropertyDeclarationTypeHints" config:"inlayHints.propertyDeclarationTypes.enabled"` - IncludeInlayFunctionLikeReturnTypeHints core.Tristate `raw:"includeInlayFunctionLikeReturnTypeHints" config:"inlayHints.functionLikeReturnTypes.enabled"` - IncludeInlayEnumMemberValueHints core.Tristate `raw:"includeInlayEnumMemberValueHints" config:"inlayHints.enumMemberValues.enabled"` } -type CodeLensUserPreferences struct { - ReferencesCodeLensEnabled core.Tristate `raw:"referencesCodeLensEnabled" config:"referencesCodeLens.enabled"` - ImplementationsCodeLensEnabled core.Tristate `raw:"implementationsCodeLensEnabled" config:"implementationsCodeLens.enabled"` - ReferencesCodeLensShowOnAllFunctions core.Tristate `raw:"referencesCodeLensShowOnAllFunctions" config:"referencesCodeLens.showOnAllFunctions"` - ImplementationsCodeLensShowOnInterfaceMethods core.Tristate `raw:"implementationsCodeLensShowOnInterfaceMethods" config:"implementationsCodeLens.showOnInterfaceMethods"` - ImplementationsCodeLensShowOnAllClassMethods core.Tristate `raw:"implementationsCodeLensShowOnAllClassMethods" config:"implementationsCodeLens.showOnAllClassMethods"` -} - -// --- Enum Types --- - type QuotePreference string -type WorkspaceSymbolsScope string - -const ( - WorkspaceSymbolsScopeAllOpenProjects WorkspaceSymbolsScope = "allOpenProjects" - WorkspaceSymbolsScopeCurrentProject WorkspaceSymbolsScope = "currentProject" -) - const ( QuotePreferenceUnknown QuotePreference = "" QuotePreferenceAuto QuotePreference = "auto" @@ -267,6 +45,13 @@ const ( QuotePreferenceSingle QuotePreference = "single" ) +type WorkspaceSymbolsScope string + +const ( + WorkspaceSymbolsScopeAllOpenProjects WorkspaceSymbolsScope = "allOpenProjects" + WorkspaceSymbolsScopeCurrentProject WorkspaceSymbolsScope = "currentProject" +) + type JsxAttributeCompletionStyle string const ( @@ -304,9 +89,9 @@ const ( type OrganizeImportsCaseFirst int const ( - OrganizeImportsCaseFirstFalse OrganizeImportsCaseFirst = 0 - OrganizeImportsCaseFirstLower OrganizeImportsCaseFirst = 1 - OrganizeImportsCaseFirstUpper OrganizeImportsCaseFirst = 2 + OrganizeImportsCaseFirstDefault OrganizeImportsCaseFirst = 0 + OrganizeImportsCaseFirstLower OrganizeImportsCaseFirst = 1 + OrganizeImportsCaseFirstUpper OrganizeImportsCaseFirst = 2 ) type OrganizeImportsTypeOrder int @@ -318,352 +103,49 @@ const ( OrganizeImportsTypeOrderFirst OrganizeImportsTypeOrder = 3 ) -// --- Reflection-based parsing infrastructure --- - -// typeParsers maps reflect.Type to a function that parses a value into that type. -var typeParsers = map[reflect.Type]func(any) any{ - reflect.TypeFor[core.Tristate](): func(val any) any { - if b, ok := val.(bool); ok { - if b { - return core.TSTrue - } - return core.TSFalse - } - return core.TSUnknown - }, - reflect.TypeFor[IndentStyle](): func(val any) any { - return parseIndentStyle(val) - }, - reflect.TypeFor[SemicolonPreference](): func(val any) any { - return parseSemicolonPreference(val) - }, - reflect.TypeFor[QuotePreference](): func(val any) any { - if s, ok := val.(string); ok { - switch strings.ToLower(s) { - case "auto": - return QuotePreferenceAuto - case "double": - return QuotePreferenceDouble - case "single": - return QuotePreferenceSingle - } - } - return QuotePreferenceUnknown - }, - reflect.TypeFor[JsxAttributeCompletionStyle](): func(val any) any { - if s, ok := val.(string); ok { - switch strings.ToLower(s) { - case "braces": - return JsxAttributeCompletionStyleBraces - case "none": - return JsxAttributeCompletionStyleNone - } - } - return JsxAttributeCompletionStyleAuto - }, - reflect.TypeFor[IncludeInlayParameterNameHints](): func(val any) any { - if s, ok := val.(string); ok { - switch s { - case "all": - return IncludeInlayParameterNameHintsAll - case "literals": - return IncludeInlayParameterNameHintsLiterals - } - } - return IncludeInlayParameterNameHintsNone - }, - reflect.TypeFor[OrganizeImportsSort](): func(val any) any { - if s, ok := val.(string); ok { - switch strings.ToLower(s) { - case "ordinal": - return OrganizeImportsSortOrdinal - case "ordinalignorecase": - return OrganizeImportsSortOrdinalIgnoreCase - case "natural": - return OrganizeImportsSortNatural - case "naturalignorecase": - return OrganizeImportsSortNaturalIgnoreCase - } - } - return OrganizeImportsSortAuto - }, - reflect.TypeFor[OrganizeImportsCollation](): func(val any) any { - if s, ok := val.(string); ok && strings.ToLower(s) == "unicode" { - return OrganizeImportsCollationUnicode - } - return OrganizeImportsCollationOrdinal - }, - reflect.TypeFor[OrganizeImportsCaseFirst](): func(val any) any { - if s, ok := val.(string); ok { - switch s { - case "lower": - return OrganizeImportsCaseFirstLower - case "upper": - return OrganizeImportsCaseFirstUpper - } - } - return OrganizeImportsCaseFirstFalse - }, - reflect.TypeFor[OrganizeImportsTypeOrder](): func(val any) any { - if s, ok := val.(string); ok { - switch s { - case "last": - return OrganizeImportsTypeOrderLast - case "inline": - return OrganizeImportsTypeOrderInline - case "first": - return OrganizeImportsTypeOrderFirst - } - } - return OrganizeImportsTypeOrderAuto - }, - reflect.TypeFor[modulespecifiers.ImportModuleSpecifierPreference](): func(val any) any { - if s, ok := val.(string); ok { - switch strings.ToLower(s) { - case "project-relative": - return modulespecifiers.ImportModuleSpecifierPreferenceProjectRelative - case "relative": - return modulespecifiers.ImportModuleSpecifierPreferenceRelative - case "non-relative": - return modulespecifiers.ImportModuleSpecifierPreferenceNonRelative - } - } - return modulespecifiers.ImportModuleSpecifierPreferenceShortest - }, - reflect.TypeFor[modulespecifiers.ImportModuleSpecifierEndingPreference](): func(val any) any { - if s, ok := val.(string); ok { - switch strings.ToLower(s) { - case "minimal": - return modulespecifiers.ImportModuleSpecifierEndingPreferenceMinimal - case "index": - return modulespecifiers.ImportModuleSpecifierEndingPreferenceIndex - case "js": - return modulespecifiers.ImportModuleSpecifierEndingPreferenceJs - } - } - return modulespecifiers.ImportModuleSpecifierEndingPreferenceAuto - }, -} - -// typeSerializers maps reflect.Type to a function that serializes a value of that type. -// For types which do not serialize as-is (tristate, enums, etc). -var typeSerializers = map[reflect.Type]func(any) any{ - reflect.TypeFor[core.Tristate](): func(val any) any { - switch val.(core.Tristate) { - case core.TSTrue: - return true - case core.TSFalse: - return false - default: - return nil - } - }, - reflect.TypeFor[OrganizeImportsSort](): func(val any) any { - switch val.(OrganizeImportsSort) { - case OrganizeImportsSortOrdinal: - return "ordinal" - case OrganizeImportsSortOrdinalIgnoreCase: - return "ordinalIgnoreCase" - case OrganizeImportsSortNatural: - return "natural" - case OrganizeImportsSortNaturalIgnoreCase: - return "naturalIgnoreCase" - default: - return "auto" - } - }, - reflect.TypeFor[OrganizeImportsCollation](): func(val any) any { - if val.(OrganizeImportsCollation) == OrganizeImportsCollationUnicode { - return "unicode" - } - return "ordinal" - }, - reflect.TypeFor[OrganizeImportsCaseFirst](): func(val any) any { - switch val.(OrganizeImportsCaseFirst) { - case OrganizeImportsCaseFirstLower: - return "lower" - case OrganizeImportsCaseFirstUpper: - return "upper" - default: - return "default" - } - }, - reflect.TypeFor[OrganizeImportsTypeOrder](): func(val any) any { - switch val.(OrganizeImportsTypeOrder) { - case OrganizeImportsTypeOrderLast: - return "last" - case OrganizeImportsTypeOrderInline: - return "inline" - case OrganizeImportsTypeOrderFirst: - return "first" - default: - return "auto" - } - }, - // These enums distinguish an unset zero value (e.g. "") from their effective - // default (e.g. "auto"): the parser promotes unset/unknown input to the - // non-zero default. Plain string serialization would therefore write "" for - // an unset field and the parser would read it back as the non-zero default, - // breaking round-tripping. Mirror the core.Tristate serializer above and omit - // the unset value (return nil) so it decodes back to the zero value. (Enums - // whose default already is their zero value, like the OrganizeImports* ones, - // round-trip without this.) - // - // TODO: These three are the only parsers whose fallback is a non-zero value; - // every other parser returns its zero value as the fallback. They should be - // made consistent: change the parser fallback to return the zero value and - // remove this serializer (relying on the default string serialization, which - // already omits ""). The consumer must then treat the zero value as the - // effective default. The two module-specifier enums are safe to convert (all - // read sites already treat the "" zero identically to the promoted default). - reflect.TypeFor[JsxAttributeCompletionStyle](): func(val any) any { - // TODO: make consistent with other enums (see note above). Unlike the - // module-specifier enums, the consumer in completions.go distinguishes - // JsxAttributeCompletionStyleUnknown from ...Auto, so converting this one - // requires updating that consumer to treat the zero value as "auto". - if v := val.(JsxAttributeCompletionStyle); v != JsxAttributeCompletionStyleUnknown { - return string(v) - } - return nil - }, - reflect.TypeFor[modulespecifiers.ImportModuleSpecifierPreference](): func(val any) any { - // TODO: make consistent with other enums (see note above): have the parser - // return the zero value (None) as its fallback and drop this serializer. - if v := val.(modulespecifiers.ImportModuleSpecifierPreference); v != "" { - return string(v) - } - return nil - }, - reflect.TypeFor[modulespecifiers.ImportModuleSpecifierEndingPreference](): func(val any) any { - // TODO: make consistent with other enums (see note above): have the parser - // return the zero value (None) as its fallback and drop this serializer. - if v := val.(modulespecifiers.ImportModuleSpecifierEndingPreference); v != "" { - return string(v) - } - return nil - }, +func parsePreferenceTristate(value any) core.Tristate { + if value, ok := value.(bool); ok { + return core.BoolToTristate(value) + } + return core.TSUnknown } -// configPathParsers provides field-specific config value parsers that override the default -// type-based parser when the VS Code config value format differs from the Go field type. -var configPathParsers = map[string]func(any) any{ - // VS Code sends caseSensitivity as a string ("auto"/"caseSensitive"/"caseInsensitive"), - // but OrganizeImportsIgnoreCase is a core.Tristate. - "preferences.organizeImports.caseSensitivity": func(val any) any { - if s, ok := val.(string); ok { - switch strings.ToLower(s) { - case "caseinsensitive": - return core.TSTrue - case "casesensitive": - return core.TSFalse - } - } - if b, ok := val.(bool); ok { - if b { - return core.TSTrue - } +func parseOrganizeImportsCaseSensitivity(value any) core.Tristate { + if value, ok := value.(string); ok { + switch strings.ToLower(value) { + case "caseinsensitive": + return core.TSTrue + case "casesensitive": return core.TSFalse } - return core.TSUnknown - }, -} - -type fieldInfo struct { - rawName string // raw name for unstable section lookup (e.g., "quotePreference") - configPath string // dotted path for config (e.g., "preferences.quoteStyle") - fallbackConfigPaths []configPathInfo - fieldPath []int // index path to field in struct - rawInvert bool // whether to invert boolean values for raw name - configInvert bool // whether to invert boolean values for config path -} - -type configPathInfo struct { - path string - invert bool -} - -var fieldInfoCache = sync.OnceValue(func() []fieldInfo { - return collectFieldInfos(reflect.TypeFor[UserPreferences](), nil) -}) - -// unstableNameIndex maps raw names to fieldInfo index for unstable section lookup. -var unstableNameIndex = sync.OnceValue(func() map[string]int { - infos := fieldInfoCache() - index := make(map[string]int, len(infos)) - for i, info := range infos { - if info.rawName != "" { - index[info.rawName] = i - } } - return index -}) - -func collectFieldInfos(t reflect.Type, indexPath []int) []fieldInfo { - var infos []fieldInfo - for i := range t.NumField() { - field := t.Field(i) - currentPath := append(slices.Clone(indexPath), i) - - rawTag := field.Tag.Get("raw") - configTag := field.Tag.Get("config") - fallbackConfigTag := field.Tag.Get("fallbackConfig") - - if rawTag == "" && configTag == "" { - // Embedded struct without tags - recurse into it - if field.Type.Kind() == reflect.Struct { - infos = append(infos, collectFieldInfos(field.Type, currentPath)...) - continue - } - panic("raw or config tag required for field " + field.Name) - } - - info := fieldInfo{ - fieldPath: currentPath, - } - - // Parse raw tag: "name" or "name,invert" - if rawTag != "" { - parts := strings.Split(rawTag, ",") - info.rawName = parts[0] - for _, part := range parts[1:] { - if part == "invert" { - info.rawInvert = true - } - } - } - - // Parse config tag: "path.to.setting" or "path.to.setting,invert" - if configTag != "" { - configPath := parseConfigPathTag(configTag) - info.configPath = configPath.path - info.configInvert = configPath.invert - } - if fallbackConfigTag != "" { - for tag := range strings.SplitSeq(fallbackConfigTag, ";") { - info.fallbackConfigPaths = append(info.fallbackConfigPaths, parseConfigPathTag(tag)) - } - } + return parsePreferenceTristate(value) +} - infos = append(infos, info) +func invertPreferenceValue(value any) any { + if value, ok := value.(bool); ok { + return !value } - return infos + return value } -func parseConfigPathTag(tag string) configPathInfo { - parts := strings.Split(tag, ",") - info := configPathInfo{path: parts[0]} - for _, part := range parts[1:] { - if part == "invert" { - info.invert = true +func getPreferenceConfigValue(config map[string]any, paths ...string) (any, bool) { + for _, tag := range paths { + path, modifier, _ := strings.Cut(tag, ",") + value, ok := getNestedValue(config, path) + if ok { + if modifier == "invert" { + value = invertPreferenceValue(value) + } + return value, true } } - return info + return nil, false } func getNestedValue(config map[string]any, path string) (any, bool) { - parts := strings.Split(path, ".") current := any(config) - for _, part := range parts { + for part := range strings.SplitSeq(path, ".") { m, ok := current.(map[string]any) if !ok { return nil, false @@ -690,200 +172,12 @@ func setNestedValue(config map[string]any, path string, value any) { current[parts[len(parts)-1]] = value } -func setRawFieldsFromConfig(v reflect.Value, infos []fieldInfo, settings map[string]any) { - index := unstableNameIndex() - for name, value := range settings { - if idx, found := index[name]; found { - info := infos[idx] - field := getFieldByPath(v, info.fieldPath) - if info.rawInvert { - if b, ok := value.(bool); ok { - value = !b - } - } - setFieldFromValue(field, value) - } - } -} - -func (p UserPreferences) withConfig(config map[string]any) UserPreferences { - v := reflect.ValueOf(&p).Elem() - infos := fieldInfoCache() - - // Raw UserPreferences can be provided directly, notably via LSP initializationOptions. - setRawFieldsFromConfig(v, infos, config) - - // Process "unstable" section first - allows any field to be set by raw name. - // This mirrors VS Code's behavior: { ...config.get('unstable'), ...stableOptions } - // where stable options are spread after and take precedence. - if unstable, ok := config["unstable"].(map[string]any); ok { - setRawFieldsFromConfig(v, infos, unstable) - } - - // Process path-based config (VS Code style nested paths). - // These run after unstable, so stable config values take precedence. - for _, info := range infos { - if info.configPath == "" { - continue - } - configPath := configPathInfo{path: info.configPath, invert: info.configInvert} - val, ok := getNestedValue(config, configPath.path) - if !ok { - for _, fallbackConfigPath := range info.fallbackConfigPaths { - val, ok = getNestedValue(config, fallbackConfigPath.path) - if ok { - configPath = fallbackConfigPath - break - } - } - } - if !ok { - continue - } - - field := getFieldByPath(v, info.fieldPath) - if configPath.invert { - if b, ok := val.(bool); ok { - val = !b - } - } - if parser, ok := configPathParsers[configPath.path]; ok { - field.Set(reflect.ValueOf(parser(val))) - continue - } - setFieldFromValue(field, val) - } - - // Validate CustomConfigFileName for path traversal - if p.CustomConfigFileName != "" { - name := strings.TrimSpace(p.CustomConfigFileName) - if strings.ContainsAny(name, "/\\") || name == ".." || name == "." { - p.CustomConfigFileName = "" - } else { - p.CustomConfigFileName = name - } - } - - return p -} - -func getFieldByPath(v reflect.Value, path []int) reflect.Value { - for _, idx := range path { - v = v.Field(idx) - } - return v -} - -func setFieldFromValue(field reflect.Value, val any) { - if val == nil { - return - } - - // Check custom parsers first (for types like Tristate, enums, etc.) - if parser, ok := typeParsers[field.Type()]; ok { - field.Set(reflect.ValueOf(parser(val))) - return - } - - switch field.Kind() { - case reflect.Bool: - if b, ok := val.(bool); ok { - field.SetBool(b) - } - case reflect.Int: - switch v := val.(type) { - case int: - field.SetInt(int64(v)) - case float64: - field.SetInt(int64(v)) - } - case reflect.String: - if s, ok := val.(string); ok { - field.SetString(s) - } - case reflect.Slice: - if arr, ok := val.([]any); ok { - result := reflect.MakeSlice(field.Type(), 0, len(arr)) - for _, item := range arr { - if s, ok := item.(string); ok { - result = reflect.Append(result, reflect.ValueOf(s)) - } - } - field.Set(result) - } - } -} - -func (p *UserPreferences) MarshalJSONTo(enc *json.Encoder) error { - config := make(map[string]any) - v := reflect.ValueOf(p).Elem() - - for _, info := range fieldInfoCache() { - field := getFieldByPath(v, info.fieldPath) - - val := serializeField(field) - if val == nil { - continue - } - - // Prefer config path if available, otherwise use unstable section - if info.configPath != "" { - if info.configInvert { - if b, ok := val.(bool); ok { - val = !b - } - } - setNestedValue(config, info.configPath, val) - } else if info.rawName != "" { - if info.rawInvert { - if b, ok := val.(bool); ok { - val = !b - } - } - setNestedValue(config, "unstable."+info.rawName, val) - } - } - - return json.MarshalEncode(enc, config, json.Deterministic(true)) -} - -func serializeField(field reflect.Value) any { - // Check custom serializers first (for types like Tristate, enums, etc.) - if serializer, ok := typeSerializers[field.Type()]; ok { - return serializer(field.Interface()) - } - - switch field.Kind() { - case reflect.Bool: - return field.Bool() - case reflect.Int: - // Zero means "unset" for these preference fields. Omit it so a partial - // config does not clobber defaults with zeros when round-tripped through - // withConfig. - i := field.Int() - if i == 0 { - return nil - } - return int(i) - case reflect.String: - // Zero ("") means "unset"; omit it for the same reason as int above. - s := field.String() - if s == "" { - return nil - } - return s - case reflect.Slice: - if field.IsNil() { - return nil - } - result := make([]string, field.Len()) - for i := range field.Len() { - result[i] = field.Index(i).String() - } - return result - default: - return field.Interface() +func normalizeCustomConfigFileName(name string) string { + name = strings.TrimSpace(name) + if strings.ContainsAny(name, "/\\") || name == ".." || name == "." { + return "" } + return name } func (p *UserPreferences) UnmarshalJSONFrom(dec *json.Decoder) error { @@ -891,12 +185,19 @@ func (p *UserPreferences) UnmarshalJSONFrom(dec *json.Decoder) error { if err := json.UnmarshalDecode(dec, &config); err != nil { return err } - // Start with defaults, then overlay parsed values *p = NewDefaultUserPreferences().withConfig(config) return nil } -// --- Helper methods --- +// IsATADisabled returns whether Automatic Type Acquisition is disabled based on user preferences. +// It checks the unified setting (tsserver.automaticTypeAcquisition.enabled) first, +// then falls back to the deprecated setting (disableAutomaticTypeAcquisition). +func (p UserPreferences) IsATADisabled() bool { + if !p.AutomaticTypeAcquisitionEnabled.IsUnknown() { + return !p.AutomaticTypeAcquisitionEnabled.IsTrue() + } + return p.DisableAutomaticTypeAcquisition.IsTrue() +} func (p UserPreferences) ModuleSpecifierPreferences() modulespecifiers.UserPreferences { return modulespecifiers.UserPreferences{ diff --git a/tsc/internal/ls/lsutil/userpreferences_generated.go b/tsc/internal/ls/lsutil/userpreferences_generated.go new file mode 100644 index 0000000000000..a6e2a786b0f67 --- /dev/null +++ b/tsc/internal/ls/lsutil/userpreferences_generated.go @@ -0,0 +1,1348 @@ +// Code generated by gen-preferences from tools/userPreferences.schema.json; DO NOT EDIT. + +package lsutil + +import ( + "slices" + "strings" + + "github.com/microsoft/TypeScript/tsc/internal/core" + "github.com/microsoft/TypeScript/tsc/internal/json" + "github.com/microsoft/TypeScript/tsc/internal/modulespecifiers" +) + +type CodeLensUserPreferences struct { + ImplementationsCodeLensEnabled core.Tristate `json:"implementationsCodeLensEnabled,omitempty"` + ImplementationsCodeLensShowOnAllClassMethods core.Tristate `json:"implementationsCodeLensShowOnAllClassMethods,omitempty"` + ImplementationsCodeLensShowOnInterfaceMethods core.Tristate `json:"implementationsCodeLensShowOnInterfaceMethods,omitempty"` + ReferencesCodeLensEnabled core.Tristate `json:"referencesCodeLensEnabled,omitempty"` + ReferencesCodeLensShowOnAllFunctions core.Tristate `json:"referencesCodeLensShowOnAllFunctions,omitempty"` +} + +// CompletionPreferences contains preferences used while producing completions. +type CompletionPreferences struct { + // Unless this option is `false`, member completion lists triggered with `.` will include entries + // on potentially-null and potentially-undefined values, with insertion text to replace + // preceding `.` tokens with `?.`. + IncludeAutomaticOptionalChainCompletions core.Tristate `json:"includeAutomaticOptionalChainCompletions,omitempty"` + // Enables auto-import-style completions on partially-typed import statements. E.g., allows + // `import write|` to be completed to `import { writeFile } from "fs"`. + IncludeCompletionsForImportStatements core.Tristate `json:"includeCompletionsForImportStatements,omitempty"` + // If enabled, TypeScript will search through all external modules' exports and add them to the completions list. + // This affects lone identifier completions but not completions on the right hand side of `obj.`. + IncludeCompletionsForModuleExports core.Tristate `json:"includeCompletionsForModuleExports,omitempty"` + // If enabled, completions for class members (e.g. methods and properties) will include + // a whole declaration for the member. + IncludeCompletionsWithClassMemberSnippets core.Tristate `json:"includeCompletionsWithClassMemberSnippets,omitempty"` + // If enabled, object literal methods will have a method declaration completion entry in addition + // to the regular completion entry containing just the method name. + IncludeCompletionsWithObjectLiteralMethodSnippets core.Tristate `json:"includeCompletionsWithObjectLiteralMethodSnippets,omitempty"` + JsxAttributeCompletionStyle JsxAttributeCompletionStyle `json:"jsxAttributeCompletionStyle,omitempty"` +} + +type EditorSettings struct { + BaseIndentSize int `json:"baseIndentSize,omitempty"` + ConvertTabsToSpaces core.Tristate `json:"convertTabsToSpaces,omitempty"` + IndentSize int `json:"indentSize,omitempty"` + IndentStyle IndentStyle `json:"indentStyle,omitempty"` + NewLineCharacter string `json:"newLineCharacter,omitempty"` + TabSize int `json:"tabSize,omitempty"` + TrimTrailingWhitespace core.Tristate `json:"trimTrailingWhitespace,omitempty"` +} + +type FormatCodeSettings struct { + EditorSettings + IndentMultiLineObjectLiteralBeginningOnBlankLine core.Tristate `json:"indentMultiLineObjectLiteralBeginningOnBlankLine,omitempty"` + IndentSwitchCase core.Tristate `json:"indentSwitchCase,omitempty"` + InsertSpaceAfterCommaDelimiter core.Tristate `json:"insertSpaceAfterCommaDelimiter,omitempty"` + InsertSpaceAfterConstructor core.Tristate `json:"insertSpaceAfterConstructor,omitempty"` + InsertSpaceAfterFunctionKeywordForAnonymousFunctions core.Tristate `json:"insertSpaceAfterFunctionKeywordForAnonymousFunctions,omitempty"` + InsertSpaceAfterKeywordsInControlFlowStatements core.Tristate `json:"insertSpaceAfterKeywordsInControlFlowStatements,omitempty"` + InsertSpaceAfterOpeningAndBeforeClosingEmptyBraces core.Tristate `json:"insertSpaceAfterOpeningAndBeforeClosingEmptyBraces,omitempty"` + InsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces core.Tristate `json:"insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces,omitempty"` + InsertSpaceAfterOpeningAndBeforeClosingNonemptyBraces core.Tristate `json:"insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces,omitempty"` + InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets core.Tristate `json:"insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets,omitempty"` + InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis core.Tristate `json:"insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis,omitempty"` + InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces core.Tristate `json:"insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces,omitempty"` + InsertSpaceAfterSemicolonInForStatements core.Tristate `json:"insertSpaceAfterSemicolonInForStatements,omitempty"` + InsertSpaceAfterTypeAssertion core.Tristate `json:"insertSpaceAfterTypeAssertion,omitempty"` + InsertSpaceBeforeAndAfterBinaryOperators core.Tristate `json:"insertSpaceBeforeAndAfterBinaryOperators,omitempty"` + InsertSpaceBeforeFunctionParenthesis core.Tristate `json:"insertSpaceBeforeFunctionParenthesis,omitempty"` + InsertSpaceBeforeTypeAnnotation core.Tristate `json:"insertSpaceBeforeTypeAnnotation,omitempty"` + PlaceOpenBraceOnNewLineForControlBlocks core.Tristate `json:"placeOpenBraceOnNewLineForControlBlocks,omitempty"` + PlaceOpenBraceOnNewLineForFunctions core.Tristate `json:"placeOpenBraceOnNewLineForFunctions,omitempty"` + Semicolons SemicolonPreference `json:"semicolons,omitempty"` +} + +type InlayHintsPreferences struct { + IncludeInlayEnumMemberValueHints core.Tristate `json:"includeInlayEnumMemberValueHints,omitempty"` + IncludeInlayFunctionLikeReturnTypeHints core.Tristate `json:"includeInlayFunctionLikeReturnTypeHints,omitempty"` + IncludeInlayFunctionParameterTypeHints core.Tristate `json:"includeInlayFunctionParameterTypeHints,omitempty"` + IncludeInlayParameterNameHints IncludeInlayParameterNameHints `json:"includeInlayParameterNameHints,omitempty"` + IncludeInlayParameterNameHintsWhenArgumentMatchesName core.Tristate `json:"includeInlayParameterNameHintsWhenArgumentMatchesName,omitempty"` + IncludeInlayPropertyDeclarationTypeHints core.Tristate `json:"includeInlayPropertyDeclarationTypeHints,omitempty"` + IncludeInlayVariableTypeHints core.Tristate `json:"includeInlayVariableTypeHints,omitempty"` + IncludeInlayVariableTypeHintsWhenTypeMatchesName core.Tristate `json:"includeInlayVariableTypeHintsWhenTypeMatchesName,omitempty"` +} + +// UserPreferences represents TypeScript language service preferences. +type UserPreferences struct { + FormatCodeSettings + CompletionPreferences + InlayHintsPreferences + CodeLensUserPreferences + AllowRenameOfImportPath core.Tristate `json:"allowRenameOfImportPath,omitempty"` + AllowTextChangesInNewFiles core.Tristate `json:"allowTextChangesInNewFiles,omitempty"` + AutoClosingTags core.Tristate `json:"autoClosingTags,omitempty"` + AutoImportEntrypointDirectorySearch core.Tristate `json:"autoImportEntrypointDirectorySearch,omitempty"` + AutoImportFileExcludePatterns []string `json:"autoImportFileExcludePatterns,omitempty"` + AutoImportSpecifierExcludeRegexes []string `json:"autoImportSpecifierExcludeRegexes,omitempty"` + // AutomaticTypeAcquisitionEnabled is the unified setting from tsserver.automaticTypeAcquisition.enabled under the js/ts section. + // When set, it takes precedence over DisableAutomaticTypeAcquisition. + AutomaticTypeAcquisitionEnabled core.Tristate `json:"automaticTypeAcquisitionEnabled,omitempty"` + CompleteJSDocs core.Tristate `json:"completeJSDocs,omitempty"` + // CustomConfigFileName specifies a custom config file name to use before defaulting to tsconfig.json/jsconfig.json. + CustomConfigFileName string `json:"customConfigFileName,omitempty"` + // DisableAutomaticTypeAcquisition is the deprecated setting from typescript.disableAutomaticTypeAcquisition. + DisableAutomaticTypeAcquisition core.Tristate `json:"disableAutomaticTypeAcquisition,omitempty"` + DisableLineTextInReferences core.Tristate `json:"disableLineTextInReferences,omitempty"` + DisableSuggestions core.Tristate `json:"disableSuggestions,omitempty"` + DisplayPartsForJSDoc core.Tristate `json:"displayPartsForJSDoc,omitempty"` + ExcludeLibrarySymbolsInNavTo core.Tristate `json:"excludeLibrarySymbolsInNavTo,omitempty"` + FormatEnabled core.Tristate `json:"formatEnabled,omitempty"` + GenerateReturnInDocTemplate core.Tristate `json:"generateReturnInDocTemplate,omitempty"` + // Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" + ImportModuleSpecifierEnding modulespecifiers.ImportModuleSpecifierEndingPreference `json:"importModuleSpecifierEnding,omitempty"` + ImportModuleSpecifierPreference modulespecifiers.ImportModuleSpecifierPreference `json:"importModuleSpecifierPreference,omitempty"` + LazyConfiguredProjectsFromExternalProject core.Tristate `json:"lazyConfiguredProjectsFromExternalProject,omitempty"` + Locale string `json:"locale,omitempty"` + // A positive integer indicating the maximum length of a hover text before it is truncated. + // + // Default: `500` + MaximumHoverLength int `json:"maximumHoverLength,omitempty"` + // Indicates whether accents and other diacritic marks are considered unequal for the purpose of sorting. + // + // This preference is ignored if organizeImportsCollation is not `unicode`. + // + // Default: `true` + OrganizeImportsAccentCollation core.Tristate `json:"organizeImportsAccentCollation,omitempty"` + // Indicates whether upper case or lower case should sort first. + // + // This permission is ignored if: + // - organizeImportsCollation is not `unicode` + // - organizeImportsIgnoreCase is `true` + // - organizeImportsIgnoreCase is `auto` and the auto-detected case sensitivity is case-insensitive. + // + // Default: `false` + OrganizeImportsCaseFirst OrganizeImportsCaseFirst `json:"organizeImportsCaseFirst,omitempty"` + // Indicates whether imports should be organized via an "ordinal" (binary) comparison using the numeric value of their + // code points, or via "unicode" natural sorting. This implementation is locale-agnostic and approximates the practical + // import-sorting behavior rather than the full Unicode Collation Algorithm. + // + // Default: Ordinal + OrganizeImportsCollation OrganizeImportsCollation `json:"organizeImportsCollation,omitempty"` + // Indicates whether imports should be organized in a case-insensitive manner. + // + // If unspecified, case sensitivity is detected. + OrganizeImportsIgnoreCase core.Tristate `json:"organizeImportsIgnoreCase,omitempty"` + // Indicates the locale to use for "unicode" collation in legacy clients. This is accepted for compatibility, but + // currently ignored because organize-import sorting is deterministic and locale-agnostic. + // + // This preference is ignored if organizeImportsCollation is not `unicode`. + // + // Default: `"en"` + OrganizeImportsLocale string `json:"organizeImportsLocale,omitempty"` + // Indicates whether numeric collation should be used for digit sequences in strings. When `true`, will collate + // strings such that `a1z < a2z < a100z`. When `false`, will collate strings such that `a1z < a100z < a2z`. + // + // This preference is ignored if organizeImportsCollation is not `unicode`. + // + // Default: `false` + OrganizeImportsNumericCollation core.Tristate `json:"organizeImportsNumericCollation,omitempty"` + // Indicates which deterministic preset should be used to sort imports. + // "auto" detects the existing ordinal case sensitivity where possible. + OrganizeImportsSort OrganizeImportsSort `json:"organizeImportsSort,omitempty"` + // Indicates where named type-only imports should sort. "inline" sorts named imports without regard to if the import is type-only. + // + // Default: `auto`, which defaults to `last` + OrganizeImportsTypeOrder OrganizeImportsTypeOrder `json:"organizeImportsTypeOrder,omitempty"` + PreferGoToSourceDefinition bool `json:"preferGoToSourceDefinition,omitempty"` + PreferTypeOnlyAutoImports core.Tristate `json:"preferTypeOnlyAutoImports,omitempty"` + ProvidePrefixAndSuffixTextForRename core.Tristate `json:"providePrefixAndSuffixTextForRename,omitempty"` + ProvideRefactorNotApplicableReason core.Tristate `json:"provideRefactorNotApplicableReason,omitempty"` + QuotePreference QuotePreference `json:"quotePreference,omitempty"` + ReportStyleChecksAsWarnings core.Tristate `json:"reportStyleChecksAsWarnings,omitempty"` + ValidateEnabled core.Tristate `json:"validateEnabled,omitempty"` + WorkspaceSymbolsScope WorkspaceSymbolsScope `json:"workspaceSymbolsScope,omitempty"` +} + +func parsePreferenceIncludeInlayParameterNameHints(value any) IncludeInlayParameterNameHints { + if value, ok := value.(string); ok { + switch strings.ToLower(value) { + case "none": + return IncludeInlayParameterNameHintsNone + case "literals": + return IncludeInlayParameterNameHintsLiterals + case "all": + return IncludeInlayParameterNameHintsAll + } + } + return IncludeInlayParameterNameHintsNone +} + +func parsePreferenceIndentStyle(value any) IndentStyle { + if value, ok := value.(string); ok { + switch strings.ToLower(value) { + case "none": + return IndentStyleNone + case "block": + return IndentStyleBlock + case "smart": + return IndentStyleSmart + } + } + switch value := value.(type) { + case int: + return IndentStyle(value) + case float64: + return IndentStyle(value) + } + return IndentStyleSmart +} + +func parsePreferenceJsxAttributeCompletionStyle(value any) JsxAttributeCompletionStyle { + if value, ok := value.(string); ok { + switch strings.ToLower(value) { + case "auto": + return JsxAttributeCompletionStyleAuto + case "braces": + return JsxAttributeCompletionStyleBraces + case "none": + return JsxAttributeCompletionStyleNone + } + } + return JsxAttributeCompletionStyleAuto +} + +func parsePreferenceOrganizeImportsCaseFirst(value any) OrganizeImportsCaseFirst { + if value, ok := value.(string); ok { + switch strings.ToLower(value) { + case "default": + return OrganizeImportsCaseFirstDefault + case "lower": + return OrganizeImportsCaseFirstLower + case "upper": + return OrganizeImportsCaseFirstUpper + } + } + return OrganizeImportsCaseFirstDefault +} + +func serializePreferenceOrganizeImportsCaseFirst(value OrganizeImportsCaseFirst) string { + switch value { + case OrganizeImportsCaseFirstDefault: + return "default" + case OrganizeImportsCaseFirstLower: + return "lower" + case OrganizeImportsCaseFirstUpper: + return "upper" + default: + return "default" + } +} + +func parsePreferenceOrganizeImportsCollation(value any) OrganizeImportsCollation { + if value, ok := value.(string); ok { + switch strings.ToLower(value) { + case "ordinal": + return OrganizeImportsCollationOrdinal + case "unicode": + return OrganizeImportsCollationUnicode + } + } + return OrganizeImportsCollationOrdinal +} + +func serializePreferenceOrganizeImportsCollation(value OrganizeImportsCollation) string { + switch value { + case OrganizeImportsCollationOrdinal: + return "ordinal" + case OrganizeImportsCollationUnicode: + return "unicode" + default: + return "ordinal" + } +} + +func parsePreferenceOrganizeImportsSort(value any) OrganizeImportsSort { + if value, ok := value.(string); ok { + switch strings.ToLower(value) { + case "auto": + return OrganizeImportsSortAuto + case "ordinal": + return OrganizeImportsSortOrdinal + case "ordinalignorecase": + return OrganizeImportsSortOrdinalIgnoreCase + case "natural": + return OrganizeImportsSortNatural + case "naturalignorecase": + return OrganizeImportsSortNaturalIgnoreCase + } + } + return OrganizeImportsSortAuto +} + +func serializePreferenceOrganizeImportsSort(value OrganizeImportsSort) string { + switch value { + case OrganizeImportsSortAuto: + return "auto" + case OrganizeImportsSortOrdinal: + return "ordinal" + case OrganizeImportsSortOrdinalIgnoreCase: + return "ordinalIgnoreCase" + case OrganizeImportsSortNatural: + return "natural" + case OrganizeImportsSortNaturalIgnoreCase: + return "naturalIgnoreCase" + default: + return "auto" + } +} + +func parsePreferenceOrganizeImportsTypeOrder(value any) OrganizeImportsTypeOrder { + if value, ok := value.(string); ok { + switch strings.ToLower(value) { + case "auto": + return OrganizeImportsTypeOrderAuto + case "last": + return OrganizeImportsTypeOrderLast + case "inline": + return OrganizeImportsTypeOrderInline + case "first": + return OrganizeImportsTypeOrderFirst + } + } + return OrganizeImportsTypeOrderAuto +} + +func serializePreferenceOrganizeImportsTypeOrder(value OrganizeImportsTypeOrder) string { + switch value { + case OrganizeImportsTypeOrderAuto: + return "auto" + case OrganizeImportsTypeOrderLast: + return "last" + case OrganizeImportsTypeOrderInline: + return "inline" + case OrganizeImportsTypeOrderFirst: + return "first" + default: + return "auto" + } +} + +func parsePreferenceQuotePreference(value any) QuotePreference { + if value, ok := value.(string); ok { + switch strings.ToLower(value) { + case "auto": + return QuotePreferenceAuto + case "double": + return QuotePreferenceDouble + case "single": + return QuotePreferenceSingle + } + } + return QuotePreference("") +} + +func parsePreferenceSemicolonPreference(value any) SemicolonPreference { + if value, ok := value.(string); ok { + switch strings.ToLower(value) { + case "ignore": + return SemicolonPreferenceIgnore + case "insert": + return SemicolonPreferenceInsert + case "remove": + return SemicolonPreferenceRemove + } + } + return SemicolonPreferenceIgnore +} + +func parsePreferenceWorkspaceSymbolsScope(value any) WorkspaceSymbolsScope { + if value, ok := value.(string); ok { + switch strings.ToLower(value) { + case "allopenprojects": + return WorkspaceSymbolsScopeAllOpenProjects + case "currentproject": + return WorkspaceSymbolsScopeCurrentProject + } + } + return WorkspaceSymbolsScope("") +} + +func parsePreferenceImportModuleSpecifierEndingPreference(value any) modulespecifiers.ImportModuleSpecifierEndingPreference { + if value, ok := value.(string); ok { + switch strings.ToLower(value) { + case "auto": + return modulespecifiers.ImportModuleSpecifierEndingPreferenceAuto + case "minimal": + return modulespecifiers.ImportModuleSpecifierEndingPreferenceMinimal + case "index": + return modulespecifiers.ImportModuleSpecifierEndingPreferenceIndex + case "js": + return modulespecifiers.ImportModuleSpecifierEndingPreferenceJs + } + } + return modulespecifiers.ImportModuleSpecifierEndingPreferenceAuto +} + +func parsePreferenceImportModuleSpecifierPreference(value any) modulespecifiers.ImportModuleSpecifierPreference { + if value, ok := value.(string); ok { + switch strings.ToLower(value) { + case "shortest": + return modulespecifiers.ImportModuleSpecifierPreferenceShortest + case "project-relative": + return modulespecifiers.ImportModuleSpecifierPreferenceProjectRelative + case "relative": + return modulespecifiers.ImportModuleSpecifierPreferenceRelative + case "non-relative": + return modulespecifiers.ImportModuleSpecifierPreferenceNonRelative + } + } + return modulespecifiers.ImportModuleSpecifierPreferenceShortest +} + +func (p *UserPreferences) applyRawPreferences(settings map[string]any) { + for name, value := range settings { + if value == nil { + continue + } + switch name { + case "baseIndentSize": + switch value := value.(type) { + case int: + p.FormatCodeSettings.EditorSettings.BaseIndentSize = int(value) + case float64: + p.FormatCodeSettings.EditorSettings.BaseIndentSize = int(value) + } + case "convertTabsToSpaces": + p.FormatCodeSettings.EditorSettings.ConvertTabsToSpaces = parsePreferenceTristate(value) + case "indentSize": + switch value := value.(type) { + case int: + p.FormatCodeSettings.EditorSettings.IndentSize = int(value) + case float64: + p.FormatCodeSettings.EditorSettings.IndentSize = int(value) + } + case "indentStyle": + p.FormatCodeSettings.EditorSettings.IndentStyle = parsePreferenceIndentStyle(value) + case "newLineCharacter": + if value, ok := value.(string); ok { + p.FormatCodeSettings.EditorSettings.NewLineCharacter = string(value) + } + case "tabSize": + switch value := value.(type) { + case int: + p.FormatCodeSettings.EditorSettings.TabSize = int(value) + case float64: + p.FormatCodeSettings.EditorSettings.TabSize = int(value) + } + case "trimTrailingWhitespace": + p.FormatCodeSettings.EditorSettings.TrimTrailingWhitespace = parsePreferenceTristate(value) + case "indentMultiLineObjectLiteralBeginningOnBlankLine": + p.FormatCodeSettings.IndentMultiLineObjectLiteralBeginningOnBlankLine = parsePreferenceTristate(value) + case "indentSwitchCase": + p.FormatCodeSettings.IndentSwitchCase = parsePreferenceTristate(value) + case "insertSpaceAfterCommaDelimiter": + p.FormatCodeSettings.InsertSpaceAfterCommaDelimiter = parsePreferenceTristate(value) + case "insertSpaceAfterConstructor": + p.FormatCodeSettings.InsertSpaceAfterConstructor = parsePreferenceTristate(value) + case "insertSpaceAfterFunctionKeywordForAnonymousFunctions": + p.FormatCodeSettings.InsertSpaceAfterFunctionKeywordForAnonymousFunctions = parsePreferenceTristate(value) + case "insertSpaceAfterKeywordsInControlFlowStatements": + p.FormatCodeSettings.InsertSpaceAfterKeywordsInControlFlowStatements = parsePreferenceTristate(value) + case "insertSpaceAfterOpeningAndBeforeClosingEmptyBraces": + p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingEmptyBraces = parsePreferenceTristate(value) + case "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": + p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces = parsePreferenceTristate(value) + case "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": + p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingNonemptyBraces = parsePreferenceTristate(value) + case "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": + p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets = parsePreferenceTristate(value) + case "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": + p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = parsePreferenceTristate(value) + case "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": + p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces = parsePreferenceTristate(value) + case "insertSpaceAfterSemicolonInForStatements": + p.FormatCodeSettings.InsertSpaceAfterSemicolonInForStatements = parsePreferenceTristate(value) + case "insertSpaceAfterTypeAssertion": + p.FormatCodeSettings.InsertSpaceAfterTypeAssertion = parsePreferenceTristate(value) + case "insertSpaceBeforeAndAfterBinaryOperators": + p.FormatCodeSettings.InsertSpaceBeforeAndAfterBinaryOperators = parsePreferenceTristate(value) + case "insertSpaceBeforeFunctionParenthesis": + p.FormatCodeSettings.InsertSpaceBeforeFunctionParenthesis = parsePreferenceTristate(value) + case "insertSpaceBeforeTypeAnnotation": + p.FormatCodeSettings.InsertSpaceBeforeTypeAnnotation = parsePreferenceTristate(value) + case "placeOpenBraceOnNewLineForControlBlocks": + p.FormatCodeSettings.PlaceOpenBraceOnNewLineForControlBlocks = parsePreferenceTristate(value) + case "placeOpenBraceOnNewLineForFunctions": + p.FormatCodeSettings.PlaceOpenBraceOnNewLineForFunctions = parsePreferenceTristate(value) + case "semicolons": + p.FormatCodeSettings.Semicolons = parsePreferenceSemicolonPreference(value) + case "includeAutomaticOptionalChainCompletions": + p.CompletionPreferences.IncludeAutomaticOptionalChainCompletions = parsePreferenceTristate(value) + case "includeCompletionsForImportStatements": + p.CompletionPreferences.IncludeCompletionsForImportStatements = parsePreferenceTristate(value) + case "includeCompletionsForModuleExports": + p.CompletionPreferences.IncludeCompletionsForModuleExports = parsePreferenceTristate(value) + case "includeCompletionsWithClassMemberSnippets": + p.CompletionPreferences.IncludeCompletionsWithClassMemberSnippets = parsePreferenceTristate(value) + case "includeCompletionsWithObjectLiteralMethodSnippets": + p.CompletionPreferences.IncludeCompletionsWithObjectLiteralMethodSnippets = parsePreferenceTristate(value) + case "jsxAttributeCompletionStyle": + p.CompletionPreferences.JsxAttributeCompletionStyle = parsePreferenceJsxAttributeCompletionStyle(value) + case "includeInlayEnumMemberValueHints": + p.InlayHintsPreferences.IncludeInlayEnumMemberValueHints = parsePreferenceTristate(value) + case "includeInlayFunctionLikeReturnTypeHints": + p.InlayHintsPreferences.IncludeInlayFunctionLikeReturnTypeHints = parsePreferenceTristate(value) + case "includeInlayFunctionParameterTypeHints": + p.InlayHintsPreferences.IncludeInlayFunctionParameterTypeHints = parsePreferenceTristate(value) + case "includeInlayParameterNameHints": + p.InlayHintsPreferences.IncludeInlayParameterNameHints = parsePreferenceIncludeInlayParameterNameHints(value) + case "includeInlayParameterNameHintsWhenArgumentMatchesName": + p.InlayHintsPreferences.IncludeInlayParameterNameHintsWhenArgumentMatchesName = parsePreferenceTristate(value) + case "includeInlayPropertyDeclarationTypeHints": + p.InlayHintsPreferences.IncludeInlayPropertyDeclarationTypeHints = parsePreferenceTristate(value) + case "includeInlayVariableTypeHints": + p.InlayHintsPreferences.IncludeInlayVariableTypeHints = parsePreferenceTristate(value) + case "includeInlayVariableTypeHintsWhenTypeMatchesName": + p.InlayHintsPreferences.IncludeInlayVariableTypeHintsWhenTypeMatchesName = parsePreferenceTristate(value) + case "implementationsCodeLensEnabled": + p.CodeLensUserPreferences.ImplementationsCodeLensEnabled = parsePreferenceTristate(value) + case "implementationsCodeLensShowOnAllClassMethods": + p.CodeLensUserPreferences.ImplementationsCodeLensShowOnAllClassMethods = parsePreferenceTristate(value) + case "implementationsCodeLensShowOnInterfaceMethods": + p.CodeLensUserPreferences.ImplementationsCodeLensShowOnInterfaceMethods = parsePreferenceTristate(value) + case "referencesCodeLensEnabled": + p.CodeLensUserPreferences.ReferencesCodeLensEnabled = parsePreferenceTristate(value) + case "referencesCodeLensShowOnAllFunctions": + p.CodeLensUserPreferences.ReferencesCodeLensShowOnAllFunctions = parsePreferenceTristate(value) + case "allowRenameOfImportPath": + p.AllowRenameOfImportPath = parsePreferenceTristate(value) + case "allowTextChangesInNewFiles": + p.AllowTextChangesInNewFiles = parsePreferenceTristate(value) + case "autoClosingTags": + p.AutoClosingTags = parsePreferenceTristate(value) + case "autoImportEntrypointDirectorySearch": + p.AutoImportEntrypointDirectorySearch = parsePreferenceTristate(value) + case "autoImportFileExcludePatterns": + if values, ok := value.([]any); ok { + result := make([]string, 0, len(values)) + for _, value := range values { + if value, ok := value.(string); ok { + result = append(result, value) + } + } + p.AutoImportFileExcludePatterns = result + } + case "autoImportSpecifierExcludeRegexes": + if values, ok := value.([]any); ok { + result := make([]string, 0, len(values)) + for _, value := range values { + if value, ok := value.(string); ok { + result = append(result, value) + } + } + p.AutoImportSpecifierExcludeRegexes = result + } + case "automaticTypeAcquisitionEnabled": + p.AutomaticTypeAcquisitionEnabled = parsePreferenceTristate(value) + case "completeJSDocs": + p.CompleteJSDocs = parsePreferenceTristate(value) + case "customConfigFileName": + if value, ok := value.(string); ok { + p.CustomConfigFileName = string(value) + } + case "disableAutomaticTypeAcquisition": + p.DisableAutomaticTypeAcquisition = parsePreferenceTristate(value) + case "disableLineTextInReferences": + p.DisableLineTextInReferences = parsePreferenceTristate(value) + case "disableSuggestions": + p.DisableSuggestions = parsePreferenceTristate(value) + case "displayPartsForJSDoc": + p.DisplayPartsForJSDoc = parsePreferenceTristate(value) + case "excludeLibrarySymbolsInNavTo": + p.ExcludeLibrarySymbolsInNavTo = parsePreferenceTristate(value) + case "formatEnabled": + p.FormatEnabled = parsePreferenceTristate(value) + case "generateReturnInDocTemplate": + p.GenerateReturnInDocTemplate = parsePreferenceTristate(value) + case "importModuleSpecifierEnding": + p.ImportModuleSpecifierEnding = parsePreferenceImportModuleSpecifierEndingPreference(value) + case "importModuleSpecifierPreference": + p.ImportModuleSpecifierPreference = parsePreferenceImportModuleSpecifierPreference(value) + case "lazyConfiguredProjectsFromExternalProject": + p.LazyConfiguredProjectsFromExternalProject = parsePreferenceTristate(value) + case "locale": + if value, ok := value.(string); ok { + p.Locale = string(value) + } + case "maximumHoverLength": + switch value := value.(type) { + case int: + p.MaximumHoverLength = int(value) + case float64: + p.MaximumHoverLength = int(value) + } + case "organizeImportsAccentCollation": + p.OrganizeImportsAccentCollation = parsePreferenceTristate(value) + case "organizeImportsCaseFirst": + p.OrganizeImportsCaseFirst = parsePreferenceOrganizeImportsCaseFirst(value) + case "organizeImportsCollation": + p.OrganizeImportsCollation = parsePreferenceOrganizeImportsCollation(value) + case "organizeImportsIgnoreCase": + p.OrganizeImportsIgnoreCase = parsePreferenceTristate(value) + case "organizeImportsLocale": + if value, ok := value.(string); ok { + p.OrganizeImportsLocale = string(value) + } + case "organizeImportsNumericCollation": + p.OrganizeImportsNumericCollation = parsePreferenceTristate(value) + case "organizeImportsSort": + p.OrganizeImportsSort = parsePreferenceOrganizeImportsSort(value) + case "organizeImportsTypeOrder": + p.OrganizeImportsTypeOrder = parsePreferenceOrganizeImportsTypeOrder(value) + case "preferGoToSourceDefinition": + if value, ok := value.(bool); ok { + p.PreferGoToSourceDefinition = bool(value) + } + case "preferTypeOnlyAutoImports": + p.PreferTypeOnlyAutoImports = parsePreferenceTristate(value) + case "providePrefixAndSuffixTextForRename": + p.ProvidePrefixAndSuffixTextForRename = parsePreferenceTristate(value) + case "provideRefactorNotApplicableReason": + p.ProvideRefactorNotApplicableReason = parsePreferenceTristate(value) + case "quotePreference": + p.QuotePreference = parsePreferenceQuotePreference(value) + case "reportStyleChecksAsWarnings": + p.ReportStyleChecksAsWarnings = parsePreferenceTristate(value) + case "validateEnabled": + p.ValidateEnabled = parsePreferenceTristate(value) + case "workspaceSymbolsScope": + p.WorkspaceSymbolsScope = parsePreferenceWorkspaceSymbolsScope(value) + } + } +} + +func (p *CompletionPreferences) applyRawPreferences(settings map[string]any) { + for name, value := range settings { + if value == nil { + continue + } + switch name { + case "includeAutomaticOptionalChainCompletions": + p.IncludeAutomaticOptionalChainCompletions = parsePreferenceTristate(value) + case "includeCompletionsForImportStatements": + p.IncludeCompletionsForImportStatements = parsePreferenceTristate(value) + case "includeCompletionsForModuleExports": + p.IncludeCompletionsForModuleExports = parsePreferenceTristate(value) + case "includeCompletionsWithClassMemberSnippets": + p.IncludeCompletionsWithClassMemberSnippets = parsePreferenceTristate(value) + case "includeCompletionsWithObjectLiteralMethodSnippets": + p.IncludeCompletionsWithObjectLiteralMethodSnippets = parsePreferenceTristate(value) + case "jsxAttributeCompletionStyle": + p.JsxAttributeCompletionStyle = parsePreferenceJsxAttributeCompletionStyle(value) + } + } +} + +func (p UserPreferences) withConfig(config map[string]any) UserPreferences { + p.applyRawPreferences(config) + if unstable, ok := config["unstable"].(map[string]any); ok { + p.applyRawPreferences(unstable) + } + if value, ok := getPreferenceConfigValue(config, "format.baseIndentSize"); ok { + if value != nil { + switch value := value.(type) { + case int: + p.FormatCodeSettings.EditorSettings.BaseIndentSize = int(value) + case float64: + p.FormatCodeSettings.EditorSettings.BaseIndentSize = int(value) + } + } + } + if value, ok := getPreferenceConfigValue(config, "format.convertTabsToSpaces"); ok { + if value != nil { + p.FormatCodeSettings.EditorSettings.ConvertTabsToSpaces = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.indentSize"); ok { + if value != nil { + switch value := value.(type) { + case int: + p.FormatCodeSettings.EditorSettings.IndentSize = int(value) + case float64: + p.FormatCodeSettings.EditorSettings.IndentSize = int(value) + } + } + } + if value, ok := getPreferenceConfigValue(config, "format.indentStyle"); ok { + if value != nil { + p.FormatCodeSettings.EditorSettings.IndentStyle = parsePreferenceIndentStyle(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.newLineCharacter"); ok { + if value != nil { + if value, ok := value.(string); ok { + p.FormatCodeSettings.EditorSettings.NewLineCharacter = string(value) + } + } + } + if value, ok := getPreferenceConfigValue(config, "format.tabSize"); ok { + if value != nil { + switch value := value.(type) { + case int: + p.FormatCodeSettings.EditorSettings.TabSize = int(value) + case float64: + p.FormatCodeSettings.EditorSettings.TabSize = int(value) + } + } + } + if value, ok := getPreferenceConfigValue(config, "format.trimTrailingWhitespace"); ok { + if value != nil { + p.FormatCodeSettings.EditorSettings.TrimTrailingWhitespace = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.indentMultiLineObjectLiteralBeginningOnBlankLine"); ok { + if value != nil { + p.FormatCodeSettings.IndentMultiLineObjectLiteralBeginningOnBlankLine = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.indentSwitchCase"); ok { + if value != nil { + p.FormatCodeSettings.IndentSwitchCase = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.insertSpaceAfterCommaDelimiter"); ok { + if value != nil { + p.FormatCodeSettings.InsertSpaceAfterCommaDelimiter = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.insertSpaceAfterConstructor"); ok { + if value != nil { + p.FormatCodeSettings.InsertSpaceAfterConstructor = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions"); ok { + if value != nil { + p.FormatCodeSettings.InsertSpaceAfterFunctionKeywordForAnonymousFunctions = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.insertSpaceAfterKeywordsInControlFlowStatements"); ok { + if value != nil { + p.FormatCodeSettings.InsertSpaceAfterKeywordsInControlFlowStatements = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces"); ok { + if value != nil { + p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingEmptyBraces = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"); ok { + if value != nil { + p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"); ok { + if value != nil { + p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingNonemptyBraces = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"); ok { + if value != nil { + p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"); ok { + if value != nil { + p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"); ok { + if value != nil { + p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.insertSpaceAfterSemicolonInForStatements"); ok { + if value != nil { + p.FormatCodeSettings.InsertSpaceAfterSemicolonInForStatements = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.insertSpaceAfterTypeAssertion"); ok { + if value != nil { + p.FormatCodeSettings.InsertSpaceAfterTypeAssertion = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.insertSpaceBeforeAndAfterBinaryOperators"); ok { + if value != nil { + p.FormatCodeSettings.InsertSpaceBeforeAndAfterBinaryOperators = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.insertSpaceBeforeFunctionParenthesis"); ok { + if value != nil { + p.FormatCodeSettings.InsertSpaceBeforeFunctionParenthesis = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.insertSpaceBeforeTypeAnnotation"); ok { + if value != nil { + p.FormatCodeSettings.InsertSpaceBeforeTypeAnnotation = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.placeOpenBraceOnNewLineForControlBlocks"); ok { + if value != nil { + p.FormatCodeSettings.PlaceOpenBraceOnNewLineForControlBlocks = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.placeOpenBraceOnNewLineForFunctions"); ok { + if value != nil { + p.FormatCodeSettings.PlaceOpenBraceOnNewLineForFunctions = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.semicolons"); ok { + if value != nil { + p.FormatCodeSettings.Semicolons = parsePreferenceSemicolonPreference(value) + } + } + if value, ok := getPreferenceConfigValue(config, "suggest.includeAutomaticOptionalChainCompletions"); ok { + if value != nil { + p.CompletionPreferences.IncludeAutomaticOptionalChainCompletions = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "suggest.includeCompletionsForImportStatements"); ok { + if value != nil { + p.CompletionPreferences.IncludeCompletionsForImportStatements = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "suggest.autoImports"); ok { + if value != nil { + p.CompletionPreferences.IncludeCompletionsForModuleExports = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "suggest.classMemberSnippets.enabled"); ok { + if value != nil { + p.CompletionPreferences.IncludeCompletionsWithClassMemberSnippets = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "suggest.objectLiteralMethodSnippets.enabled"); ok { + if value != nil { + p.CompletionPreferences.IncludeCompletionsWithObjectLiteralMethodSnippets = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "preferences.jsxAttributeCompletionStyle"); ok { + if value != nil { + p.CompletionPreferences.JsxAttributeCompletionStyle = parsePreferenceJsxAttributeCompletionStyle(value) + } + } + if value, ok := getPreferenceConfigValue(config, "inlayHints.enumMemberValues.enabled"); ok { + if value != nil { + p.InlayHintsPreferences.IncludeInlayEnumMemberValueHints = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "inlayHints.functionLikeReturnTypes.enabled"); ok { + if value != nil { + p.InlayHintsPreferences.IncludeInlayFunctionLikeReturnTypeHints = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "inlayHints.parameterTypes.enabled"); ok { + if value != nil { + p.InlayHintsPreferences.IncludeInlayFunctionParameterTypeHints = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "inlayHints.parameterNames.enabled"); ok { + if value != nil { + p.InlayHintsPreferences.IncludeInlayParameterNameHints = parsePreferenceIncludeInlayParameterNameHints(value) + } + } + if value, ok := getPreferenceConfigValue(config, "inlayHints.parameterNames.suppressWhenArgumentMatchesName,invert"); ok { + if value != nil { + p.InlayHintsPreferences.IncludeInlayParameterNameHintsWhenArgumentMatchesName = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "inlayHints.propertyDeclarationTypes.enabled"); ok { + if value != nil { + p.InlayHintsPreferences.IncludeInlayPropertyDeclarationTypeHints = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "inlayHints.variableTypes.enabled"); ok { + if value != nil { + p.InlayHintsPreferences.IncludeInlayVariableTypeHints = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "inlayHints.variableTypes.suppressWhenTypeMatchesName,invert"); ok { + if value != nil { + p.InlayHintsPreferences.IncludeInlayVariableTypeHintsWhenTypeMatchesName = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "implementationsCodeLens.enabled"); ok { + if value != nil { + p.CodeLensUserPreferences.ImplementationsCodeLensEnabled = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "implementationsCodeLens.showOnAllClassMethods"); ok { + if value != nil { + p.CodeLensUserPreferences.ImplementationsCodeLensShowOnAllClassMethods = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "implementationsCodeLens.showOnInterfaceMethods"); ok { + if value != nil { + p.CodeLensUserPreferences.ImplementationsCodeLensShowOnInterfaceMethods = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "referencesCodeLens.enabled"); ok { + if value != nil { + p.CodeLensUserPreferences.ReferencesCodeLensEnabled = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "referencesCodeLens.showOnAllFunctions"); ok { + if value != nil { + p.CodeLensUserPreferences.ReferencesCodeLensShowOnAllFunctions = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "autoClosingTags.enabled", "autoClosingTags"); ok { + if value != nil { + p.AutoClosingTags = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "preferences.autoImportEntrypointDirectorySearch"); ok { + if value != nil { + p.AutoImportEntrypointDirectorySearch = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "preferences.autoImportFileExcludePatterns"); ok { + if value != nil { + if values, ok := value.([]any); ok { + result := make([]string, 0, len(values)) + for _, value := range values { + if value, ok := value.(string); ok { + result = append(result, value) + } + } + p.AutoImportFileExcludePatterns = result + } + } + } + if value, ok := getPreferenceConfigValue(config, "preferences.autoImportSpecifierExcludeRegexes"); ok { + if value != nil { + if values, ok := value.([]any); ok { + result := make([]string, 0, len(values)) + for _, value := range values { + if value, ok := value.(string); ok { + result = append(result, value) + } + } + p.AutoImportSpecifierExcludeRegexes = result + } + } + } + if value, ok := getPreferenceConfigValue(config, "tsserver.automaticTypeAcquisition.enabled"); ok { + if value != nil { + p.AutomaticTypeAcquisitionEnabled = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "suggest.jsdoc.enabled", "suggest.completeJSDocs"); ok { + if value != nil { + p.CompleteJSDocs = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "customConfigFileName"); ok { + if value != nil { + if value, ok := value.(string); ok { + p.CustomConfigFileName = string(value) + } + } + } + if value, ok := getPreferenceConfigValue(config, "disableAutomaticTypeAcquisition"); ok { + if value != nil { + p.DisableAutomaticTypeAcquisition = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "workspaceSymbols.excludeLibrarySymbols"); ok { + if value != nil { + p.ExcludeLibrarySymbolsInNavTo = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "format.enabled", "format.enable"); ok { + if value != nil { + p.FormatEnabled = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "suggest.jsdoc.generateReturns"); ok { + if value != nil { + p.GenerateReturnInDocTemplate = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "preferences.importModuleSpecifierEnding"); ok { + if value != nil { + p.ImportModuleSpecifierEnding = parsePreferenceImportModuleSpecifierEndingPreference(value) + } + } + if value, ok := getPreferenceConfigValue(config, "preferences.importModuleSpecifier"); ok { + if value != nil { + p.ImportModuleSpecifierPreference = parsePreferenceImportModuleSpecifierPreference(value) + } + } + if value, ok := getPreferenceConfigValue(config, "locale"); ok { + if value != nil { + if value, ok := value.(string); ok { + p.Locale = string(value) + } + } + } + if value, ok := getPreferenceConfigValue(config, "preferences.organizeImports.accentCollation"); ok { + if value != nil { + p.OrganizeImportsAccentCollation = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "preferences.organizeImports.caseFirst"); ok { + if value != nil { + p.OrganizeImportsCaseFirst = parsePreferenceOrganizeImportsCaseFirst(value) + } + } + if value, ok := getPreferenceConfigValue(config, "preferences.organizeImports.unicodeCollation"); ok { + if value != nil { + p.OrganizeImportsCollation = parsePreferenceOrganizeImportsCollation(value) + } + } + if value, ok := getPreferenceConfigValue(config, "preferences.organizeImports.caseSensitivity"); ok { + p.OrganizeImportsIgnoreCase = parseOrganizeImportsCaseSensitivity(value) + } + if value, ok := getPreferenceConfigValue(config, "preferences.organizeImports.locale"); ok { + if value != nil { + if value, ok := value.(string); ok { + p.OrganizeImportsLocale = string(value) + } + } + } + if value, ok := getPreferenceConfigValue(config, "preferences.organizeImports.numericCollation"); ok { + if value != nil { + p.OrganizeImportsNumericCollation = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "preferences.organizeImports.sort"); ok { + if value != nil { + p.OrganizeImportsSort = parsePreferenceOrganizeImportsSort(value) + } + } + if value, ok := getPreferenceConfigValue(config, "preferences.organizeImports.typeOrder"); ok { + if value != nil { + p.OrganizeImportsTypeOrder = parsePreferenceOrganizeImportsTypeOrder(value) + } + } + if value, ok := getPreferenceConfigValue(config, "preferences.preferTypeOnlyAutoImports"); ok { + if value != nil { + p.PreferTypeOnlyAutoImports = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "preferences.useAliasesForRenames"); ok { + if value != nil { + p.ProvidePrefixAndSuffixTextForRename = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "preferences.quoteStyle"); ok { + if value != nil { + p.QuotePreference = parsePreferenceQuotePreference(value) + } + } + if value, ok := getPreferenceConfigValue(config, "reportStyleChecksAsWarnings"); ok { + if value != nil { + p.ReportStyleChecksAsWarnings = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "validate.enabled", "validate.enable"); ok { + if value != nil { + p.ValidateEnabled = parsePreferenceTristate(value) + } + } + if value, ok := getPreferenceConfigValue(config, "workspaceSymbols.scope"); ok { + if value != nil { + p.WorkspaceSymbolsScope = parsePreferenceWorkspaceSymbolsScope(value) + } + } + p.CustomConfigFileName = normalizeCustomConfigFileName(p.CustomConfigFileName) + return p +} + +func (p *CompletionPreferences) UnmarshalJSONFrom(dec *json.Decoder) error { + var settings map[string]any + if err := json.UnmarshalDecode(dec, &settings); err != nil { + return err + } + p.applyRawPreferences(settings) + return nil +} + +func (p UserPreferences) WithCompletionPreferences(overrides CompletionPreferences) UserPreferences { + if overrides.IncludeAutomaticOptionalChainCompletions.IsTrue() || overrides.IncludeAutomaticOptionalChainCompletions.IsFalse() { + p.CompletionPreferences.IncludeAutomaticOptionalChainCompletions = overrides.IncludeAutomaticOptionalChainCompletions + } + if overrides.IncludeCompletionsForImportStatements.IsTrue() || overrides.IncludeCompletionsForImportStatements.IsFalse() { + p.CompletionPreferences.IncludeCompletionsForImportStatements = overrides.IncludeCompletionsForImportStatements + } + if overrides.IncludeCompletionsForModuleExports.IsTrue() || overrides.IncludeCompletionsForModuleExports.IsFalse() { + p.CompletionPreferences.IncludeCompletionsForModuleExports = overrides.IncludeCompletionsForModuleExports + } + if overrides.IncludeCompletionsWithClassMemberSnippets.IsTrue() || overrides.IncludeCompletionsWithClassMemberSnippets.IsFalse() { + p.CompletionPreferences.IncludeCompletionsWithClassMemberSnippets = overrides.IncludeCompletionsWithClassMemberSnippets + } + if overrides.IncludeCompletionsWithObjectLiteralMethodSnippets.IsTrue() || overrides.IncludeCompletionsWithObjectLiteralMethodSnippets.IsFalse() { + p.CompletionPreferences.IncludeCompletionsWithObjectLiteralMethodSnippets = overrides.IncludeCompletionsWithObjectLiteralMethodSnippets + } + if overrides.JsxAttributeCompletionStyle != "" { + p.CompletionPreferences.JsxAttributeCompletionStyle = overrides.JsxAttributeCompletionStyle + } + return p +} + +func (p *UserPreferences) MarshalJSONTo(enc *json.Encoder) error { + config := make(map[string]any) + if p.FormatCodeSettings.EditorSettings.BaseIndentSize != 0 { + setNestedValue(config, "format.baseIndentSize", int(p.FormatCodeSettings.EditorSettings.BaseIndentSize)) + } + if p.FormatCodeSettings.EditorSettings.ConvertTabsToSpaces.IsTrue() || p.FormatCodeSettings.EditorSettings.ConvertTabsToSpaces.IsFalse() { + setNestedValue(config, "format.convertTabsToSpaces", p.FormatCodeSettings.EditorSettings.ConvertTabsToSpaces.IsTrue()) + } + if p.FormatCodeSettings.EditorSettings.IndentSize != 0 { + setNestedValue(config, "format.indentSize", int(p.FormatCodeSettings.EditorSettings.IndentSize)) + } + if p.FormatCodeSettings.EditorSettings.IndentStyle != 0 { + setNestedValue(config, "format.indentStyle", int(p.FormatCodeSettings.EditorSettings.IndentStyle)) + } + if p.FormatCodeSettings.EditorSettings.NewLineCharacter != "" { + setNestedValue(config, "format.newLineCharacter", string(p.FormatCodeSettings.EditorSettings.NewLineCharacter)) + } + if p.FormatCodeSettings.EditorSettings.TabSize != 0 { + setNestedValue(config, "format.tabSize", int(p.FormatCodeSettings.EditorSettings.TabSize)) + } + if p.FormatCodeSettings.EditorSettings.TrimTrailingWhitespace.IsTrue() || p.FormatCodeSettings.EditorSettings.TrimTrailingWhitespace.IsFalse() { + setNestedValue(config, "format.trimTrailingWhitespace", p.FormatCodeSettings.EditorSettings.TrimTrailingWhitespace.IsTrue()) + } + if p.FormatCodeSettings.IndentMultiLineObjectLiteralBeginningOnBlankLine.IsTrue() || p.FormatCodeSettings.IndentMultiLineObjectLiteralBeginningOnBlankLine.IsFalse() { + setNestedValue(config, "format.indentMultiLineObjectLiteralBeginningOnBlankLine", p.FormatCodeSettings.IndentMultiLineObjectLiteralBeginningOnBlankLine.IsTrue()) + } + if p.FormatCodeSettings.IndentSwitchCase.IsTrue() || p.FormatCodeSettings.IndentSwitchCase.IsFalse() { + setNestedValue(config, "format.indentSwitchCase", p.FormatCodeSettings.IndentSwitchCase.IsTrue()) + } + if p.FormatCodeSettings.InsertSpaceAfterCommaDelimiter.IsTrue() || p.FormatCodeSettings.InsertSpaceAfterCommaDelimiter.IsFalse() { + setNestedValue(config, "format.insertSpaceAfterCommaDelimiter", p.FormatCodeSettings.InsertSpaceAfterCommaDelimiter.IsTrue()) + } + if p.FormatCodeSettings.InsertSpaceAfterConstructor.IsTrue() || p.FormatCodeSettings.InsertSpaceAfterConstructor.IsFalse() { + setNestedValue(config, "format.insertSpaceAfterConstructor", p.FormatCodeSettings.InsertSpaceAfterConstructor.IsTrue()) + } + if p.FormatCodeSettings.InsertSpaceAfterFunctionKeywordForAnonymousFunctions.IsTrue() || p.FormatCodeSettings.InsertSpaceAfterFunctionKeywordForAnonymousFunctions.IsFalse() { + setNestedValue(config, "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions", p.FormatCodeSettings.InsertSpaceAfterFunctionKeywordForAnonymousFunctions.IsTrue()) + } + if p.FormatCodeSettings.InsertSpaceAfterKeywordsInControlFlowStatements.IsTrue() || p.FormatCodeSettings.InsertSpaceAfterKeywordsInControlFlowStatements.IsFalse() { + setNestedValue(config, "format.insertSpaceAfterKeywordsInControlFlowStatements", p.FormatCodeSettings.InsertSpaceAfterKeywordsInControlFlowStatements.IsTrue()) + } + if p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingEmptyBraces.IsTrue() || p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingEmptyBraces.IsFalse() { + setNestedValue(config, "format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces", p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingEmptyBraces.IsTrue()) + } + if p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces.IsTrue() || p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces.IsFalse() { + setNestedValue(config, "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces", p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces.IsTrue()) + } + if p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingNonemptyBraces.IsTrue() || p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingNonemptyBraces.IsFalse() { + setNestedValue(config, "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces", p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingNonemptyBraces.IsTrue()) + } + if p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets.IsTrue() || p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets.IsFalse() { + setNestedValue(config, "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets", p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets.IsTrue()) + } + if p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis.IsTrue() || p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis.IsFalse() { + setNestedValue(config, "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis", p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis.IsTrue()) + } + if p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces.IsTrue() || p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces.IsFalse() { + setNestedValue(config, "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces", p.FormatCodeSettings.InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces.IsTrue()) + } + if p.FormatCodeSettings.InsertSpaceAfterSemicolonInForStatements.IsTrue() || p.FormatCodeSettings.InsertSpaceAfterSemicolonInForStatements.IsFalse() { + setNestedValue(config, "format.insertSpaceAfterSemicolonInForStatements", p.FormatCodeSettings.InsertSpaceAfterSemicolonInForStatements.IsTrue()) + } + if p.FormatCodeSettings.InsertSpaceAfterTypeAssertion.IsTrue() || p.FormatCodeSettings.InsertSpaceAfterTypeAssertion.IsFalse() { + setNestedValue(config, "format.insertSpaceAfterTypeAssertion", p.FormatCodeSettings.InsertSpaceAfterTypeAssertion.IsTrue()) + } + if p.FormatCodeSettings.InsertSpaceBeforeAndAfterBinaryOperators.IsTrue() || p.FormatCodeSettings.InsertSpaceBeforeAndAfterBinaryOperators.IsFalse() { + setNestedValue(config, "format.insertSpaceBeforeAndAfterBinaryOperators", p.FormatCodeSettings.InsertSpaceBeforeAndAfterBinaryOperators.IsTrue()) + } + if p.FormatCodeSettings.InsertSpaceBeforeFunctionParenthesis.IsTrue() || p.FormatCodeSettings.InsertSpaceBeforeFunctionParenthesis.IsFalse() { + setNestedValue(config, "format.insertSpaceBeforeFunctionParenthesis", p.FormatCodeSettings.InsertSpaceBeforeFunctionParenthesis.IsTrue()) + } + if p.FormatCodeSettings.InsertSpaceBeforeTypeAnnotation.IsTrue() || p.FormatCodeSettings.InsertSpaceBeforeTypeAnnotation.IsFalse() { + setNestedValue(config, "format.insertSpaceBeforeTypeAnnotation", p.FormatCodeSettings.InsertSpaceBeforeTypeAnnotation.IsTrue()) + } + if p.FormatCodeSettings.PlaceOpenBraceOnNewLineForControlBlocks.IsTrue() || p.FormatCodeSettings.PlaceOpenBraceOnNewLineForControlBlocks.IsFalse() { + setNestedValue(config, "format.placeOpenBraceOnNewLineForControlBlocks", p.FormatCodeSettings.PlaceOpenBraceOnNewLineForControlBlocks.IsTrue()) + } + if p.FormatCodeSettings.PlaceOpenBraceOnNewLineForFunctions.IsTrue() || p.FormatCodeSettings.PlaceOpenBraceOnNewLineForFunctions.IsFalse() { + setNestedValue(config, "format.placeOpenBraceOnNewLineForFunctions", p.FormatCodeSettings.PlaceOpenBraceOnNewLineForFunctions.IsTrue()) + } + if p.FormatCodeSettings.Semicolons != "" { + setNestedValue(config, "format.semicolons", string(p.FormatCodeSettings.Semicolons)) + } + if p.CompletionPreferences.IncludeAutomaticOptionalChainCompletions.IsTrue() || p.CompletionPreferences.IncludeAutomaticOptionalChainCompletions.IsFalse() { + setNestedValue(config, "suggest.includeAutomaticOptionalChainCompletions", p.CompletionPreferences.IncludeAutomaticOptionalChainCompletions.IsTrue()) + } + if p.CompletionPreferences.IncludeCompletionsForImportStatements.IsTrue() || p.CompletionPreferences.IncludeCompletionsForImportStatements.IsFalse() { + setNestedValue(config, "suggest.includeCompletionsForImportStatements", p.CompletionPreferences.IncludeCompletionsForImportStatements.IsTrue()) + } + if p.CompletionPreferences.IncludeCompletionsForModuleExports.IsTrue() || p.CompletionPreferences.IncludeCompletionsForModuleExports.IsFalse() { + setNestedValue(config, "suggest.autoImports", p.CompletionPreferences.IncludeCompletionsForModuleExports.IsTrue()) + } + if p.CompletionPreferences.IncludeCompletionsWithClassMemberSnippets.IsTrue() || p.CompletionPreferences.IncludeCompletionsWithClassMemberSnippets.IsFalse() { + setNestedValue(config, "suggest.classMemberSnippets.enabled", p.CompletionPreferences.IncludeCompletionsWithClassMemberSnippets.IsTrue()) + } + if p.CompletionPreferences.IncludeCompletionsWithObjectLiteralMethodSnippets.IsTrue() || p.CompletionPreferences.IncludeCompletionsWithObjectLiteralMethodSnippets.IsFalse() { + setNestedValue(config, "suggest.objectLiteralMethodSnippets.enabled", p.CompletionPreferences.IncludeCompletionsWithObjectLiteralMethodSnippets.IsTrue()) + } + if p.CompletionPreferences.JsxAttributeCompletionStyle != "" { + setNestedValue(config, "preferences.jsxAttributeCompletionStyle", string(p.CompletionPreferences.JsxAttributeCompletionStyle)) + } + if p.InlayHintsPreferences.IncludeInlayEnumMemberValueHints.IsTrue() || p.InlayHintsPreferences.IncludeInlayEnumMemberValueHints.IsFalse() { + setNestedValue(config, "inlayHints.enumMemberValues.enabled", p.InlayHintsPreferences.IncludeInlayEnumMemberValueHints.IsTrue()) + } + if p.InlayHintsPreferences.IncludeInlayFunctionLikeReturnTypeHints.IsTrue() || p.InlayHintsPreferences.IncludeInlayFunctionLikeReturnTypeHints.IsFalse() { + setNestedValue(config, "inlayHints.functionLikeReturnTypes.enabled", p.InlayHintsPreferences.IncludeInlayFunctionLikeReturnTypeHints.IsTrue()) + } + if p.InlayHintsPreferences.IncludeInlayFunctionParameterTypeHints.IsTrue() || p.InlayHintsPreferences.IncludeInlayFunctionParameterTypeHints.IsFalse() { + setNestedValue(config, "inlayHints.parameterTypes.enabled", p.InlayHintsPreferences.IncludeInlayFunctionParameterTypeHints.IsTrue()) + } + if p.InlayHintsPreferences.IncludeInlayParameterNameHints != "" { + setNestedValue(config, "inlayHints.parameterNames.enabled", string(p.InlayHintsPreferences.IncludeInlayParameterNameHints)) + } + if p.InlayHintsPreferences.IncludeInlayParameterNameHintsWhenArgumentMatchesName.IsTrue() || p.InlayHintsPreferences.IncludeInlayParameterNameHintsWhenArgumentMatchesName.IsFalse() { + setNestedValue(config, "inlayHints.parameterNames.suppressWhenArgumentMatchesName", !p.InlayHintsPreferences.IncludeInlayParameterNameHintsWhenArgumentMatchesName.IsTrue()) + } + if p.InlayHintsPreferences.IncludeInlayPropertyDeclarationTypeHints.IsTrue() || p.InlayHintsPreferences.IncludeInlayPropertyDeclarationTypeHints.IsFalse() { + setNestedValue(config, "inlayHints.propertyDeclarationTypes.enabled", p.InlayHintsPreferences.IncludeInlayPropertyDeclarationTypeHints.IsTrue()) + } + if p.InlayHintsPreferences.IncludeInlayVariableTypeHints.IsTrue() || p.InlayHintsPreferences.IncludeInlayVariableTypeHints.IsFalse() { + setNestedValue(config, "inlayHints.variableTypes.enabled", p.InlayHintsPreferences.IncludeInlayVariableTypeHints.IsTrue()) + } + if p.InlayHintsPreferences.IncludeInlayVariableTypeHintsWhenTypeMatchesName.IsTrue() || p.InlayHintsPreferences.IncludeInlayVariableTypeHintsWhenTypeMatchesName.IsFalse() { + setNestedValue(config, "inlayHints.variableTypes.suppressWhenTypeMatchesName", !p.InlayHintsPreferences.IncludeInlayVariableTypeHintsWhenTypeMatchesName.IsTrue()) + } + if p.CodeLensUserPreferences.ImplementationsCodeLensEnabled.IsTrue() || p.CodeLensUserPreferences.ImplementationsCodeLensEnabled.IsFalse() { + setNestedValue(config, "implementationsCodeLens.enabled", p.CodeLensUserPreferences.ImplementationsCodeLensEnabled.IsTrue()) + } + if p.CodeLensUserPreferences.ImplementationsCodeLensShowOnAllClassMethods.IsTrue() || p.CodeLensUserPreferences.ImplementationsCodeLensShowOnAllClassMethods.IsFalse() { + setNestedValue(config, "implementationsCodeLens.showOnAllClassMethods", p.CodeLensUserPreferences.ImplementationsCodeLensShowOnAllClassMethods.IsTrue()) + } + if p.CodeLensUserPreferences.ImplementationsCodeLensShowOnInterfaceMethods.IsTrue() || p.CodeLensUserPreferences.ImplementationsCodeLensShowOnInterfaceMethods.IsFalse() { + setNestedValue(config, "implementationsCodeLens.showOnInterfaceMethods", p.CodeLensUserPreferences.ImplementationsCodeLensShowOnInterfaceMethods.IsTrue()) + } + if p.CodeLensUserPreferences.ReferencesCodeLensEnabled.IsTrue() || p.CodeLensUserPreferences.ReferencesCodeLensEnabled.IsFalse() { + setNestedValue(config, "referencesCodeLens.enabled", p.CodeLensUserPreferences.ReferencesCodeLensEnabled.IsTrue()) + } + if p.CodeLensUserPreferences.ReferencesCodeLensShowOnAllFunctions.IsTrue() || p.CodeLensUserPreferences.ReferencesCodeLensShowOnAllFunctions.IsFalse() { + setNestedValue(config, "referencesCodeLens.showOnAllFunctions", p.CodeLensUserPreferences.ReferencesCodeLensShowOnAllFunctions.IsTrue()) + } + if p.AllowRenameOfImportPath.IsTrue() || p.AllowRenameOfImportPath.IsFalse() { + setNestedValue(config, "unstable.allowRenameOfImportPath", p.AllowRenameOfImportPath.IsTrue()) + } + if p.AllowTextChangesInNewFiles.IsTrue() || p.AllowTextChangesInNewFiles.IsFalse() { + setNestedValue(config, "unstable.allowTextChangesInNewFiles", p.AllowTextChangesInNewFiles.IsTrue()) + } + if p.AutoClosingTags.IsTrue() || p.AutoClosingTags.IsFalse() { + setNestedValue(config, "autoClosingTags.enabled", p.AutoClosingTags.IsTrue()) + } + if p.AutoImportEntrypointDirectorySearch.IsTrue() || p.AutoImportEntrypointDirectorySearch.IsFalse() { + setNestedValue(config, "preferences.autoImportEntrypointDirectorySearch", p.AutoImportEntrypointDirectorySearch.IsTrue()) + } + if p.AutoImportFileExcludePatterns != nil { + setNestedValue(config, "preferences.autoImportFileExcludePatterns", slices.Clone(p.AutoImportFileExcludePatterns)) + } + if p.AutoImportSpecifierExcludeRegexes != nil { + setNestedValue(config, "preferences.autoImportSpecifierExcludeRegexes", slices.Clone(p.AutoImportSpecifierExcludeRegexes)) + } + if p.AutomaticTypeAcquisitionEnabled.IsTrue() || p.AutomaticTypeAcquisitionEnabled.IsFalse() { + setNestedValue(config, "tsserver.automaticTypeAcquisition.enabled", p.AutomaticTypeAcquisitionEnabled.IsTrue()) + } + if p.CompleteJSDocs.IsTrue() || p.CompleteJSDocs.IsFalse() { + setNestedValue(config, "suggest.jsdoc.enabled", p.CompleteJSDocs.IsTrue()) + } + if p.CustomConfigFileName != "" { + setNestedValue(config, "customConfigFileName", string(p.CustomConfigFileName)) + } + if p.DisableAutomaticTypeAcquisition.IsTrue() || p.DisableAutomaticTypeAcquisition.IsFalse() { + setNestedValue(config, "disableAutomaticTypeAcquisition", p.DisableAutomaticTypeAcquisition.IsTrue()) + } + if p.DisableLineTextInReferences.IsTrue() || p.DisableLineTextInReferences.IsFalse() { + setNestedValue(config, "unstable.disableLineTextInReferences", p.DisableLineTextInReferences.IsTrue()) + } + if p.DisableSuggestions.IsTrue() || p.DisableSuggestions.IsFalse() { + setNestedValue(config, "unstable.disableSuggestions", p.DisableSuggestions.IsTrue()) + } + if p.DisplayPartsForJSDoc.IsTrue() || p.DisplayPartsForJSDoc.IsFalse() { + setNestedValue(config, "unstable.displayPartsForJSDoc", p.DisplayPartsForJSDoc.IsTrue()) + } + if p.ExcludeLibrarySymbolsInNavTo.IsTrue() || p.ExcludeLibrarySymbolsInNavTo.IsFalse() { + setNestedValue(config, "workspaceSymbols.excludeLibrarySymbols", p.ExcludeLibrarySymbolsInNavTo.IsTrue()) + } + if p.FormatEnabled.IsTrue() || p.FormatEnabled.IsFalse() { + setNestedValue(config, "format.enabled", p.FormatEnabled.IsTrue()) + } + if p.GenerateReturnInDocTemplate.IsTrue() || p.GenerateReturnInDocTemplate.IsFalse() { + setNestedValue(config, "suggest.jsdoc.generateReturns", p.GenerateReturnInDocTemplate.IsTrue()) + } + if p.ImportModuleSpecifierEnding != "" { + setNestedValue(config, "preferences.importModuleSpecifierEnding", string(p.ImportModuleSpecifierEnding)) + } + if p.ImportModuleSpecifierPreference != "" { + setNestedValue(config, "preferences.importModuleSpecifier", string(p.ImportModuleSpecifierPreference)) + } + if p.LazyConfiguredProjectsFromExternalProject.IsTrue() || p.LazyConfiguredProjectsFromExternalProject.IsFalse() { + setNestedValue(config, "unstable.lazyConfiguredProjectsFromExternalProject", p.LazyConfiguredProjectsFromExternalProject.IsTrue()) + } + if p.Locale != "" { + setNestedValue(config, "locale", string(p.Locale)) + } + if p.MaximumHoverLength != 0 { + setNestedValue(config, "unstable.maximumHoverLength", int(p.MaximumHoverLength)) + } + if p.OrganizeImportsAccentCollation.IsTrue() || p.OrganizeImportsAccentCollation.IsFalse() { + setNestedValue(config, "preferences.organizeImports.accentCollation", p.OrganizeImportsAccentCollation.IsTrue()) + } + setNestedValue(config, "preferences.organizeImports.caseFirst", serializePreferenceOrganizeImportsCaseFirst(p.OrganizeImportsCaseFirst)) + setNestedValue(config, "preferences.organizeImports.unicodeCollation", serializePreferenceOrganizeImportsCollation(p.OrganizeImportsCollation)) + if p.OrganizeImportsIgnoreCase.IsTrue() || p.OrganizeImportsIgnoreCase.IsFalse() { + setNestedValue(config, "preferences.organizeImports.caseSensitivity", p.OrganizeImportsIgnoreCase.IsTrue()) + } + if p.OrganizeImportsLocale != "" { + setNestedValue(config, "preferences.organizeImports.locale", string(p.OrganizeImportsLocale)) + } + if p.OrganizeImportsNumericCollation.IsTrue() || p.OrganizeImportsNumericCollation.IsFalse() { + setNestedValue(config, "preferences.organizeImports.numericCollation", p.OrganizeImportsNumericCollation.IsTrue()) + } + setNestedValue(config, "preferences.organizeImports.sort", serializePreferenceOrganizeImportsSort(p.OrganizeImportsSort)) + setNestedValue(config, "preferences.organizeImports.typeOrder", serializePreferenceOrganizeImportsTypeOrder(p.OrganizeImportsTypeOrder)) + setNestedValue(config, "unstable.preferGoToSourceDefinition", p.PreferGoToSourceDefinition) + if p.PreferTypeOnlyAutoImports.IsTrue() || p.PreferTypeOnlyAutoImports.IsFalse() { + setNestedValue(config, "preferences.preferTypeOnlyAutoImports", p.PreferTypeOnlyAutoImports.IsTrue()) + } + if p.ProvidePrefixAndSuffixTextForRename.IsTrue() || p.ProvidePrefixAndSuffixTextForRename.IsFalse() { + setNestedValue(config, "preferences.useAliasesForRenames", p.ProvidePrefixAndSuffixTextForRename.IsTrue()) + } + if p.ProvideRefactorNotApplicableReason.IsTrue() || p.ProvideRefactorNotApplicableReason.IsFalse() { + setNestedValue(config, "unstable.provideRefactorNotApplicableReason", p.ProvideRefactorNotApplicableReason.IsTrue()) + } + if p.QuotePreference != "" { + setNestedValue(config, "preferences.quoteStyle", string(p.QuotePreference)) + } + if p.ReportStyleChecksAsWarnings.IsTrue() || p.ReportStyleChecksAsWarnings.IsFalse() { + setNestedValue(config, "reportStyleChecksAsWarnings", p.ReportStyleChecksAsWarnings.IsTrue()) + } + if p.ValidateEnabled.IsTrue() || p.ValidateEnabled.IsFalse() { + setNestedValue(config, "validate.enabled", p.ValidateEnabled.IsTrue()) + } + if p.WorkspaceSymbolsScope != "" { + setNestedValue(config, "workspaceSymbols.scope", string(p.WorkspaceSymbolsScope)) + } + return json.MarshalEncode(enc, config, json.Deterministic(true)) +} diff --git a/tsc/internal/ls/lsutil/userpreferences_test.go b/tsc/internal/ls/lsutil/userpreferences_test.go index 0ff3cb7bff647..403b347ddaafc 100644 --- a/tsc/internal/ls/lsutil/userpreferences_test.go +++ b/tsc/internal/ls/lsutil/userpreferences_test.go @@ -19,6 +19,98 @@ func TestCompletionPreferencesUnmarshal(t *testing.T) { userPreferences := NewDefaultUserPreferences().WithCompletionPreferences(preferences) assert.Equal(t, userPreferences.IncludeCompletionsForModuleExports, core.TSFalse) assert.Equal(t, userPreferences.IncludeCompletionsForImportStatements, core.TSTrue) + userPreferences = userPreferences.WithCompletionPreferences(CompletionPreferences{ + IncludeCompletionsForModuleExports: core.Tristate(99), + }) + assert.Equal(t, userPreferences.IncludeCompletionsForModuleExports, core.TSFalse) +} + +func TestUserPreferencesParsingEdgeCases(t *testing.T) { + t.Parallel() + tests := []struct { + name string + config map[string]any + expected func(*UserPreferences) + }{ + { + name: "null raw values leave preferences unchanged", + config: map[string]any{ + "quotePreference": nil, "maximumHoverLength": nil, "includeCompletionsForModuleExports": nil, + }, + expected: func(*UserPreferences) {}, + }, + { + name: "invalid boolean becomes unknown", + config: map[string]any{"includeCompletionsForModuleExports": "invalid"}, + expected: func(p *UserPreferences) { p.IncludeCompletionsForModuleExports = core.TSUnknown }, + }, + { + name: "case-insensitive enums", + config: map[string]any{ + "quotePreference": "SINGLE", "jsxAttributeCompletionStyle": "BRACES", + "organizeImportsCaseFirst": "LOWER", "includeInlayParameterNameHints": "ALL", + "organizeImportsTypeOrder": "FIRST", "workspaceSymbolsScope": "CURRENTPROJECT", + }, + expected: func(p *UserPreferences) { + p.QuotePreference = QuotePreferenceSingle + p.JsxAttributeCompletionStyle = JsxAttributeCompletionStyleBraces + p.OrganizeImportsCaseFirst = OrganizeImportsCaseFirstLower + p.InlayHintsPreferences.IncludeInlayParameterNameHints = IncludeInlayParameterNameHintsAll + p.OrganizeImportsTypeOrder = OrganizeImportsTypeOrderFirst + p.WorkspaceSymbolsScope = WorkspaceSymbolsScopeCurrentProject + }, + }, + { + name: "present null primary path prevents fallback", + config: map[string]any{ + "suggest": map[string]any{"jsdoc": map[string]any{"enabled": nil}, "completeJSDocs": false}, + }, + expected: func(*UserPreferences) {}, + }, + { + name: "null case sensitivity becomes unknown", + config: map[string]any{ + "preferences": map[string]any{"organizeImports": map[string]any{"caseSensitivity": nil}}, + }, + expected: func(p *UserPreferences) { p.OrganizeImportsIgnoreCase = core.TSUnknown }, + }, + { + name: "numeric conversion and array filtering", + config: map[string]any{ + "maximumHoverLength": float64(9.8), "indentStyle": float64(1.7), + "autoImportFileExcludePatterns": []any{"first", false, 3, "second"}, + }, + expected: func(p *UserPreferences) { + p.MaximumHoverLength = 9 + p.IndentStyle = IndentStyleBlock + p.AutoImportFileExcludePatterns = []string{"first", "second"} + }, + }, + { + name: "empty array is not nil", + config: map[string]any{"autoImportFileExcludePatterns": []any{}}, + expected: func(p *UserPreferences) { p.AutoImportFileExcludePatterns = []string{} }, + }, + { + name: "invalid module specifier preference uses its default", + config: map[string]any{"importModuleSpecifierPreference": true}, + expected: func(p *UserPreferences) { + p.ImportModuleSpecifierPreference = modulespecifiers.ImportModuleSpecifierPreferenceShortest + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + base := NewDefaultUserPreferences() + base.QuotePreference = QuotePreferenceDouble + base.MaximumHoverLength = 17 + base.OrganizeImportsIgnoreCase = core.TSTrue + expected := base + test.expected(&expected) + assert.DeepEqual(t, base.withConfig(test.config), expected) + }) + } } func fillNonZeroValues(v reflect.Value) { @@ -53,6 +145,8 @@ func getValidStringValue(t reflect.Type) string { switch typeName { case "lsutil.QuotePreference": return string(QuotePreferenceSingle) + case "lsutil.WorkspaceSymbolsScope": + return string(WorkspaceSymbolsScopeAllOpenProjects) case "lsutil.JsxAttributeCompletionStyle": return string(JsxAttributeCompletionStyleBraces) case "lsutil.IncludeInlayParameterNameHints": @@ -133,10 +227,8 @@ func TestUserPreferencesSerialize(t *testing.T) { t.Run("inlay hint inversion on serialize", func(t *testing.T) { t.Parallel() prefs := &UserPreferences{ - InlayHints: InlayHintsPreferences{ - IncludeInlayParameterNameHints: IncludeInlayParameterNameHintsAll, - IncludeInlayParameterNameHintsWhenArgumentMatchesName: core.TSTrue, - }, + IncludeInlayParameterNameHints: IncludeInlayParameterNameHintsAll, + IncludeInlayParameterNameHintsWhenArgumentMatchesName: core.TSTrue, } jsonBytes, err := json.Marshal(prefs) assert.NilError(t, err) @@ -206,8 +298,8 @@ func TestUserPreferencesParseUnstable(t *testing.T) { } }`, expected: UserPreferences{ - QuotePreference: QuotePreferenceSingle, - UseAliasesForRename: core.TSTrue, + QuotePreference: QuotePreferenceSingle, + ProvidePrefixAndSuffixTextForRename: core.TSTrue, }, }, { @@ -234,7 +326,7 @@ func TestUserPreferencesParseUnstable(t *testing.T) { } }`, expected: UserPreferences{ - InlayHints: InlayHintsPreferences{ + InlayHintsPreferences: InlayHintsPreferences{ IncludeInlayParameterNameHints: IncludeInlayParameterNameHintsAll, IncludeInlayParameterNameHintsWhenArgumentMatchesName: core.TSFalse, // inverted }, @@ -313,11 +405,11 @@ func TestUserPreferencesParseUnstable(t *testing.T) { } }`, expected: UserPreferences{ - IncludeCompletionsForModuleExports: core.TSTrue, - QuotePreference: QuotePreferenceSingle, - UseAliasesForRename: core.TSTrue, - OrganizeImportsLocale: "en", - InlayHints: InlayHintsPreferences{ + IncludeCompletionsForModuleExports: core.TSTrue, + QuotePreference: QuotePreferenceSingle, + ProvidePrefixAndSuffixTextForRename: core.TSTrue, + OrganizeImportsLocale: "en", + InlayHintsPreferences: InlayHintsPreferences{ IncludeInlayParameterNameHints: IncludeInlayParameterNameHintsAll, }, }, @@ -498,9 +590,9 @@ func TestUserPreferencesParseServerFeaturePreferences(t *testing.T) { }, }, }) - assert.Equal(t, prefs.EnableValidation, core.TSFalse) - assert.Equal(t, prefs.EnableFormatting, core.TSFalse) - assert.Equal(t, prefs.EnableAutoClosingTags, core.TSFalse) + assert.Equal(t, prefs.ValidateEnabled, core.TSFalse) + assert.Equal(t, prefs.FormatEnabled, core.TSFalse) + assert.Equal(t, prefs.AutoClosingTags, core.TSFalse) }) t.Run("legacy server feature fallbacks", func(t *testing.T) { @@ -512,9 +604,9 @@ func TestUserPreferencesParseServerFeaturePreferences(t *testing.T) { "autoClosingTags": false, }, }) - assert.Equal(t, prefs.EnableValidation, core.TSFalse) - assert.Equal(t, prefs.EnableFormatting, core.TSFalse) - assert.Equal(t, prefs.EnableAutoClosingTags, core.TSFalse) + assert.Equal(t, prefs.ValidateEnabled, core.TSFalse) + assert.Equal(t, prefs.FormatEnabled, core.TSFalse) + assert.Equal(t, prefs.AutoClosingTags, core.TSFalse) }) t.Run("preferred settings take precedence over fallbacks", func(t *testing.T) { @@ -533,9 +625,9 @@ func TestUserPreferencesParseServerFeaturePreferences(t *testing.T) { }, }, }) - assert.Equal(t, prefs.EnableValidation, core.TSTrue) - assert.Equal(t, prefs.EnableFormatting, core.TSTrue) - assert.Equal(t, prefs.EnableAutoClosingTags, core.TSTrue) + assert.Equal(t, prefs.ValidateEnabled, core.TSTrue) + assert.Equal(t, prefs.FormatEnabled, core.TSTrue) + assert.Equal(t, prefs.AutoClosingTags, core.TSTrue) }) } @@ -568,7 +660,7 @@ func TestUserPreferencesParseJSDocCompletionPreferences(t *testing.T) { }, }, }) - assert.Equal(t, prefs.EnableJSDocCompletions, core.TSFalse) + assert.Equal(t, prefs.CompleteJSDocs, core.TSFalse) }) t.Run("language fallback completeJSDocs setting", func(t *testing.T) { @@ -580,7 +672,7 @@ func TestUserPreferencesParseJSDocCompletionPreferences(t *testing.T) { }, }, }) - assert.Equal(t, prefs.EnableJSDocCompletions, core.TSFalse) + assert.Equal(t, prefs.CompleteJSDocs, core.TSFalse) }) t.Run("unified jsdoc enabled takes precedence over language fallback", func(t *testing.T) { @@ -599,7 +691,7 @@ func TestUserPreferencesParseJSDocCompletionPreferences(t *testing.T) { }, }, }) - assert.Equal(t, prefs.EnableJSDocCompletions, core.TSTrue) + assert.Equal(t, prefs.CompleteJSDocs, core.TSTrue) }) t.Run("unified jsdoc generateReturns setting", func(t *testing.T) { diff --git a/tsc/internal/ls/rename.go b/tsc/internal/ls/rename.go index 9aa51be791e34..912d53f74d6f5 100644 --- a/tsc/internal/ls/rename.go +++ b/tsc/internal/ls/rename.go @@ -116,7 +116,7 @@ func (l *LanguageService) symbolAndEntriesToRename(ctx context.Context, params * defer done() quotePreference := lsutil.GetQuotePreference(sourceFile, l.UserPreferences()) - useAliasesForRename := l.UserPreferences().UseAliasesForRename.IsTrueOrUnknown() + useAliasesForRename := l.UserPreferences().ProvidePrefixAndSuffixTextForRename.IsTrueOrUnknown() for _, entry := range entries { uri := l.getFileNameOfEntry(entry) @@ -254,7 +254,7 @@ func isDefinedInLibraryFile(program *compiler.Program, declaration *ast.Node) bo // wouldRenameInOtherNodeModules checks if renaming the symbol would affect node_modules. func wouldRenameInOtherNodeModules(originalFile *ast.SourceFile, symbol *ast.Symbol, ch *checker.Checker, preferences lsutil.UserPreferences) *diagnostics.Message { sym := symbol - if !preferences.UseAliasesForRename.IsTrueOrUnknown() && sym.Flags&ast.SymbolFlagsAlias != 0 { + if !preferences.ProvidePrefixAndSuffixTextForRename.IsTrueOrUnknown() && sym.Flags&ast.SymbolFlagsAlias != 0 { importSpecifier := core.Find(sym.Declarations, ast.IsImportSpecifier) if importSpecifier != nil && importSpecifier.AsImportSpecifier().PropertyName == nil { sym = ch.GetAliasedSymbol(sym) diff --git a/tsc/internal/project/project_test.go b/tsc/internal/project/project_test.go index de28824783d22..042cb34d0b81e 100644 --- a/tsc/internal/project/project_test.go +++ b/tsc/internal/project/project_test.go @@ -552,7 +552,7 @@ func TestPushDiagnostics(t *testing.T) { } session, utils := projecttestutil.Setup(files) prefs := lsutil.NewDefaultUserPreferences() - prefs.EnableValidation = core.TSFalse + prefs.ValidateEnabled = core.TSFalse session.Configure(prefs) session.DidOpenFile(context.Background(), "file:///src/index.ts", 1, files["/src/index.ts"].(string), lsproto.LanguageKindTypeScript) _, err := session.GetLanguageService(context.Background(), lsproto.DocumentUri("file:///src/index.ts")) @@ -587,7 +587,7 @@ func TestPushDiagnostics(t *testing.T) { assert.Assert(t, len(tsconfigCalls[len(tsconfigCalls)-1].Params.Diagnostics) > 0, "expected initial diagnostics") prefs := lsutil.NewDefaultUserPreferences() - prefs.EnableValidation = core.TSFalse + prefs.ValidateEnabled = core.TSFalse session.Configure(prefs) _, err = session.GetLanguageService(context.Background(), lsproto.DocumentUri("file:///src/index.ts")) assert.NilError(t, err) diff --git a/tsc/internal/project/session.go b/tsc/internal/project/session.go index 08585aa678b49..796e3f8630eaf 100644 --- a/tsc/internal/project/session.go +++ b/tsc/internal/project/session.go @@ -1829,7 +1829,7 @@ func (s *Session) NpmInstall(cwd string, npmInstallArgs []string) ([]byte, error } func (s *Session) refreshInlayHintsIfNeeded(oldPrefs lsutil.UserPreferences, newPrefs lsutil.UserPreferences) { - if oldPrefs.InlayHints != newPrefs.InlayHints { + if oldPrefs.InlayHintsPreferences != newPrefs.InlayHintsPreferences { if err := s.client.RefreshInlayHints(s.backgroundContext()); err != nil && s.options.LoggingEnabled { s.logger.Logf("Error refreshing inlay hints: %v", err) } @@ -1837,7 +1837,7 @@ func (s *Session) refreshInlayHintsIfNeeded(oldPrefs lsutil.UserPreferences, new } func (s *Session) refreshCodeLensIfNeeded(oldPrefs lsutil.UserPreferences, newPrefs lsutil.UserPreferences) { - if oldPrefs.CodeLens != newPrefs.CodeLens { + if oldPrefs.CodeLensUserPreferences != newPrefs.CodeLensUserPreferences { if err := s.client.RefreshCodeLens(s.backgroundContext()); err != nil && s.options.LoggingEnabled { s.logger.Logf("Error refreshing code lens: %v", err) } @@ -1847,7 +1847,7 @@ func (s *Session) refreshCodeLensIfNeeded(oldPrefs lsutil.UserPreferences, newPr func (s *Session) refreshDiagnosticsIfNeeded(oldPrefs lsutil.UserPreferences, newPrefs lsutil.UserPreferences) { if oldPrefs.CustomConfigFileName != newPrefs.CustomConfigFileName || oldPrefs.ReportStyleChecksAsWarnings != newPrefs.ReportStyleChecksAsWarnings || - oldPrefs.EnableValidation != newPrefs.EnableValidation { + oldPrefs.ValidateEnabled != newPrefs.ValidateEnabled { s.ScheduleDiagnosticsRefresh() } } @@ -1864,8 +1864,8 @@ func (s *Session) publishProgramDiagnostics(oldSnapshot *Snapshot, newSnapshot * if !s.options.PushDiagnosticsEnabled { return } - if newSnapshot.UserPreferences().EnableValidation.IsFalse() { - if oldSnapshot.UserPreferences().EnableValidation.IsFalse() { + if newSnapshot.UserPreferences().ValidateEnabled.IsFalse() { + if oldSnapshot.UserPreferences().ValidateEnabled.IsFalse() { return } for _, oldProject := range oldSnapshot.ProjectCollection.ProjectsByID().Entries() { @@ -1942,7 +1942,7 @@ func shouldPublishProgramDiagnostics(p *Project, snapshotID uint64) bool { } func (s *Session) publishProjectDiagnostics(ctx context.Context, configFilePath string, diagnostics []*ast.Diagnostic, converters *lsconv.Converters) { - if s.Config().EnableValidation.IsFalse() { + if s.Config().ValidateEnabled.IsFalse() { diagnostics = nil } ctx = s.WithCurrentLocale(ctx) @@ -1963,7 +1963,7 @@ func (s *Session) publishProjectDiagnostics(ctx context.Context, configFilePath // global diagnostics from checker pools, re-publishing tsconfig diagnostics if changed. // Multiple calls are coalesced into a single background task. func (s *Session) EnqueuePublishGlobalDiagnostics() { - if !s.options.PushDiagnosticsEnabled || s.Config().EnableValidation.IsFalse() { + if !s.options.PushDiagnosticsEnabled || s.Config().ValidateEnabled.IsFalse() { return } if s.globalDiagPublishPending.CompareAndSwap(false, true) { diff --git a/tsc/internal/project/session_test.go b/tsc/internal/project/session_test.go index 504c78ae02083..c5c48440da9ef 100644 --- a/tsc/internal/project/session_test.go +++ b/tsc/internal/project/session_test.go @@ -1492,8 +1492,8 @@ export const value = content;`, session.Configure(lsutil.NewDefaultUserPreferences()) // Change user preferences for code lens and inlay hints. newPrefs := session.Config() - newPrefs.CodeLens.ReferencesCodeLensEnabled = core.TSTrue - newPrefs.InlayHints.IncludeInlayFunctionLikeReturnTypeHints = core.TSTrue + newPrefs.CodeLensUserPreferences.ReferencesCodeLensEnabled = core.TSTrue + newPrefs.InlayHintsPreferences.IncludeInlayFunctionLikeReturnTypeHints = core.TSTrue session.Configure(newPrefs) @@ -1533,7 +1533,7 @@ export const value = content;`, initialProgram := session.Snapshot().ProjectCollection.ConfiguredProject(configPath).Program preferences := session.Config() - preferences.CodeLens.ReferencesCodeLensEnabled = core.TSTrue + preferences.CodeLensUserPreferences.ReferencesCodeLensEnabled = core.TSTrue session.Configure(preferences) _, err = session.GetLanguageService(ctx, uri) assert.NilError(t, err) @@ -1561,7 +1561,7 @@ export const value = content;`, return nil } prefs := lsutil.NewDefaultUserPreferences() - prefs.CodeLens.ReferencesCodeLensEnabled = core.TSTrue + prefs.CodeLensUserPreferences.ReferencesCodeLensEnabled = core.TSTrue session.Configure(prefs) @@ -1618,7 +1618,7 @@ export const value = content;`, session.Configure(lsutil.ParseUserPreferences(map[string]any{"js/ts": configMap1})) actualConfig1 := session.Config() expectedPrefs1 := lsutil.NewDefaultUserPreferences() - expectedPrefs1.UseAliasesForRename = core.TSTrue + expectedPrefs1.ProvidePrefixAndSuffixTextForRename = core.TSTrue expectedPrefs1.QuotePreference = lsutil.QuotePreferenceSingle expectedPrefs1.OrganizeImportsSort = lsutil.OrganizeImportsSortOrdinalIgnoreCase @@ -1636,7 +1636,7 @@ export const value = content;`, session.Configure(lsutil.ParseUserPreferences(map[string]any{"js/ts": configMap2})) actualConfig2 := session.Config() expectedPrefs2 := lsutil.NewDefaultUserPreferences() - expectedPrefs2.UseAliasesForRename = core.TSFalse + expectedPrefs2.ProvidePrefixAndSuffixTextForRename = core.TSFalse expectedPrefs2.QuotePreference = lsutil.QuotePreferenceDouble expectedPrefs2.OrganizeImportsSort = lsutil.OrganizeImportsSortOrdinal From 3547a0cc4c4e859dc55ccc2e83bbd8f325a7f435 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 30 Sep 2026 13:20:21 -0700 Subject: [PATCH 3/5] PR feedback --- .golangci.yml | 2 + packages/typescript/src/api/async/api.ts | 5 +- packages/typescript/src/api/async/types.ts | 3 -- .../typescript/src/api/proto.generated.ts | 6 +-- packages/typescript/src/api/sync/api.ts | 6 ++- packages/typescript/src/api/sync/types.ts | 3 -- packages/typescript/test/async/api.test.ts | 17 ++++-- packages/typescript/test/sync/api.test.ts | 17 ++++-- tools/gen-preferences/main.go | 2 +- tools/gen-preferences/main_test.go | 4 +- tools/gen-preferences/methods.go | 28 +++------- tools/gen-proto/main.go | 3 +- tools/gen-proto/main_test.go | 2 +- tsc/internal/api/proto.go | 13 +++-- tsc/internal/api/session.go | 5 +- tsc/internal/api/session_completion_test.go | 21 ++++---- tsc/internal/ls/languageservice.go | 4 -- .../ls/lsutil/userpreferences_generated.go | 53 ------------------- .../ls/lsutil/userpreferences_test.go | 15 ------ 19 files changed, 63 insertions(+), 146 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index b2a47fb458a92..72b7797fa8072 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -68,6 +68,8 @@ linters: depguard: rules: main: + files: + - '**/tsc/**/*.go' deny: - pkg: 'encoding/json$' desc: 'Use "github.com/microsoft/TypeScript/tsc/internal/json" instead.' diff --git a/packages/typescript/src/api/async/api.ts b/packages/typescript/src/api/async/api.ts index 0c9ca9cb64b47..7eff7d6957053 100644 --- a/packages/typescript/src/api/async/api.ts +++ b/packages/typescript/src/api/async/api.ts @@ -63,6 +63,7 @@ import type { BuildResponse, CleanBuildResponse, CompilerOptions, + CompletionPreferences, ConfiguredProjectId, CreateBuildOrchestratorResponse, CreateProgramOptions as ProtocolCreateProgramOptions, @@ -106,6 +107,7 @@ import type { TypePropertyMethod, TypeResponse, TypesPropertyMethod, + UserPreferences, } from "../proto.ts"; import { resolveFileName, @@ -184,6 +186,7 @@ export type { CompletionEntry, CompletionInfo, CompletionOptions, + CompletionPreferences, ConditionalType, ConfiguredProjectId, CreateSourceFileOptions, @@ -246,6 +249,7 @@ export type { TypeReference, UnionOrIntersectionType, UnionType, + UserPreferences, }; export interface ModuleResolverOptions { @@ -1533,7 +1537,6 @@ export class LanguageService { position, triggerCharacter: options?.triggerCharacter, includeSymbol: options?.includeSymbol, - preferences: options?.preferences, }); if (!data) return undefined; return { diff --git a/packages/typescript/src/api/async/types.ts b/packages/typescript/src/api/async/types.ts index 4910895f63c5f..0844a354223f2 100644 --- a/packages/typescript/src/api/async/types.ts +++ b/packages/typescript/src/api/async/types.ts @@ -9,7 +9,6 @@ import type { ParameterDeclaration, } from "../../ast/ast.ts"; import type { - CompletionPreferences, Diagnostic, RequestFileSystem, } from "../proto.ts"; @@ -389,8 +388,6 @@ export interface CompletionOptions { triggerCharacter?: string | undefined; /** Include a `symbol` property on each completion entry. Only populated for symbol-based completions (not keywords or literals). */ includeSymbol?: boolean | undefined; - /** Overrides the snapshot preferences used to produce this completion list. */ - preferences?: CompletionPreferences | undefined; } /** A single completion item returned by {@link LanguageService.getCompletionsAtPosition}. */ diff --git a/packages/typescript/src/api/proto.generated.ts b/packages/typescript/src/api/proto.generated.ts index 3b1a2a26b22d3..ebca91f6feca8 100644 --- a/packages/typescript/src/api/proto.generated.ts +++ b/packages/typescript/src/api/proto.generated.ts @@ -8,10 +8,7 @@ import { NewLineKind } from "#enums/newLineKind"; import { ScriptKind } from "#enums/scriptKind"; import { ScriptTarget } from "#enums/scriptTarget"; import type { Path } from "../ast/index.ts"; -import type { - CompletionPreferences, - UserPreferences, -} from "./userPreferences.generated.ts"; +import type { UserPreferences } from "./userPreferences.generated.ts"; export { JsxEmit } from "#enums/jsxEmit"; export { ModuleDetectionKind } from "#enums/moduleDetectionKind"; @@ -959,7 +956,6 @@ export interface GetCompletionsAtPositionParams { position: number; triggerCharacter?: string | undefined; includeSymbol?: boolean | undefined; - preferences?: CompletionPreferences | undefined; } /** CompletionInfoResponse wraps a list of completion entries. */ diff --git a/packages/typescript/src/api/sync/api.ts b/packages/typescript/src/api/sync/api.ts index d34525f067eb7..fcbace9081bc2 100644 --- a/packages/typescript/src/api/sync/api.ts +++ b/packages/typescript/src/api/sync/api.ts @@ -80,6 +80,7 @@ import type { BuildResponse, CleanBuildResponse, CompilerOptions, + CompletionPreferences, ConfiguredProjectId, CreateBuildOrchestratorResponse, CreateProgramOptions as ProtocolCreateProgramOptions, @@ -123,6 +124,7 @@ import type { TypePropertyMethod, TypeResponse, TypesPropertyMethod, + UserPreferences, } from "../proto.ts"; import { resolveFileName, @@ -201,6 +203,7 @@ export type { CompletionEntry, CompletionInfo, CompletionOptions, + CompletionPreferences, ConditionalType, ConfiguredProjectId, CreateSourceFileOptions, @@ -263,6 +266,7 @@ export type { TypeReference, UnionOrIntersectionType, UnionType, + UserPreferences, }; export interface ModuleResolverOptions { @@ -2666,7 +2670,6 @@ export class LanguageService { position, triggerCharacter: options?.triggerCharacter, includeSymbol: options?.includeSymbol, - preferences: options?.preferences, }); if (!data) return undefined; return { @@ -2685,7 +2688,6 @@ export class LanguageService { position, triggerCharacter: options?.triggerCharacter, includeSymbol: options?.includeSymbol, - preferences: options?.preferences, }); if (!data) return undefined; return { diff --git a/packages/typescript/src/api/sync/types.ts b/packages/typescript/src/api/sync/types.ts index 1eec5b22902e1..a6a0e7b1c310d 100644 --- a/packages/typescript/src/api/sync/types.ts +++ b/packages/typescript/src/api/sync/types.ts @@ -22,7 +22,6 @@ import type { ParameterDeclaration, } from "../../ast/ast.ts"; import type { - CompletionPreferences, Diagnostic, RequestFileSystem, } from "../proto.ts"; @@ -528,8 +527,6 @@ export interface CompletionOptions { triggerCharacter?: string | undefined; /** Include a `symbol` property on each completion entry. Only populated for symbol-based completions (not keywords or literals). */ includeSymbol?: boolean | undefined; - /** Overrides the snapshot preferences used to produce this completion list. */ - preferences?: CompletionPreferences | undefined; } /** A single completion item returned by {@link LanguageService.getCompletionsAtPosition}. */ diff --git a/packages/typescript/test/async/api.test.ts b/packages/typescript/test/async/api.test.ts index 796607b04513f..90050a0ad3082 100644 --- a/packages/typescript/test/async/api.test.ts +++ b/packages/typescript/test/async/api.test.ts @@ -98,6 +98,7 @@ import { TypePredicateKind, type TypeReference, type UnionOrIntersectionType, + type UserPreferences, } from "@typescript/typescript/unstable/async"; // @sync: } from "@typescript/typescript/unstable/sync"; import { createFileSystem, @@ -2093,7 +2094,7 @@ describe("LanguageService - getCompletionsAtPosition", { concurrency }, () => { const unprepared = await api.createSnapshot({ openProject: "/tsconfig.json", - userPreferences: { includeCompletionsForModuleExports: true }, + userPreferences: { includeCompletionsForModuleExports: true } satisfies UserPreferences, }); const unpreparedProject = unprepared.getConfiguredProject("/tsconfig.json")!; // @sync-skip-block-start @@ -2112,7 +2113,7 @@ describe("LanguageService - getCompletionsAtPosition", { concurrency }, () => { assert.ok(completions?.entries.some(entry => entry.name === "someValue")); }); - test("completion preferences override snapshot preferences", async () => { + test("snapshot preferences disable auto-import completions", async () => { const src = "someV"; await using api = spawnAPI({ "/tsconfig.json": `{ "compilerOptions": { "module": "esnext", "target": "esnext" }, "include": ["src"] }`, @@ -2122,15 +2123,21 @@ describe("LanguageService - getCompletionsAtPosition", { concurrency }, () => { const snapshot = await api.createSnapshot({ openProject: "/tsconfig.json", - prepareAutoImports: "/src/main.ts", - userPreferences: { includeCompletionsForModuleExports: true }, + userPreferences: { includeCompletionsForModuleExports: false } satisfies UserPreferences, }); const project = snapshot.getConfiguredProject("/tsconfig.json")!; const completions = await project.languageService.getCompletionsAtPosition("/src/main.ts", src.length, { - preferences: { includeCompletionsForModuleExports: false }, + includeSymbol: true, }); assert.ok(completions); assert.ok(!completions.entries.some(entry => entry.name === "someValue")); + const prepared = await snapshot.update({ + userPreferences: { includeCompletionsForModuleExports: true }, + prepareAutoImports: "/src/main.ts", + }); + const preparedProject = prepared.getConfiguredProject("/tsconfig.json")!; + const enabled = await preparedProject.languageService.getCompletionsAtPosition("/src/main.ts", src.length, { includeSymbol: true }); + assert.ok(enabled?.entries.some(entry => entry.name === "someValue")); }); }); diff --git a/packages/typescript/test/sync/api.test.ts b/packages/typescript/test/sync/api.test.ts index 3fd5ef0e775b8..03e23f9b6b381 100644 --- a/packages/typescript/test/sync/api.test.ts +++ b/packages/typescript/test/sync/api.test.ts @@ -113,6 +113,7 @@ import { TypePredicateKind, type TypeReference, type UnionOrIntersectionType, + type UserPreferences, } from "@typescript/typescript/unstable/sync"; import assert from "node:assert"; import { globSync } from "node:fs"; @@ -1960,7 +1961,7 @@ describe("LanguageService - getCompletionsAtPosition", { concurrency }, () => { const unprepared = api.createSnapshot({ openProject: "/tsconfig.json", - userPreferences: { includeCompletionsForModuleExports: true }, + userPreferences: { includeCompletionsForModuleExports: true } satisfies UserPreferences, }); const unpreparedProject = unprepared.getConfiguredProject("/tsconfig.json")!; assert.throws(() => unpreparedProject.languageService.getCompletionsAtPosition("/src/main.ts", src.length, { includeSymbol: true }), /snapshot is not prepared for auto-imports/); @@ -1971,7 +1972,7 @@ describe("LanguageService - getCompletionsAtPosition", { concurrency }, () => { assert.ok(completions?.entries.some(entry => entry.name === "someValue")); }); - test("completion preferences override snapshot preferences", () => { + test("snapshot preferences disable auto-import completions", () => { const src = "someV"; using api = spawnAPI({ "/tsconfig.json": `{ "compilerOptions": { "module": "esnext", "target": "esnext" }, "include": ["src"] }`, @@ -1981,15 +1982,21 @@ describe("LanguageService - getCompletionsAtPosition", { concurrency }, () => { const snapshot = api.createSnapshot({ openProject: "/tsconfig.json", - prepareAutoImports: "/src/main.ts", - userPreferences: { includeCompletionsForModuleExports: true }, + userPreferences: { includeCompletionsForModuleExports: false } satisfies UserPreferences, }); const project = snapshot.getConfiguredProject("/tsconfig.json")!; const completions = project.languageService.getCompletionsAtPosition("/src/main.ts", src.length, { - preferences: { includeCompletionsForModuleExports: false }, + includeSymbol: true, }); assert.ok(completions); assert.ok(!completions.entries.some(entry => entry.name === "someValue")); + const prepared = snapshot.update({ + userPreferences: { includeCompletionsForModuleExports: true }, + prepareAutoImports: "/src/main.ts", + }); + const preparedProject = prepared.getConfiguredProject("/tsconfig.json")!; + const enabled = preparedProject.languageService.getCompletionsAtPosition("/src/main.ts", src.length, { includeSymbol: true }); + assert.ok(enabled?.entries.some(entry => entry.name === "someValue")); }); }); diff --git a/tools/gen-preferences/main.go b/tools/gen-preferences/main.go index 69471a7f4389b..391c7c722adda 100644 --- a/tools/gen-preferences/main.go +++ b/tools/gen-preferences/main.go @@ -2,7 +2,7 @@ package main import ( "bytes" - "encoding/json" //nolint:depguard // The tools module cannot import tsc/internal/json. + "encoding/json" "errors" "fmt" "go/format" diff --git a/tools/gen-preferences/main_test.go b/tools/gen-preferences/main_test.go index 4a4d72f2cc17e..b8e947b97e740 100644 --- a/tools/gen-preferences/main_test.go +++ b/tools/gen-preferences/main_test.go @@ -29,7 +29,6 @@ func TestGenerate(t *testing.T) { `getPreferenceConfigValue(config, "suggest.jsdoc.enabled", "suggest.completeJSDocs")`, "func (p UserPreferences) withConfig(config map[string]any) UserPreferences", "func (p *UserPreferences) MarshalJSONTo(enc *json.Encoder) error", - "func (p UserPreferences) WithCompletionPreferences(overrides CompletionPreferences) UserPreferences", } { if !strings.Contains(strings.Join(strings.Fields(string(goOutput)), " "), expected) { t.Errorf("Go output does not contain %q", expected) @@ -55,6 +54,9 @@ func TestGenerate(t *testing.T) { if bytes.Contains(goOutput, []byte("reflect.")) { t.Error("generated preferences must use typed field access") } + if bytes.Contains(goOutput, []byte("WithCompletionPreferences")) { + t.Error("generated preferences must not provide per-call completion overrides") + } } func TestInvalidSchema(t *testing.T) { diff --git a/tools/gen-preferences/methods.go b/tools/gen-preferences/methods.go index 8126983236724..7b171c119882d 100644 --- a/tools/gen-preferences/methods.go +++ b/tools/gen-preferences/methods.go @@ -37,9 +37,6 @@ func (s schema) writePreferenceMethods(out *bytes.Buffer, imports map[string]str if root != "UserPreferences" { return errors.New("preference schema must define UserPreferences as its root") } - if _, ok := s.Defs["CompletionPreferences"]; !ok { - return errors.New("preference schema must define CompletionPreferences") - } imports["json"] = "github.com/microsoft/TypeScript/tsc/internal/json" fields := s.flattenedFields(root, "") enumTypes := map[string]property{} @@ -64,15 +61,13 @@ func (s schema) writePreferenceMethods(out *bytes.Buffer, imports map[string]str } } - for _, name := range []string{root, "CompletionPreferences"} { - fmt.Fprintf(out, "func (p *%s) applyRawPreferences(settings map[string]any) {\n", name) - out.WriteString("for name, value := range settings {\nif value == nil { continue }\nswitch name {\n") - for _, field := range s.flattenedFields(name, "") { - fmt.Fprintf(out, "case %q:\n", field.name) - writeAssignment(out, "p."+field.selector, field.property) - } - out.WriteString("}\n}\n}\n\n") + fmt.Fprintf(out, "func (p *%s) applyRawPreferences(settings map[string]any) {\n", root) + out.WriteString("for name, value := range settings {\nif value == nil { continue }\nswitch name {\n") + for _, field := range fields { + fmt.Fprintf(out, "case %q:\n", field.name) + writeAssignment(out, "p."+field.selector, field.property) } + out.WriteString("}\n}\n}\n\n") out.WriteString("func (p UserPreferences) withConfig(config map[string]any) UserPreferences {\n") out.WriteString("p.applyRawPreferences(config)\nif unstable, ok := config[\"unstable\"].(map[string]any); ok { p.applyRawPreferences(unstable) }\n") @@ -103,17 +98,6 @@ func (s schema) writePreferenceMethods(out *bytes.Buffer, imports map[string]str } out.WriteString("return p\n}\n\n") - out.WriteString("func (p *CompletionPreferences) UnmarshalJSONFrom(dec *json.Decoder) error {\nvar settings map[string]any\nif err := json.UnmarshalDecode(dec, &settings); err != nil { return err }\np.applyRawPreferences(settings)\nreturn nil\n}\n\n") - out.WriteString("func (p UserPreferences) WithCompletionPreferences(overrides CompletionPreferences) UserPreferences {\n") - for _, field := range s.flattenedFields("CompletionPreferences", "") { - rootFieldIndex := slices.IndexFunc(fields, func(candidate preferenceField) bool { return candidate.name == field.name }) - if rootFieldIndex < 0 { - return fmt.Errorf("completion preference %s is not inherited by UserPreferences", field.name) - } - fmt.Fprintf(out, "if %s {\np.%s = overrides.%s\n}\n", presentCondition("overrides."+field.selector, field.property), fields[rootFieldIndex].selector, field.selector) - } - out.WriteString("return p\n}\n\n") - out.WriteString("func (p *UserPreferences) MarshalJSONTo(enc *json.Encoder) error {\nconfig := make(map[string]any)\n") for _, field := range fields { target := field.Config diff --git a/tools/gen-proto/main.go b/tools/gen-proto/main.go index a9373624ba587..15635e7a0d010 100644 --- a/tools/gen-proto/main.go +++ b/tools/gen-proto/main.go @@ -513,8 +513,7 @@ func (r *typeRenderer) namedType(named *types.Named) string { return "unknown" case "github.com/microsoft/TypeScript/tsc/internal/core.Tristate": return "boolean" - case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.UserPreferences", - "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.CompletionPreferences": + case "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil.UserPreferences": return r.importTypeOnly(obj.Name(), "./userPreferences.generated.ts") case "github.com/microsoft/TypeScript/tsc/internal/core.JsxEmit": return r.importType("JsxEmit", "#enums/jsxEmit") diff --git a/tools/gen-proto/main_test.go b/tools/gen-proto/main_test.go index 533862d5bb0ca..1e66b6bbbba4b 100644 --- a/tools/gen-proto/main_test.go +++ b/tools/gen-proto/main_test.go @@ -33,7 +33,7 @@ func TestGenerate(t *testing.T) { `export interface UpdateSnapshotParams`, `export interface CreateSnapshotParams extends SnapshotRequestChangesParams`, `export interface LanguageServerSnapshotChanges extends SnapshotRequestChangesParams`, - `import type { CompletionPreferences, UserPreferences } from "./userPreferences.generated.ts";`, + `import type { UserPreferences } from "./userPreferences.generated.ts";`, `userPreferences?: UserPreferences | undefined;`, `prepareAutoImports?: DocumentIdentifier | undefined;`, `openProjects?: readonly DocumentIdentifier[] | undefined;`, diff --git a/tsc/internal/api/proto.go b/tsc/internal/api/proto.go index 79b281837093a..76eac70a4f413 100644 --- a/tsc/internal/api/proto.go +++ b/tsc/internal/api/proto.go @@ -1543,13 +1543,12 @@ type SignatureUsageResponse struct { // GetCompletionsAtPositionParams are the parameters for the getCompletionsAtPosition method. type GetCompletionsAtPositionParams struct { - Snapshot SnapshotID `json:"snapshot"` - Project project.ID `json:"project"` - File DocumentIdentifier `json:"file"` - Position uint32 `json:"position"` - TriggerCharacter *string `json:"triggerCharacter,omitempty"` - IncludeSymbol bool `json:"includeSymbol,omitempty"` - Preferences *lsutil.CompletionPreferences `json:"preferences,omitempty"` + Snapshot SnapshotID `json:"snapshot"` + Project project.ID `json:"project"` + File DocumentIdentifier `json:"file"` + Position uint32 `json:"position"` + TriggerCharacter *string `json:"triggerCharacter,omitempty"` + IncludeSymbol bool `json:"includeSymbol,omitempty"` } // CompletionEntryLabelDetailsResponse holds additional label display text for a completion entry. diff --git a/tsc/internal/api/session.go b/tsc/internal/api/session.go index 361b49411760a..591297f56736e 100644 --- a/tsc/internal/api/session.go +++ b/tsc/internal/api/session.go @@ -5028,13 +5028,10 @@ func (s *Session) handleGetCompletionsAtPosition(ctx context.Context, params *Ge if sourceFile == nil { return nil, nil } - langSvc, e := s.setupLanguageService(snapshot, program, params.Project, "") + langSvc, e := s.setupLanguageService(snapshot, program, params.Project, sourceFile.FileName()) if e != nil { return nil, e } - if params.Preferences != nil { - langSvc.SetUserPreferences(langSvc.UserPreferences().WithCompletionPreferences(*params.Preferences)) - } internalPos := sourceFile.GetPositionMap().UTF16ToUTF8(int(params.Position)) return langSvc.GetCompletionsAtPosition(ctx, sourceFile, internalPos, params.TriggerCharacter, params.IncludeSymbol) } diff --git a/tsc/internal/api/session_completion_test.go b/tsc/internal/api/session_completion_test.go index 3d97b9150ded0..ca82ffb8f21d6 100644 --- a/tsc/internal/api/session_completion_test.go +++ b/tsc/internal/api/session_completion_test.go @@ -279,7 +279,7 @@ func TestCompletionWithSymbolsUsesPreparedSnapshot(t *testing.T) { t.Fatal("expected auto-import completion for someValue") } -func TestCompletionPreferencesOverrideSnapshot(t *testing.T) { +func TestCompletionUsesSnapshotPreferences(t *testing.T) { t.Parallel() if !bundled.Embedded { t.Skip("bundled files are not embedded") @@ -298,10 +298,9 @@ func TestCompletionPreferencesOverrideSnapshot(t *testing.T) { defer session.Close() snapshotResp, err := session.handleCreateSnapshot(t.Context(), &CreateSnapshotParams{ - OpenFiles: []DocumentIdentifier{{FileName: fileName}}, - PrepareAutoImports: &DocumentIdentifier{FileName: fileName}, + OpenFiles: []DocumentIdentifier{{FileName: fileName}}, UserPreferences: &lsutil.UserPreferences{ - IncludeCompletionsForModuleExports: core.TSTrue, + IncludeCompletionsForModuleExports: core.TSFalse, }, }) assert.NilError(t, err) @@ -312,18 +311,16 @@ func TestCompletionPreferencesOverrideSnapshot(t *testing.T) { assert.NilError(t, err) completions, err := session.handleGetCompletionsAtPosition(t.Context(), &GetCompletionsAtPositionParams{ - Snapshot: snapshotResp.Snapshot, - Project: proj.Id, - File: DocumentIdentifier{FileName: fileName}, - Position: uint32(len(content)), - Preferences: &lsutil.CompletionPreferences{ - IncludeCompletionsForModuleExports: core.TSFalse, - }, + Snapshot: snapshotResp.Snapshot, + Project: proj.Id, + File: DocumentIdentifier{FileName: fileName}, + Position: uint32(len(content)), + IncludeSymbol: true, }) assert.NilError(t, err) assert.Assert(t, completions != nil) for _, entry := range completions.Entries { - assert.Assert(t, entry.Name != "someValue", "per-call preferences should disable auto-import completions") + assert.Assert(t, entry.Name != "someValue", "snapshot preferences should disable auto-import completions") } } diff --git a/tsc/internal/ls/languageservice.go b/tsc/internal/ls/languageservice.go index cf28be37b5a4b..b88ed55a4bca0 100644 --- a/tsc/internal/ls/languageservice.go +++ b/tsc/internal/ls/languageservice.go @@ -50,10 +50,6 @@ func (l *LanguageService) UserPreferences() lsutil.UserPreferences { return l.activeConfig } -func (l *LanguageService) SetUserPreferences(preferences lsutil.UserPreferences) { - l.activeConfig = preferences -} - func (l *LanguageService) FormatOptions() lsutil.FormatCodeSettings { return l.activeConfig.FormatCodeSettings } diff --git a/tsc/internal/ls/lsutil/userpreferences_generated.go b/tsc/internal/ls/lsutil/userpreferences_generated.go index a6e2a786b0f67..d0f4d3a07aa64 100644 --- a/tsc/internal/ls/lsutil/userpreferences_generated.go +++ b/tsc/internal/ls/lsutil/userpreferences_generated.go @@ -634,28 +634,6 @@ func (p *UserPreferences) applyRawPreferences(settings map[string]any) { } } -func (p *CompletionPreferences) applyRawPreferences(settings map[string]any) { - for name, value := range settings { - if value == nil { - continue - } - switch name { - case "includeAutomaticOptionalChainCompletions": - p.IncludeAutomaticOptionalChainCompletions = parsePreferenceTristate(value) - case "includeCompletionsForImportStatements": - p.IncludeCompletionsForImportStatements = parsePreferenceTristate(value) - case "includeCompletionsForModuleExports": - p.IncludeCompletionsForModuleExports = parsePreferenceTristate(value) - case "includeCompletionsWithClassMemberSnippets": - p.IncludeCompletionsWithClassMemberSnippets = parsePreferenceTristate(value) - case "includeCompletionsWithObjectLiteralMethodSnippets": - p.IncludeCompletionsWithObjectLiteralMethodSnippets = parsePreferenceTristate(value) - case "jsxAttributeCompletionStyle": - p.JsxAttributeCompletionStyle = parsePreferenceJsxAttributeCompletionStyle(value) - } - } -} - func (p UserPreferences) withConfig(config map[string]any) UserPreferences { p.applyRawPreferences(config) if unstable, ok := config["unstable"].(map[string]any); ok { @@ -1072,37 +1050,6 @@ func (p UserPreferences) withConfig(config map[string]any) UserPreferences { return p } -func (p *CompletionPreferences) UnmarshalJSONFrom(dec *json.Decoder) error { - var settings map[string]any - if err := json.UnmarshalDecode(dec, &settings); err != nil { - return err - } - p.applyRawPreferences(settings) - return nil -} - -func (p UserPreferences) WithCompletionPreferences(overrides CompletionPreferences) UserPreferences { - if overrides.IncludeAutomaticOptionalChainCompletions.IsTrue() || overrides.IncludeAutomaticOptionalChainCompletions.IsFalse() { - p.CompletionPreferences.IncludeAutomaticOptionalChainCompletions = overrides.IncludeAutomaticOptionalChainCompletions - } - if overrides.IncludeCompletionsForImportStatements.IsTrue() || overrides.IncludeCompletionsForImportStatements.IsFalse() { - p.CompletionPreferences.IncludeCompletionsForImportStatements = overrides.IncludeCompletionsForImportStatements - } - if overrides.IncludeCompletionsForModuleExports.IsTrue() || overrides.IncludeCompletionsForModuleExports.IsFalse() { - p.CompletionPreferences.IncludeCompletionsForModuleExports = overrides.IncludeCompletionsForModuleExports - } - if overrides.IncludeCompletionsWithClassMemberSnippets.IsTrue() || overrides.IncludeCompletionsWithClassMemberSnippets.IsFalse() { - p.CompletionPreferences.IncludeCompletionsWithClassMemberSnippets = overrides.IncludeCompletionsWithClassMemberSnippets - } - if overrides.IncludeCompletionsWithObjectLiteralMethodSnippets.IsTrue() || overrides.IncludeCompletionsWithObjectLiteralMethodSnippets.IsFalse() { - p.CompletionPreferences.IncludeCompletionsWithObjectLiteralMethodSnippets = overrides.IncludeCompletionsWithObjectLiteralMethodSnippets - } - if overrides.JsxAttributeCompletionStyle != "" { - p.CompletionPreferences.JsxAttributeCompletionStyle = overrides.JsxAttributeCompletionStyle - } - return p -} - func (p *UserPreferences) MarshalJSONTo(enc *json.Encoder) error { config := make(map[string]any) if p.FormatCodeSettings.EditorSettings.BaseIndentSize != 0 { diff --git a/tsc/internal/ls/lsutil/userpreferences_test.go b/tsc/internal/ls/lsutil/userpreferences_test.go index 403b347ddaafc..42222958eca16 100644 --- a/tsc/internal/ls/lsutil/userpreferences_test.go +++ b/tsc/internal/ls/lsutil/userpreferences_test.go @@ -10,21 +10,6 @@ import ( "gotest.tools/v3/assert" ) -func TestCompletionPreferencesUnmarshal(t *testing.T) { - t.Parallel() - var preferences CompletionPreferences - assert.NilError(t, json.Unmarshal([]byte(`{"includeCompletionsForModuleExports":false}`), &preferences)) - assert.Equal(t, preferences.IncludeCompletionsForModuleExports, core.TSFalse) - - userPreferences := NewDefaultUserPreferences().WithCompletionPreferences(preferences) - assert.Equal(t, userPreferences.IncludeCompletionsForModuleExports, core.TSFalse) - assert.Equal(t, userPreferences.IncludeCompletionsForImportStatements, core.TSTrue) - userPreferences = userPreferences.WithCompletionPreferences(CompletionPreferences{ - IncludeCompletionsForModuleExports: core.Tristate(99), - }) - assert.Equal(t, userPreferences.IncludeCompletionsForModuleExports, core.TSFalse) -} - func TestUserPreferencesParsingEdgeCases(t *testing.T) { t.Parallel() tests := []struct { From a72d18d922410b31296b0138de9d81ffd4b11a79 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 30 Sep 2026 13:50:13 -0700 Subject: [PATCH 4/5] Fix inlay-hints test after merging main Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tsc/internal/fourslash/tests/contentMapperInlayHints_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsc/internal/fourslash/tests/contentMapperInlayHints_test.go b/tsc/internal/fourslash/tests/contentMapperInlayHints_test.go index 7d8f6cd03b739..ef99cc9938715 100644 --- a/tsc/internal/fourslash/tests/contentMapperInlayHints_test.go +++ b/tsc/internal/fourslash/tests/contentMapperInlayHints_test.go @@ -37,6 +37,6 @@ const value = () => 1; f.GoToFile(t, "/app.vue") f.VerifyBaselineInlayHints(t, nil, &lsutil.UserPreferences{ - InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: core.TSTrue}, + IncludeInlayVariableTypeHints: core.TSTrue, }) } From 2c2999e1ff39929af87518e2d050379af02d94a9 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 30 Sep 2026 14:06:07 -0700 Subject: [PATCH 5/5] Fix build --- packages/typescript/src/api/userPreferences.generated.ts | 2 +- tools/userPreferences.schema.json | 2 +- tsc/internal/ls/lsutil/userpreferences_generated.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/typescript/src/api/userPreferences.generated.ts b/packages/typescript/src/api/userPreferences.generated.ts index bea3f03d426de..bf1e2110b88ea 100644 --- a/packages/typescript/src/api/userPreferences.generated.ts +++ b/packages/typescript/src/api/userPreferences.generated.ts @@ -20,7 +20,7 @@ export interface CompletionPreferences { includeAutomaticOptionalChainCompletions?: boolean | undefined; /** * Enables auto-import-style completions on partially-typed import statements. E.g., allows - * `import write|` to be completed to `import { writeFile } from "fs"`. + * `import write|` to be completed to `import { writeResult } from "./utils.js"`. */ includeCompletionsForImportStatements?: boolean | undefined; /** diff --git a/tools/userPreferences.schema.json b/tools/userPreferences.schema.json index bc1f6fa40fe77..d2f1837b5c0c2 100644 --- a/tools/userPreferences.schema.json +++ b/tools/userPreferences.schema.json @@ -35,7 +35,7 @@ "x-config": "suggest.includeAutomaticOptionalChainCompletions" }, "includeCompletionsForImportStatements": { - "description": "Enables auto-import-style completions on partially-typed import statements. E.g., allows\n`import write|` to be completed to `import { writeFile } from \"fs\"`.", + "description": "Enables auto-import-style completions on partially-typed import statements. E.g., allows\n`import write|` to be completed to `import { writeResult } from \"./utils.js\"`.", "type": "boolean", "x-config": "suggest.includeCompletionsForImportStatements" }, diff --git a/tsc/internal/ls/lsutil/userpreferences_generated.go b/tsc/internal/ls/lsutil/userpreferences_generated.go index d0f4d3a07aa64..a552acb6e46ca 100644 --- a/tsc/internal/ls/lsutil/userpreferences_generated.go +++ b/tsc/internal/ls/lsutil/userpreferences_generated.go @@ -26,7 +26,7 @@ type CompletionPreferences struct { // preceding `.` tokens with `?.`. IncludeAutomaticOptionalChainCompletions core.Tristate `json:"includeAutomaticOptionalChainCompletions,omitempty"` // Enables auto-import-style completions on partially-typed import statements. E.g., allows - // `import write|` to be completed to `import { writeFile } from "fs"`. + // `import write|` to be completed to `import { writeResult } from "./utils.js"`. IncludeCompletionsForImportStatements core.Tristate `json:"includeCompletionsForImportStatements,omitempty"` // If enabled, TypeScript will search through all external modules' exports and add them to the completions list. // This affects lone identifier completions but not completions on the right hand side of `obj.`.