Skip to content

Commit

Permalink
separate commands and events checkers
Browse files Browse the repository at this point in the history
  • Loading branch information
Yokozuna59 committed Apr 24, 2024
1 parent c993cbe commit 45a1875
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class StatemachineCodeActionProvider implements CodeActionProvider {
case IssueCodes.StateNameUppercase:
accept(this.makeUpperCase(diagnostic, document));
break;
case IssueCodes.UnusedSymbol:
case IssueCodes.UnreachedState:
accept(this.removeUnusedSymbol(diagnostic, document));
break;
}
Expand Down
82 changes: 53 additions & 29 deletions examples/statemachine/src/language-server/statemachine-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import { MultiMap, diagnosticData } from 'langium';

export namespace IssueCodes {
export const StateNameUppercase = 'state-name-uppercase';
export const UnusedSymbol = 'unused-symbol';
export const UnreachedState = 'unreached-state';
export const UnreachedCommand = 'unreached-command';
export const UnreachedEvent = 'unreached-event';
}

export function registerValidationChecks(services: StatemachineServices) {
Expand All @@ -22,7 +24,8 @@ export function registerValidationChecks(services: StatemachineServices) {
Statemachine: [
validator.checkUniqueSymbolName,
validator.checkUnreachedStates,
validator.checkUnusedCommandsAndEvents,
validator.checkUnreachedCommands,
validator.checkUnreachedEvents,
]
};
registry.register(checks, validator);
Expand Down Expand Up @@ -69,7 +72,7 @@ export class StatemachineValidator {
}

/**
* Checks if there are unreached states.
* Checks for unreached states within the statemachine.
* @param statemachine the statemachine to check
* @param accept the acceptor to report errors
*/
Expand All @@ -88,57 +91,78 @@ export class StatemachineValidator {
for (const [name, state] of states.entries()) {
accept('hint', `Unreached state: ${name}`, {
node: state,
data: diagnosticData(IssueCodes.UnusedSymbol),
data: diagnosticData(IssueCodes.UnreachedState),
tags: [1],
});
}
}

private removeStates(states: Map<string, State>, transitions: Transition[]): void {
for (const { state: { ref } } of transitions) {
if (ref && states.has(ref.name)) {
states.delete(ref.name);
this.removeStates(states, ref.transitions);
/**
* Checks for unreached commands within the statemachine.
* @param statemachine The statemachine to check.
* @param acceptor The acceptor to report errors.
*/
checkUnreachedCommands(statemachine: Statemachine, acceptor: ValidationAcceptor): void {
const commandsByName = new Map<string, Command>();

for (const command of statemachine.commands) {
commandsByName.set(command.name, command);
}

for (const { actions } of statemachine.states) {
for (const { ref } of actions) {
if (ref && commandsByName.has(ref.name)) {
commandsByName.delete(ref.name);
}
}
}

for (const [name, command] of commandsByName.entries()) {
acceptor('warning', `Unreached command: ${name}`, {
node: command,
property: 'name',
data: diagnosticData(IssueCodes.UnreachedCommand),
tags: [1],
});
}
}

/**
* Checks if there are unused commands and events.
* Checks for unreached evens within the statemachine.
* @param statemachine the statemachine to check
* @param accept the acceptor to report errors
*/
checkUnusedCommandsAndEvents(statemachine: Statemachine, accept: ValidationAcceptor): void {
const commands = new Map<string, Command>();
for (const command of statemachine.commands) {
commands.set(command.name, command);
}
checkUnreachedEvents(statemachine: Statemachine, acceptor: ValidationAcceptor): void {
const eventsByName = new Map<string, Event>();

const events = new Map<string, Event>();
for (const event of statemachine.events) {
events.set(event.name, event);
eventsByName.set(event.name, event);
}

for (const { actions, transitions } of statemachine.states) {
for (const { ref } of actions) {
if (ref && commands.has(ref.name)) {
commands.delete(ref.name);
}
}
for (const { transitions } of statemachine.states) {
for (const { event: { ref: refEvent } } of transitions) {
if (refEvent && events.has(refEvent.name)) {
events.delete(refEvent.name);
if (refEvent && eventsByName.has(refEvent.name)) {
eventsByName.delete(refEvent.name);
}
}
}

for (const [name, symbol] of [...commands.entries(), ...events.entries()]) {
accept('warning', `Unused command or event name: ${name}`, {
node: symbol,
for (const [name, event] of eventsByName.entries()) {
acceptor('warning', `Unreached event: ${name}`, {
node: event,
property: 'name',
data: diagnosticData(IssueCodes.UnusedSymbol),
data: diagnosticData(IssueCodes.UnreachedEvent),
tags: [1],
});
}
}

private removeStates(states: Map<string, State>, transitions: Transition[]): void {
for (const { state: { ref } } of transitions) {
if (ref && states.has(ref.name)) {
states.delete(ref.name);
this.removeStates(states, ref.transitions);
}
}
}
}

0 comments on commit 45a1875

Please sign in to comment.