diff --git a/CHANGELOG.md b/CHANGELOG.md index 39162a1a..227723a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Add ObjectScript enter rules for semicolon (`;`) continuation on line break. (#5) - Auto-indent dot syntax on Enter for `objectscript`/`objectscript-int` (replicates leading dots). (#6) - Added `resolveContextExpression` command: posts current line/routine to API, inserts returned code on success, shows error otherwise. (#7) + - Refactor API: extracted request util and updated endpoints (#8) ## [3.0.6] 09-Sep-2025 diff --git a/src/api/ccs/sourceControl.ts b/src/api/ccs/sourceControl.ts new file mode 100644 index 00000000..fd65ad88 --- /dev/null +++ b/src/api/ccs/sourceControl.ts @@ -0,0 +1,53 @@ +import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"; +import * as https from "https"; +import * as vscode from "vscode"; + +import { AtelierAPI } from "../"; + +export class SourceControlApi { + private readonly client: AxiosInstance; + + private constructor(client: AxiosInstance) { + this.client = client; + } + + public static fromAtelierApi(api: AtelierAPI): SourceControlApi { + const { host, port, username, password, https: useHttps, pathPrefix } = api.config; + + if (!host || !port) { + throw new Error("No active InterSystems server connection for this file."); + } + + const normalizedPrefix = pathPrefix ? (pathPrefix.startsWith("/") ? pathPrefix : `/${pathPrefix}`) : ""; + const baseUrl = `${useHttps ? "https" : "http"}://${host}:${port}${encodeURI(normalizedPrefix)}`; + + const httpsAgent = new https.Agent({ + rejectUnauthorized: vscode.workspace.getConfiguration("http").get("proxyStrictSSL"), + }); + + const client = axios.create({ + baseURL: `${baseUrl}/api/sourcecontrol/vscode`, + headers: { + "Content-Type": "application/json", + }, + httpsAgent, + auth: + typeof username === "string" && typeof password === "string" + ? { + username, + password, + } + : undefined, + }); + + return new SourceControlApi(client); + } + + public post>( + endpoint: string, + data?: unknown, + config?: AxiosRequestConfig + ): Promise { + return this.client.post(endpoint, data, config); + } +} diff --git a/src/commands/contextHelp.ts b/src/commands/ccs/contextHelp.ts similarity index 57% rename from src/commands/contextHelp.ts rename to src/commands/ccs/contextHelp.ts index 09368472..7e78c0ca 100644 --- a/src/commands/contextHelp.ts +++ b/src/commands/ccs/contextHelp.ts @@ -1,10 +1,9 @@ -import axios from "axios"; -import * as https from "https"; import * as path from "path"; import * as vscode from "vscode"; -import { AtelierAPI } from "../api"; -import { handleError } from "../utils"; +import { AtelierAPI } from "../../api"; +import { SourceControlApi } from "../../api/ccs/sourceControl"; +import { handleError } from "../../utils"; interface ResolveContextExpressionResponse { status?: string; @@ -30,43 +29,20 @@ export async function resolveContextExpression(): Promise { const routine = path.basename(document.fileName); const api = new AtelierAPI(document.uri); - const { host, port, username, password, https: useHttps, pathPrefix } = api.config; - if (!host || !port) { - void vscode.window.showErrorMessage("No active InterSystems server connection for this file."); + let sourceControlApi: SourceControlApi; + try { + sourceControlApi = SourceControlApi.fromAtelierApi(api); + } catch (error) { + void vscode.window.showErrorMessage(error instanceof Error ? error.message : String(error)); return; } - const normalizedPrefix = pathPrefix ? (pathPrefix.startsWith("/") ? pathPrefix : `/${pathPrefix}`) : ""; - - const baseUrl = `${useHttps ? "https" : "http"}://${host}:${port}${encodeURI(normalizedPrefix)}`; - const url = `${baseUrl}/api/sourcecontrol/vscode/resolveContextExpression`; - - const httpsAgent = new https.Agent({ - rejectUnauthorized: vscode.workspace.getConfiguration("http").get("proxyStrictSSL"), - }); - try { - const response = await axios.post( - url, - { - routine, - contextExpression, - }, - { - headers: { - "Content-Type": "application/json", - }, - auth: - typeof username === "string" && typeof password === "string" - ? { - username, - password, - } - : undefined, - httpsAgent, - } - ); + const response = await sourceControlApi.post("/resolveContextExpression", { + routine, + contextExpression, + }); const data = response.data ?? {}; if (typeof data.status === "string" && data.status.toLowerCase() === "success" && data.textExpression) { diff --git a/src/extension.ts b/src/extension.ts index cc5488f2..8df09db5 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -162,7 +162,7 @@ import { import { WorkspaceNode, NodeBase } from "./explorer/nodes"; import { showPlanWebview } from "./commands/showPlanPanel"; import { isfsConfig } from "./utils/FileProviderUtil"; -import { resolveContextExpression } from "./commands/contextHelp"; +import { resolveContextExpression } from "./commands/ccs/contextHelp"; const packageJson = vscode.extensions.getExtension(extensionId).packageJSON; const extensionVersion = packageJson.version;