Skip to content
This repository has been archived by the owner on Apr 16, 2022. It is now read-only.

Commit

Permalink
implement Fn::Split
Browse files Browse the repository at this point in the history
  • Loading branch information
Jarrad Whitaker authored and akdor1154 committed Apr 26, 2018
1 parent 1b5c3df commit 2f14472
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 1 deletion.
2 changes: 1 addition & 1 deletion data/aws_intrinsic_functions.json
Expand Up @@ -13,7 +13,7 @@
"Fn::Select": {},
"Fn::Select::Index": {"supportedFunctions": ["Ref", "Fn::FindInMap"]},
"Fn::Select::List": {"supportedFunctions" : ["Fn::FindInMap", "Fn::GetAtt", "Fn::GetAZs", "Fn::If", "Fn::Split", "Ref"] },
"Fn::Split": {},
"Fn::Split": {"supportedFunctions": ["Fn::Base64", "Fn::FindInMap", "Fn::GetAtt", "Fn::If", "Fn::Join", "Fn::Select", "Ref"]},
"Fn::Sub": { "supportedFunctions": ["Fn::Base64", "Fn::FindInMap", "Fn::GetAtt", "Fn::GetAZs", "Fn::If", "Fn::Join", "Fn::Select", "Ref"]},
"Ref": {}
}
91 changes: 91 additions & 0 deletions src/test/validatorTest.ts
Expand Up @@ -526,6 +526,97 @@ describe('validator', () => {

});

describe('Fn::Split', () => {
it('should split a basic string', () => {
const input = {
'Fn::Split': ['-', 'asdf-fdsa']
};
const result = validator.doInstrinsicSplit(input, 'Fn::Split');
expect(result).to.deep.equal(['asdf', 'fdsa']);
});

it('should split a string that doesn\'t contain the delimiter', () => {
const input = {
'Fn::Split': ['-', 'asdffdsa']
};
const result = validator.doInstrinsicSplit(input, 'Fn::Split');
expect(result).to.deep.equal(['asdffdsa']);
});

it('should resolve an intrinsic function', () => {
const input = {
'Fn::Split': ['-', {
'Fn::Select': [1, ['0-0', '1-1', '2-2']]
}]
};
const result = validator.doInstrinsicSplit(input, 'Fn::Split');
expect(result).to.deep.equal(['1', '1']);
});

it('should reject a parameter that is an object', () => {
const input = {
'Fn::Split': {}
};
const result = validator.doInstrinsicSplit(input, 'Fn::Split');
expect(result).to.deep.equal(['INVALID_SPLIT']);
});

it('should reject a parameter that is a string', () => {
const input = {
'Fn::Split': 'split-me-plz'
};
const result = validator.doInstrinsicSplit(input, 'Fn::Split');
expect(result).to.deep.equal(['INVALID_SPLIT']);
});

it('should reject a parameter that is an empty array', () => {
const input = {
'Fn::Split': []
};
const result = validator.doInstrinsicSplit(input, 'Fn::Split');
expect(result).to.deep.equal(['INVALID_SPLIT']);
});

it('should reject a parameter that is a single length array', () => {
const input = {
'Fn::Split': ['delim']
};
const result = validator.doInstrinsicSplit(input, 'Fn::Split');
expect(result).to.deep.equal(['INVALID_SPLIT']);
});

it('should reject a delimiter that isn\'t a string', () => {
const input = {
'Fn::Split': [{}, 'asd-asd-asd']
};
const result = validator.doInstrinsicSplit(input, 'Fn::Split');
expect(result).to.deep.equal(['INVALID_SPLIT']);
});

describe('validator test', () => {
let result: validator.ErrorObject;
before(() => {
validator.resetValidator();
const input = './testData/valid/yaml/split.yaml';
result = validator.validateFile(input);
});
it('should have no errors', () => {
console.dir(result['errors']);
expect(result).to.have.deep.property('templateValid', true);
expect(result['errors']['crit']).to.have.lengthOf(0);
});
it('should resolve a simple split', () => {
expect(result['outputs']['Simple']).to.deep.equal(['asdf', 'fdsa']);
});
it('should resolve a split of a join', () => {
expect(result['outputs']['Nested']).to.deep.equal(['asdf', 'fdsa_asdf', 'fdsa']);
});
it('should resolve a select of a split', () => {
expect(result['outputs']['SelectASplit']).to.deep.equal('b');
});
});
})

