Skip to content

Commit d728f40

Browse files
authored
Feat: implement converterArquivo and converterArquivoCustomizado endpoints with text/plain response (#88)
1 parent 8826295 commit d728f40

10 files changed

Lines changed: 529 additions & 11 deletions

File tree

package.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,14 @@
362362
{
363363
"command": "vscode-objectscript.connectFolderToServerNamespace",
364364
"when": "!vscode-objectscript.connectActive && vscode-objectscript.explorerRootCount == 0 && workspaceFolderCount != 0"
365+
},
366+
{
367+
"command": "vscode-objectscript.ccs.convertCurrentItem",
368+
"when": "editorLangId =~ /^objectscript/ && vscode-objectscript.connectActive"
369+
},
370+
{
371+
"command": "vscode-objectscript.ccs.convertCurrentItemCustom",
372+
"when": "editorLangId =~ /^objectscript/ && vscode-objectscript.connectActive"
365373
}
366374
],
367375
"view/title": [
@@ -1305,6 +1313,16 @@
13051313
"command": "vscode-objectscript.showAllClassMembers",
13061314
"title": "Show All Class Members",
13071315
"icon": "$(symbol-class)"
1316+
},
1317+
{
1318+
"category": "Consistem",
1319+
"command": "vscode-objectscript.ccs.convertCurrentItem",
1320+
"title": "Converter Item (Simples)"
1321+
},
1322+
{
1323+
"category": "Consistem",
1324+
"command": "vscode-objectscript.ccs.convertCurrentItemCustom",
1325+
"title": "Converter Item Customizado"
13081326
}
13091327
],
13101328
"keybindings": [
@@ -1369,6 +1387,22 @@
13691387
"type": "string",
13701388
"default": "",
13711389
"when": "config.consistem.globalDocumentation.openInFile"
1390+
},
1391+
"consistem.converterItem.autoConvertOnSave": {
1392+
"description": "Converter Item ao Salvar",
1393+
"type": "boolean",
1394+
"default": true
1395+
},
1396+
"consistem.converterItem.autoConvertExcludePackages": {
1397+
"markdownDescription": "Excluir pacotes ao Salvar e Converter Item Automático (ex.: `cswutil70`). Essa opção depende de `consistem.converterItem.autoConvertOnSave` ativado.",
1398+
"type": "array",
1399+
"items": {
1400+
"type": "string"
1401+
},
1402+
"default": [
1403+
"cswutil70"
1404+
],
1405+
"when": "config.consistem.converterItem.autoConvertOnSave"
13721406
}
13731407
}
13741408
},

