Skip to content

Commit 06a166c

Browse files
authored
fix: validation of counter in scg configs (#837)
* Fix validation of counter in scg configs * Use ajv for validating data schemas * Fix import path and improve error message * Allow additional properties in scg validation
1 parent 1c768e6 commit 06a166c

5 files changed

Lines changed: 433 additions & 98 deletions

File tree

client/src/scg.ts

Lines changed: 16 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import * as yaml from 'js-yaml';
22
import * as path from 'path';
33
import * as vscode from 'vscode';
4+
import Ajv from 'ajv';
5+
6+
import * as scgSchema from '../../schemas/scg_config.schema.json';
7+
8+
const ajv = new Ajv();
9+
const validate_scg = ajv.compile<ScgConfigSchema>(scgSchema);
410

511
export interface ScgConfigSchema {
612
outputfile?: string;
@@ -153,89 +159,32 @@ export async function readScgConfig(filePath: string): Promise<ScgConfigSchema |
153159
const uri = vscode.Uri.file(filePath);
154160
const document = await vscode.workspace.openTextDocument(uri);
155161
const fileContents = document.getText();
156-
const data = yaml.load(fileContents) as ScgConfigSchema;
157-
if (!validateScgConfig(data)) {
158-
return undefined;
162+
const data = yaml.load(fileContents);
163+
164+
if (validate_scg(data)) {
165+
return data;
159166
}
160-
return data;
167+
let errorMessage = `Error validating ${filePath} against the SCG schema:\n`;
168+
errorMessage += validate_scg.errors.map(error => `SCG config validation error at ${error.instancePath}: ${error.message}`).join('\n');
169+
vscode.window.showErrorMessage(errorMessage);
170+
return undefined;
161171
} catch {
162172
return undefined;
163173
}
164174
}
165175

166-
export function validateScgConfig(data: ScgConfigSchema): boolean {
167-
if (!data.templatepath || typeof data.templatepath !== 'string') return false;
168-
if (data.adjustspacing && typeof data.adjustspacing !== 'boolean') return false;
169-
if (data.verifycontent && typeof data.verifycontent !== 'boolean') return false;
170-
171-
// Validate optional fields
172-
if (data.outputfile && typeof data.outputfile !== 'string') return false;
173-
174-
// Validate counters
175-
if (data.counters) {
176-
for (const counter of data.counters) {
177-
if (typeof counter.name !== 'string' || typeof counter.value !== 'number') return false;
178-
}
179-
}
180-
181-
// Validate sources
182-
for (const source of data.sources) {
183-
if (typeof source.filename !== 'string' || typeof source.id !== 'string') return false;
184-
if (source.sheet && typeof source.sheet !== 'string') return false;
185-
if (source.delimiter && typeof source.delimiter !== 'string') return false;
186-
}
187-
188-
// Validate layout
189-
for (const layout of data.layout) {
190-
if (typeof layout.name !== 'string') return false;
191-
if (layout.source && typeof layout.source !== 'string') return false;
192-
if (layout.include && typeof layout.include !== 'object') return false;
193-
}
194-
195-
return true;
196-
}
197-
198176
export async function isScgConfig(filePath: string): Promise<boolean> {
199177
try {
200178
const uri = vscode.Uri.file(filePath);
201179
const document = await vscode.workspace.openTextDocument(uri);
202180
const fileContents = document.getText();
203-
const data = yaml.load(fileContents) as ScgConfigSchema;
204-
return validateScgConfig(data);
181+
const data = yaml.load(fileContents);
182+
return validate_scg(data);
205183
} catch {
206184
return false;
207185
}
208186
}
209187

210-
export async function findScgConfigFiles(): Promise<vscode.Uri[]> {
211-
try {
212-
const activeEditor = vscode.window.activeTextEditor;
213-
if (!activeEditor) {
214-
return [];
215-
}
216-
let currentFolder = vscode.Uri.file(activeEditor.document.uri.fsPath).with({ path: vscode.Uri.file(activeEditor.document.uri.fsPath).path.replace(/\/[^/]+$/, '') });
217-
const workspaceFolder = vscode.workspace.workspaceFolders?.[0].uri.fsPath;
218-
219-
while (currentFolder.fsPath.startsWith(workspaceFolder || '') && currentFolder.fsPath !== workspaceFolder) {
220-
const files = await vscode.workspace.findFiles(new vscode.RelativePattern(currentFolder, '*.yaml'));
221-
const scgConfigFiles: vscode.Uri[] = [];
222-
for (const file of files) {
223-
if (await isScgConfig(file.fsPath)) {
224-
scgConfigFiles.push(file);
225-
}
226-
}
227-
if (scgConfigFiles.length > 0) {
228-
return scgConfigFiles;
229-
}
230-
currentFolder = vscode.Uri.file(currentFolder.fsPath).with({ path: vscode.Uri.file(currentFolder.fsPath).path.replace(/\/[^/]+$/, '') });
231-
}
232-
return [];
233-
} catch (error) {
234-
console.error('Error finding SCG config files:', error);
235-
return [];
236-
}
237-
}
238-
239188

240189
export class ScgSource {
241190
id: string;

client/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"sourceMap": true,
1111
"jsx": "react",
1212
"jsxFactory": "vscpp",
13-
"jsxFragmentFactory": "vscppf"
13+
"jsxFragmentFactory": "vscppf",
14+
"resolveJsonModule": true
1415
},
1516
"include": [
1617
"src",

0 commit comments

Comments
 (0)