describe('templateVersion', () => {

it('1 invalid template version should return an object with validTemplate = false, 1 crit errors', () => {
Expand Down
41 changes: 41 additions & 0 deletions src/validator.ts
Expand Up @@ -552,6 +552,8 @@ function resolveIntrinsicFunction(ref: any, key: string) : string | boolean | st
return doIntrinsicImportValue(ref, key);
case 'Fn::Select':
return doIntrinsicSelect(ref, key);
case 'Fn::Split':
return doInstrinsicSplit(ref, key);
default:
addError("warn", `Unhandled Intrinsic Function ${key}, this needs implementing. Some errors might be missed.`, placeInTemplate, "Functions");
return null;
Expand Down Expand Up @@ -1047,8 +1049,47 @@ function doIntrinsicImportValue(ref: any, key: string){
addError('warn', `Something went wrong when resolving references for a Fn::ImportValue`, placeInTemplate, 'Fn::ImportValue');
return 'INVALID_FN_IMPORTVALUE';
}
}

export function doInstrinsicSplit(ref: any, key: string): string[] {
const args = ref[key];

if (!Array.isArray(args) || args.length !== 2) {
addError('crit', 'Invalid parameter for Fn::Split. It needs an Array of length 2.', placeInTemplate, 'Fn::Split');
return ['INVALID_SPLIT'];
}

const delimiter: string = args[0];

if (typeof delimiter !== 'string') {
addError ('crit', `Invalid parameter for Fn::Split. The delimiter, ${util.inspect(delimiter)}, needs to be a string.`, placeInTemplate, 'Fn::Split');
return ['INVALID_SPLIT'];
}

const stringOrInstrinsic = args[1];
let stringToSplit: string;

if (typeof stringOrInstrinsic === 'object') {
const fnName = Object.keys(stringOrInstrinsic)[0];

if (awsIntrinsicFunctions['Fn::Split']['supportedFunctions'].indexOf(fnName) == -1) {
addError('crit', `Fn::Split does not support function '${fnName}' here`, placeInTemplate, 'Fn::Split');
return ['INVALID_SPLIT'];
}

stringToSplit = resolveIntrinsicFunction(stringOrInstrinsic, fnName) as string;
} else if (typeof stringOrInstrinsic === 'string') {
stringToSplit = stringOrInstrinsic;
} else {
addError('crit', `Invalid parameters for Fn::Split. The parameter, ${stringOrInstrinsic}, needs to be a string or a supported intrinsic function.`, placeInTemplate, 'Fn::Split');
return ['INVALID_SPLIT'];
}

return fnSplit(delimiter, stringToSplit);
}

function fnSplit(delimiter: string, stringToSplit: string): string[] {
return stringToSplit.split(delimiter);
}

function fnJoin(join: any, parts: any){
Expand Down
22 changes: 22 additions & 0 deletions testData/valid/yaml/split.yaml
@@ -0,0 +1,22 @@
AWSTemplateFormatVersion: '2010-09-09'

Resources:
WebServerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Desc
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
FromPort: '80'
IpProtocol: tcp
ToPort: '80'

Outputs:
Simple:
Value: !Split ['-', 'asdf-fdsa']
Nested:
Value: !Split ['^', !Join ['_', [asdf^fdsa, asdf^fdsa]]]
SelectASplit:
Value: !Select
- 1,
- !Split ['@', 'a@b@c']

0 comments on commit 2f14472

Please sign in to comment.