src/ccs/AGENTS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ Base path: `GET/POST {baseURL}/api/sourcecontrol/vscode` (see `BASE_PATH` in `sr
5757
- `POST /namespaces/{NAMESPACE}/obterGatilhosPorEmpresa`
5858
- Used by: `vscode-objectscript.ccs.locateTriggersByCompany` (`src/ccs/commands/locateTriggers.ts`)
5959
- Behavior: returns available company accounts and trigger counts for a routine.
60+
- `POST /namespaces/{NAMESPACE}/converterArquivo`
61+
- Used by: `vscode-objectscript.ccs.convertCurrentItem` (`src/ccs/commands/converterItem.ts`)
62+
- Behavior: runs default conversion for the active routine/file and returns plain text output.
63+
- `POST /namespaces/{NAMESPACE}/converterArquivoCustomizado`
64+
- Used by: `vscode-objectscript.ccs.convertCurrentItemCustom` (`src/ccs/commands/converterItem.ts`)
65+
- Behavior: runs conversion with user-selected options and returns plain text output.
6066

6167
## Reliability & UX
6268

src/ccs/commands/converterItem.ts

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import * as path from "path";
2+
import * as vscode from "vscode";
3+
4+
import { waitForCompileToFinish } from "../../commands/compile";
5+
import { handleError, outputChannel } from "../../utils";
6+
import { getCcsSettings } from "../config/settings";
7+
import { logDebug } from "../core/logging";
8+
import { ConverterClient, ConverterCustomRequestBody } from "../sourcecontrol/clients/converterClient";
9+
10+
const sharedClient = new ConverterClient();
11+
12+
interface NumericOption<T extends number> extends vscode.QuickPickItem {
13+
value: T;
14+
}
15+
16+
const tipoConversaoOptions: NumericOption<0 | 1 | 2>[] = [
17+
{ label: "Completa", description: "0", value: 0 },
18+
{ label: "Básica", description: "1", value: 1 },
19+
{ label: "Somente Flags", description: "2", value: 2 },
20+
];
21+
22+
const persistenciaOptions: NumericOption<0 | 1 | 2>[] = [
23+
{ label: "Não", description: "0", value: 0 },
24+
{ label: "Globais Conf.", description: "1", value: 1 },
25+
{ label: "Todas as Globais", description: "2", value: 2 },
26+
];
27+
28+
const eliminarCsmvOptions: NumericOption<0 | 1>[] = [
29+
{ label: "Sim", description: "0", value: 0 },
30+
{ label: "Não", description: "1", value: 1 },
31+
];
32+
33+
const flagsOptions: vscode.QuickPickItem[] = [{ label: "agrupSetPiece" }, { label: "objDynamic" }];
34+
35+
export async function convertCurrentItem(): Promise<void> {
36+
const editor = vscode.window.activeTextEditor;
37+
38+
if (!editor) {
39+
void vscode.window.showErrorMessage("Nenhum arquivo ativo para conversão.");
40+
return;
41+
}
42+
43+
await convertDocumentItem(editor.document, "Falha ao converter item.");
44+
}
45+
46+
export async function convertCurrentItemCustom(): Promise<void> {
47+
const editor = vscode.window.activeTextEditor;
48+
49+
if (!editor) {
50+
void vscode.window.showErrorMessage("Nenhum arquivo ativo para conversão.");
51+
return;
52+
}
53+
54+
const item = getItemName(editor.document);
55+
56+
try {
57+
const tipoConversao = await pickOption("Tipo de conversão", tipoConversaoOptions);
58+
if (tipoConversao === undefined) return;
59+
60+
const flgPersistencia = await pickOption("Persistência", persistenciaOptions);
61+
if (flgPersistencia === undefined) return;
62+
63+
const flgEliminarCSMV = await pickOption("Eliminar %CSMV", eliminarCsmvOptions);
64+
if (flgEliminarCSMV === undefined) return;
65+
66+
const selectedFlags = await vscode.window.showQuickPick(flagsOptions, {
67+
title: "Flags de conversão",
68+
placeHolder: "Selecione as flags de conversão",
69+
canPickMany: true,
70+
ignoreFocusOut: true,
71+
});
72+
73+
if (selectedFlags === undefined) return;
74+
75+
const strParamPersist = await vscode.window.showInputBox({
76+
title: "Complemento de persistência",
77+
prompt: "Informe strParamPersist (opcional)",
78+
placeHolder: "Ex: -log",
79+
ignoreFocusOut: true,
80+
});
81+
82+
if (strParamPersist === undefined) return;
83+
84+
const payload: ConverterCustomRequestBody = {
85+
item,
86+
tipoConversao,
87+
flgPersistencia,
88+
flgEliminarCSMV,
89+
strFlagsConv: selectedFlags.map((flag) => flag.label).join(","),
90+
strParamPersist,
91+
};
92+
93+
const responseText = await sharedClient.convertCustom(editor.document, payload);
94+
95+
renderConversionOutput(responseText);
96+
} catch (error) {
97+
handleError(error, "Falha ao converter item customizado.");
98+
}
99+
}
100+
101+
export async function convertCurrentItemOnSave(document: vscode.TextDocument): Promise<void> {
102+
const settings = getCcsSettings();
103+
104+
if (
105+
!settings.autoConvertOnSave ||
106+
!isMacDocument(document) ||
107+
isInExcludedPackage(document, settings.autoConvertExcludePackages)
108+
) {
109+
return;
110+
}
111+
112+
await waitForCompileBeforeAutoConvert(document);
113+
await convertDocumentItem(document, "Falha ao converter item automaticamente ao salvar.", true);
114+
}
115+
116+
async function waitForCompileBeforeAutoConvert(document: vscode.TextDocument): Promise<void> {
117+
try {
118+
await waitForCompileToFinish(document);
119+
} catch (error) {
120+
logDebug("Falha ao aguardar compilação antes da conversão automática", error);
121+
}
122+
}
123+
124+
async function convertDocumentItem(
125+
document: vscode.TextDocument,
126+
errorMessage: string,
127+
silentError = false
128+
): Promise<void> {
129+
const item = getItemName(document);
130+
131+
try {
132+
const responseText = await sharedClient.convertDefault(document, item);
133+
renderConversionOutput(responseText);
134+
} catch (error) {
135+
if (silentError) {
136+
logDebug("Falha na conversão automática ao salvar", error);
137+
return;
138+
}
139+
140+
handleError(error, errorMessage);
141+
}
142+
}
143+
144+
function isMacDocument(document: vscode.TextDocument): boolean {
145+
return path.extname(document.fileName).toLowerCase() === ".mac";
146+
}
147+
148+
function isInExcludedPackage(document: vscode.TextDocument, excludedPackages: string[]): boolean {
149+
const normalizedExcluded = new Set(excludedPackages.map((pkg) => pkg.toLowerCase()));
150+
const pathParts = document.fileName
151+
.split(/[/\\]+/)
152+
.map((part) => part.trim().toLowerCase())
153+
.filter((part) => part.length > 0);
154+
155+
return pathParts.some((part) => normalizedExcluded.has(part));
156+
}
157+
158+
function renderConversionOutput(responseText: string): void {
159+
responseText
160+
.split(/\r?\n/)
161+
.filter((line) => line.length > 0)
162+
.forEach((line) => outputChannel.appendLine(line));
163+
164+
outputChannel.show(true);
165+
}
166+
167+
async function pickOption<T extends number>(title: string, options: NumericOption<T>[]): Promise<T | undefined> {
168+
const selected = await vscode.window.showQuickPick(options, {
169+
title,
170+
ignoreFocusOut: true,
171+
});
172+
173+
return selected?.value;
174+
}
175+
176+
function getItemName(document: vscode.TextDocument): string {
177+
return path.basename(document.fileName);
178+
}

src/ccs/config/schema.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
# Configuração do módulo CCS
22

3-
As opções abaixo ficam no escopo `objectscript.ccs` e controlam as integrações específicas
4-
para o fork da Consistem.
5-
6-
| Chave | Tipo | Padrão | Descrição |
7-
| ---------------- | ------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------- |
8-
| `endpoint` | `string` | `undefined` | URL base alternativa para a API. Se não definida, a URL é derivada da conexão ativa do Atelier. |
9-
| `requestTimeout` | `number` | `5000` | Tempo limite (ms) aplicado às chamadas HTTP do módulo. Valores menores ou inválidos são normalizados para zero. |
10-
| `debugLogging` | `boolean` | `false` | Quando verdadeiro, registra mensagens detalhadas no `ObjectScript` Output Channel. |
11-
| `flags` | `Record<string, boolean>` | `{}` | Feature flags opcionais que podem ser lidas pelas features do módulo. |
3+
As opções abaixo controlam as integrações específicas para o fork da Consistem.
4+
5+
| Chave | Tipo | Padrão | Descrição |
6+
| ----------------------------------------- | ------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------- |
7+
| `objectscript.ccs.endpoint` | `string` | `undefined` | URL base alternativa para a API. Se não definida, a URL é derivada da conexão ativa do Atelier. |
8+
| `objectscript.ccs.requestTimeout` | `number` | `5000` | Tempo limite (ms) aplicado às chamadas HTTP do módulo. Valores menores ou inválidos são normalizados para zero. |
9+
| `objectscript.ccs.debugLogging` | `boolean` | `false` | Quando verdadeiro, registra mensagens detalhadas no `ObjectScript` Output Channel. |
10+
| `objectscript.ccs.flags` | `Record<string, boolean>` | `{}` | Feature flags opcionais que podem ser lidas pelas features do módulo. |
11+
| `consistem.converterItem.autoConvertOnSave` | `boolean` | `true` | Quando verdadeiro, executa a conversão simples ao salvar arquivos `.mac`. |
12+
| `consistem.converterItem.autoConvertExcludePackages` | `string[]` | `["cswutil70"]` | Lista de pacotes/pastas excluídos da conversão automática ao salvar. |
13+
14+
> Compatibilidade: as chaves antigas `objectscript.ccs.autoConvertOnSave` e
15+
> `objectscript.ccs.autoConvertExcludePackages` ainda são lidas como fallback.
1216
1317
Essas configurações não exigem reload da janela; toda leitura é feita sob demanda.

src/ccs/config/settings.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,34 @@ export interface CcsSettings {
55
requestTimeout: number;
66
debugLogging: boolean;
77
flags: Record<string, boolean>;
8+
autoConvertOnSave: boolean;
9+
autoConvertExcludePackages: string[];
810
}
911

1012
const CCS_CONFIGURATION_SECTION = "objectscript.ccs";
13+
const CONSISTEM_CONFIGURATION_SECTION = "consistem";
1114
const DEFAULT_TIMEOUT = 5000;
15+
const DEFAULT_AUTO_CONVERT_EXCLUDE_PACKAGES = ["cswutil70"];
1216

1317
export function getCcsSettings(): CcsSettings {
1418
const configuration = vscode.workspace.getConfiguration(CCS_CONFIGURATION_SECTION);
1519
const endpoint = sanitizeEndpoint(configuration.get<string | undefined>("endpoint"));
1620
const requestTimeout = coerceTimeout(configuration.get<number | undefined>("requestTimeout"));
1721
const debugLogging = Boolean(configuration.get<boolean | undefined>("debugLogging"));
1822
const flags = configuration.get<Record<string, boolean>>("flags") ?? {};
23+
const consistemConfiguration = vscode.workspace.getConfiguration(CONSISTEM_CONFIGURATION_SECTION);
24+
const autoConvertOnSave = getAutoConvertOnSaveSetting(consistemConfiguration);
25+
const autoConvertExcludePackages = sanitizeExcludePackages(
26+
getAutoConvertExcludePackagesSetting(consistemConfiguration)
27+
);
1928

2029
return {
2130
endpoint,
2231
requestTimeout,
2332
debugLogging,
2433
flags,
34+
autoConvertOnSave,
35+
autoConvertExcludePackages,
2536
};
2637
}
2738

@@ -49,3 +60,35 @@ function coerceTimeout(timeout: number | undefined): number {
4960

5061
return Math.max(0, Math.floor(timeout));
5162
}
63+
64+
function sanitizeExcludePackages(packages: string[] | undefined): string[] {
65+
if (!Array.isArray(packages)) {
66+
return DEFAULT_AUTO_CONVERT_EXCLUDE_PACKAGES;
67+
}
68+
69+
return packages
70+
.map((pkg) => (typeof pkg === "string" ? pkg.trim().toLowerCase() : ""))
71+
.filter((pkg) => pkg.length > 0);
72+
}
73+
74+
function getAutoConvertOnSaveSetting(configuration: vscode.WorkspaceConfiguration): boolean {
75+
const consistemValue = configuration.get<boolean | undefined>("converterItem.autoConvertOnSave");
76+
if (typeof consistemValue === "boolean") {
77+
return consistemValue;
78+
}
79+
80+
// Backward compatibility for previous key path
81+
return vscode.workspace.getConfiguration(CCS_CONFIGURATION_SECTION).get<boolean>("autoConvertOnSave", true);
82+
}
83+
84+
function getAutoConvertExcludePackagesSetting(configuration: vscode.WorkspaceConfiguration): string[] | undefined {
85+
const consistemValue = configuration.get<string[] | undefined>("converterItem.autoConvertExcludePackages");
86+
if (Array.isArray(consistemValue)) {
87+
return consistemValue;
88+
}
89+
90+
// Backward compatibility for previous key path
91+
return vscode.workspace
92+
.getConfiguration(CCS_CONFIGURATION_SECTION)
93+
.get<string[] | undefined>("autoConvertExcludePackages");
94+
}

src/ccs/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,5 @@ export {
2929
followSourceAnalysisLinkCommand,
3030
} from "./providers/SourceAnalysisLinkProvider";
3131
export { createItem } from "./commands/createItem";
32+
33+
export { convertCurrentItem, convertCurrentItemCustom, convertCurrentItemOnSave } from "./commands/converterItem";

0 commit comments

Comments
 (0)