Skip to content

Commit

Permalink
Merge pull request #125 from ditrit/feature/error_management
Browse files Browse the repository at this point in the history
Feature: error management
  • Loading branch information
Zorin95670 authored Aug 1, 2024
2 parents 63b4d53 + 32d0723 commit b005ee3
Show file tree
Hide file tree
Showing 19 changed files with 881 additions and 612 deletions.
7 changes: 7 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Default attributes for metadata.
- Error management.
- I18n management.
- Unknown definition attribute.

### Changed

- Update plugin-core to version 0.26.0.

## [0.10.0] - 2024/07/11

Expand Down
1,084 changes: 499 additions & 585 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"homepage": "https://github.com/ditrit/terrator-plugin#readme",
"dependencies": {
"antlr4": "=4.13.1",
"leto-modelizer-plugin-core": "github:ditrit/leto-modelizer-plugin-core#0.25.0",
"leto-modelizer-plugin-core": "github:ditrit/leto-modelizer-plugin-core#0.26.1",
"nunjucks": "=3.2.4"
},
"devDependencies": {
Expand Down
47 changes: 46 additions & 1 deletion src/models/TerraformComponent.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component } from 'leto-modelizer-plugin-core';
import { Component, ParserLog } from 'leto-modelizer-plugin-core';
import TerraformComponentAttribute from 'src/models/TerraformComponentAttribute';

/**
Expand All @@ -23,6 +23,51 @@ class TerraformComponent extends Component {
getConfigurationKey() {
return `${this.definition.type}.${this.externalId}`;
}

/**
* Set all errors of component.
* @param {ParserLog[]} [logs] - Logs to set, can be null.
* @returns {ParserLog[]} All component logs.
*/
getErrors(logs = []) {
this.validateExternalId(logs);

return super.getErrors(logs);
}

/**
* Set warning if definition is unknown.
* @param {ParserLog[]} [logs] - Logs to set, can be null.
* @returns {ParserLog[]} All component logs.
*/
validateDefinition(logs = []) {
if (this.definition?.isUnknown) {
logs.push(new ParserLog({
componentId: this.id,
severity: ParserLog.SEVERITY_WARNING,
message: 'parser.warning.noComponentDefinition',
}));
}

return logs;
}

/**
* Set logs if external id is null.
* @param {ParserLog[]} [logs] - Logs to set, can be null.
* @returns {ParserLog[]} All component logs.
*/
validateExternalId(logs = []) {
if (this.externalId === null || this.externalId.length === 0) {
logs.push(new ParserLog({
componentId: this.id,
severity: ParserLog.SEVERITY_ERROR,
message: 'terrator-plugin.parser.error.noExternalId',
}));
}

return logs;
}
}

export default TerraformComponent;
7 changes: 7 additions & 0 deletions src/models/TerraformComponentDefinition.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ class TerraformComponentDefinition extends ComponentDefinition {
* @param {object} props - Terraform block properties.
* @param {string} [props.blockType] - Type of Terraform block.
* @param {string} [props.provider] - Related provider of terraform block.
* @param {boolean} [props.isUnknown] - Indicates if definition is isUnknown or not.
* @see ComponentDefinition
*/
constructor(props = {
blockType: null,
provider: null,
isUnknown: false,
}) {
super({
...props,
Expand All @@ -37,6 +39,11 @@ class TerraformComponentDefinition extends ComponentDefinition {
* @type {string}
*/
this.provider = props.provider || null;
/**
* Indicates if definition is isUnknown or not.
* @type {boolean}
*/
this.isUnknown = props.isUnknown || false;
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/models/TerraformConfiguration.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ class TerraformConfiguration extends DefaultConfiguration {
},
defaultFileName: 'new_file.tf',
defaultFileExtension: 'tf',
i18n: {
'en-US': {
parser: {
error: {
noExternalId: 'Id can\'t be null.',
},
},
},
},
});
}
}
Expand Down
33 changes: 33 additions & 0 deletions src/parser/TerraformErrorListener.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import antlr4 from 'antlr4';
import { ParserLog } from 'leto-modelizer-plugin-core';

/**
* Class to manage default error from antlr parser.
*/
class TerraformErrorListener extends antlr4.error.ErrorListener {
/**
* Default constructor.
* @param {object} pluginData - Plugin data with components
* @param {FileInformation} [file] - File information.
*/
constructor(pluginData, file) {
super();
this.pluginData = pluginData;
this.file = file;
}

syntaxError(recognizer, offendingSymbol, line, column, msg) {
this.pluginData.parseLogs.push(new ParserLog({
startLineNumber: line,
startColumn: column + 1,
endLineNumber: line,
endColumn: column + offendingSymbol.stop - offendingSymbol.start + 2,
severity: ParserLog.SEVERITY_ERROR,
path: this.file.path,
message: 'terrator-plugin.parser.error.parsing',
initialErrorMessage: msg,
}));
}
}

export default TerraformErrorListener;
51 changes: 46 additions & 5 deletions src/parser/TerraformListener.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class TerraformListener extends antlr4.tree.ParseTreeListener {
this.ids = new Map();
// We need this idCounter because we can't use pluginData to generate the id.
this.idCounter = 1;
this.componentErrors = [];
}

getUnknownDefinition(type) {
Expand All @@ -35,15 +36,20 @@ class TerraformListener extends antlr4.tree.ParseTreeListener {
icon: 'unknown',
type: type || 'unknown',
blockType: this.currentBlockType,
isUnknown: true,
});
}

