From fe8f86f651be11d5b47ddbd8d821767549badfbf Mon Sep 17 00:00:00 2001 From: braunc8 Date: Fri, 12 Jul 2024 13:47:11 -0400 Subject: [PATCH 01/36] fixed issue with automatic overriding of input jar file, added ocnifguration manager --- .../image-generation/image-generator.ts | 176 ++++++++++++-- .../image-generation/preview-provider.ts | 42 ++-- .../image-generation/save-image-command.ts | 219 ------------------ langium/src/extension/main.ts | 22 +- .../managers/configuration-manager.ts | 167 +++++++++++++ langium/tsconfig.json | 2 +- 6 files changed, 350 insertions(+), 278 deletions(-) delete mode 100644 langium/src/extension/image-generation/save-image-command.ts create mode 100644 langium/src/extension/managers/configuration-manager.ts diff --git a/langium/src/extension/image-generation/image-generator.ts b/langium/src/extension/image-generation/image-generator.ts index e6ceb35..ec3e524 100644 --- a/langium/src/extension/image-generation/image-generator.ts +++ b/langium/src/extension/image-generation/image-generator.ts @@ -1,21 +1,28 @@ import * as vscode from 'vscode'; import util from "node:util"; -import { SaveImageCommand } from './save-image-command.js'; import { Command, CommandUser } from '../managers/command-manager.js'; +import { EventSubscriber, isTextEditor } from '../managers/event-manager.js'; +import { ConfigurationManager } from '../managers/configuration-manager.js'; -export class ImageGenerator implements CommandUser{ +export class ImageGenerator implements CommandUser, EventSubscriber{ // New channel created in vscode terminal for user debugging. private output_channel: vscode.OutputChannel; - // Defines the command needed to execute the extension. - private save_image_command: SaveImageCommand; - + //configuration manager to fetch configurations from + private configuration: ConfigurationManager; + + private editor!: vscode.TextEditor; //current editor + private document!: vscode.TextDocument; //current document + private directory!: vscode.WorkspaceFolder; //current directory + //possible image types and associated commands private types: ImageType[]; - constructor(save_image_command: SaveImageCommand, output_channel: vscode.OutputChannel) { - this.save_image_command = save_image_command; + constructor(configuration: ConfigurationManager, output_channel: vscode.OutputChannel) { this.output_channel = output_channel; + + this.configuration = configuration; + this.types = [ { exe_command: "jpipe.downloadPNG", @@ -26,6 +33,9 @@ export class ImageGenerator implements CommandUser{ format: Format.SVG } ]; + + //automatically registers to start + this.update(vscode.window.activeTextEditor); } //used to register commands with command manager @@ -34,29 +44,152 @@ export class ImageGenerator implements CommandUser{ this.types.forEach( (type) =>{ command_list.push({ command: type.exe_command, - callback: () => {this.saveImage(type.format)} + callback: () => {this.generate({format: type.format, save_image: true})} }); }); return command_list; } - //Generates an image for the selected justification diagram - public async saveImage(format: Format): Promise { + //updater functions + public async update(data: vscode.TextEditor | undefined): Promise{ + if(isTextEditor(data)){ + const {editor, document, directory} = this.updateEditor(data); + + this.editor = editor; + this.document = document; + this.directory = directory; + } + } + + public async generate(command_settings: CommandSettings): Promise<{stdout: any}>{ const { exec } = require('node:child_process'); const execPromise = util.promisify(exec); - // Execute the command, and wait for the result (must be synchronous). - // TODO: Validate that this actually executes synchronously. - try{ - let command = await this.save_image_command.makeCommand({ format: format, save_image: true}); - const {stdout, stderr} = await execPromise(command); + const command = await this.makeCommand(command_settings); + const output: {stdout: any, stderr: any} = await execPromise(command); + + this.output_channel.appendLine(output.stderr.toString()); + + return {stdout: output.stdout}; + } - this.output_channel.appendLine(stdout.toString()); - this.output_channel.appendLine(stderr.toString()); - } catch (error: any){ - this.output_channel.appendLine(error.toString()); + //creates the command based on command settings + private async makeCommand(command_settings: CommandSettings): Promise{ + let jar_file = this.configuration.getConfiguration("jpipe.jarFile"); + + let input_file = this.document.uri; + + let diagram_name = this.findDiagramName(this.document,this.editor); + + let format = this.getFormat(command_settings); + + let log_level = this.configuration.getConfiguration("jpipe.logLevel"); + + let command = 'java -jar ' + jar_file + ' -i ' + input_file.path + ' -d '+ diagram_name + ' --format ' + format + ' --log-level ' + log_level; + + this.output_channel.appendLine("Made using jar file: " + jar_file.toString()); + if(command_settings.save_image){ + let output_file = await this.makeOutputPath(diagram_name, command_settings); + command += ' -o ' + output_file.path; } + + return command; + } + + //returns the current diagram name + public getDiagramName(): string{ + return this.findDiagramName(this.document, this.editor); + } + + //helper function to get the diagram name from the document + private findDiagramName(document: vscode.TextDocument, editor: vscode.TextEditor): string{ + let diagram_name: string | undefined; + let match: RegExpExecArray | null; + let i = 0; + + let lines = document.getText().split("\n"); + let line_num = editor.selection.active.line + 1; + + while(i < lines.length && (i < line_num || diagram_name===null)){ + match = /justification .*/i.exec(lines[i]) || /pattern .*/i.exec(lines[i]); + + if (match){ + diagram_name = match[0].split(' ')[1]; + } + + i++; + } + + if(diagram_name === undefined){ + throw new Error("Diagram name not found"); + } + + return diagram_name; + } + + //helper function to set default format + private getFormat(command_settings: CommandSettings): Format{ + let format = command_settings.format; + + if(format === undefined){ + format = Format.PNG; + } + + return format; + } + + //creates the output filepath by asking for user input + private async makeOutputPath(diagram_name: string, command_settings: CommandSettings): Promise{ + if(command_settings.format === undefined){ + command_settings.format = Format.PNG; + } + + let default_output_file = vscode.Uri.joinPath(this.directory.uri, diagram_name + "." + command_settings.format.toLowerCase()); + + let save_dialog_options: vscode.SaveDialogOptions = { + defaultUri: default_output_file, + saveLabel: "Save proof model", + filters: { + 'Images': [Format.PNG.toLowerCase(), Format.SVG.toLowerCase()] + } + } + + let output_file = await vscode.window.showSaveDialog(save_dialog_options); + + if(!output_file){ + throw new Error("Please enter a save location"); + } + + return output_file; + } + + //helper function to perform updates related to a new text editor + private updateEditor(editor: vscode.TextEditor | undefined): {editor: vscode.TextEditor, document: vscode.TextDocument, directory: vscode.WorkspaceFolder}{ + let document: vscode.TextDocument; + let directory: vscode.WorkspaceFolder; + + if(!editor){ + editor = this.editor; + document = this.document; + directory = this.directory; + }else{ + document = editor.document; + directory = this.getDirectory(document); + } + + return{editor, document, directory}; + } + + //helper function to get directory for updating + private getDirectory(document: vscode.TextDocument): vscode.WorkspaceFolder{ + let directory = vscode.workspace.getWorkspaceFolder(document.uri); + + if(!directory){ + directory = this.directory; + } + + return directory; } } @@ -70,4 +203,7 @@ export enum Format{ SVG = "SVG", } - +type CommandSettings = { + format?: Format, + save_image: boolean +} \ No newline at end of file diff --git a/langium/src/extension/image-generation/preview-provider.ts b/langium/src/extension/image-generation/preview-provider.ts index a7b9119..baabbd9 100644 --- a/langium/src/extension/image-generation/preview-provider.ts +++ b/langium/src/extension/image-generation/preview-provider.ts @@ -1,10 +1,9 @@ -import * as vscode from 'vscode' -import util from "node:util"; -import { SaveImageCommand } from './save-image-command.js'; -import { Format } from './image-generator.js'; +import * as vscode from 'vscode'; +import { Format, ImageGenerator } from './image-generator.js'; import { Command, CommandUser } from '../managers/command-manager.js'; import { EventSubscriber, isTextEditor, isTextEditorSelectionChangeEvent } from '../managers/event-manager.js'; + //altered from editorReader export class PreviewProvider implements vscode.CustomTextEditorProvider, CommandUser, EventSubscriber, EventSubscriber { @@ -31,15 +30,15 @@ export class PreviewProvider implements vscode.CustomTextEditorProvider, Command // Global text panel used to display the jd code. private static textPanel: Thenable; - private static save_image_command: SaveImageCommand; + private static image_generator: ImageGenerator; - constructor(save_image_command: SaveImageCommand, output_channel: vscode.OutputChannel) { + constructor(image_generator: ImageGenerator, output_channel: vscode.OutputChannel) { // Without any initial data, must be empty string to prevent null error. PreviewProvider.svg_data = ""; this.output_channel = output_channel; PreviewProvider.updating = false; PreviewProvider.webviewDisposed = true; - PreviewProvider.save_image_command = save_image_command; + PreviewProvider.image_generator = image_generator; vscode.window.registerCustomEditorProvider(PreviewProvider.ext_command, this); } @@ -51,16 +50,14 @@ export class PreviewProvider implements vscode.CustomTextEditorProvider, Command public async update(editor: vscode.TextEditor | undefined): Promise; public async update(changes: vscode.TextEditorSelectionChangeEvent): Promise; public async update(data: (vscode.TextEditor | undefined) | vscode.TextEditorSelectionChangeEvent): Promise{ - if(PreviewProvider.webviewDisposed){ - return; + if(!PreviewProvider.webviewDisposed){ + if(isTextEditorSelectionChangeEvent(data)){ + this.updateTextSelection(data); + } + else if(isTextEditor(data)){ + this.updateEditor(data); + } } - - if(isTextEditorSelectionChangeEvent(data)){ - this.updateTextSelection(data); - } - else if(isTextEditor(data)){ - this.updateEditor(data); - } } private async createWebview(): Promise{ @@ -149,15 +146,10 @@ export class PreviewProvider implements vscode.CustomTextEditorProvider, Command // Executes the jar file for updated SVG public async updateSVG(): Promise { - const { exec } = require('node:child_process'); - const execPromise = util.promisify(exec); - try{ - let command = await PreviewProvider.save_image_command.makeCommand({format: Format.SVG, save_image: false}); - PreviewProvider.webviewPanel.title = PreviewProvider.save_image_command.getDiagramName(); - - const {stdout, stderr} = await execPromise(command); - this.output_channel.appendLine(stderr.toString()); + const {stdout} = await PreviewProvider.image_generator.generate({format: Format.SVG, save_image: false}) + + PreviewProvider.webviewPanel.title = PreviewProvider.image_generator.getDiagramName(); PreviewProvider.svg_data = stdout; }catch (error: any){ this.output_channel.appendLine(error.toString()); @@ -192,7 +184,7 @@ export class PreviewProvider implements vscode.CustomTextEditorProvider, Command //helper function to update text selection private async updateTextSelection(event: vscode.TextEditorSelectionChangeEvent){ if (event !== undefined && event.textEditor.document.languageId=="jpipe" && !PreviewProvider.webviewDisposed){ - let new_diagram = PreviewProvider.save_image_command.getDiagramName(); + let new_diagram = PreviewProvider.image_generator.getDiagramName(); let token : vscode.CancellationTokenSource = new vscode.CancellationTokenSource(); diff --git a/langium/src/extension/image-generation/save-image-command.ts b/langium/src/extension/image-generation/save-image-command.ts deleted file mode 100644 index 4394a23..0000000 --- a/langium/src/extension/image-generation/save-image-command.ts +++ /dev/null @@ -1,219 +0,0 @@ -import * as vscode from 'vscode'; -import { Format } from './image-generator.js'; -import { EventSubscriber, isConfigurationChangeEvent, isTextEditor } from '../managers/event-manager.js'; - -//creates the command required to run to generate the image -export class SaveImageCommand implements EventSubscriber, EventSubscriber{ - private output_channel: vscode.OutputChannel - - private jar_file: string; //location of the jar file - private log_level: string; //log level setting - - private editor!: vscode.TextEditor; //current editor - private document!: vscode.TextDocument; //current document - private directory!: vscode.WorkspaceFolder; //current directory - - constructor(private readonly context: vscode.ExtensionContext, editor: vscode.TextEditor | undefined, output_channel: vscode.OutputChannel){ - this.output_channel = output_channel; - - //Finding the associated compiler - this.jar_file = this.getJarFile(); - - //the log level should only change on configuration change - this.log_level = this.getLogLevel(); - - //automatically registers to start - this.update(editor); - } - - //updater functions - public async update(change: vscode.ConfigurationChangeEvent): Promise; - public async update(editor: vscode.TextEditor | undefined): Promise; - public async update(data: vscode.ConfigurationChangeEvent | vscode.TextEditor | undefined): Promise{ - if(isConfigurationChangeEvent(data)){ - if(data.affectsConfiguration("jpipe.logLevel")){ - this.log_level = this.getLogLevel(); - } - else if(data.affectsConfiguration("jpipe.jarFile")){ - this.jar_file = this.getJarFile(); - } - }else if(isTextEditor(data)){ - const {editor, document, directory} = this.updateEditor(data); - - this.editor = editor; - this.document = document; - this.directory = directory; - } - } - - //creates the command based on command settings - public async makeCommand(command_settings: CommandSettings): Promise{ - let input_file = this.document.uri; - let diagram_name = this.findDiagramName(this.document,this.editor); - let format = this.getFormat(command_settings); - - let command = 'java -jar ' + this.jar_file + ' -i ' + input_file.path + ' -d '+ diagram_name + ' --format ' + format + ' --log-level ' + this.log_level; - - if(command_settings.save_image){ - let output_file = await this.makeOutputPath(diagram_name, command_settings); - command += ' -o ' + output_file.path; - } - - return command; - } - - //returns the current diagram name - public getDiagramName(): string{ - return this.findDiagramName(this.document, this.editor); - } - - //helper function to get the diagram name from the document - private findDiagramName(document: vscode.TextDocument, editor: vscode.TextEditor): string{ - let diagram_name: string | undefined; - let match: RegExpExecArray | null; - let i = 0; - - let lines = document.getText().split("\n"); - let line_num = editor.selection.active.line + 1; - - while(i < lines.length && (i < line_num || diagram_name===null)){ - match = /justification .*/i.exec(lines[i]) || /pattern .*/i.exec(lines[i]); - - if (match){ - diagram_name = match[0].split(' ')[1]; - } - - i++; - } - - if(diagram_name === undefined){ - throw new Error("Diagram name not found"); - } - - return diagram_name; - } - - //helper function to set default format - private getFormat(command_settings: CommandSettings): Format{ - let format = command_settings.format; - - if(format === undefined){ - format = Format.PNG; - } - - return format; - } - - //creates the output filepath by asking for user input - private async makeOutputPath(diagram_name: string, command_settings: CommandSettings): Promise{ - if(command_settings.format === undefined){ - command_settings.format = Format.PNG; - } - - let default_output_file = vscode.Uri.joinPath(this.directory.uri, diagram_name + "." + command_settings.format.toLowerCase()); - - let save_dialog_options: vscode.SaveDialogOptions = { - defaultUri: default_output_file, - saveLabel: "Save proof model", - filters: { - 'Images': [Format.PNG.toLowerCase(), Format.SVG.toLowerCase()] - } - } - - let output_file = await vscode.window.showSaveDialog(save_dialog_options); - - if(!output_file){ - throw new Error("Please enter a save location"); - } - - return output_file; - } - - //helper function to perform updates related to a new text editor - private updateEditor(editor: vscode.TextEditor | undefined): {editor: vscode.TextEditor, document: vscode.TextDocument, directory: vscode.WorkspaceFolder}{ - let document: vscode.TextDocument; - let directory: vscode.WorkspaceFolder; - - if(!editor){ - editor = this.editor; - document = this.document; - directory = this.directory; - }else{ - document = editor.document; - directory = this.getDirectory(document); - } - - return{editor, document, directory}; - } - - //helper function to get directory for updating - private getDirectory(document: vscode.TextDocument): vscode.WorkspaceFolder{ - let directory = vscode.workspace.getWorkspaceFolder(document.uri); - - if(!directory){ - directory = this.directory; - } - - return directory; - } - - //helper function to fetch the log level on configuration change - private getLogLevel(): string{ - let log_level: string; - let configuration = vscode.workspace.getConfiguration().inspect("jpipe.logLevel")?.globalValue; - - if(typeof configuration === "string"){ - log_level = configuration; - }else{ - log_level = "error"; - } - - return log_level; - } - - //helper function to fetch the input jar file path - private getJarFile(): string{ - let jar_file: string; - let default_value = "";//must be kept in sync with the actual default value manually - let configuration = vscode.workspace.getConfiguration().inspect("jpipe.jarFile")?.globalValue; - - if(typeof configuration === "string"){ - jar_file = configuration; - }else{ - jar_file = default_value; - } - - if(jar_file === default_value){ - jar_file = vscode.Uri.joinPath(this.context.extensionUri, 'jar', 'jpipe.jar').path; - vscode.workspace.getConfiguration().update("jpipe.jarFile", jar_file); - }else if(!this.jarPathExists(jar_file)){ - throw new Error("Specified jar path does not exist"); - } - - return jar_file; - } - - private jarPathExists(file_path: string): boolean{ - let jar_path_exists: boolean; - - try{ - let file = vscode.Uri.file(file_path); - let new_uri = vscode.Uri.joinPath(this.directory.uri, "example.jar"); - - vscode.workspace.fs.copy(file, new_uri); - vscode.workspace.fs.delete(new_uri); - - jar_path_exists = true; - }catch(error: any){ - this.output_channel.appendLine(error.toString()); - - jar_path_exists = false; - } - return jar_path_exists; - } -} - -type CommandSettings = { - format?: Format, - save_image: boolean -} diff --git a/langium/src/extension/main.ts b/langium/src/extension/main.ts index 395e347..7eaf3fb 100644 --- a/langium/src/extension/main.ts +++ b/langium/src/extension/main.ts @@ -3,30 +3,30 @@ import * as vscode from 'vscode'; import {window} from 'vscode'; import * as path from 'node:path'; import { LanguageClient, TransportKind } from 'vscode-languageclient/node.js'; -import { SaveImageCommand } from './image-generation/save-image-command.js'; + import { ImageGenerator } from './image-generation/image-generator.js'; import { ContextManager } from './managers/context-manager.js'; import { PreviewProvider } from './image-generation/preview-provider.js'; import { CommandManager } from './managers/command-manager.js'; import { EventManager, EventRunner } from './managers/event-manager.js'; +import { ConfigurationManager } from './managers/configuration-manager.js'; let client: LanguageClient; // This function is called when the extension is activated. export function activate(context: vscode.ExtensionContext): void { client = startLanguageClient(context); + //create universal output channel + const output_channel = vscode.window.createOutputChannel("jpipe_console"); //managers for updating and registration const command_manager = new CommandManager(context); const event_manager = new EventManager(); const context_manager = new ContextManager(window.activeTextEditor); - - //create universal output channel - const output_channel = vscode.window.createOutputChannel("jpipe_console"); + const configuration_manager = new ConfigurationManager(context, output_channel); //create needs for image generation - const save_image_command = new SaveImageCommand(context, window.activeTextEditor, output_channel); - const image_generator = new ImageGenerator(save_image_command, output_channel); - const preview_provider = new PreviewProvider(save_image_command, output_channel); + const image_generator = new ImageGenerator(configuration_manager, output_channel); + const preview_provider = new PreviewProvider(image_generator, output_channel); //register commands from classes command_manager.register( @@ -36,12 +36,8 @@ export function activate(context: vscode.ExtensionContext): void { //register subscribers for events that need to monitor changes event_manager.register(new EventRunner(window.onDidChangeTextEditorSelection), context_manager, preview_provider); - event_manager.register(new EventRunner(window.onDidChangeActiveTextEditor), context_manager, save_image_command, preview_provider); - event_manager.register(new EventRunner(vscode.workspace.onDidChangeConfiguration), save_image_command); - - vscode.workspace.onDidChangeConfiguration(() =>{ - output_channel.appendLine("configuration changed"); - }); + event_manager.register(new EventRunner(window.onDidChangeActiveTextEditor), context_manager, image_generator, preview_provider); + event_manager.register(new EventRunner(vscode.workspace.onDidChangeConfiguration), configuration_manager); //activate listening for events event_manager.listen(); diff --git a/langium/src/extension/managers/configuration-manager.ts b/langium/src/extension/managers/configuration-manager.ts new file mode 100644 index 0000000..783943d --- /dev/null +++ b/langium/src/extension/managers/configuration-manager.ts @@ -0,0 +1,167 @@ +import * as vscode from 'vscode'; +import { EventSubscriber, isConfigurationChangeEvent, isTextEditor } from './event-manager.js'; + +type Configuration = { + readonly key: string, + readonly function: () => T, + value: T +} + +//keeps track of values of configuration settings +export class ConfigurationManager implements EventSubscriber, EventSubscriber{ + // Output channel used for debugging + private output_channel: vscode.OutputChannel; + + //list of all configurations including their key, update function, and current associated value + private configurations: Configuration[]; + + //map to reference from key, the location of the configuration values in configurations array + private configuration_indices: Map; + + //current directory + private directory!: vscode.WorkspaceFolder; + + constructor(private readonly context: vscode.ExtensionContext, output_channel: vscode.OutputChannel){ + this.output_channel = output_channel; + + this.update(vscode.window.activeTextEditor); + + this.configurations = [ + { + key: "jpipe.logLevel", + function: this.updateLogLevel, + value: this.updateLogLevel() + }, + { + key: "jpipe.jarFile", + function: this.updateJarFile, + value: this.updateJarFile() + } + ] + + this.configuration_indices = this.setIndices(this.configurations); + } + + //updater functions + public async update(change: vscode.ConfigurationChangeEvent): Promise; + public async update(editor: vscode.TextEditor | undefined): Promise; + public async update(data: vscode.ConfigurationChangeEvent | vscode.TextEditor | undefined): Promise{ + if(isTextEditor(data)){ + this.updateEditor(data); + }else if(isConfigurationChangeEvent(data)){ + this.updateConfiguration(data); + } + } + + //getter function to return the current value of any configuration being monitored + public getConfiguration(configuration_key: string): any{ + let target_config: any; + + let config_index = this.configuration_indices.get(configuration_key); + + if(config_index !== undefined){ + target_config = this.configurations[config_index].value; + }else{ + throw new Error("Configuration: " + configuration_key + " cannot be found in configuration key list"); + } + + return target_config; + } + + //helper function to manage editor updates + private updateEditor(editor: vscode.TextEditor | undefined): void{ + if(editor){ + let document = editor.document + let directory = vscode.workspace.getWorkspaceFolder(document.uri); + + if(directory){ + this.directory = directory; + } + } + } + + //helper function to manage configuration updates + private updateConfiguration(configuration_change: vscode.ConfigurationChangeEvent): void{ + this.configurations.forEach((configuration)=>{ + if(configuration_change.affectsConfiguration(configuration.key)){ + try{ + configuration.value = configuration.function.call(this); + }catch(error: any){ + this.output_channel.appendLine(error); + } + + } + }); + } + + //helper function to fetch the current log level + private updateLogLevel(): string{ + let log_level: string; + let configuration = vscode.workspace.getConfiguration().inspect("jpipe.logLevel")?.globalValue; + + if(typeof configuration === "string"){ + log_level = configuration; + }else{ + log_level = "error"; + } + + return log_level; + } + + //helper function to fetch and verify the input jar file path + private updateJarFile(): string{ + let jar_file: string; + let default_value = "";//must be kept in sync with the actual default value manually + let configuration = vscode.workspace.getConfiguration().inspect("jpipe.jarFile")?.globalValue; + + if(typeof configuration === "string"){ + jar_file = configuration; + }else{ + jar_file = default_value; + } + + if(jar_file === default_value){ + jar_file = vscode.Uri.joinPath(this.context.extensionUri, 'jar', 'jpipe.jar').path; + vscode.workspace.getConfiguration().update("jpipe.jarFile", jar_file); + }else if(!this.jarPathExists(jar_file)){ + throw new Error("Specified jar path does not exist"); + } + + return jar_file; + } + + //helper function to verify jar file path + private jarPathExists(file_path: string): boolean{ + let jar_path_exists: boolean; + + try{ + let file = vscode.Uri.file(file_path); + let new_uri = vscode.Uri.joinPath(this.directory.uri, "example.jar"); + + vscode.workspace.fs.copy(file, new_uri); + vscode.workspace.fs.delete(new_uri); + + jar_path_exists = true; + }catch(error: any){ + this.output_channel.appendLine(error.toString()); + + jar_path_exists = false; + } + return jar_path_exists; + } + + //helper function to parse through the configuration array, and set a search location based on configuration key + private setIndices(array: Configuration[]): Map{ + let map: Map = new Map(); + + let counter = 0; + + array.forEach(configuration =>{ + map.set(configuration.key, counter); + + counter++; + }) + + return map; + } +} \ No newline at end of file diff --git a/langium/tsconfig.json b/langium/tsconfig.json index ae02089..38545c9 100644 --- a/langium/tsconfig.json +++ b/langium/tsconfig.json @@ -21,7 +21,7 @@ "include": [ "src/**/*.ts", "test/**/*.ts" -, "src/language/services/old/jpipe-command-handler.ts-old" ], +, "src/language/services/old/jpipe-command-handler.ts-old", "src/extension/image-generation/save-image-command.ts-old" ], "exclude": [ "out", "node_modules" From f2b6e1e42cbe68867ac3f9d78a1b3633f8b1f425 Mon Sep 17 00:00:00 2001 From: braunc8 Date: Thu, 18 Jul 2024 15:49:21 -0400 Subject: [PATCH 02/36] minor refactor + added developer mode in settings, specifically in reference to jar file --- langium/package.json | 10 +- .../image-generation/image-generator.ts | 6 +- .../managers/configuration-manager.ts | 117 ++++++++++++------ 3 files changed, 88 insertions(+), 45 deletions(-) diff --git a/langium/package.json b/langium/package.json index 9d2d9fc..2139579 100644 --- a/langium/package.json +++ b/langium/package.json @@ -56,13 +56,19 @@ "configuration":{ "title": "Jpipe Configuration", "properties": { - "jpipe.jarFile":{ + "jpipe.developerMode": { + "type": "boolean", + "scope": "window", + "default": false, + "markdownDescription": "When developer mode is turned on, all automatic fixes are disabled" + }, + "jpipe.jarFile": { "type": "string", "scope": "window", "default": "", "markdownDescription": "Set the path to the jar file compiler" }, - "jpipe.strictLeftFiltering":{ + "jpipe.strictLeftFiltering": { "type": "boolean", "scope": "window", "default": true, diff --git a/langium/src/extension/image-generation/image-generator.ts b/langium/src/extension/image-generation/image-generator.ts index ec3e524..1f0bd8b 100644 --- a/langium/src/extension/image-generation/image-generator.ts +++ b/langium/src/extension/image-generation/image-generator.ts @@ -2,7 +2,7 @@ import * as vscode from 'vscode'; import util from "node:util"; import { Command, CommandUser } from '../managers/command-manager.js'; import { EventSubscriber, isTextEditor } from '../managers/event-manager.js'; -import { ConfigurationManager } from '../managers/configuration-manager.js'; +import { ConfigKey, ConfigurationManager } from '../managers/configuration-manager.js'; export class ImageGenerator implements CommandUser, EventSubscriber{ // New channel created in vscode terminal for user debugging. @@ -76,7 +76,7 @@ export class ImageGenerator implements CommandUser, EventSubscriber{ - let jar_file = this.configuration.getConfiguration("jpipe.jarFile"); + let jar_file = this.configuration.getConfiguration(ConfigKey.JARFILE); let input_file = this.document.uri; @@ -84,7 +84,7 @@ export class ImageGenerator implements CommandUser, EventSubscriber = { - readonly key: string, - readonly function: () => T, + readonly key: ConfigKey, + readonly update_function: () => T, value: T } @@ -28,20 +28,26 @@ export class ConfigurationManager implements EventSubscriber; public async update(editor: vscode.TextEditor | undefined): Promise; @@ -53,21 +59,20 @@ export class ConfigurationManager implements EventSubscriber{ + if(configuration_change.affectsConfiguration(configuration.key)){ + try{ + configuration.value = configuration.update_function.call(this); + }catch(error: any){ + this.output_channel.appendLine(error); + } + + } + }); } - + //helper function to manage editor updates private updateEditor(editor: vscode.TextEditor | undefined): void{ if(editor){ @@ -80,24 +85,10 @@ export class ConfigurationManager implements EventSubscriber{ - if(configuration_change.affectsConfiguration(configuration.key)){ - try{ - configuration.value = configuration.function.call(this); - }catch(error: any){ - this.output_channel.appendLine(error); - } - - } - }); - } - //helper function to fetch the current log level private updateLogLevel(): string{ let log_level: string; - let configuration = vscode.workspace.getConfiguration().inspect("jpipe.logLevel")?.globalValue; + let configuration = vscode.workspace.getConfiguration().inspect(ConfigKey.LOGLEVEL)?.globalValue; if(typeof configuration === "string"){ log_level = configuration; @@ -108,11 +99,27 @@ export class ConfigurationManager implements EventSubscriber Date: Mon, 22 Jul 2024 15:04:57 -0400 Subject: [PATCH 03/36] Justification refactor --- langium/src/language/jpipe.langium | 24 ++++++++++++------- .../language/services/jpipe-hover-provider.ts | 4 ++-- .../src/language/services/jpipe-validator.ts | 5 ++-- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/langium/src/language/jpipe.langium b/langium/src/language/jpipe.langium index 769a69c..d9f6d41 100644 --- a/langium/src/language/jpipe.langium +++ b/langium/src/language/jpipe.langium @@ -1,22 +1,28 @@ grammar Jpipe entry Model: - (entries+=Body)*; + (entries+=Justification)*; + -Body: - Justification; Justification: - kind=('justification') name=ID '{' (variables+=Variable | instructions+=Instruction | supports += Support )* '}'; + JustificationClass body=JustificationBody; + +JustificationClass: + kind=('justification') name=ID; -Variable: +JustificationBody: + '{' (variables+=JustificationVariable | instructions+=JustificationInstruction | supports += JustificationSupport )* '}'; + +JustificationVariable: kind=('evidence' | 'strategy' | 'sub-conclusion' | 'conclusion') name=ID; -Instruction: - Variable 'is' information=STRING; +JustificationInstruction: + JustificationVariable 'is' information=STRING; + +JustificationSupport: + left=[JustificationVariable:ID] 'supports' right=[JustificationVariable:ID]; -Support: - left=[Variable:ID] 'supports' right=[Variable:ID]; hidden terminal WS: /\s+/; terminal ID: /[_a-zA-Z][\w_]*/; diff --git a/langium/src/language/services/jpipe-hover-provider.ts b/langium/src/language/services/jpipe-hover-provider.ts index 94b798a..a110b51 100644 --- a/langium/src/language/services/jpipe-hover-provider.ts +++ b/langium/src/language/services/jpipe-hover-provider.ts @@ -2,7 +2,7 @@ import { type AstNode, type MaybePromise, } from 'langium'; import { AstNodeHoverProvider } from 'langium/lsp'; import { Hover } from 'vscode-languageserver'; -import { isJustification, isVariable } from '../generated/ast.js'; +import { isJustificationClass, isVariable } from '../generated/ast.js'; //provides hover for variables and class types @@ -18,7 +18,7 @@ export class JpipeHoverProvider extends AstNodeHoverProvider{ } } - if(isJustification(node)){ + if(isJustificationClass(node)){ return { contents: { kind: 'markdown', diff --git a/langium/src/language/services/jpipe-validator.ts b/langium/src/language/services/jpipe-validator.ts index ba2c5b0..fb804f6 100644 --- a/langium/src/language/services/jpipe-validator.ts +++ b/langium/src/language/services/jpipe-validator.ts @@ -27,7 +27,7 @@ export class JpipeValidator { //Checks that variables are defined private checkVariables(model: Model, accept: ValidationAcceptor): void{ model.entries.forEach( (entry) =>{ - entry.supports.forEach( (support) =>{ + entry.body.supports.forEach( (support) =>{ this.checkSupport(support, accept); }); }); @@ -85,7 +85,8 @@ export class JpipeValidator { ]); model.entries.forEach( (entry) =>{ - entry.supports.forEach( (support) =>{ + entry.body.supports + entry.body.supports.forEach( (support) =>{ if(support.left.ref !== undefined && support.right.ref !==undefined){ let leftKind = support.left.ref?.kind; let rightKind = support.right.ref?.kind; From ffe9fc50325c84d3ce99e61f335126e3ea4eadfa Mon Sep 17 00:00:00 2001 From: braunc8 Date: Mon, 22 Jul 2024 15:10:16 -0400 Subject: [PATCH 04/36] second justification refactor --- langium/src/language/jpipe.langium | 8 +++----- .../src/language/services/jpipe-completion-provider.ts | 8 ++++---- langium/src/language/services/jpipe-hover-provider.ts | 4 ++-- langium/src/language/services/jpipe-validator.ts | 4 ++-- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/langium/src/language/jpipe.langium b/langium/src/language/jpipe.langium index d9f6d41..a48a9fb 100644 --- a/langium/src/language/jpipe.langium +++ b/langium/src/language/jpipe.langium @@ -3,25 +3,23 @@ grammar Jpipe entry Model: (entries+=Justification)*; - - Justification: JustificationClass body=JustificationBody; -JustificationClass: +JustificationClass infers Class: kind=('justification') name=ID; JustificationBody: '{' (variables+=JustificationVariable | instructions+=JustificationInstruction | supports += JustificationSupport )* '}'; -JustificationVariable: +JustificationVariable infers Variable: kind=('evidence' | 'strategy' | 'sub-conclusion' | 'conclusion') name=ID; JustificationInstruction: JustificationVariable 'is' information=STRING; JustificationSupport: - left=[JustificationVariable:ID] 'supports' right=[JustificationVariable:ID]; + left=[Variable:ID] 'supports' right=[Variable:ID]; hidden terminal WS: /\s+/; diff --git a/langium/src/language/services/jpipe-completion-provider.ts b/langium/src/language/services/jpipe-completion-provider.ts index 1ece361..696e9d7 100644 --- a/langium/src/language/services/jpipe-completion-provider.ts +++ b/langium/src/language/services/jpipe-completion-provider.ts @@ -1,6 +1,6 @@ import { AstNodeDescription, ReferenceInfo, Stream } from "langium"; import { CompletionContext, DefaultCompletionProvider } from "langium/lsp"; -import { Support, isSupport, isVariable } from "../generated/ast.js"; +import { isJustificationSupport, isVariable, JustificationSupport } from "../generated/ast.js"; import { stream } from "../../../node_modules/langium/src/utils/stream.js" export class JpipeCompletionProvider extends DefaultCompletionProvider{ @@ -23,7 +23,7 @@ export class JpipeCompletionProvider extends DefaultCompletionProvider{ let variables = this.findVariables(potential_references); //if the current context is of a supporting statement, determines which variables should appear for autocomplete - if(isSupport(_context.node)){ + if(isJustificationSupport(_context.node)){ let support_variables: AstNodeDescription[]; if(this.onRightSide(_context.node)){ @@ -68,7 +68,7 @@ export class JpipeCompletionProvider extends DefaultCompletionProvider{ } //helper functino to determine which side of support statement we are on - onRightSide(context_node: Support){ + onRightSide(context_node: JustificationSupport){ return context_node.left.ref !== undefined; } @@ -79,7 +79,7 @@ export class JpipeCompletionProvider extends DefaultCompletionProvider{ getRightVariables(variables: AstNodeDescription[], _context: CompletionContext): AstNodeDescription[]{ let rightVariables: AstNodeDescription[] = []; - if(isSupport(_context.node)){ + if(isJustificationSupport(_context.node)){ if(_context.node.left.ref !== undefined){ let supporter_kind = _context.node.left.ref.kind; let allowable_types = this.typeMap.get(supporter_kind); diff --git a/langium/src/language/services/jpipe-hover-provider.ts b/langium/src/language/services/jpipe-hover-provider.ts index a110b51..cd0a425 100644 --- a/langium/src/language/services/jpipe-hover-provider.ts +++ b/langium/src/language/services/jpipe-hover-provider.ts @@ -2,7 +2,7 @@ import { type AstNode, type MaybePromise, } from 'langium'; import { AstNodeHoverProvider } from 'langium/lsp'; import { Hover } from 'vscode-languageserver'; -import { isJustificationClass, isVariable } from '../generated/ast.js'; +import { isClass, isVariable } from '../generated/ast.js'; //provides hover for variables and class types @@ -18,7 +18,7 @@ export class JpipeHoverProvider extends AstNodeHoverProvider{ } } - if(isJustificationClass(node)){ + if(isClass(node)){ return { contents: { kind: 'markdown', diff --git a/langium/src/language/services/jpipe-validator.ts b/langium/src/language/services/jpipe-validator.ts index fb804f6..e4fb62d 100644 --- a/langium/src/language/services/jpipe-validator.ts +++ b/langium/src/language/services/jpipe-validator.ts @@ -1,5 +1,5 @@ import { Reference, type ValidationAcceptor, type ValidationChecks } from 'langium'; -import type { JpipeAstType, Model, Support, Variable} from '../generated/ast.js'; +import type { JpipeAstType, JustificationSupport, Model, Variable} from '../generated/ast.js'; import type { JpipeServices } from '../jpipe-module.js'; @@ -34,7 +34,7 @@ export class JpipeValidator { } //helper function to test if variables are defined - private checkSupport(support: Support, accept: ValidationAcceptor): void{ + private checkSupport(support: JustificationSupport, accept: ValidationAcceptor): void{ if(this.hasError(support.left, support.right)){ let errorStatement = this.getErrorStatement(support.left, support.right); accept("error", errorStatement, {node: support}); From ddada95a29636c99b43b87efa2857415617bfda3 Mon Sep 17 00:00:00 2001 From: braunc8 Date: Mon, 22 Jul 2024 15:34:07 -0400 Subject: [PATCH 05/36] final justification refactor --- langium/src/language/jpipe.langium | 29 ++++++++++++--- .../services/jpipe-completion-provider.ts | 9 ++--- .../language/services/jpipe-hover-provider.ts | 18 +++++----- .../src/language/services/jpipe-validator.ts | 36 ++++++++++--------- 4 files changed, 58 insertions(+), 34 deletions(-) diff --git a/langium/src/language/jpipe.langium b/langium/src/language/jpipe.langium index a48a9fb..5871b71 100644 --- a/langium/src/language/jpipe.langium +++ b/langium/src/language/jpipe.langium @@ -3,22 +3,41 @@ grammar Jpipe entry Model: (entries+=Justification)*; +interface Class{ + kind: 'justification' | 'pattern' | 'composition' + name: string +} + +interface Variable{ + kind: 'evidence' | 'strategy' | 'sub-conclusion' | 'conclusion' + name: string +} + +interface Instruction{ + information: string +} + +interface Support{ + left: @Variable + right: @Variable +} + Justification: JustificationClass body=JustificationBody; -JustificationClass infers Class: +JustificationClass returns Class: kind=('justification') name=ID; JustificationBody: - '{' (variables+=JustificationVariable | instructions+=JustificationInstruction | supports += JustificationSupport )* '}'; + '{' (instructions+=JustificationInstruction | supports += JustificationSupport)* '}'; -JustificationVariable infers Variable: +JustificationVariable returns Variable: kind=('evidence' | 'strategy' | 'sub-conclusion' | 'conclusion') name=ID; -JustificationInstruction: +JustificationInstruction returns Instruction: JustificationVariable 'is' information=STRING; -JustificationSupport: +JustificationSupport returns Support: left=[Variable:ID] 'supports' right=[Variable:ID]; diff --git a/langium/src/language/services/jpipe-completion-provider.ts b/langium/src/language/services/jpipe-completion-provider.ts index 696e9d7..890eefb 100644 --- a/langium/src/language/services/jpipe-completion-provider.ts +++ b/langium/src/language/services/jpipe-completion-provider.ts @@ -1,6 +1,6 @@ import { AstNodeDescription, ReferenceInfo, Stream } from "langium"; import { CompletionContext, DefaultCompletionProvider } from "langium/lsp"; -import { isJustificationSupport, isVariable, JustificationSupport } from "../generated/ast.js"; +import { isSupport, isVariable, Support } from "../generated/ast.js"; import { stream } from "../../../node_modules/langium/src/utils/stream.js" export class JpipeCompletionProvider extends DefaultCompletionProvider{ @@ -23,7 +23,7 @@ export class JpipeCompletionProvider extends DefaultCompletionProvider{ let variables = this.findVariables(potential_references); //if the current context is of a supporting statement, determines which variables should appear for autocomplete - if(isJustificationSupport(_context.node)){ + if(isSupport(_context.node)){ let support_variables: AstNodeDescription[]; if(this.onRightSide(_context.node)){ @@ -68,7 +68,7 @@ export class JpipeCompletionProvider extends DefaultCompletionProvider{ } //helper functino to determine which side of support statement we are on - onRightSide(context_node: JustificationSupport){ + onRightSide(context_node: Support){ return context_node.left.ref !== undefined; } @@ -79,7 +79,8 @@ export class JpipeCompletionProvider extends DefaultCompletionProvider{ getRightVariables(variables: AstNodeDescription[], _context: CompletionContext): AstNodeDescription[]{ let rightVariables: AstNodeDescription[] = []; - if(isJustificationSupport(_context.node)){ + if(isSupport(_context.node)){ + if(_context.node.left.ref !== undefined){ let supporter_kind = _context.node.left.ref.kind; let allowable_types = this.typeMap.get(supporter_kind); diff --git a/langium/src/language/services/jpipe-hover-provider.ts b/langium/src/language/services/jpipe-hover-provider.ts index cd0a425..46f5b79 100644 --- a/langium/src/language/services/jpipe-hover-provider.ts +++ b/langium/src/language/services/jpipe-hover-provider.ts @@ -2,20 +2,22 @@ import { type AstNode, type MaybePromise, } from 'langium'; import { AstNodeHoverProvider } from 'langium/lsp'; import { Hover } from 'vscode-languageserver'; -import { isClass, isVariable } from '../generated/ast.js'; +import { isClass, isInstruction, isVariable } from '../generated/ast.js'; //provides hover for variables and class types export class JpipeHoverProvider extends AstNodeHoverProvider{ protected getAstNodeHoverContent(node: AstNode): MaybePromise { if(isVariable(node)){ - return { - contents: { - kind: 'markdown', - language: 'Jpipe', - value: `${node.kind}: ${node.information}` - } - } + if(isInstruction(node.$container)){ + return { + contents: { + kind: 'markdown', + language: 'Jpipe', + value: `${node.kind}: ${node.$container.information}` + } + } + } } if(isClass(node)){ diff --git a/langium/src/language/services/jpipe-validator.ts b/langium/src/language/services/jpipe-validator.ts index e4fb62d..6b47dbd 100644 --- a/langium/src/language/services/jpipe-validator.ts +++ b/langium/src/language/services/jpipe-validator.ts @@ -1,5 +1,5 @@ import { Reference, type ValidationAcceptor, type ValidationChecks } from 'langium'; -import type { JpipeAstType, JustificationSupport, Model, Variable} from '../generated/ast.js'; +import { isSupport, type JpipeAstType, type Support, type Model, type Variable} from '../generated/ast.js'; import type { JpipeServices } from '../jpipe-module.js'; @@ -28,13 +28,15 @@ export class JpipeValidator { private checkVariables(model: Model, accept: ValidationAcceptor): void{ model.entries.forEach( (entry) =>{ entry.body.supports.forEach( (support) =>{ - this.checkSupport(support, accept); + if(isSupport(support)){ + this.checkSupport(support, accept); + } }); }); } //helper function to test if variables are defined - private checkSupport(support: JustificationSupport, accept: ValidationAcceptor): void{ + private checkSupport(support: Support, accept: ValidationAcceptor): void{ if(this.hasError(support.left, support.right)){ let errorStatement = this.getErrorStatement(support.left, support.right); accept("error", errorStatement, {node: support}); @@ -85,24 +87,24 @@ export class JpipeValidator { ]); model.entries.forEach( (entry) =>{ - entry.body.supports entry.body.supports.forEach( (support) =>{ - if(support.left.ref !== undefined && support.right.ref !==undefined){ - let leftKind = support.left.ref?.kind; - let rightKind = support.right.ref?.kind; - let possibleRights: string[] | undefined = possibleSupports.get(leftKind); - - if(rightKind !== undefined){ - if (possibleRights?.includes(rightKind)){ - return; + if(isSupport(support)){ + if(support.left.ref !== undefined && support.right.ref !==undefined){ + let leftKind = support.left.ref?.kind; + let rightKind = support.right.ref?.kind; + let possibleRights: string[] | undefined = possibleSupports.get(leftKind); + + if(rightKind !== undefined){ + if (possibleRights?.includes(rightKind)){ + return; + } } + + accept("error", `It is not possible to have ${leftKind} support ${rightKind}.`, { + node:support + }); } - - accept("error", `It is not possible to have ${leftKind} support ${rightKind}.`, { - node:support - }); } - }); }); } From 696d26135621de0c18f3d0b135509e1d4dc1cb8e Mon Sep 17 00:00:00 2001 From: braunc8 Date: Mon, 22 Jul 2024 16:31:20 -0400 Subject: [PATCH 06/36] Patterns added --- langium/src/language/jpipe.langium | 57 +++++++++++-------- .../services/jpipe-completion-provider.ts | 23 +++++++- .../language/services/jpipe-hover-provider.ts | 26 +++++---- .../src/language/services/jpipe-validator.ts | 10 ++-- 4 files changed, 73 insertions(+), 43 deletions(-) diff --git a/langium/src/language/jpipe.langium b/langium/src/language/jpipe.langium index 5871b71..cc3e8c5 100644 --- a/langium/src/language/jpipe.langium +++ b/langium/src/language/jpipe.langium @@ -1,44 +1,53 @@ grammar Jpipe entry Model: - (entries+=Justification)*; + (entries += (Justification | Pattern))*; -interface Class{ - kind: 'justification' | 'pattern' | 'composition' - name: string -} +type Variable = JustificationVariable | PatternVariable; -interface Variable{ - kind: 'evidence' | 'strategy' | 'sub-conclusion' | 'conclusion' - name: string -} +type Instruction = JustificationInstruction | PatternInstruction; -interface Instruction{ - information: string -} - -interface Support{ - left: @Variable - right: @Variable -} +type Class = JustificationClass | PatternClass; Justification: - JustificationClass body=JustificationBody; + (JustificationClass | JustificationImplementsClass) body=JustificationBody; -JustificationClass returns Class: +JustificationClass: kind=('justification') name=ID; +JustificationImplementsClass: + kind=('justification') name=ID 'implements' class=[PatternClass]; + JustificationBody: - '{' (instructions+=JustificationInstruction | supports += JustificationSupport)* '}'; + '{' (variables+=JustificationVariable | instructions+=JustificationInstruction | supports += JustificationSupport)* '}'; -JustificationVariable returns Variable: +JustificationVariable: kind=('evidence' | 'strategy' | 'sub-conclusion' | 'conclusion') name=ID; -JustificationInstruction returns Instruction: +JustificationInstruction: JustificationVariable 'is' information=STRING; -JustificationSupport returns Support: - left=[Variable:ID] 'supports' right=[Variable:ID]; +JustificationSupport: + left=[JustificationVariable:ID] 'supports' right=[JustificationVariable:ID]; + + +Pattern: + PatternClass body=PatternBody; + +PatternClass: + kind=('pattern') name=ID; + +PatternBody: + '{' (variables+=PatternVariable | instructions += PatternInstruction | supports += PatternSupport)* '}'; + +PatternVariable: + kind=('evidence' | 'strategy' | 'sub-conclusion' | 'conclusion' | '@support') name=ID; + +PatternInstruction: + PatternVariable 'is' information=STRING; + +PatternSupport: + left=[PatternVariable:ID] 'supports' right=[PatternVariable:ID]; hidden terminal WS: /\s+/; diff --git a/langium/src/language/services/jpipe-completion-provider.ts b/langium/src/language/services/jpipe-completion-provider.ts index 890eefb..7067f3a 100644 --- a/langium/src/language/services/jpipe-completion-provider.ts +++ b/langium/src/language/services/jpipe-completion-provider.ts @@ -1,6 +1,6 @@ -import { AstNodeDescription, ReferenceInfo, Stream } from "langium"; +import { AstNode, AstNodeDescription, ReferenceInfo, Stream } from "langium"; import { CompletionContext, DefaultCompletionProvider } from "langium/lsp"; -import { isSupport, isVariable, Support } from "../generated/ast.js"; +import { isJustificationClass, isJustificationImplementsClass, isJustificationInstruction, isJustificationSupport, isJustificationVariable, isPatternClass, isPatternInstruction, isPatternSupport, isPatternVariable, JustificationClass, JustificationImplementsClass, JustificationInstruction, JustificationSupport, JustificationVariable, PatternClass, PatternInstruction, PatternSupport, PatternVariable } from "../generated/ast.js"; import { stream } from "../../../node_modules/langium/src/utils/stream.js" export class JpipeCompletionProvider extends DefaultCompletionProvider{ @@ -68,7 +68,7 @@ export class JpipeCompletionProvider extends DefaultCompletionProvider{ } //helper functino to determine which side of support statement we are on - onRightSide(context_node: Support){ + onRightSide(context_node: PatternSupport | JustificationSupport){ return context_node.left.ref !== undefined; } @@ -176,3 +176,20 @@ export class JpipeCompletionProvider extends DefaultCompletionProvider{ return result; } } + +export function isSupport(node: AstNode | undefined): node is JustificationSupport | PatternSupport{ + return isJustificationSupport(node) || isPatternSupport(node); +} + +export function isVariable(node: AstNode | undefined): node is JustificationVariable | PatternVariable{ + return isJustificationVariable(node) || isPatternVariable(node); +} + +export function isInstruction(node: AstNode | undefined): node is JustificationInstruction | PatternInstruction{ + return isJustificationInstruction(node) || isPatternInstruction(node); +} + + +export function isClass(node: AstNode | undefined): node is JustificationClass | JustificationImplementsClass | PatternClass{ + return isJustificationClass(node) || isPatternClass(node) || isJustificationImplementsClass(node); +} \ No newline at end of file diff --git a/langium/src/language/services/jpipe-hover-provider.ts b/langium/src/language/services/jpipe-hover-provider.ts index 46f5b79..982d084 100644 --- a/langium/src/language/services/jpipe-hover-provider.ts +++ b/langium/src/language/services/jpipe-hover-provider.ts @@ -2,22 +2,24 @@ import { type AstNode, type MaybePromise, } from 'langium'; import { AstNodeHoverProvider } from 'langium/lsp'; import { Hover } from 'vscode-languageserver'; -import { isClass, isInstruction, isVariable } from '../generated/ast.js'; +import { isClass, isInstruction, isVariable } from './jpipe-completion-provider.js'; //provides hover for variables and class types export class JpipeHoverProvider extends AstNodeHoverProvider{ protected getAstNodeHoverContent(node: AstNode): MaybePromise { + if(isInstruction(node)){ + node.$cstNode + } if(isVariable(node)){ - if(isInstruction(node.$container)){ - return { - contents: { - kind: 'markdown', - language: 'Jpipe', - value: `${node.kind}: ${node.$container.information}` - } - } - } + console.log('node'); + return { + contents: { + kind: 'markdown', + language: 'Jpipe', + value: `${node.kind}: ${node.information}` + } + } } if(isClass(node)){ @@ -29,7 +31,7 @@ export class JpipeHoverProvider extends AstNodeHoverProvider{ } } } - - return undefined; + + return undefined; } } diff --git a/langium/src/language/services/jpipe-validator.ts b/langium/src/language/services/jpipe-validator.ts index 6b47dbd..0980b1f 100644 --- a/langium/src/language/services/jpipe-validator.ts +++ b/langium/src/language/services/jpipe-validator.ts @@ -1,6 +1,7 @@ import { Reference, type ValidationAcceptor, type ValidationChecks } from 'langium'; -import { isSupport, type JpipeAstType, type Support, type Model, type Variable} from '../generated/ast.js'; +import { JustificationSupport, JustificationVariable, PatternSupport, PatternVariable, Variable, type JpipeAstType, type Model} from '../generated/ast.js'; import type { JpipeServices } from '../jpipe-module.js'; +import { isSupport } from './jpipe-completion-provider.js'; /** @@ -36,7 +37,7 @@ export class JpipeValidator { } //helper function to test if variables are defined - private checkSupport(support: Support, accept: ValidationAcceptor): void{ + private checkSupport(support: PatternSupport | JustificationSupport, accept: ValidationAcceptor): void{ if(this.hasError(support.left, support.right)){ let errorStatement = this.getErrorStatement(support.left, support.right); accept("error", errorStatement, {node: support}); @@ -44,7 +45,7 @@ export class JpipeValidator { } //helper function to determine if there is an error in a support statement - private hasError(leftSupport: Reference, rightSupport: Reference): boolean{ + private hasError(leftSupport: Reference, rightSupport: Reference): boolean{ let hasError: boolean; let leftKind = leftSupport.ref?.kind; @@ -83,7 +84,8 @@ export class JpipeValidator { ['evidence', ['strategy']], ['strategy', ['sub-conclusion', 'conclusion']], ['sub-conclusion', ['strategy', 'conclusion']], - ['conclusion', []] + ['conclusion', []] , + ['@support', ['evidence', 'strategy', 'sub-conclusion', 'conclusion']] ]); model.entries.forEach( (entry) =>{ From 7f6d3bf0d1c165155977cb84355a6b5bea4aa7d0 Mon Sep 17 00:00:00 2001 From: braunc8 Date: Mon, 22 Jul 2024 20:27:14 -0400 Subject: [PATCH 07/36] added compositions --- langium/src/language/jpipe.langium | 20 ++++++- .../services/jpipe-completion-provider.ts | 16 +++--- .../language/services/jpipe-hover-provider.ts | 3 +- .../src/language/services/jpipe-validator.ts | 52 +++++++++++-------- 4 files changed, 60 insertions(+), 31 deletions(-) diff --git a/langium/src/language/jpipe.langium b/langium/src/language/jpipe.langium index cc3e8c5..381bc69 100644 --- a/langium/src/language/jpipe.langium +++ b/langium/src/language/jpipe.langium @@ -1,7 +1,7 @@ grammar Jpipe entry Model: - (entries += (Justification | Pattern))*; + (entries += (Justification | Pattern | Composition))*; type Variable = JustificationVariable | PatternVariable; @@ -50,6 +50,24 @@ PatternSupport: left=[PatternVariable:ID] 'supports' right=[PatternVariable:ID]; + +Composition: + CompositionClass body=CompositionBody; + +CompositionClass: + kind=('composition') name=ID; + +CompositionBody: + '{' (variables+=CompositionVariable | instructions += CompositionInstruction)* '}'; + +CompositionVariable: + kind='justification' name=ID; + +CompositionInstruction: + CompositionVariable 'is' information=CompositionInformation; + +CompositionInformation: + left=[JustificationClass] 'with' right=[JustificationClass]; hidden terminal WS: /\s+/; terminal ID: /[_a-zA-Z][\w_]*/; terminal STRING: /"(\\.|[^"\\])*"|'(\\.|[^'\\])*'/; diff --git a/langium/src/language/services/jpipe-completion-provider.ts b/langium/src/language/services/jpipe-completion-provider.ts index 7067f3a..5516806 100644 --- a/langium/src/language/services/jpipe-completion-provider.ts +++ b/langium/src/language/services/jpipe-completion-provider.ts @@ -1,6 +1,6 @@ import { AstNode, AstNodeDescription, ReferenceInfo, Stream } from "langium"; import { CompletionContext, DefaultCompletionProvider } from "langium/lsp"; -import { isJustificationClass, isJustificationImplementsClass, isJustificationInstruction, isJustificationSupport, isJustificationVariable, isPatternClass, isPatternInstruction, isPatternSupport, isPatternVariable, JustificationClass, JustificationImplementsClass, JustificationInstruction, JustificationSupport, JustificationVariable, PatternClass, PatternInstruction, PatternSupport, PatternVariable } from "../generated/ast.js"; +import { CompositionClass, CompositionInstruction, isCompositionClass, isCompositionInstruction, isJustification, isJustificationClass, isJustificationImplementsClass, isJustificationInstruction, isJustificationSupport, isJustificationVariable, isPattern, isPatternClass, isPatternInstruction, isPatternSupport, isPatternVariable, Justification, JustificationClass, JustificationImplementsClass, JustificationInstruction, JustificationSupport, JustificationVariable, Pattern, PatternClass, PatternInstruction, PatternSupport, PatternVariable } from "../generated/ast.js"; import { stream } from "../../../node_modules/langium/src/utils/stream.js" export class JpipeCompletionProvider extends DefaultCompletionProvider{ @@ -181,15 +181,19 @@ export function isSupport(node: AstNode | undefined): node is JustificationSuppo return isJustificationSupport(node) || isPatternSupport(node); } -export function isVariable(node: AstNode | undefined): node is JustificationVariable | PatternVariable{ +export function isVariable(node: AstNode | undefined): node is JustificationVariable | PatternVariable { return isJustificationVariable(node) || isPatternVariable(node); } -export function isInstruction(node: AstNode | undefined): node is JustificationInstruction | PatternInstruction{ - return isJustificationInstruction(node) || isPatternInstruction(node); +export function isInstruction(node: AstNode | undefined): node is JustificationInstruction | PatternInstruction | CompositionInstruction{ + return isJustificationInstruction(node) || isPatternInstruction(node) || isCompositionInstruction(node); } -export function isClass(node: AstNode | undefined): node is JustificationClass | JustificationImplementsClass | PatternClass{ - return isJustificationClass(node) || isPatternClass(node) || isJustificationImplementsClass(node); +export function isClass(node: AstNode | undefined): node is JustificationClass | JustificationImplementsClass | PatternClass | CompositionClass{ + return isJustificationClass(node) || isPatternClass(node) || isJustificationImplementsClass(node) || isCompositionClass(node); +} + +export function hasSupports(node: AstNode): node is Pattern | Justification{ + return isPattern(node) || isJustification(node); } \ No newline at end of file diff --git a/langium/src/language/services/jpipe-hover-provider.ts b/langium/src/language/services/jpipe-hover-provider.ts index 982d084..9e34a92 100644 --- a/langium/src/language/services/jpipe-hover-provider.ts +++ b/langium/src/language/services/jpipe-hover-provider.ts @@ -1,5 +1,4 @@ import { type AstNode, type MaybePromise, } from 'langium'; - import { AstNodeHoverProvider } from 'langium/lsp'; import { Hover } from 'vscode-languageserver'; import { isClass, isInstruction, isVariable } from './jpipe-completion-provider.js'; @@ -17,7 +16,7 @@ export class JpipeHoverProvider extends AstNodeHoverProvider{ contents: { kind: 'markdown', language: 'Jpipe', - value: `${node.kind}: ${node.information}` + value: `${node.kind}: ${node.information.toString()}` } } } diff --git a/langium/src/language/services/jpipe-validator.ts b/langium/src/language/services/jpipe-validator.ts index 0980b1f..c44a832 100644 --- a/langium/src/language/services/jpipe-validator.ts +++ b/langium/src/language/services/jpipe-validator.ts @@ -1,7 +1,7 @@ import { Reference, type ValidationAcceptor, type ValidationChecks } from 'langium'; import { JustificationSupport, JustificationVariable, PatternSupport, PatternVariable, Variable, type JpipeAstType, type Model} from '../generated/ast.js'; import type { JpipeServices } from '../jpipe-module.js'; -import { isSupport } from './jpipe-completion-provider.js'; +import { hasSupports, isSupport } from './jpipe-completion-provider.js'; /** @@ -28,11 +28,14 @@ export class JpipeValidator { //Checks that variables are defined private checkVariables(model: Model, accept: ValidationAcceptor): void{ model.entries.forEach( (entry) =>{ - entry.body.supports.forEach( (support) =>{ - if(isSupport(support)){ - this.checkSupport(support, accept); - } - }); + if(hasSupports(entry)){ + entry.body.supports.forEach( (support) =>{ + if(isSupport(support)){ + this.checkSupport(support, accept); + } + }); + } + }); } @@ -89,25 +92,30 @@ export class JpipeValidator { ]); model.entries.forEach( (entry) =>{ - entry.body.supports.forEach( (support) =>{ - if(isSupport(support)){ - if(support.left.ref !== undefined && support.right.ref !==undefined){ - let leftKind = support.left.ref?.kind; - let rightKind = support.right.ref?.kind; - let possibleRights: string[] | undefined = possibleSupports.get(leftKind); - - if(rightKind !== undefined){ - if (possibleRights?.includes(rightKind)){ - return; + if(hasSupports(entry)){ + entry.body.supports.forEach( (support) =>{ + if(isSupport(support)){ + if(support.left.ref !== undefined && support.right.ref !==undefined){ + let leftKind = support.left.ref?.kind; + let rightKind = support.right.ref?.kind; + let possibleRights: string[] | undefined = possibleSupports.get(leftKind); + + if(rightKind !== undefined){ + if (possibleRights?.includes(rightKind)){ + return; + } } + + accept("error", `It is not possible to have ${leftKind} support ${rightKind}.`, { + node:support + }); } - - accept("error", `It is not possible to have ${leftKind} support ${rightKind}.`, { - node:support - }); } - } - }); + }); + } + }); } } + + From ee4aa1a5e6de03f96bfe7b8244f77fe4dee51ef7 Mon Sep 17 00:00:00 2001 From: braunc8 Date: Tue, 23 Jul 2024 09:34:57 -0400 Subject: [PATCH 08/36] small refactor of possible support mapping --- .../services/jpipe-completion-provider.ts | 15 ++---- .../src/language/services/jpipe-validator.ts | 17 ++++--- .../services/old/jpipe-command-handler.ts-old | 8 ---- .../services/old/jpipe-scope-provider.ts-old | 46 ------------------- 4 files changed, 12 insertions(+), 74 deletions(-) delete mode 100644 langium/src/language/services/old/jpipe-command-handler.ts-old delete mode 100644 langium/src/language/services/old/jpipe-scope-provider.ts-old diff --git a/langium/src/language/services/jpipe-completion-provider.ts b/langium/src/language/services/jpipe-completion-provider.ts index 5516806..16d5a6c 100644 --- a/langium/src/language/services/jpipe-completion-provider.ts +++ b/langium/src/language/services/jpipe-completion-provider.ts @@ -2,17 +2,10 @@ import { AstNode, AstNodeDescription, ReferenceInfo, Stream } from "langium"; import { CompletionContext, DefaultCompletionProvider } from "langium/lsp"; import { CompositionClass, CompositionInstruction, isCompositionClass, isCompositionInstruction, isJustification, isJustificationClass, isJustificationImplementsClass, isJustificationInstruction, isJustificationSupport, isJustificationVariable, isPattern, isPatternClass, isPatternInstruction, isPatternSupport, isPatternVariable, Justification, JustificationClass, JustificationImplementsClass, JustificationInstruction, JustificationSupport, JustificationVariable, Pattern, PatternClass, PatternInstruction, PatternSupport, PatternVariable } from "../generated/ast.js"; import { stream } from "../../../node_modules/langium/src/utils/stream.js" +import { possible_supports } from "./jpipe-validator.js"; export class JpipeCompletionProvider extends DefaultCompletionProvider{ - //track which variable types can support other variable types - readonly typeMap: Map = new Map([ - ['evidence', ['strategy']], - ['strategy', ['sub-conclusion', 'conclusion']], - ['sub-conclusion', ['strategy', 'conclusion']], - ['conclusion', []] - ]); - //filters reference candidates for variables in support statements for autocompletion protected override getReferenceCandidates(refInfo: ReferenceInfo, _context: CompletionContext): Stream { let strict_left_filtering = false; //to be added as a configuration option @@ -83,7 +76,7 @@ export class JpipeCompletionProvider extends DefaultCompletionProvider{ if(_context.node.left.ref !== undefined){ let supporter_kind = _context.node.left.ref.kind; - let allowable_types = this.typeMap.get(supporter_kind); + let allowable_types = possible_supports.get(supporter_kind); rightVariables = this.findRightVariables(variables, allowable_types); } @@ -132,7 +125,7 @@ export class JpipeCompletionProvider extends DefaultCompletionProvider{ variables.forEach(variable =>{ if(isVariable(variable.node)){ let variable_kind = variable.node.kind; - let allowable_types = this.typeMap.get(variable_kind); + let allowable_types = possible_supports.get(variable_kind); if (!(allowable_types === undefined || allowable_types.length === 0)){ left_variables.push(variable); @@ -150,7 +143,7 @@ export class JpipeCompletionProvider extends DefaultCompletionProvider{ variables.forEach((variable) =>{ if(isVariable(variable.node)){ - let allowable_types = this.typeMap.get(variable.node.kind); + let allowable_types = possible_supports.get(variable.node.kind); if (this.hasRightVariableDefined(variables,allowable_types)){ left_variables.push(variable); diff --git a/langium/src/language/services/jpipe-validator.ts b/langium/src/language/services/jpipe-validator.ts index c44a832..af1851e 100644 --- a/langium/src/language/services/jpipe-validator.ts +++ b/langium/src/language/services/jpipe-validator.ts @@ -83,13 +83,6 @@ export class JpipeValidator { //checks if support statements follow proper typing convention private checkSupportingStatements(model: Model, accept: ValidationAcceptor): void{ - let possibleSupports: Map = new Map([ - ['evidence', ['strategy']], - ['strategy', ['sub-conclusion', 'conclusion']], - ['sub-conclusion', ['strategy', 'conclusion']], - ['conclusion', []] , - ['@support', ['evidence', 'strategy', 'sub-conclusion', 'conclusion']] - ]); model.entries.forEach( (entry) =>{ if(hasSupports(entry)){ @@ -98,7 +91,7 @@ export class JpipeValidator { if(support.left.ref !== undefined && support.right.ref !==undefined){ let leftKind = support.left.ref?.kind; let rightKind = support.right.ref?.kind; - let possibleRights: string[] | undefined = possibleSupports.get(leftKind); + let possibleRights: string[] | undefined = possible_supports.get(leftKind); if(rightKind !== undefined){ if (possibleRights?.includes(rightKind)){ @@ -118,4 +111,10 @@ export class JpipeValidator { } } - +export var possible_supports = new Map([ + ['evidence', ['strategy', '@support']], + ['strategy', ['sub-conclusion', 'conclusion', '@support']], + ['sub-conclusion', ['strategy', 'conclusion', '@support']], + ['conclusion', []] , + ['@support', ['strategy', 'sub-conclusion', 'conclusion']] +]); \ No newline at end of file diff --git a/langium/src/language/services/old/jpipe-command-handler.ts-old b/langium/src/language/services/old/jpipe-command-handler.ts-old deleted file mode 100644 index 36b15d4..0000000 --- a/langium/src/language/services/old/jpipe-command-handler.ts-old +++ /dev/null @@ -1,8 +0,0 @@ -import { AbstractExecuteCommandHandler, ExecuteCommandAcceptor } from "langium/lsp"; -export class JpipeExecuteCommandHandler extends AbstractExecuteCommandHandler{ - override registerCommands(acceptor: ExecuteCommandAcceptor): void { - - acceptor("jpipe.sayHello",args => console.log("Jpipe says hello!")); - } -} - diff --git a/langium/src/language/services/old/jpipe-scope-provider.ts-old b/langium/src/language/services/old/jpipe-scope-provider.ts-old deleted file mode 100644 index b06294c..0000000 --- a/langium/src/language/services/old/jpipe-scope-provider.ts-old +++ /dev/null @@ -1,46 +0,0 @@ - -/* -import { AstUtils, AstNodeDescriptionProvider, Scope, LangiumCoreServices, ReferenceInfo, ScopeProvider, EMPTY_SCOPE, MapScope } from "langium"; -import { Model, isModel, isSupportingStatement } from "../generated/ast.js"; -export class JpipeScopeProvider implements ScopeProvider { - private astNodeDescriptionProvider: AstNodeDescriptionProvider; - - constructor(services: LangiumCoreServices) { - //get some helper services - this.astNodeDescriptionProvider = services.workspace.AstNodeDescriptionProvider; - } - - getScope(context: ReferenceInfo): Scope { - if(isSupportingStatement(context.container) && (context.property === 'supporter' || context.property === 'supportee')){ - const model = AstUtils.getContainerOfType(context.container, isModel); - if( model !== undefined){ - const variables = model.variables; - - //might have to map to variable.description idk - const descriptions = variables.map(variable => this.astNodeDescriptionProvider.createDescription(variable,variable.name)); - return new MapScope(descriptions); - } - } - return EMPTY_SCOPE; - } - - makeSupporterArray(model: Model | undefined){ - let arr: any[] = []; - if(model !== undefined){ - model.supports.forEach((support) =>{ - arr.push(support.supporter); - }); - } - return arr; - } - - makeSupporteArray(model: Model): any[]{ - let arr: any[] = []; - model.supports.forEach((support) =>{ - arr.push(support.supportee); - }); - return arr; - } - -} -*/ \ No newline at end of file From 2a497e0bd67133e0d87652450c44c33641034726 Mon Sep 17 00:00:00 2001 From: braunc8 Date: Tue, 23 Jul 2024 10:05:13 -0400 Subject: [PATCH 09/36] added changelog update --- langium/CHANGELOG.md | 5 +++++ .../src/language/services/jpipe-completion-provider.ts | 9 ++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/langium/CHANGELOG.md b/langium/CHANGELOG.md index ce8457b..a1d7c1f 100644 --- a/langium/CHANGELOG.md +++ b/langium/CHANGELOG.md @@ -2,6 +2,11 @@ ### Unreleased +- Leader: Cass Braun + - Features: + - Added patterns and compositions to grammar with basic language support + + ### v0.2.0 (2024-07-19) - Leader: Cass Braun diff --git a/langium/src/language/services/jpipe-completion-provider.ts b/langium/src/language/services/jpipe-completion-provider.ts index 16d5a6c..6d51220 100644 --- a/langium/src/language/services/jpipe-completion-provider.ts +++ b/langium/src/language/services/jpipe-completion-provider.ts @@ -70,16 +70,19 @@ export class JpipeCompletionProvider extends DefaultCompletionProvider{ //ex. if your JD defines evidence 'e1', strategy 'e2' and conclusion e3', when starting the statement: //e2 supports ___ auto-completion will only show e3 as an option getRightVariables(variables: AstNodeDescription[], _context: CompletionContext): AstNodeDescription[]{ - let rightVariables: AstNodeDescription[] = []; + let rightVariables: AstNodeDescription[]; if(isSupport(_context.node)){ - if(_context.node.left.ref !== undefined){ let supporter_kind = _context.node.left.ref.kind; let allowable_types = possible_supports.get(supporter_kind); rightVariables = this.findRightVariables(variables, allowable_types); + }else{ + rightVariables = []; } + }else{ + rightVariables = []; } return rightVariables; @@ -93,7 +96,7 @@ export class JpipeCompletionProvider extends DefaultCompletionProvider{ if(isVariable(variable.node)){ if(allowable_types?.includes(variable.node.kind)){ right_variables.push(variable); - } + } } }); From 5df42fda541424a6177e5fe1fdb7a1bee3af5e1e Mon Sep 17 00:00:00 2001 From: braunc8 Date: Tue, 23 Jul 2024 10:18:52 -0400 Subject: [PATCH 10/36] refactor of pattern and justification grammar --- langium/src/language/jpipe.langium | 57 +++++-------------- .../services/jpipe-completion-provider.ts | 24 +++----- .../language/services/jpipe-hover-provider.ts | 7 ++- .../src/language/services/jpipe-validator.ts | 8 +-- 4 files changed, 31 insertions(+), 65 deletions(-) diff --git a/langium/src/language/jpipe.langium b/langium/src/language/jpipe.langium index 381bc69..705307b 100644 --- a/langium/src/language/jpipe.langium +++ b/langium/src/language/jpipe.langium @@ -1,54 +1,25 @@ grammar Jpipe entry Model: - (entries += (Justification | Pattern | Composition))*; + (entries += (JustificationPattern | Composition))*; -type Variable = JustificationVariable | PatternVariable; +JustificationPattern: + Class body=Body; -type Instruction = JustificationInstruction | PatternInstruction; +Class: + kind=('justification' | 'pattern') (name=ID | name=ID 'implements' implemented=[Class]); -type Class = JustificationClass | PatternClass; +Body: + '{' (variables+=Variable | instructions+=Instruction | supports += Support)* '}'; -Justification: - (JustificationClass | JustificationImplementsClass) body=JustificationBody; - -JustificationClass: - kind=('justification') name=ID; - -JustificationImplementsClass: - kind=('justification') name=ID 'implements' class=[PatternClass]; - -JustificationBody: - '{' (variables+=JustificationVariable | instructions+=JustificationInstruction | supports += JustificationSupport)* '}'; - -JustificationVariable: - kind=('evidence' | 'strategy' | 'sub-conclusion' | 'conclusion') name=ID; - -JustificationInstruction: - JustificationVariable 'is' information=STRING; - -JustificationSupport: - left=[JustificationVariable:ID] 'supports' right=[JustificationVariable:ID]; - - -Pattern: - PatternClass body=PatternBody; - -PatternClass: - kind=('pattern') name=ID; - -PatternBody: - '{' (variables+=PatternVariable | instructions += PatternInstruction | supports += PatternSupport)* '}'; - -PatternVariable: +Variable: kind=('evidence' | 'strategy' | 'sub-conclusion' | 'conclusion' | '@support') name=ID; -PatternInstruction: - PatternVariable 'is' information=STRING; - -PatternSupport: - left=[PatternVariable:ID] 'supports' right=[PatternVariable:ID]; +Instruction: + Variable 'is' information=STRING; +Support: + left=[Variable:ID] 'supports' right=[Variable:ID]; Composition: @@ -67,7 +38,9 @@ CompositionInstruction: CompositionVariable 'is' information=CompositionInformation; CompositionInformation: - left=[JustificationClass] 'with' right=[JustificationClass]; + left=[Class] 'with' right=[Class]; + + hidden terminal WS: /\s+/; terminal ID: /[_a-zA-Z][\w_]*/; terminal STRING: /"(\\.|[^"\\])*"|'(\\.|[^'\\])*'/; diff --git a/langium/src/language/services/jpipe-completion-provider.ts b/langium/src/language/services/jpipe-completion-provider.ts index 6d51220..f6413d2 100644 --- a/langium/src/language/services/jpipe-completion-provider.ts +++ b/langium/src/language/services/jpipe-completion-provider.ts @@ -1,6 +1,6 @@ import { AstNode, AstNodeDescription, ReferenceInfo, Stream } from "langium"; import { CompletionContext, DefaultCompletionProvider } from "langium/lsp"; -import { CompositionClass, CompositionInstruction, isCompositionClass, isCompositionInstruction, isJustification, isJustificationClass, isJustificationImplementsClass, isJustificationInstruction, isJustificationSupport, isJustificationVariable, isPattern, isPatternClass, isPatternInstruction, isPatternSupport, isPatternVariable, Justification, JustificationClass, JustificationImplementsClass, JustificationInstruction, JustificationSupport, JustificationVariable, Pattern, PatternClass, PatternInstruction, PatternSupport, PatternVariable } from "../generated/ast.js"; +import { Class, CompositionClass, CompositionInstruction, Instruction, isClass, isCompositionClass, isCompositionInstruction, isInstruction, isJustificationPattern, isSupport, isVariable, JustificationPattern, Support, } from "../generated/ast.js"; import { stream } from "../../../node_modules/langium/src/utils/stream.js" import { possible_supports } from "./jpipe-validator.js"; @@ -61,7 +61,7 @@ export class JpipeCompletionProvider extends DefaultCompletionProvider{ } //helper functino to determine which side of support statement we are on - onRightSide(context_node: PatternSupport | JustificationSupport){ + onRightSide(context_node: Support){ return context_node.left.ref !== undefined; } @@ -173,23 +173,15 @@ export class JpipeCompletionProvider extends DefaultCompletionProvider{ } } -export function isSupport(node: AstNode | undefined): node is JustificationSupport | PatternSupport{ - return isJustificationSupport(node) || isPatternSupport(node); -} - -export function isVariable(node: AstNode | undefined): node is JustificationVariable | PatternVariable { - return isJustificationVariable(node) || isPatternVariable(node); -} - -export function isInstruction(node: AstNode | undefined): node is JustificationInstruction | PatternInstruction | CompositionInstruction{ - return isJustificationInstruction(node) || isPatternInstruction(node) || isCompositionInstruction(node); +export function isInstructionType(node: AstNode | undefined): node is Instruction | CompositionInstruction{ + return isInstruction(node) || isCompositionInstruction(node); } -export function isClass(node: AstNode | undefined): node is JustificationClass | JustificationImplementsClass | PatternClass | CompositionClass{ - return isJustificationClass(node) || isPatternClass(node) || isJustificationImplementsClass(node) || isCompositionClass(node); +export function isClassType(node: AstNode | undefined): node is Class | CompositionClass{ + return isClass(node) || isCompositionClass(node); } -export function hasSupports(node: AstNode): node is Pattern | Justification{ - return isPattern(node) || isJustification(node); +export function hasSupports(node: AstNode): node is JustificationPattern{ + return isJustificationPattern(node); } \ No newline at end of file diff --git a/langium/src/language/services/jpipe-hover-provider.ts b/langium/src/language/services/jpipe-hover-provider.ts index 9e34a92..8b984cb 100644 --- a/langium/src/language/services/jpipe-hover-provider.ts +++ b/langium/src/language/services/jpipe-hover-provider.ts @@ -1,13 +1,14 @@ import { type AstNode, type MaybePromise, } from 'langium'; import { AstNodeHoverProvider } from 'langium/lsp'; import { Hover } from 'vscode-languageserver'; -import { isClass, isInstruction, isVariable } from './jpipe-completion-provider.js'; +import { isClassType, isInstructionType } from './jpipe-completion-provider.js'; +import { isVariable } from '../generated/ast.js'; //provides hover for variables and class types export class JpipeHoverProvider extends AstNodeHoverProvider{ protected getAstNodeHoverContent(node: AstNode): MaybePromise { - if(isInstruction(node)){ + if(isInstructionType(node)){ node.$cstNode } if(isVariable(node)){ @@ -21,7 +22,7 @@ export class JpipeHoverProvider extends AstNodeHoverProvider{ } } - if(isClass(node)){ + if(isClassType(node)){ return { contents: { kind: 'markdown', diff --git a/langium/src/language/services/jpipe-validator.ts b/langium/src/language/services/jpipe-validator.ts index af1851e..c1c8751 100644 --- a/langium/src/language/services/jpipe-validator.ts +++ b/langium/src/language/services/jpipe-validator.ts @@ -1,7 +1,7 @@ import { Reference, type ValidationAcceptor, type ValidationChecks } from 'langium'; -import { JustificationSupport, JustificationVariable, PatternSupport, PatternVariable, Variable, type JpipeAstType, type Model} from '../generated/ast.js'; +import { isSupport, Support, Variable, type JpipeAstType, type Model} from '../generated/ast.js'; import type { JpipeServices } from '../jpipe-module.js'; -import { hasSupports, isSupport } from './jpipe-completion-provider.js'; +import { hasSupports } from './jpipe-completion-provider.js'; /** @@ -40,7 +40,7 @@ export class JpipeValidator { } //helper function to test if variables are defined - private checkSupport(support: PatternSupport | JustificationSupport, accept: ValidationAcceptor): void{ + private checkSupport(support: Support, accept: ValidationAcceptor): void{ if(this.hasError(support.left, support.right)){ let errorStatement = this.getErrorStatement(support.left, support.right); accept("error", errorStatement, {node: support}); @@ -48,7 +48,7 @@ export class JpipeValidator { } //helper function to determine if there is an error in a support statement - private hasError(leftSupport: Reference, rightSupport: Reference): boolean{ + private hasError(leftSupport: Reference, rightSupport: Reference): boolean{ let hasError: boolean; let leftKind = leftSupport.ref?.kind; From f1d84b3488b704bcba3949a27062c7a13b8972c2 Mon Sep 17 00:00:00 2001 From: braunc8 Date: Tue, 23 Jul 2024 10:54:00 -0400 Subject: [PATCH 11/36] fixed validation issue for support variables only --- .../src/language/services/jpipe-validator.ts | 49 +++++++++---------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/langium/src/language/services/jpipe-validator.ts b/langium/src/language/services/jpipe-validator.ts index c1c8751..37c8cd3 100644 --- a/langium/src/language/services/jpipe-validator.ts +++ b/langium/src/language/services/jpipe-validator.ts @@ -1,5 +1,5 @@ -import { Reference, type ValidationAcceptor, type ValidationChecks } from 'langium'; -import { isSupport, Support, Variable, type JpipeAstType, type Model} from '../generated/ast.js'; +import { type ValidationAcceptor, type ValidationChecks } from 'langium'; +import { isSupport, Support, type JpipeAstType, type Model} from '../generated/ast.js'; import type { JpipeServices } from '../jpipe-module.js'; import { hasSupports } from './jpipe-completion-provider.js'; @@ -11,7 +11,7 @@ export function registerValidationChecks(services: JpipeServices) { const registry = services.validation.ValidationRegistry; const validator = services.validation.JpipeValidator; const checks: ValidationChecks = { - Model: [validator.allChecks] + Model: [validator.testChecks] }; registry.register(checks, validator); } @@ -19,12 +19,15 @@ export function registerValidationChecks(services: JpipeServices) { export class JpipeValidator { //edit to implement validation hierarchy (no duplicate statements) - allChecks(model: Model, accept: ValidationAcceptor): void{ - //this.checkNaming(model, accept); + public allChecks(model: Model, accept: ValidationAcceptor): void{ this.checkVariables(model, accept); this.checkSupportingStatements(model, accept); } + public testChecks(model: Model, accept: ValidationAcceptor): void{ + this.checkSupportingStatements(model, accept); + } + //Checks that variables are defined private checkVariables(model: Model, accept: ValidationAcceptor): void{ model.entries.forEach( (entry) =>{ @@ -41,41 +44,33 @@ export class JpipeValidator { //helper function to test if variables are defined private checkSupport(support: Support, accept: ValidationAcceptor): void{ - if(this.hasError(support.left, support.right)){ - let errorStatement = this.getErrorStatement(support.left, support.right); + if(this.hasError(support)){ + let errorStatement = this.getErrorStatement(support); accept("error", errorStatement, {node: support}); } } //helper function to determine if there is an error in a support statement - private hasError(leftSupport: Reference, rightSupport: Reference): boolean{ - let hasError: boolean; - - let leftKind = leftSupport.ref?.kind; - let rightKind = rightSupport.ref?.kind; - - if(leftKind === undefined || rightKind === undefined){ - hasError = true; - }else{ - hasError = false; - } + private hasError(support: Support): boolean{ + let left = support.left.ref; + let right = support.right.ref; - return hasError; + return left === undefined || right === undefined; } //helper function to determine the necessary error statement - private getErrorStatement(leftSupport: Reference, rightSupport: Reference): string{ + private getErrorStatement(support: Support): string{ let errorStatement: string - let leftKind = leftSupport.ref?.kind; - let rightKind = rightSupport.ref?.kind; + let left = support.left.ref; + let right = support.right.ref; - if(leftKind === undefined && rightKind === undefined){ - errorStatement = `Variables ${leftSupport.$refText} and ${rightSupport.$refText} are undefined.` - }else if(leftKind === undefined){ - errorStatement = `Variable ${leftSupport.$refText} is undefined.` + if(left === undefined && right === undefined){ + errorStatement = `Left and right variable are undefined.` + }else if(left === undefined){ + errorStatement = `Left variable is undefined.` }else{ - errorStatement = `Variable ${rightSupport.$refText} is undefined.` + errorStatement = `Right variable is undefined.` } return errorStatement; From 1ab8d723fe0a5e46d4dcd1b229a0ed15cd103455 Mon Sep 17 00:00:00 2001 From: braunc8 Date: Tue, 23 Jul 2024 11:47:42 -0400 Subject: [PATCH 12/36] fixed issue with whole document errors for support verification ONLY --- .../src/language/services/jpipe-validator.ts | 73 +++++++++++++++---- langium/tsconfig.json | 2 +- 2 files changed, 58 insertions(+), 17 deletions(-) diff --git a/langium/src/language/services/jpipe-validator.ts b/langium/src/language/services/jpipe-validator.ts index 37c8cd3..28e84ca 100644 --- a/langium/src/language/services/jpipe-validator.ts +++ b/langium/src/language/services/jpipe-validator.ts @@ -1,5 +1,5 @@ -import { type ValidationAcceptor, type ValidationChecks } from 'langium'; -import { isSupport, Support, type JpipeAstType, type Model} from '../generated/ast.js'; +import { Reference, type ValidationAcceptor, type ValidationChecks } from 'langium'; +import { isSupport, Support, Variable, type JpipeAstType, type Model} from '../generated/ast.js'; import type { JpipeServices } from '../jpipe-module.js'; import { hasSupports } from './jpipe-completion-provider.js'; @@ -25,7 +25,8 @@ export class JpipeValidator { } public testChecks(model: Model, accept: ValidationAcceptor): void{ - this.checkSupportingStatements(model, accept); + this.checkVariables(model, accept); + } //Checks that variables are defined @@ -38,28 +39,62 @@ export class JpipeValidator { } }); } - }); } //helper function to test if variables are defined private checkSupport(support: Support, accept: ValidationAcceptor): void{ - if(this.hasError(support)){ - let errorStatement = this.getErrorStatement(support); - accept("error", errorStatement, {node: support}); + try{ + let error = this.getErrorType(support.left, support.right); + if(error !== ErrorType.NoError){ + let errorStatement = this.getErrorStatement(error); + accept("error", errorStatement.call(this, support), {node: support}); + } + }catch(error: any){ + accept("error", "Unknown issue with phrase", {node: support}); } } //helper function to determine if there is an error in a support statement - private hasError(support: Support): boolean{ - let left = support.left.ref; - let right = support.right.ref; + private getErrorType(left: Reference, right: Reference): ErrorType{ + let errorType: ErrorType; - return left === undefined || right === undefined; + if(left.error !== undefined || right.error !== undefined){ + errorType = ErrorType.LinkingError; + }else if(left.ref === undefined || right.ref === undefined){ + errorType = ErrorType.ReferenceError; + }else{ + errorType = ErrorType.NoError; + } + + return errorType; } //helper function to determine the necessary error statement - private getErrorStatement(support: Support): string{ + private getErrorStatement(errorType: ErrorType): (support: Support) => string{ + let errorFunction: (support: Support) => string; + + let errors = new Map string>([ + [ErrorType.LinkingError, this.getLinkingError], + [ErrorType.ReferenceError, this.getReferenceError] + ]); + + let returnFunction = errors.get(errorType); + + if(returnFunction){ + errorFunction = returnFunction; + }else{ + errorFunction = () => ""; + } + + return errorFunction; + } + + private getLinkingError = (support: Support): string => { + return ""; + }; + + private getReferenceError = (support: Support): string => { let errorStatement: string let left = support.left.ref; @@ -74,18 +109,17 @@ export class JpipeValidator { } return errorStatement; - } + }; //checks if support statements follow proper typing convention private checkSupportingStatements(model: Model, accept: ValidationAcceptor): void{ - model.entries.forEach( (entry) =>{ if(hasSupports(entry)){ entry.body.supports.forEach( (support) =>{ if(isSupport(support)){ if(support.left.ref !== undefined && support.right.ref !==undefined){ - let leftKind = support.left.ref?.kind; - let rightKind = support.right.ref?.kind; + let leftKind = support.left.ref.kind; + let rightKind = support.right.ref.kind; let possibleRights: string[] | undefined = possible_supports.get(leftKind); if(rightKind !== undefined){ @@ -106,6 +140,13 @@ export class JpipeValidator { } } +enum ErrorType{ + NoError, + LinkingError, + ReferenceError +} + + export var possible_supports = new Map([ ['evidence', ['strategy', '@support']], ['strategy', ['sub-conclusion', 'conclusion', '@support']], diff --git a/langium/tsconfig.json b/langium/tsconfig.json index 38545c9..fa95368 100644 --- a/langium/tsconfig.json +++ b/langium/tsconfig.json @@ -8,7 +8,7 @@ "sourceMap": true, "outDir": "out", "strict": true, - "noUnusedLocals": true, + "noUnusedLocals": false, "noImplicitReturns": true, "noImplicitOverride": true, "moduleResolution": "Node16", From fc3a392bde341d7b07688585a2d89bd7ee126f09 Mon Sep 17 00:00:00 2001 From: braunc8 Date: Tue, 23 Jul 2024 12:01:59 -0400 Subject: [PATCH 13/36] refactor of support statement error correction --- .../src/language/services/jpipe-validator.ts | 43 ++++++++----------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/langium/src/language/services/jpipe-validator.ts b/langium/src/language/services/jpipe-validator.ts index 28e84ca..e5df82a 100644 --- a/langium/src/language/services/jpipe-validator.ts +++ b/langium/src/language/services/jpipe-validator.ts @@ -47,8 +47,11 @@ export class JpipeValidator { try{ let error = this.getErrorType(support.left, support.right); if(error !== ErrorType.NoError){ - let errorStatement = this.getErrorStatement(error); - accept("error", errorStatement.call(this, support), {node: support}); + let errorStatements = this.getError(error).call(this,support); + + errorStatements.forEach(statement =>{ + accept("error", statement, {node: support}); + }) } }catch(error: any){ accept("error", "Unknown issue with phrase", {node: support}); @@ -59,9 +62,7 @@ export class JpipeValidator { private getErrorType(left: Reference, right: Reference): ErrorType{ let errorType: ErrorType; - if(left.error !== undefined || right.error !== undefined){ - errorType = ErrorType.LinkingError; - }else if(left.ref === undefined || right.ref === undefined){ + if(left.ref === undefined || right.ref === undefined){ errorType = ErrorType.ReferenceError; }else{ errorType = ErrorType.NoError; @@ -71,11 +72,10 @@ export class JpipeValidator { } //helper function to determine the necessary error statement - private getErrorStatement(errorType: ErrorType): (support: Support) => string{ - let errorFunction: (support: Support) => string; + private getError(errorType: ErrorType): (support: Support) => string[]{ + let errorFunction: (support: Support) => string[]; - let errors = new Map string>([ - [ErrorType.LinkingError, this.getLinkingError], + let errors = new Map string[]>([ [ErrorType.ReferenceError, this.getReferenceError] ]); @@ -84,28 +84,24 @@ export class JpipeValidator { if(returnFunction){ errorFunction = returnFunction; }else{ - errorFunction = () => ""; + errorFunction = () => []; } return errorFunction; } - - private getLinkingError = (support: Support): string => { - return ""; - }; - private getReferenceError = (support: Support): string => { - let errorStatement: string + private getReferenceError = (support: Support): string[] => { + let errorStatement: string[]; - let left = support.left.ref; - let right = support.right.ref; + let left = support.left; + let right = support.right; - if(left === undefined && right === undefined){ - errorStatement = `Left and right variable are undefined.` - }else if(left === undefined){ - errorStatement = `Left variable is undefined.` + if(left.ref === undefined && right.ref === undefined){ + errorStatement =[ `Variables ${left.$refText} and ${right.$refText} are undefined.`]; + }else if(left.ref === undefined){ + errorStatement = [`Variable ${left.$refText} is undefined.`]; }else{ - errorStatement = `Right variable is undefined.` + errorStatement = [`Variable ${right.$refText}is undefined.`]; } return errorStatement; @@ -142,7 +138,6 @@ export class JpipeValidator { enum ErrorType{ NoError, - LinkingError, ReferenceError } From fc7987b5e3bbfe6a6877c2d3aae9ecdf301cf57a Mon Sep 17 00:00:00 2001 From: braunc8 Date: Tue, 23 Jul 2024 12:29:40 -0400 Subject: [PATCH 14/36] fixed issue with whole highlighting of doucment entirely, refactored validation checks somewhat --- .../src/language/services/jpipe-validator.ts | 94 +++++++++++-------- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/langium/src/language/services/jpipe-validator.ts b/langium/src/language/services/jpipe-validator.ts index e5df82a..7c147b5 100644 --- a/langium/src/language/services/jpipe-validator.ts +++ b/langium/src/language/services/jpipe-validator.ts @@ -11,7 +11,7 @@ export function registerValidationChecks(services: JpipeServices) { const registry = services.validation.ValidationRegistry; const validator = services.validation.JpipeValidator; const checks: ValidationChecks = { - Model: [validator.testChecks] + Model: [validator.allChecks] }; registry.register(checks, validator); } @@ -19,43 +19,54 @@ export function registerValidationChecks(services: JpipeServices) { export class JpipeValidator { //edit to implement validation hierarchy (no duplicate statements) - public allChecks(model: Model, accept: ValidationAcceptor): void{ - this.checkVariables(model, accept); - this.checkSupportingStatements(model, accept); - } - - public testChecks(model: Model, accept: ValidationAcceptor): void{ - this.checkVariables(model, accept); - + allChecks(model: Model, accept: ValidationAcceptor): void{ + this.checkSupportStatements(model, accept); } //Checks that variables are defined - private checkVariables(model: Model, accept: ValidationAcceptor): void{ + private checkSupportStatements(model: Model, accept: ValidationAcceptor): void{ model.entries.forEach( (entry) =>{ if(hasSupports(entry)){ entry.body.supports.forEach( (support) =>{ - if(isSupport(support)){ - this.checkSupport(support, accept); - } + if(this.referencesCorrect(support, accept)){ + this.checkSupportRelations(support, accept); + } }); } }); } //helper function to test if variables are defined - private checkSupport(support: Support, accept: ValidationAcceptor): void{ + private referencesCorrect(support: Support, accept: ValidationAcceptor): boolean{ + let symbolNamesCorrect: boolean; + try{ let error = this.getErrorType(support.left, support.right); - if(error !== ErrorType.NoError){ + if(error === ErrorType.NoError){ + symbolNamesCorrect = true; + }else{ + symbolNamesCorrect = false; + let errorStatements = this.getError(error).call(this,support); errorStatements.forEach(statement =>{ accept("error", statement, {node: support}); - }) + }); } }catch(error: any){ + symbolNamesCorrect = false; accept("error", "Unknown issue with phrase", {node: support}); } + + return symbolNamesCorrect; + } + + //checks if support statements follow proper typing convention + private checkSupportRelations(support: Support, accept: ValidationAcceptor): void{ + if(!this.supportRelationCorrect(support)){ + let error_message = this.getRelationErrorMessage(support); + accept("error", error_message, {node:support}); + } } //helper function to determine if there is an error in a support statement @@ -107,32 +118,33 @@ export class JpipeValidator { return errorStatement; }; - //checks if support statements follow proper typing convention - private checkSupportingStatements(model: Model, accept: ValidationAcceptor): void{ - model.entries.forEach( (entry) =>{ - if(hasSupports(entry)){ - entry.body.supports.forEach( (support) =>{ - if(isSupport(support)){ - if(support.left.ref !== undefined && support.right.ref !==undefined){ - let leftKind = support.left.ref.kind; - let rightKind = support.right.ref.kind; - let possibleRights: string[] | undefined = possible_supports.get(leftKind); - - if(rightKind !== undefined){ - if (possibleRights?.includes(rightKind)){ - return; - } - } - - accept("error", `It is not possible to have ${leftKind} support ${rightKind}.`, { - node:support - }); - } - } - }); - } + private supportRelationCorrect(support: Support): boolean{ + let supportCorrect: boolean; - }); + if(support.left.ref !== undefined && support.right.ref !==undefined){ + let rightKind = support.right.ref.kind; + let possibleRights = possible_supports.get(support.left.ref.kind); + + if(possibleRights?.includes(rightKind)){ + supportCorrect = true; + }else{ + supportCorrect = false; + } + }else{ + supportCorrect = false; + } + + return supportCorrect; + } + + private getRelationErrorMessage(support: Support): string{ + let error_message: string = ""; + + if(support.left.ref !== undefined && support.right.ref !== undefined){ + error_message = `It is not possible to have ${support.left.ref.kind} support ${support.right.ref.kind}.` + } + + return error_message; } } From 9d88efa702dd19a595aa47b0df1f11e11af5153f Mon Sep 17 00:00:00 2001 From: braunc8 Date: Wed, 24 Jul 2024 11:13:37 -0400 Subject: [PATCH 15/36] refactored validation completely to make validation checks easier in the future --- langium/src/language/jpipe-module.ts | 13 ++-- langium/src/language/jpipe.langium | 4 +- .../services/jpipe-completion-provider.ts | 22 ++---- .../language/services/jpipe-hover-provider.ts | 5 +- .../services/validation/main-validation.ts | 57 ++++++++++++++ .../support-validator.ts} | 78 +++++++------------ 6 files changed, 98 insertions(+), 81 deletions(-) create mode 100644 langium/src/language/services/validation/main-validation.ts rename langium/src/language/services/{jpipe-validator.ts => validation/support-validator.ts} (69%) diff --git a/langium/src/language/jpipe-module.ts b/langium/src/language/jpipe-module.ts index 20692a5..082c420 100644 --- a/langium/src/language/jpipe-module.ts +++ b/langium/src/language/jpipe-module.ts @@ -1,15 +1,16 @@ import { type Module, inject, } from 'langium'; import { createDefaultModule, createDefaultSharedModule, type DefaultSharedModuleContext, type LangiumServices, type LangiumSharedServices, type PartialLangiumServices } from 'langium/lsp'; import { JpipeGeneratedModule, JpipeGeneratedSharedModule } from './generated/module.js'; -import { JpipeValidator, registerValidationChecks } from './services/jpipe-validator.js'; import { JpipeHoverProvider } from './services/jpipe-hover-provider.js'; import { JpipeCompletionProvider } from './services/jpipe-completion-provider.js'; +import { makeValidators, registerValidationChecks, Validator } from './services/validation/main-validation.js'; +import { SupportValidator } from './services/validation/support-validator.js'; /** * Declaration of custom services - add your own service classes here. */ export type JpipeAddedServices = { validation: { - JpipeValidator: JpipeValidator + validators: Validator[] } } @@ -26,7 +27,7 @@ export type JpipeServices = LangiumServices & JpipeAddedServices */ export const JpipeModule: Module = { validation: { - JpipeValidator: () => new JpipeValidator() + validators: () => makeValidators() }, lsp:{ CompletionProvider: (services) => new JpipeCompletionProvider(services), @@ -35,8 +36,6 @@ export const JpipeModule: Module