Skip to content

Commit

Permalink
Merge branch 'release/v1.0.0-alpha'
Browse files Browse the repository at this point in the history
  • Loading branch information
Kamil Mrzygłód committed Aug 7, 2017
2 parents 28caa53 + 3789c04 commit d68079d
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 56 deletions.
2 changes: 1 addition & 1 deletion app/components/Visualization.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default class Visualization extends Component {
const dependencies = [];
for (let i = 0; i < this.resources.length; i += 1) {
const resource = this.resources[i];
const id = `${resource.type}/${resource.displayName}`;
const id = `${resource.type}${resource.displayName}`;

const dependsOn = resource.dependsOn || [];
for (let y = 0; y < dependsOn.length; y += 1) {
Expand Down
2 changes: 2 additions & 0 deletions app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ ipcRenderer.on('open-file', (event, filename) => {
} catch (e) {
if (e instanceof TypeError) {
store.dispatch(layoutActions.error(e.message));
} else if (e instanceof SyntaxError) {
store.dispatch(layoutActions.error(e.message));
} else {
store.dispatch(layoutActions.error(e));
}
Expand Down
2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ARMata",
"productName": "ARMata",
"version": "v1.0.0-prealpha",
"version": "v1.0.0-alpha",
"description": "ARM templates visualizer & editor",
"main": "./main.prod.js",
"author": {
Expand Down
165 changes: 111 additions & 54 deletions app/parsers/templateParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ export default class TemplateParser {
for (let index = 0; index < parsedTemplate.resources.length; index += 1) {
const resource = parsedTemplate.resources[index];
resource.displayName = TemplateParser.parseResourceName(resource.name, parsedTemplate);
resource.displayName = TemplateParser.parseResourceName(resource.displayName, parsedTemplate);

for (let dependencyIndex = 0;
dependencyIndex < resource.dependsOn.length;
Expand All @@ -126,42 +125,97 @@ export default class TemplateParser {
static parseResourceName(name: string, parsedTemplate: Template): string {
let normalizedName = name;

const variablesRegex = /variables\([a-zA-Z-0-9-_']{0,}\)/g;
const variablesMatches = variablesRegex.exec(name);

if (variablesMatches !== null) {
for (let index = 0; index < variablesMatches.length; index += 1) {
for (let variablesIndex = 0;
variablesIndex < parsedTemplate.variables.length;
variablesIndex += 1) {
// Remember that by default string comparison is case-sensitive
if (parsedTemplate.variables[variablesIndex].id.toUpperCase()
=== variablesMatches[index].toUpperCase()) {
normalizedName = normalizedName.replace(variablesMatches[index],
parsedTemplate.variables[variablesIndex].value);
normalizedName = TemplateParser.parseVariables(normalizedName, parsedTemplate);
normalizedName = TemplateParser.parseParameters(normalizedName, parsedTemplate);
normalizedName = TemplateParser.parseResourceId(normalizedName);
normalizedName = TemplateParser.parseReplace(normalizedName);
normalizedName = TemplateParser.parseConcat(normalizedName);

// Remove whitespaces just for the sake of normalizing names
normalizedName = normalizedName.replace(/\s+/g, '');

// Removed [[ and ]] which have left now
normalizedName = normalizedName.replace(/\[/g, '');
normalizedName = normalizedName.replace(/\]/g, '');

return normalizedName;
}

static parseVariables(name: string, parsedTemplate: Template): string {
let normalizedName = name;
const matches = normalizedName.match(/variables/g);
if (typeof matches !== 'undefined' && matches !== null) {
for (let matchIndex = 0; matchIndex < matches.length; matchIndex += 1) {
const variablesRegex = /variables\([a-zA-Z0-9-_']{0,}\)/g;
const variablesMatches = variablesRegex.exec(normalizedName);

if (variablesMatches !== null) {
for (let index = 0; index < variablesMatches.length; index += 1) {
for (let variablesIndex = 0;
variablesIndex < parsedTemplate.variables.length;
variablesIndex += 1) {
// Remember that by default string comparison is case-sensitive
if (parsedTemplate.variables[variablesIndex].id.toUpperCase()
=== variablesMatches[index].toUpperCase()) {
normalizedName = normalizedName.replace(variablesMatches[index],
parsedTemplate.variables[variablesIndex].value);
}
}
}
}
}
}

const parametersRegex = /parameters\('[a-zA-Z0-0-9-_]{0,}'\)/g;
const parametersMatches = parametersRegex.exec(normalizedName);

if (parametersMatches !== null) {
for (let index = 0; index < parametersMatches.length; index += 1) {
for (let parametersIndex = 0;
parametersIndex < parsedTemplate.parameters.length;
parametersIndex += 1) {
if (parsedTemplate.parameters[parametersIndex].id === parametersMatches[index]) {
const nameToDisplay =
parsedTemplate.parameters[parametersIndex].defaultValue ||
parsedTemplate.parameters[parametersIndex].name;
normalizedName = normalizedName.replace(parametersMatches[index], nameToDisplay);
return normalizedName;
}

static parseParameters(name: string, parsedTemplate: Template): string {
let normalizedName = name;
const matches = normalizedName.match(/parameters/g);
if (typeof matches !== 'undefined' && matches !== null) {
for (let matchIndex = 0; matchIndex < matches.length; matchIndex += 1) {
const parametersRegex = /parameters\(['a-zA-Z0-0-9\-_]{0,}\)/g;
const parametersMatches = parametersRegex.exec(normalizedName);

if (parametersMatches !== null) {
for (let index = 0; index < parametersMatches.length; index += 1) {
for (let parametersIndex = 0;
parametersIndex < parsedTemplate.parameters.length;
parametersIndex += 1) {
if (parsedTemplate.parameters[parametersIndex].id === parametersMatches[index]) {
const nameToDisplay =
parsedTemplate.parameters[parametersIndex].defaultValue ||
parsedTemplate.parameters[parametersIndex].name;
normalizedName = normalizedName.replace(parametersMatches[index], nameToDisplay);
}
}
}
}
}
}

return normalizedName;
}

static parseResourceId(name: string): string {
let normalizedName = name;
// TODO: Instead of replacing 'resourceId' to 'concat' it should
// extract logic responsible for concatening and call it here by
// adding '/' to the end of the string
const resourceIdRegex = /resourceId\(['a-zA-Z0-9-._, ()/[\]]{0,}\)/g;
const resourceIdMatches = resourceIdRegex.exec(normalizedName);

if (resourceIdMatches !== null) {
for (let index = 0; index < resourceIdMatches.length; index += 1) {
normalizedName = normalizedName.replace('resourceId', 'concat');
}
}

return normalizedName;
}

static parseReplace(name: string): string {
let normalizedName = name;
const replaceRegex = /replace\([a-zA-Z0-9\-, ']{0,}\)/g;
const replaceMatches = replaceRegex.exec(normalizedName);

Expand All @@ -179,38 +233,41 @@ export default class TemplateParser {
}
}

const concatRegex = /concat\([a-zA-Z0-9\-_,. '[\]()]{0,}\)/g;
const concatMatches = concatRegex.exec(normalizedName);

if (concatMatches !== null) {
for (let index = 0; index < concatMatches.length; index += 1) {
let concatMatch = concatMatches[index];

concatMatch = concatMatch.replace('concat(', '');
concatMatch = concatMatch.replace(')', '');
concatMatch = concatMatch.replace(/'/g, '');
return normalizedName;
}

const concatArgs = concatMatch.split(',');
const evalConcat = (values) => {
let concated = '';
for (let concatIndex = 0; concatIndex < values.length; concatIndex += 1) {
concated = concated.concat(values[concatIndex]);
static parseConcat(name: string): string {
let normalizedName = name;
const matches = normalizedName.match(/concat/g);
if (typeof matches !== 'undefined' && matches !== null) {
for (let matchIndex = 0; matchIndex < matches.length; matchIndex += 1) {
const concatRegex = /concat\([a-zA-Z0-9\-_,./ '[\]()]{0,}\)/g;
const concatMatches = concatRegex.exec(normalizedName);

if (concatMatches !== null) {
for (let index = 0; index < concatMatches.length; index += 1) {
let concatMatch = concatMatches[index];

concatMatch = concatMatch.replace('concat(', '');
concatMatch = concatMatch.replace(')', '');
concatMatch = concatMatch.replace(/'/g, '');

const concatArgs = concatMatch.split(',');
const evalConcat = (values) => {
let concated = '';
for (let concatIndex = 0; concatIndex < values.length; concatIndex += 1) {
concated = concated.concat(values[concatIndex]);
}

return concated;
};
const concatedValue = evalConcat(concatArgs);
normalizedName = normalizedName.replace(concatMatches[index], concatedValue);
}

return concated;
};
const concatedValue = evalConcat(concatArgs);
normalizedName = normalizedName.replace(concatMatches[index], concatedValue);
}
}
}

// Remove whitespaces just for the sake or normalizing names
normalizedName = normalizedName.replace(/\s+/g, '');

// Removed [[ and ]] which have left now
normalizedName = normalizedName.replace(/\[/g, '');
normalizedName = normalizedName.replace(/\]/g, '');

return normalizedName;
}
}
103 changes: 103 additions & 0 deletions test/parsers/templateParser.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,108 @@ describe('parsers', () => {
expect(result.resources[0].dependsOn[1].name).toBe('nic-2');
expect(result.resources[0].dependsOn[2].name).toBe('diagssome_unique_string');
});

it('should handle resourceId in resource name', () => {
const json = {
$schema: 'some_schema',
contentVersion: '1.0.0.0',
resources: [
{
name: '[variables(\'virtualMachineName\')]',
dependsOn: [
'[resourceId(\'Microsoft.Web/sites\', variables(\'webappName\'))]'
]
}
],
parameters: {
'ifttt-prefix': {
type: 'string'
}
},
variables: {
webAppName: '[concat(parameters(\'ifttt-prefix\'), \'-webapp-api\')]'
}
};
const tp = new TemplateParser(json);

const result = tp.parseTemplate();
TemplateParser.normalizeNames(result);

expect(result.schema).toBe('some_schema');
expect(result.contentVersion).toBe('1.0.0.0');
expect(result.resources[0].dependsOn[0].name).toBe('Microsoft.Web/sitesifttt-prefix-webapp-api');
});

it('should connect resource and dependency', () => {
const json = {
$schema: 'some_schema',
contentVersion: '1.0.0.0',
resources: [
{
name: '[variables(\'functionAppName\')]',
dependsOn: [
'[resourceId(\'Microsoft.Web/serverfarms\', parameters(\'liczniknetFunctionAppServicePlanName\'))]'
]
},
{
name: '[parameters(\'liczniknetFunctionAppServicePlanName\')]'
}
],
parameters: {
liczniknetReleaseType: {
type: 'string'
},
liczniknetFunctionAppName: {
type: 'string'
},
liczniknetFunctionAppServicePlanName: {
type: 'string'
}
},
variables: {
webAppName: '[concat(parameters(\'liczniknetFunctionAppName\'), \'-\', parameters(\'liczniknetReleaseType\'))]'
}
};
const tp = new TemplateParser(json);

const result = tp.parseTemplate();
TemplateParser.normalizeNames(result);

expect(result.schema).toBe('some_schema');
expect(result.contentVersion).toBe('1.0.0.0');
expect(result.resources[0].dependsOn[0].name).toBe('Microsoft.Web/serverfarmsliczniknetFunctionAppServicePlanName');
expect(result.resources[1].displayName).toBe('liczniknetFunctionAppServicePlanName');
});

it('should resolve concated variables correctly in name', () => {
const json = {
$schema: 'some_schema',
contentVersion: '1.0.0.0',
resources: [
{
name: '[concat(variables(\'ifttt-trafficmanagerName\'), \'/\', variables(\'webappName\'))]',
dependsOn: [
]
}
],
parameters: {
'ifttt-prefix': {
type: 'string'
}
},
variables: {
'ifttt-trafficmanagerName': '[concat(parameters(\'ifttt-prefix\'), \'-trafficmanager\')]',
webappName: '[concat(parameters(\'ifttt-prefix\'), \'-webapp-api\')]'
}
};
const tp = new TemplateParser(json);

const result = tp.parseTemplate();
TemplateParser.normalizeNames(result);

expect(result.schema).toBe('some_schema');
expect(result.contentVersion).toBe('1.0.0.0');
expect(result.resources[0].displayName).toBe('ifttt-prefix-trafficmanager/ifttt-prefix-webapp-api');
});
});
});

0 comments on commit d68079d

Please sign in to comment.