addComponent() {
const typeExternalId = `${this.currentComponent.definition.type}.${this.currentComponent.externalId}`;

this.currentComponent.path = this.currentFile.path;
this.currentComponent.id = this.createIdFromTypeExternalId(typeExternalId);
this.pluginData.components.push(this.currentComponent);
this.componentErrors.forEach((error) => {
error.componentId = this.currentComponent.id;
error.path = this.currentFile.path;

this.pluginData.parseLogs.push(error);
});
this.componentErrors = [];
this.currentComponent = null;
this.currentBlockType = null;
this.fieldsTree = [];
Expand All @@ -56,6 +62,15 @@ class TerraformListener extends antlr4.tree.ParseTreeListener {
this.currentVariableField = null;
}

addError(ctx, error) {
error.startLineNumber = ctx.start.line;
error.startColumn = ctx.start.column + 1;
error.endLineNumber = ctx.stop.line;
error.endColumn = ctx.stop.column + ctx.getText().length + 1;

this.componentErrors.push(error);
}

getAttributeDefinition(object, name) {
return object.definition?.definedAttributes.find((def) => def.name === name) || null;
}
Expand Down Expand Up @@ -230,6 +245,9 @@ class TerraformListener extends antlr4.tree.ParseTreeListener {
.find((definition) => definition.blockType === this.currentBlockType
&& definition.type === type) || this.getUnknownDefinition(type);

this.currentComponent.validateDefinition()
.forEach((error) => this.addError(ctx, error));

if (this.currentBlockType === 'provider') {
// special case for provider, we do not have any externalId
// so we will use the `type` as the externalId
Expand All @@ -252,6 +270,11 @@ class TerraformListener extends antlr4.tree.ParseTreeListener {
exitName(ctx) {
if (this.currentComponent) {
this.currentComponent.externalId = getText(ctx);
this.currentComponent.validateExternalId()
.forEach((error) => this.addError(ctx, error));

const typeExternalId = `${this.currentComponent.definition.type}.${this.currentComponent.externalId}`;
this.currentComponent.id = this.createIdFromTypeExternalId(typeExternalId);
} else if (this.currentVariable) {
this.currentVariable.name = getText(ctx);
}
Expand Down Expand Up @@ -307,7 +330,13 @@ class TerraformListener extends antlr4.tree.ParseTreeListener {
});
this.currentVariableField = 'value';
} else {
this.currentField = new TerraformComponentAttribute();
this.currentField = new TerraformComponentAttribute({
name: ctx.identifier().getText(),
});
this.currentField.definition = this.getAttributeDefinition(
this.currentComponent,
this.currentField.name,
);
}
}

Expand Down Expand Up @@ -513,12 +542,24 @@ class TerraformListener extends antlr4.tree.ParseTreeListener {
this.currentVariable.type = listType;
}
}
} else if (this.currentField.type === 'Array') {
return;
}

