Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/74-json-schemas #84

Merged
merged 4 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion controller/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ export function activate(context: vscode.ExtensionContext) {
"**/src/vision/sparql/*.sparql"
);
let viewpointsFolderWatcher = vscode.workspace.createFileSystemWatcher(
"**/src/vision/viewpoints/*.json"
"**/src/vision/viewpoints/**/*.json"
);
let commandsFolderWatcher = vscode.workspace.createFileSystemWatcher(
"**/src/vision/commands/*.json"
Expand Down
24 changes: 24 additions & 0 deletions controller/src/interfaces/ICommandSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Defines the structure of the JSON object that is received from the JSON files in the commands directory.
*
* @field name - The name of the command
* @field id - The id of the command
* @field command - The command object
*
*/
export default interface ICommandSchema {
name: string;
id: string;
command: Command;
}

/**
* Defines the structure of the command
*
* @field type - CRUD command
*
*/
interface Command {
type: string;
}

31 changes: 31 additions & 0 deletions controller/src/interfaces/IPagesSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Defines the structure of the JSON object that is received from the pages.json file.
*
* @field title - The title of the page item
* @field type - The type of the page item. Home = Home Page (there can only be one home page), Group = collection of pages, Diagram = Diagram Page, Tree = Tree Page, and Table = Table Page
* @field path - The path to the configuration of the page item
* @field iconUrl - The url to the icon that gets displayed in the home page. This is typically the url to a SVG published to the web
* @field children - The children of the group items
*
*/
export default interface IPagesSchema {
title: string;
type: string;
path?: string;
iconUrl?: string;
children?: Children[];
}

/**
* Defines the structure of the child pages
*
* @field title - The title of the child page item
* @field type - The type of the child page item. Home = Home Page (there can only be one home page), Group = collection of pages, Diagram = Diagram Page, Tree = Tree Page, and Table = Table Page
* @field path - The path to the configuration of the child page item
*
*/
interface Children {
title: string;
type: string;
path: string;
}
18 changes: 18 additions & 0 deletions controller/src/interfaces/ISparqlConfigSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Defines the structure of the JSON object that is received from the sparqlConfig.json file.
*
* @remarks
* This interface relates to {@link https://jena.apache.org/documentation/fuseki2/fuseki-server-info.html | Fuseki endpoints}.
*
* @field queryEndpoint - The query endpoint
* @field updateAssertionEndpoint - The update endpoint for assertions
* @field updateInferenceEndpoint - The update endpoint for inferences
* @field pingEndpoint - The ping endpoint
*
*/
export default interface ISparqlConfigSchema {
queryEndpoint: string;
updateAssertionEndpoint: string;
updateInferenceEndpoint: string;
pingEndpoint: string;
}
38 changes: 38 additions & 0 deletions controller/src/schemas/commands/commandSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import ICommandSchema from "../../interfaces/ICommandSchema";
import { JSONSchemaType } from "ajv";

/**
* This JSON schema is used with AJV to validate JSON files stored in the commands directory that is stored within OML models.
*
* @remarks
* This constant will help validate JSON data using {@link https://ajv.js.org | AJV}.
*
* The data within the constant was generated with {@link https://www.jsonschema.net | JSON Schema}.
*
*/

export const commandSchema: JSONSchemaType<ICommandSchema[]> = {
$schema: "http://json-schema.org/draft-07/schema#",
type: "array",
items: {
type: "object",
properties: {
name: {
type: "string",
},
id: {
type: "string",
},
command: {
type: "object",
properties: {
type: {
type: "string",
},
},
required: ["type"],
},
},
required: ["name", "id", "command"],
},
};
40 changes: 40 additions & 0 deletions controller/src/schemas/config/sparqlConfigSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import ISparqlConfigSchema from '../../interfaces/ISparqlConfigSchema';
import { JSONSchemaType } from "ajv";

/**
* This JSON schema is used with AJV to validate sparqlConfig.json data that is stored within OML models.
*
* @remarks
* This constant will help validate JSON data using {@link https://ajv.js.org | AJV}.
*
* The data within the constant was generated with {@link https://www.jsonschema.net | JSON Schema}.
*
*/

export const sparqlConfigSchema: JSONSchemaType<ISparqlConfigSchema> = {
type: 'object',
properties: {
queryEndpoint: {
type: 'string',
title: 'Query Endpoint',
default: 'http://example.com/sparql',
examples: ['http://example.com/sparql']
},
updateAssertionEndpoint: {
type: 'string',
title: 'Update Assertion Endpoint',
default: 'http://example.com/update/assertion'
},
updateInferenceEndpoint: {
type: 'string',
title: 'Update Inference Endpoint',
default: 'http://example.com/update/inference'
},
pingEndpoint: {
type: 'string',
title: 'Ping Endpoint',
default: 'http://example.com/ping'
}
},
required: ['queryEndpoint', 'updateAssertionEndpoint', 'updateInferenceEndpoint', 'pingEndpoint']
};
34 changes: 34 additions & 0 deletions controller/src/schemas/validator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Ajv, { JSONSchemaType } from "ajv";
import ISparqlConfigSchema from "../interfaces/ISparqlConfigSchema";
import ICommandSchema from "../interfaces/ICommandSchema";
import IPagesSchema from "../interfaces/IPagesSchema";

/**
* This schema validator uses AJV to validate JSON data based on a schema interface.
*
* @remarks
* This function will help validate JSON data using {@link https://ajv.js.org | AJV}.
*
* To learn more about Typescript interfaces refer to the official {@link https://www.typescriptlang.org/docs/handbook/2/objects.html | docs}.
*
* @param schema: The JSON schema that will be used to validate the data
* @param data: The JSON data that will be validated against a schema
*
*/
export const validateSchema = (
schema: JSONSchemaType<ISparqlConfigSchema | ICommandSchema[] | IPagesSchema[]>,
data: Object
) => {
const ajv = new Ajv();

// Validates the provided schema
const validate = ajv.compile(schema);

// Log errors
if (!validate(data)) {
console.error(validate.errors);
}

// Return true if schema is valid and false if invalid
return validate(data);
};
60 changes: 60 additions & 0 deletions controller/src/schemas/viewpoints/pagesSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import IPagesSchema from "../../interfaces/IPagesSchema";
import { JSONSchemaType } from "ajv";

/**
* This JSON schema is used with AJV to validate pages.json data that is stored within OML models.
*
* @remarks
* This constant will help validate JSON data using {@link https://ajv.js.org | AJV}.
*
* This schema has a recursive schema which you can read more {@link https://ajv.js.org/guide/combining-schemas.html | here}.
*
* This schema has nullable properties which you can read more {@link https://ajv.js.org/guide/typescript.html#utility-types-for-schemas | here}.
*
* The data within the constant was generated with {@link https://www.jsonschema.net | JSON Schema}.
*
*/

export const pagesSchema: JSONSchemaType<IPagesSchema[]> = {
$schema: "http://json-schema.org/draft-07/schema#",
type: "array",
items: {
type: "object",
properties: {
title: {
type: "string",
},
type: {
type: "string",
},
path: {
type: "string",
nullable: true,
},
iconUrl: {
type: "string",
nullable: true,
},
children: {
type: "array",
nullable: true,
items: {
type: "object",
properties: {
title: {
type: "string",
},
type: {
type: "string",
},
path: {
type: "string",
},
},
required: ["title", "type", "path"],
},
},
},
required: ["title", "type"],
},
};
17 changes: 10 additions & 7 deletions controller/src/utilities/loaders/loadCommandFiles.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { workspace, Uri, commands, window, FileType } from "vscode";
import { TablePanel } from "../../panels/TablePanel";
import { PropertyPanelProvider } from "../../panels/PropertyPanelProvider";
import { validateSchema } from "../../schemas/validator";
import { commandSchema } from "../../schemas/commands/commandSchema";
// TODO: handle multiple workspaces (currently assumes model is in the 1st)

/**
Expand Down Expand Up @@ -35,7 +37,14 @@ export const loadCommandFiles = async (
const fileUri = Uri.joinPath(commandFolderUri, file);
const buffer = await workspace.fs.readFile(fileUri);
const content = JSON.parse(buffer.toString());

// Validate if the content matches the JSON Command Schema
const validate = validateSchema(commandSchema, content);
if (files.length > 0 && validate) {
commands.executeCommand("setContext", "vision:hasCommand", true);
window.showInformationMessage(`${file} loaded successfully.`);
} else {
window.showErrorMessage(`Invalid or missing ${file}.`);
}
try {
TablePanel.updateCommands();
PropertyPanelProvider.updateCommands();
Expand All @@ -46,12 +55,6 @@ export const loadCommandFiles = async (
}
}
}
if (files.length > 0) {
commands.executeCommand("setContext", "vision:hasCommand", true);
window.showInformationMessage("Command files loaded successfully.");
} else {
window.showWarningMessage("Command files not found.");
}
} catch (err) {
if (
err instanceof Error &&
Expand Down
Loading