From ea37b2b914f0498bef94d77682e94acb28ea8f9e Mon Sep 17 00:00:00 2001 From: Beatrix <68532117+abeatrix@users.noreply.github.com> Date: Tue, 10 Sep 2024 10:10:48 -0700 Subject: [PATCH] Codegen: Improve Formatter for better field name handling (#5534) CLOSE https://linear.app/sourcegraph/issue/CODY-3696/codegen-generated-invalid-field-name-causing-jetbrains-build-to-fail This PR fixes the issue where codegen does not escape all the invalid characters for field names. - Replace non-alphanumeric characters with underscores for Kotlin field names - Add helper function `getEscapedValue` to handle various field name formatting rules Also removed the bindings from the agent/bindings/kotlin/lib/bin/main/com/sourcegraph/cody/agent/protocol_generated directory ## Test plan Run the generate agent bindings command to confirm everything works as expected. Some before and after comparison: before: const val `recently used` = "recently used" const val `https__/example.com` = "https://example.com" after: const val `recently-used` = "recently used" const val `https-example-com` = "https://example.com" ## Changelog --- .../protocol_generated/ClientCapabilities.kt | 93 ------------------- .../agent/protocol_generated/Constants.kt | 87 ----------------- .../WorkspaceFolder_DidChangeParams.kt | 7 -- .../agent/protocol_generated/Constants.kt | 2 +- agent/src/cli/scip-codegen/Formatter.ts | 18 +++- 5 files changed, 17 insertions(+), 190 deletions(-) delete mode 100644 agent/bindings/kotlin/lib/bin/main/com/sourcegraph/cody/agent/protocol_generated/ClientCapabilities.kt delete mode 100644 agent/bindings/kotlin/lib/bin/main/com/sourcegraph/cody/agent/protocol_generated/Constants.kt delete mode 100644 agent/bindings/kotlin/lib/bin/main/com/sourcegraph/cody/agent/protocol_generated/WorkspaceFolder_DidChangeParams.kt diff --git a/agent/bindings/kotlin/lib/bin/main/com/sourcegraph/cody/agent/protocol_generated/ClientCapabilities.kt b/agent/bindings/kotlin/lib/bin/main/com/sourcegraph/cody/agent/protocol_generated/ClientCapabilities.kt deleted file mode 100644 index 13e505aadc47..000000000000 --- a/agent/bindings/kotlin/lib/bin/main/com/sourcegraph/cody/agent/protocol_generated/ClientCapabilities.kt +++ /dev/null @@ -1,93 +0,0 @@ -@file:Suppress("FunctionName", "ClassName", "unused", "EnumEntryName", "UnusedImport") -package com.sourcegraph.cody.agent.protocol_generated; - -import com.google.gson.annotations.SerializedName; - -data class ClientCapabilities( - val completions: CompletionsEnum? = null, // Oneof: none - val chat: ChatEnum? = null, // Oneof: none, streaming - val git: GitEnum? = null, // Oneof: none, enabled - val progressBars: ProgressBarsEnum? = null, // Oneof: none, enabled - val edit: EditEnum? = null, // Oneof: none, enabled - val editWorkspace: EditWorkspaceEnum? = null, // Oneof: none, enabled - val untitledDocuments: UntitledDocumentsEnum? = null, // Oneof: none, enabled - val showDocument: ShowDocumentEnum? = null, // Oneof: none, enabled - val codeLenses: CodeLensesEnum? = null, // Oneof: none, enabled - val showWindowMessage: ShowWindowMessageEnum? = null, // Oneof: notification, request - val ignore: IgnoreEnum? = null, // Oneof: none, enabled - val codeActions: CodeActionsEnum? = null, // Oneof: none, enabled - val webviewMessages: WebviewMessagesEnum? = null, // Oneof: object-encoded, string-encoded - val webview: WebviewEnum? = null, // Oneof: agentic, native - val webviewNativeConfig: WebviewNativeConfigParams? = null, -) { - - enum class CompletionsEnum { - @SerializedName("none") None, - } - - enum class ChatEnum { - @SerializedName("none") None, - @SerializedName("streaming") Streaming, - } - - enum class GitEnum { - @SerializedName("none") None, - @SerializedName("enabled") Enabled, - } - - enum class ProgressBarsEnum { - @SerializedName("none") None, - @SerializedName("enabled") Enabled, - } - - enum class EditEnum { - @SerializedName("none") None, - @SerializedName("enabled") Enabled, - } - - enum class EditWorkspaceEnum { - @SerializedName("none") None, - @SerializedName("enabled") Enabled, - } - - enum class UntitledDocumentsEnum { - @SerializedName("none") None, - @SerializedName("enabled") Enabled, - } - - enum class ShowDocumentEnum { - @SerializedName("none") None, - @SerializedName("enabled") Enabled, - } - - enum class CodeLensesEnum { - @SerializedName("none") None, - @SerializedName("enabled") Enabled, - } - - enum class ShowWindowMessageEnum { - @SerializedName("notification") Notification, - @SerializedName("request") Request, - } - - enum class IgnoreEnum { - @SerializedName("none") None, - @SerializedName("enabled") Enabled, - } - - enum class CodeActionsEnum { - @SerializedName("none") None, - @SerializedName("enabled") Enabled, - } - - enum class WebviewMessagesEnum { - @SerializedName("object-encoded") `Object-encoded`, - @SerializedName("string-encoded") `String-encoded`, - } - - enum class WebviewEnum { - @SerializedName("agentic") Agentic, - @SerializedName("native") Native, - } -} - diff --git a/agent/bindings/kotlin/lib/bin/main/com/sourcegraph/cody/agent/protocol_generated/Constants.kt b/agent/bindings/kotlin/lib/bin/main/com/sourcegraph/cody/agent/protocol_generated/Constants.kt deleted file mode 100644 index eb6b5f34d9f2..000000000000 --- a/agent/bindings/kotlin/lib/bin/main/com/sourcegraph/cody/agent/protocol_generated/Constants.kt +++ /dev/null @@ -1,87 +0,0 @@ -@file:Suppress("unused", "ConstPropertyName") -package com.sourcegraph.cody.agent.protocol_generated; - -object Constants { - const val Applied = "Applied" - const val Applying = "Applying" - const val Automatic = "Automatic" - const val Error = "Error" - const val Finished = "Finished" - const val IDEEXTENSION = "IDEEXTENSION" - const val Idle = "Idle" - const val Inserting = "Inserting" - const val Invoke = "Invoke" - const val Pending = "Pending" - const val Working = "Working" - const val accuracy = "accuracy" - const val agentic = "agentic" - const val ask = "ask" - const val assistant = "assistant" - const val autocomplete = "autocomplete" - const val balanced = "balanced" - const val byok = "byok" - const val chat = "chat" - const val `class` = "class" - const val complete = "complete" - const val `create-file` = "create-file" - const val default = "default" - const val delete = "delete" - const val `delete-file` = "delete-file" - const val deprecated = "deprecated" - const val dev = "dev" - const val edit = "edit" - const val `edit-file` = "edit-file" - const val editor = "editor" - const val embeddings = "embeddings" - const val enabled = "enabled" - const val enterprise = "enterprise" - const val error = "error" - const val errored = "errored" - const val experimental = "experimental" - const val fetching = "fetching" - const val file = "file" - const val free = "free" - const val function = "function" - const val gateway = "gateway" - const val history = "history" - const val human = "human" - const val ignore = "ignore" - const val indentation = "indentation" - const val info = "info" - const val information = "information" - const val initial = "initial" - const val insert = "insert" - const val isChatErrorGuard = "isChatErrorGuard" - const val local = "local" - const val method = "method" - const val native = "native" - const val none = "none" - const val notification = "notification" - const val `object-encoded` = "object-encoded" - const val ollama = "ollama" - const val openctx = "openctx" - const val paused = "paused" - const val pro = "pro" - const val `recently used` = "recently used" - const val recommended = "recommended" - const val `rename-file` = "rename-file" - const val replace = "replace" - const val repository = "repository" - const val request = "request" - const val search = "search" - const val selection = "selection" - const val speed = "speed" - const val streaming = "streaming" - const val `string-encoded` = "string-encoded" - const val suggestion = "suggestion" - const val symbol = "symbol" - const val system = "system" - const val terminal = "terminal" - const val tree = "tree" - const val `tree-sitter` = "tree-sitter" - const val unified = "unified" - const val use = "use" - const val user = "user" - const val warning = "warning" - const val workspace = "workspace" -} diff --git a/agent/bindings/kotlin/lib/bin/main/com/sourcegraph/cody/agent/protocol_generated/WorkspaceFolder_DidChangeParams.kt b/agent/bindings/kotlin/lib/bin/main/com/sourcegraph/cody/agent/protocol_generated/WorkspaceFolder_DidChangeParams.kt deleted file mode 100644 index e83e24840f5e..000000000000 --- a/agent/bindings/kotlin/lib/bin/main/com/sourcegraph/cody/agent/protocol_generated/WorkspaceFolder_DidChangeParams.kt +++ /dev/null @@ -1,7 +0,0 @@ -@file:Suppress("FunctionName", "ClassName", "unused", "EnumEntryName", "UnusedImport") -package com.sourcegraph.cody.agent.protocol_generated; - -data class WorkspaceFolder_DidChangeParams( - val uri: String, -) - diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/agent/protocol_generated/Constants.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/agent/protocol_generated/Constants.kt index 8de6f8b43091..3bfa2dc4cf2e 100644 --- a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/agent/protocol_generated/Constants.kt +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/agent/protocol_generated/Constants.kt @@ -60,7 +60,7 @@ object Constants { const val openctx = "openctx" const val power = "power" const val pro = "pro" - const val `recently used` = "recently used" + const val `recently-used` = "recently used" const val recommended = "recommended" const val `rename-file` = "rename-file" const val replace = "replace" diff --git a/agent/src/cli/scip-codegen/Formatter.ts b/agent/src/cli/scip-codegen/Formatter.ts index b19c7b18b54b..ef75c6473f9a 100644 --- a/agent/src/cli/scip-codegen/Formatter.ts +++ b/agent/src/cli/scip-codegen/Formatter.ts @@ -265,10 +265,13 @@ export class Formatter { if (this.language === TargetLanguage.Kotlin) { const isKeyword = this.kotlinKeywords.has(escaped) const needsBacktick = isKeyword || !/^[a-zA-Z0-9_]+$/.test(escaped) - return needsBacktick ? `\`${escaped}\`` : escaped + // Replace all non-alphanumeric characters with underscores + const fieldName = getEscapedValue(escaped, '-') + return needsBacktick ? `\`${fieldName}\`` : fieldName } + // CSharp if (this.language === TargetLanguage.CSharp) { - return escaped + return getEscapedValue(escaped) .split('_') .map(part => part.charAt(0).toUpperCase() + part.slice(1)) .join('') @@ -297,3 +300,14 @@ export class Formatter { return `${capitalize(name)}Enum` } } + +function getEscapedValue(name: string, replacer: '_' | '-' = '_'): string { + const nonAlphanumericRegex = replacer === '-' ? /[^a-zA-Z0-9]+/g : /[^a-zA-Z0-9]/g + const repeatedReplacerRegex = new RegExp(`${replacer}+`, 'g') + const trimReplacerRegex = new RegExp(`^${replacer}|${replacer}$`, 'g') + + return name + .replace(nonAlphanumericRegex, replacer) + .replace(repeatedReplacerRegex, replacer) + .replace(trimReplacerRegex, '') +}