Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Jep/utility #16

Merged
merged 35 commits into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c73cfac
Merge branch 'master' into jep/utility
Drakae Jun 6, 2023
6f261c3
code restructuring
Drakae Jun 6, 2023
bdce81f
pdf export (WIP)
Drakae Jun 7, 2023
a9f673f
pdf export (WIP)
Drakae Jun 7, 2023
b5fe885
markdown creation (WIP)
Drakae Jun 13, 2023
62957bd
markdown creation
Drakae Jun 13, 2023
32fadb3
internal export for control structure (WIP)
Drakae Jun 14, 2023
d745470
export control structure svg action (WIP)
Drakae Jun 19, 2023
d2f4c46
internal svg export is working
Drakae Jun 19, 2023
a1175d3
svg embedded in result report
Drakae Jun 19, 2023
b2c38fe
control structure embedded in result report
Drakae Jun 19, 2023
475eaaa
md-export: diagrams are included
Drakae Jun 20, 2023
a5f1982
md-export: filtered UCA graphs + fixed width
Drakae Jun 20, 2023
5584771
adjusted table formatting
Drakae Jun 20, 2023
0fccb85
md-export: subcomponents are considered
Drakae Jun 20, 2023
f3cdc9e
timestamp + text if no component is defined
Drakae Jun 23, 2023
72e009a
added title for the report
Drakae Jun 23, 2023
733d0ca
added table of contents
Drakae Jun 23, 2023
4c7912f
added comments
Drakae Jun 26, 2023
c29b4ad
Merge branch 'master' into jep/utility
Drakae Aug 9, 2023
2ca57af
fixed merge
Drakae Aug 9, 2023
7110eb9
restructuring
Drakae Aug 29, 2023
421f502
merge
Drakae Aug 29, 2023
19b06e2
merge fix
Drakae Aug 29, 2023
abe71b7
fixed remaining problems
Drakae Aug 29, 2023
731287d
prettier
Drakae Aug 29, 2023
ae2671b
grouping of commands
Drakae Aug 29, 2023
ff90f55
restructuring + formatting
Drakae Sep 12, 2023
faed5e3
fixed debugging
Drakae Sep 13, 2023
de39bef
context table is also considered in result report
Drakae Sep 13, 2023
6a69460
filtered controller constraints graphs
Drakae Sep 13, 2023
670798c
filtered scenario graphs
Drakae Sep 14, 2023
5471d0d
filter for scenarios with only hazards
Drakae Sep 14, 2023
7391c6b
mka feedback
Drakae Sep 18, 2023
365ec72
fixed uca grouping option
Drakae Sep 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"webpack:///./~/*": "${workspaceFolder}/extension/node_modules/*",
"webpack://?:*/*": "${workspaceFolder}/extension/*"
},
"type": "pwa-node"
"type": "node"
}
]
}
23 changes: 19 additions & 4 deletions extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@
"command": "stpa.SBM.generation",
"title": "Generate Safe Behavioral Model (SBM)",
"category": "STPA SBM"
},
{
"command": "stpa.md.creation",
"title": "Create a Markdown file",
"category": "STPA PDF Creation"
}
],
"menus": {
Expand Down Expand Up @@ -201,6 +206,10 @@
{
"command": "stpa.SBM.generation",
"when": "editorLangId == 'stpa'"
},
{
"command": "stpa.md.creation",
"when": "editorLangId == 'stpa'"
}
],
"editor/context": [
Expand All @@ -217,12 +226,17 @@
{
"submenu": "stpa.checks",
"when": "editorLangId == 'stpa'",
"group": "checks"
"group": "stpa"
},
{
"command": "stpa.SBM.generation",
"when": "editorLangId == 'stpa'",
"group": "navigation"
"group": "stpa"
},
{
"command": "stpa.md.creation",
"when": "editorLangId == 'stpa'",
"group": "stpa"
}
],
"stpa.checks": [
Expand Down Expand Up @@ -339,7 +353,8 @@
"feather-icons": "^4.28.0",
"sprotty-vscode-webview": "^0.5.0",
"@kieler/table-webview": "^0.0.3",
"snabbdom": "^3.5.1"
"snabbdom": "^3.5.1",
"dayjs": "^1.11.8"
},
"devDependencies": {
"@types/node": "^12.12.6",
Expand All @@ -365,7 +380,7 @@
"langium:generate": "langium generate",
"langium:watch": "langium generate --watch",
"lint": "eslint .",
"build": "yarn run langium:generate && webpack --mode development --devtool eval-source-map",
"build": "yarn run langium:generate && webpack --mode development",
"watch": "webpack --watch",
"package": "vsce package --yarn -o pasta.vsix",
"predistribute": "yarn run package",
Expand Down
34 changes: 26 additions & 8 deletions extension/src-language-server/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,27 @@ import { elementWithName } from "./stpa/utils";
*/
export function addNotificationHandler(connection: Connection, shared: LangiumSprottySharedServices): void {
// diagram
connection.onNotification('diagram/selected', (msg: {label: string, uri: string}) => {
connection.onNotification("diagram/selected", async (msg: { label: string; uri: string }) => {
// get the current model
const model = getModel(msg.uri, shared);
const model = await getModel(msg.uri, shared);

// determine the range in the editor of the component identified by "label"
const range = getRangeOfNode(model, msg.label);
if (range) {
// notify extension to highlight the range in the editor
connection.sendNotification('editor/highlight', ({ startLine: range.start.line, startChar: range.start.character, endLine: range.end.line, endChar: range.end.character, uri: msg.uri }));
connection.sendNotification("editor/highlight", {
startLine: range.start.line,
startChar: range.start.character,
endLine: range.end.line,
endChar: range.end.character,
uri: msg.uri,
});
} else {
console.log("The selected UCA could not be found in the editor.");
}
});
}


/**
* Determines the range of the component identified by {@code label} in the editor,
* @param model The current STPA model.
Expand All @@ -52,16 +57,29 @@ export function addNotificationHandler(connection: Connection, shared: LangiumSp
*/
function getRangeOfNode(model: Model, label: string): Range | undefined {
let range: Range | undefined = undefined;
const elements: elementWithName[] = [...model.losses, ...model.hazards, ...model.hazards.flatMap(hazard => hazard.subComps), ...model.systemLevelConstraints, ...model.systemLevelConstraints.flatMap(constraint => constraint.subComps), ...model.responsibilities.flatMap(resp => resp.responsiblitiesForOneSystem),
...model.allUCAs.flatMap(ucas => ucas.ucas), ...model.rules.flatMap(rule => rule.contexts), ...model.controllerConstraints, ...model.scenarios, ...model.safetyCons];
const elements: elementWithName[] = [
...model.losses,
...model.hazards,
...model.hazards.flatMap((hazard) => hazard.subComponents),
...model.systemLevelConstraints,
...model.systemLevelConstraints.flatMap((constraint) => constraint.subComponents),
...model.responsibilities.flatMap((resp) => resp.responsiblitiesForOneSystem),
...model.allUCAs.flatMap((ucas) =>
ucas.providingUcas.concat(ucas.notProvidingUcas, ucas.wrongTimingUcas, ucas.continousUcas)
),
...model.rules.flatMap((rule) => rule.contexts),
...model.controllerConstraints,
...model.scenarios,
...model.safetyCons,
];
if (model.controlStructure) {
elements.push(...model.controlStructure.nodes);
}
elements.forEach(component => {
elements.forEach((component) => {
if (component.name === label) {
range = component.$cstNode?.range;
return;
}
});
return range;
}
}
26 changes: 13 additions & 13 deletions extension/src-language-server/stpa.langium
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ entry Model:
('Hazards' hazards+=Hazard*)?
('SystemConstraints' systemLevelConstraints+=SystemConstraint*)?
('ControlStructure' controlStructure=Graph)?
('Responsibilities' responsibilities+=Resps*)?
('Responsibilities' responsibilities+=SystemResponsibilities*)?
(('UCAs' allUCAs+=ActionUCAs*) | ('Context-Table' rules+=Rule*))?
('DCAs' allDCAs+=DCARule*)?
('ControllerConstraints' controllerConstraints+=ContConstraint*)?
('ControllerConstraints' controllerConstraints+=ControllerConstraint*)?
('LossScenarios' scenarios+=LossScenario*)?
('SafetyRequirements' safetyCons+=SafetyConstraint*)?;

Expand All @@ -48,14 +48,14 @@ Loss:
Hazard:
name=SubID description=STRING
('['refs+=[Loss] (',' refs+=[Loss])*']')?
('{' (header=STRING? subComps+=Hazard+)*'}')?;
('{' (header=STRING? subComponents+=Hazard+)*'}')?;

SystemConstraint:
name=SubID description=STRING
'['
refs+=[Hazard:SubID] (',' refs+=[Hazard:SubID])*
']'
('{' (header=STRING? subComps+=SystemConstraint+)*'}')?;
('{' (header=STRING? subComponents+=SystemConstraint+)*'}')?;

Graph:
name=ID '{'(nodes+=Node /* | edges+=Edge */)*'}';
Expand All @@ -67,8 +67,8 @@ Node:
('processModel' '{'variables+=Variable*'}')?
('input' '[' inputs+=Command (',' inputs+=Command)* ']')?
('output' '[' outputs+=Command (',' outputs+=Command)* ']')?
('controlActions' '{'actions+=VE*'}')?
('feedback' '{'feedbacks+=VE*'}')?
('controlActions' '{'actions+=VerticalEdge*'}')?
('feedback' '{'feedbacks+=VerticalEdge*'}')?
'}';

/* Edge:
Expand All @@ -85,13 +85,13 @@ VariableValue:
firstValue=(QualifiedName | INT | 'MIN' | 'true' | 'false') (',' secondValue=(QualifiedName | INT | 'MAX'))?
secondParenthesis=(']'|')'))?;

VE:
VerticalEdge:
'[' comms+=Command (',' comms+=Command)* ']' '->' target=[Node];

Command:
name=ID label=STRING;

Resps:
SystemResponsibilities:
system=[Node] '{'responsiblitiesForOneSystem+=Responsibility*'}';

Responsibility:
Expand All @@ -102,10 +102,10 @@ Responsibility:
ActionUCAs:
system=[Node]'.'
action=[Command] '{'
'notProviding' '{'ucas+=UCA*'}'
'providing' '{'ucas+=UCA*'}'
'tooEarly/Late' '{'ucas+=UCA*'}'
'stoppedTooSoon' '{'ucas+=UCA*'}'
'notProviding' '{'notProvidingUcas+=UCA*'}'
'providing' '{'providingUcas+=UCA*'}'
'tooEarly/Late' '{'wrongTimingUcas+=UCA*'}'
'stoppedTooSoon' '{'continousUcas+=UCA*'}'
'}';

UCA:
Expand All @@ -123,7 +123,7 @@ DCARule:
DCAContext:
name=ID '['vars+=[Variable] '=' values+=QualifiedName (',' vars+=[Variable] '=' values+=QualifiedName)*']';

ContConstraint:
ControllerConstraint:
name=ID description=STRING '['refs+=[UCA] (',' refs+=[UCA])*']';

LossScenario:
Expand Down
12 changes: 6 additions & 6 deletions extension/src-language-server/stpa/ID-enforcer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export class IDEnforcer {
const hazards = collectElementsWithSubComps(model.hazards) as Hazard[];
const sysCons = collectElementsWithSubComps(model.systemLevelConstraints) as SystemConstraint[];
const responsibilities = model.responsibilities?.map(r => r.responsiblitiesForOneSystem).flat(1);
const ucas = model.allUCAs?.map(sysUCA => sysUCA.ucas).flat(1);
const ucas = model.allUCAs?.map(sysUCA => sysUCA.providingUcas.concat(sysUCA.notProvidingUcas, sysUCA.wrongTimingUcas, sysUCA.continousUcas)).flat(1);
const contexts = model.rules?.map(rule => rule.contexts).flat(1);
const scenarioHazards = model.scenarios.map(scenario => scenario.list);
const scenarioUCAs = model.scenarios;
Expand Down Expand Up @@ -277,9 +277,9 @@ export class IDEnforcer {
edits = edits.concat(edit.changes[this.currentUri]);
}
// rename children
if ((isHazard(element) || isSystemConstraint(element)) && element.subComps.length !== 0) {
if ((isHazard(element) || isSystemConstraint(element)) && element.subComponents.length !== 0) {
let index = 1;
for (const child of element.subComps) {
for (const child of element.subComponents) {
edits = edits.concat(await this.renameID(child, prefix + counter + ".", index));
index++;
}
Expand Down Expand Up @@ -340,7 +340,7 @@ export class IDEnforcer {
elements = model.responsibilities.flatMap(resp => resp.responsiblitiesForOneSystem);
prefix = IDPrefix.Responsibility;
} else if (offset < ucaConstraintOffset && offset > ucaOffset) {
elements = model.allUCAs.flatMap(uca => uca.ucas);
elements = model.allUCAs.flatMap(sysUCA => sysUCA.providingUcas.concat(sysUCA.notProvidingUcas, sysUCA.wrongTimingUcas, sysUCA.continousUcas));
elements = elements.concat(model.rules.flatMap(rule => rule.contexts));
prefix = IDPrefix.UCA;
// rules must be handled separately since they are mixed with the UCAs
Expand Down Expand Up @@ -380,8 +380,8 @@ export class IDEnforcer {
// check whether the children are affected
// if the children are affected, it must be checked whether they have again affected children
// otherwise the current elements are the affected ones
if (element.subComps.length !== 0 && element.subComps[0].$cstNode && element.subComps[0].$cstNode.offset <= offset) {
const modified = this.findAffectedSubComponents(element.subComps, element.name + ".", offset);
if (element.subComponents.length !== 0 && element.subComponents[0].$cstNode && element.subComponents[0].$cstNode.offset <= offset) {
const modified = this.findAffectedSubComponents(element.subComponents, element.name + ".", offset);
elements = modified.elements;
prefix = modified.prefix;
}
Expand Down
81 changes: 81 additions & 0 deletions extension/src-language-server/stpa/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* KIELER - Kiel Integrated Environment for Layout Eclipse RichClient
*
* http://rtsys.informatik.uni-kiel.de/kieler
*
* Copyright 2023 by
* + Kiel University
* + Department of Computer Science
* + Real-Time and Embedded Systems Group
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*/

import { Action, JsonMap, RequestAction, generateRequestId, ResponseAction } from "sprotty-protocol";

/** Send to server to generate SVGs for the STPA result report */
export interface GenerateSVGsAction extends Action {
kind: typeof GenerateSVGsAction.KIND
uri: string
options?: JsonMap;
}

export namespace GenerateSVGsAction {
export const KIND = "generateSVGs";


export function create(
Drakae marked this conversation as resolved.
Show resolved Hide resolved
uri: string,
options?: JsonMap
): GenerateSVGsAction {
return {
kind: KIND,
uri,
options
};
}

export function isThisAction(action: Action): action is GenerateSVGsAction {
Drakae marked this conversation as resolved.
Show resolved Hide resolved
return action.kind === GenerateSVGsAction.KIND;
}
}

/** Requests the current SVG from the client. */
export interface RequestSvgAction extends RequestAction<SvgAction> {
kind: typeof RequestSvgAction.KIND
}

export namespace RequestSvgAction {
export const KIND = 'requestSvg';

export function create(): RequestSvgAction {
Drakae marked this conversation as resolved.
Show resolved Hide resolved
return {
kind: KIND,
requestId: generateRequestId()
};
}
}

/** Send from client to server containing the requested SVG and its width. */
export interface SvgAction extends ResponseAction {
kind: typeof SvgAction.KIND;
svg: string
width: number
responseId: string
}
export namespace SvgAction {
export const KIND = 'svg';

export function create(svg: string, width: number, requestId: string): SvgAction {
Drakae marked this conversation as resolved.
Show resolved Hide resolved
return {
kind: KIND,
svg,
width,
responseId: requestId
};
}
}
Loading
Loading