plantuml-server/src/main/webapp/js/language/validation/listeners/start-end-validation.js

104 lines
3.4 KiB
JavaScript

/****************************************
* Language Start-End Validation Feature *
*****************************************/
/**
* Add PlantUML `@start` and `@end` command validation.
*/
PlantUmlLanguageFeatures.prototype.addStartEndValidationListeners = function() {
let diagramType = undefined;
let startCounter = 0;
let endCounter = 0;
// reset validation cache
this.addValidationEventListener("before", () => {
diagramType = undefined;
startCounter = 0;
endCounter = 0;
});
// @start should be the first command
this.addValidationEventListener("code", ({ model, code }) => {
const match = code.match(/^(?:(?:'.*)|\s)*@start(\w+)/);
if (match) {
diagramType = match[1];
return; // diagram code starts with a `@start`
}
return {
message: "PlantUML diagrams should begin with the `@start` command and `@start` should also be the first command.",
severity: monaco.MarkerSeverity.Warning,
startLineNumber: 1,
startColumn: 1,
endLineNumber: 1,
endColumn: model.getLineLength(1) + 1,
};
});
// @end should be the last command and should be of the same type (e.g. @startjson ... @endjson)
this.addValidationEventListener("code", ({ model, code }) => {
const lineCount = model.getLineCount();
const match = code.match(/\s+@end(\w+)(?:(?:'.*)|\s)*$/);
if (match) {
if (diagramType === match[1]) {
return; // diagram code ends with a `@end` of the same type as the `@start`
}
return {
message: "PlantUML diagrams should start and end with the type.\nExample: `@startjson ... @endjson`",
severity: monaco.MarkerSeverity.Error,
startLineNumber: lineCount,
startColumn: 1,
endLineNumber: lineCount,
endColumn: model.getLineLength(lineCount) + 1,
};
}
return {
message: "PlantUML diagrams should end with the `@end` command and `@end` should also be the last command.",
severity: monaco.MarkerSeverity.Warning,
startLineNumber: lineCount,
startColumn: 1,
endLineNumber: lineCount,
endColumn: model.getLineLength(lineCount) + 1,
};
});
// @start should only be used once
this.addValidationEventListener("line", ({ range, line }) => {
const match = line.match(/^\s*@start(\w+)(?:\s+.*)?$/);
if (!match) return;
startCounter += 1;
if (startCounter > 1) {
const word = "@start" + match[1];
const wordIndex = line.indexOf(word);
return {
message: "Multiple @start commands detected.",
severity: monaco.MarkerSeverity.Warning,
startLineNumber: range.startLineNumber,
startColumn: wordIndex + 1,
endLineNumber: range.endLineNumber,
endColumn: wordIndex + word.length + 1,
};
}
});
// @end should only be used once
this.addValidationEventListener("line", ({ range, line }) => {
const match = line.match(/^\s*@end(\w+)(?:\s+.*)?$/);
if (!match) return;
endCounter += 1;
if (endCounter > 1) {
const word = "@end" + match[1];
const wordIndex = line.indexOf(word);
return {
message: "Multiple @end commands detected.",
severity: monaco.MarkerSeverity.Warning,
startLineNumber: range.startLineNumber,
startColumn: wordIndex + 1,
endLineNumber: range.endLineNumber,
endColumn: wordIndex + word.length + 1,
};
}
});
};