if (this.currentField.type === 'Array') {
this.currentField.value.push(value);
} else {
this.currentField.value = value;
this.currentField.type = type;
}

this.currentField.validateDefinitionType();
this.currentField.validateType();
this.currentField.validateRequired();
this.currentField.validateRuleMinMax();
this.currentField.validateRuleValues();
this.currentField.validateRuleRegex();
this.currentField.getErrors()
.forEach((error) => this.addError(ctx, error));
}

// Enter a parse tree produced by terraformParser#functioncall.
Expand Down
14 changes: 12 additions & 2 deletions src/parser/TerraformParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
import TerraformListener from 'src/parser/TerraformListener';
import Lexer from 'src/antlr/terraformLexer';
import Parser from 'src/antlr/terraformParser';
import TerraformErrorListener from 'src/parser/TerraformErrorListener';

/**
* Class to parse and retrieve components/links from Terraform files.
Expand Down Expand Up @@ -46,10 +47,11 @@ class TerraformParser extends DefaultParser {
parse(diagram, inputs = [], parentEventId = null) {
this.pluginData.components = [];
this.pluginData.variables = [];
this.pluginData.parseLogs = [];

const listener = new TerraformListener(this.pluginData);
const diagramPath = (!diagram?.path || diagram.path.length === 0) ? '' : `${diagram.path}/`;
const regex = new RegExp(`^${diagramPath}[^/]+\\.tf$`);
const listener = new TerraformListener(this.pluginData);

inputs
.filter(({ path }) => regex.test(path))
Expand Down Expand Up @@ -89,10 +91,18 @@ class TerraformParser extends DefaultParser {
const lexer = new Lexer(stream);
const tokens = new antlr4.CommonTokenStream(lexer);
const parser = new Parser(tokens);
const errorListener = new TerraformErrorListener(this.pluginData, input);

parser.removeErrorListeners();
parser.addErrorListener(errorListener);
parser.buildParseTrees = true;

const tree = parser.file_();
antlr4.tree.ParseTreeWalker.DEFAULT.walk(listener, tree);
this.pluginData.emitEvent({ id, status: 'success' });
this.pluginData.emitEvent({
id,
status: 'success',
});
});
}
}
Expand Down
8 changes: 4 additions & 4 deletions tests/resources/js/linkDefaultMultiple.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {

export default [
new ComponentLink({
source: 'id_3',
target: 'id_1',
source: 'id_1',
target: 'id_2',
definition: new ComponentLinkDefinition({
attributeRef: 'toChild',
sourceRef: 'parent',
Expand All @@ -15,8 +15,8 @@ export default [
}),
}),
new ComponentLink({
source: 'id_3',
target: 'id_2',
source: 'id_1',
target: 'id_3',
definition: new ComponentLinkDefinition({
attributeRef: 'toChild',
sourceRef: 'parent',
Expand Down
4 changes: 2 additions & 2 deletions tests/resources/js/linkDefaultSingle.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {

export default [
new ComponentLink({
source: 'id_2',
target: 'id_1',
source: 'id_1',
target: 'id_2',
definition: new ComponentLinkDefinition({
attributeRef: 'toChild',
sourceRef: 'parent',
Expand Down
8 changes: 4 additions & 4 deletions tests/resources/js/linkReverseMultiple.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {

export default [
new ComponentLink({
source: 'id_3',
target: 'id_1',
source: 'id_1',
target: 'id_2',
isReverse: true,
definition: new ComponentLinkDefinition({
attributeRef: 'fromChild',
Expand All @@ -17,8 +17,8 @@ export default [
}),
}),
new ComponentLink({
source: 'id_3',
target: 'id_2',
source: 'id_1',
target: 'id_3',
isReverse: true,
definition: new ComponentLinkDefinition({
attributeRef: 'fromChild',
Expand Down
4 changes: 2 additions & 2 deletions tests/resources/js/linkReverseSingle.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {

export default [
new ComponentLink({
source: 'id_2',
target: 'id_1',
source: 'id_1',
target: 'id_2',
isReverse: true,
definition: new ComponentLinkDefinition({
attributeRef: 'fromChild',
Expand Down
Loading

0 comments on commit b005ee3

Please sign in to comment.