Skip to content

Commit

Permalink
Merge pull request #99 from ditrit/feature/integrate_external_id
Browse files Browse the repository at this point in the history
Feature: Integrate external
  • Loading branch information
Zorin95670 authored Jan 2, 2024
2 parents 8f2b699 + 2a09bd8 commit 83ead83
Show file tree
Hide file tree
Showing 40 changed files with 1,666 additions and 1,391 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ We use [Semantic Versioning](https://semver.org/spec/v2.0.0.html) as guideline f

Steps to release:
- Create a new branch labeled `release/vX.Y.Z` from the latest `main`.
- Improve the version number in `package.json`, `package-lock.json` and `changelog.md`.
- Increase the version number in `package.json`, `package-lock.json` and `changelog.md`.
- Verify the content of the `changelog.md`.
- Commit the modifications with the label `Release version X.Y.Z`.
- Create a pull request on github for this branch into `main`.
Expand Down
6 changes: 6 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)

## [Unreleased]

### Added

- Handle external id

## [0.7.1] - 2023/10/20

### Changed
Expand Down
2,529 changes: 1,304 additions & 1,225 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,21 @@
"homepage": "https://github.com/ditrit/terrator-plugin#readme",
"dependencies": {
"antlr4": "=4.13.1",
"leto-modelizer-plugin-core": "github:ditrit/leto-modelizer-plugin-core#0.22.0",
"leto-modelizer-plugin-core": "github:ditrit/leto-modelizer-plugin-core#0.23.0",
"nunjucks": "=3.2.4"
},
"devDependencies": {
"@babel/core": "=7.23.2",
"@babel/preset-env": "=7.23.2",
"@babel/core": "=7.23.7",
"@babel/preset-env": "=7.23.7",
"babel-jest": "=29.7.0",
"babel-loader": "=9.1.3",
"better-docs": "=2.7.2",
"eslint": "=8.51.0",
"better-docs": "=2.7.3",
"eslint": "=8.56.0",
"eslint-config-airbnb-base": "=15.0.0",
"eslint-formatter-json-relative": "=0.1.0",
"eslint-plugin-import": "=2.28.1",
"eslint-plugin-jest": "=27.4.2",
"eslint-plugin-jsdoc": "=46.8.2",
"eslint-plugin-import": "=2.29.1",
"eslint-plugin-jest": "=27.6.1",
"eslint-plugin-jsdoc": "=47.0.2",
"eslint-webpack-plugin": "=4.0.1",
"jest": "=29.7.0",
"jest-environment-jsdom": "=29.7.0",
Expand Down
2 changes: 1 addition & 1 deletion public/models/DefaultContainer.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 8 additions & 1 deletion public/models/DefaultModel.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions src/models/TerraformComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ class TerraformComponent extends Component {
createAttribute(props) {
return new TerraformComponentAttribute(props);
}

/**
* Get configuration key of the component.
* Overriden from plugin-core.
* @returns {string} Component's configuration key.
*/
getConfigurationKey() {
return `${this.definition.type}.${this.externalId}`;
}
}

export default TerraformComponent;
19 changes: 17 additions & 2 deletions src/models/TerraformData.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class TerraformData extends DefaultData {

/**
* Expand the attribute name of a link from a string.
* @param {string} value - Value to expand.a
* @param {string} value - Value to expand.
* @param {string} argName - Name of the argument to expand.
* @returns {string} Value of the linked argument.
*/
Expand All @@ -103,7 +103,7 @@ class TerraformData extends DefaultData {
* @returns {string} Component id.
*/
addComponent(definition, diagramPath) {
const id = this.generateComponentId(definition);
const id = this.generateComponentId();
const { defaultFileName } = this.configuration;

this.components.push(new TerraformComponent({
Expand All @@ -115,6 +115,21 @@ class TerraformData extends DefaultData {

return id;
}

/**
* Get component by configuration the key `type.externalId`.
* The configuration file is using a certain type of key for the components, this key is
* used to define their position. So in order to retrieve the component's position from the
* configuration file, we need to know which kind of key is used.
* Overriden from plugin-core.
* @param {string} key - Key to use for finding the component, the key is `type.externalId`.
* @returns {Component} Component or null.
*/
getComponentByConfigurationKey(key) {
const [, type, externalId] = /([^.]*)\.([^.]*)/.exec(key);
return this.components.find((component) => component.definition.type === type
&& component.externalId === externalId);
}
}

export default TerraformData;
82 changes: 59 additions & 23 deletions src/parser/TerraformListener.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@ import TerraformComponent from 'src/models/TerraformComponent';
const getText = (ctx) => ctx.getText().replaceAll('"', '').trim();

class TerraformListener extends antlr4.tree.ParseTreeListener {
constructor(definitions) {
constructor(pluginData) {
super();
this.definitions = definitions;
this.components = [];
this.variables = [];
this.errors = [];
this.pluginData = pluginData;
this.definitions = pluginData.definitions.components;

this.currentComponent = null;
this.currentBlockType = null;
Expand All @@ -23,19 +21,27 @@ class TerraformListener extends antlr4.tree.ParseTreeListener {
this.fieldsTree = [];
this.currentVariable = null;
this.currentVariableField = null;
// Map of ids in order to have for each externalId, the associated id.
// key -> type.externalId, value -> id
this.ids = new Map();
// We need this idCounter because we can't use pluginData to generate the id.
this.idCounter = 1;
}

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

this.currentComponent.path = this.currentFile.path;
this.components.push(this.currentComponent);
this.currentComponent.id = this.createIdFromTypeExternalId(typeExternalId);
this.pluginData.components.push(this.currentComponent);
this.currentComponent = null;
this.currentBlockType = null;
this.fieldsTree = [];
}

addVariable() {
this.currentVariable.path = this.currentFile.path;
this.variables.push(this.currentVariable);
this.pluginData.variables.push(this.currentVariable);
this.currentVariable = null;
this.currentVariableField = null;
}
Expand Down Expand Up @@ -112,7 +118,6 @@ class TerraformListener extends antlr4.tree.ParseTreeListener {

// Exit a parse tree produced by terraformParser#provider.
exitProvider() {
this.currentComponent.id = null;
this.addComponent();
}

Expand Down Expand Up @@ -149,7 +154,6 @@ class TerraformListener extends antlr4.tree.ParseTreeListener {

// Exit a parse tree produced by terraformParser#module.
exitModule() {
this.currentComponent.id = null;
this.addComponent();
}

Expand Down Expand Up @@ -217,6 +221,15 @@ class TerraformListener extends antlr4.tree.ParseTreeListener {
blockType: this.currentBlockType,
type,
});

if (this.currentBlockType === 'provider') {
// special case for provider, we do not have any externalId
// so we will use the `type` as the externalId
const typeExternalId = `${type}.${type}`;

this.currentComponent.externalId = type;
this.currentComponent.id = this.createIdFromTypeExternalId(typeExternalId);
}
}

// Exit a parse tree produced by terraformParser#resourcetype.
Expand All @@ -230,7 +243,7 @@ class TerraformListener extends antlr4.tree.ParseTreeListener {
// Exit a parse tree produced by terraformParser#name.
exitName(ctx) {
if (this.currentComponent) {
this.currentComponent.id = getText(ctx);
this.currentComponent.externalId = getText(ctx);
} else if (this.currentVariable) {
this.currentVariable.name = getText(ctx);
}
Expand Down Expand Up @@ -332,38 +345,62 @@ class TerraformListener extends antlr4.tree.ParseTreeListener {
}

if (this.currentField?.definition?.type === 'Reference') {
const match = /[^.]+\.([^.]+)/.exec(this.currentField.value);
const match = /([^.]+\.[^.]+)/.exec(this.currentField.value);

if (match) {
[, this.currentField.value] = match;
if (Array.isArray(this.currentField.value)) {
this.currentField.value = this.currentField.value.map((v) => {
const matching = /([^.]+\.[^.]+)\.([^.]+)/.exec(v);
// matching[1] is `type.externalId`
return this.createIdFromTypeExternalId(matching[1]);
});
} else {
this.currentField.value = this.createIdFromTypeExternalId(this.currentField.value);
}
}
}

if (this.currentField?.definition?.type === 'Link') {
this.currentField.type = 'Array';

if (Array.isArray(this.currentField.value)) {
this.currentField.value = this.currentField.value.map((v) => {
const match = /[^.]+\.([^.]+)\.([^.]+)/.exec(v);

if (match) {
return match[1];
}

return undefined;
const match = /([^.]+\.[^.]+)\.([^.]+)/.exec(v);
// match[1] is `type.externalId`
return this.createIdFromTypeExternalId(match[1]);
});
}

const match = /[^.]+\.([^.]+)(\.([^.]+))?/.exec(this.currentField.value);
const match = /([^.]+\.[^.]+)(\.([^.]+))?/.exec(this.currentField.value);

if (match) {
this.currentField.value = [match[1]];
this.currentField.value = [this.createIdFromTypeExternalId(match[1])];
}
}

this.currentField = null;
}

/**
* Create the id of a component associated to its typeExternalId.
* The typeExternalId is the unique composition of component's type and externalId.
* The created id will be like `id_X` with `X` an increasing integer and will be unique for each
* component.
* @param {string} typeExternalId - The typeExternalId is the unique concatenation of the
* component's type and externalId and represented as `type.externalId`.
* @returns {string} The id of the component.
*/
createIdFromTypeExternalId(typeExternalId) {
if (this.ids.has(typeExternalId)) {
return this.ids.get(typeExternalId);
}

const id = `id_${this.idCounter}`;
this.idCounter += 1;
this.ids.set(typeExternalId, id);

return id;
}

// Enter a parse tree produced by terraformParser#identifier.
enterIdentifier() {
}
Expand Down Expand Up @@ -409,7 +446,6 @@ class TerraformListener extends antlr4.tree.ParseTreeListener {
if (!this.currentField && !this.isVariable()) {
if (ctx.val()?.identifier()) {
const val = getText(ctx.val());

this.currentField = new TerraformComponentAttribute({
type: 'String',
value: val === 'null' ? null : val,
Expand Down
12 changes: 2 additions & 10 deletions src/parser/TerraformParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ class TerraformParser extends DefaultParser {
*/
parse(diagram, inputs = [], parentEventId = null) {
this.pluginData.components = [];
this.pluginData.variables = [];

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

Expand Down Expand Up @@ -93,15 +94,6 @@ class TerraformParser extends DefaultParser {
antlr4.tree.ParseTreeWalker.DEFAULT.walk(listener, tree);
this.pluginData.emitEvent({ id, status: 'success' });
});

listener.components.forEach((component) => {
if (component.id === null) {
component.id = this.pluginData.generateComponentId(component.definition);
}
this.pluginData.components.push(component);
});
this.pluginData.variables = listener.variables;
this.pluginData.parseErrors = listener.errors;
}
}

Expand Down
1 change: 1 addition & 0 deletions src/render/TerraformRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ class TerraformRenderer extends DefaultRender {
variables: allVariables.filter((v) => v.category === 'variable'),
locals: allVariables.filter((v) => v.category === 'local'),
outputs: allVariables.filter((v) => v.category === 'output'),
getExternalId: (value) => this.pluginData.getComponentById(value)?.externalId,
// This might cause issues with other providers.
isValueReference: (value) => value?.match(/^(data.|var.|local.|module.|aws_|random_)/),
isList: (type) => type?.startsWith('list(') || type?.startsWith('set('),
Expand Down
8 changes: 4 additions & 4 deletions src/render/TerraformTemplate.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const macro = `{% macro displayAttributeValue(attribute, value, level) %}
{% if attribute.isVariable %}{{ value | dump | indent(level * 4, true) }},
{% elif attribute.definition.type == 'Link' %}{{ attribute.definition.linkRef | indent(level * 4, true) }}.{{ value }}.{{attribute.definition.linkAttribute}},
{% elif attribute.definition.type == 'Link' %}{{ attribute.definition.linkRef | indent(level * 4, true) }}.{{ getExternalId(value) }}.{{attribute.definition.linkAttribute}},
{% elif isValueReference(value) %}{{ value | indent(level * 4, true) }},
{% else %}{{ value | dump | indent(level * 4, true) }},
{% endif %}
Expand All @@ -14,7 +14,7 @@ const root = `${macro}{% include "local" ignore missing %}
`;

const block = `{% for _block in components %}
{{ _block.definition.blockType }} {% if ['resource','data'].includes(_block.definition.blockType) %}"{{ _block.definition.type }}" {% endif %}{% if ['provider', 'module'].includes(_block.definition.blockType) %}"{{ _block.definition.type }}"{% else %}"{{ _block.id }}"{% endif %} {
{{ _block.definition.blockType }} {% if ['resource','data'].includes(_block.definition.blockType) %}"{{ _block.definition.type }}" {% endif %}{% if ['provider', 'module'].includes(_block.definition.blockType) %}"{{ _block.definition.type }}"{% else %}"{{ _block.externalId }}"{% endif %} {
{% for attribute in _block.attributes %}{% set level = 1 %}
{% include "attribute" ignore missing %}
{% endfor %}
Expand All @@ -30,14 +30,14 @@ const attribute = `{% if attribute.type == 'Object' %}
{% endfor %}{% set level = level-1 %}
{{ "}" | indent(level * 4, true) }}
{% else %}
{{ attribute.name | indent(level * 4, true) }} = {% if attribute.type == 'Array' %}[
{{ attribute.name | indent(level * 4, true) }} = {% if attribute.type == 'Array' or attribute.type == 'Link' %}[
{% set level = level+1 %}{% for value in attribute.value %}
{% call displayAttributeValue(attribute, value, level) -%}{%- endcall %}
{% endfor %}{% set level = level-1 %}
{{ "]" | indent(level * 4, true) }}
{% else %}
{% if attribute.isVariable %}{{ attribute.value }}
{% elif attribute.definition.type == 'Reference' %}{{ attribute.definition.containerRef }}.{{ attribute.value }}
{% elif attribute.definition.type == 'Reference' %}{{ attribute.definition.containerRef }}.{{ getExternalId(attribute.value) }}
{% elif attribute.type == 'Boolean' or attribute.type == 'Number' or attribute.name == 'user_data' %}{{ attribute.value }}
{% elif attribute.type == 'String' and isValueReference(attribute.value) %}{{ attribute.value }}
{% else %}{{ attribute.value | dump }}
Expand Down
Loading

0 comments on commit 83ead83

Please sign in to comment.