diff --git a/docs/providers/aws/guide/variables.md b/docs/providers/aws/guide/variables.md index 813d51e84..c163d6ed3 100644 --- a/docs/providers/aws/guide/variables.md +++ b/docs/providers/aws/guide/variables.md @@ -24,13 +24,17 @@ The Serverless framework provides a powerful variable system which allows you to **Note:** You can only use variables in `serverless.yml` property **values**, not property keys. So you can't use variables to generate dynamic logical IDs in the custom resources section for example. ## Reference Properties In serverless.yml -To self-reference properties in `serverless.yml`, use the `${self:someProperty}` syntax in your `serverless.yml`. This functionality is recursive, so you can go as deep in the object tree as you want. +To self-reference properties in `serverless.yml`, use the `${self:someProperty}` syntax in your `serverless.yml`. `someProperty` can contain the empty string for a top-level self-reference or a dotted attribute reference to any depth of attribute, so you can go as shallow or deep in the object tree as you want. ```yml service: new-service provider: aws custom: globalSchedule: rate(10 minutes) + newService: ${self:} + # the following will resolve identically in other serverless.yml files so long as they define + # `custom.newService: ${file(/serverless.yml)}` + exportName: ${self:custom.newService.service}-export functions: hello: @@ -40,7 +44,13 @@ functions: world: handler: handler.world events: - - schedule: ${self:custom.globalSchedule} + - schedule: ${self:custom.newService.custom.globalSchedule} +resources: + Outputs: + NewServiceExport: + Value: 'A Value To Export' + Export: + Name: ${self:custom.exportName} ``` In the above example you're setting a global schedule for all functions by referencing the `globalSchedule` property in the same `serverless.yml` file. This way, you can easily change the schedule for all functions whenever you like. diff --git a/lib/classes/Variables.js b/lib/classes/Variables.js index 1e95bf03e..617e1218e 100644 --- a/lib/classes/Variables.js +++ b/lib/classes/Variables.js @@ -15,7 +15,7 @@ class Variables { this.fileRefSyntax = RegExp(/^file\(([a-zA-Z0-9._\-/]+?)\)/g); this.envRefSyntax = RegExp(/^env:./g); this.optRefSyntax = RegExp(/^opt:./g); - this.selfRefSyntax = RegExp(/^self:./g); + this.selfRefSyntax = RegExp(/^self:/g); } loadVariableSyntax() { @@ -70,7 +70,10 @@ class Variables { property = this.populateVariable(property, matchedString, valueToPopulate); }); - return this.populateProperty(property); + if (property !== this.service) { + property = this.populateProperty(property); + } + return property; } return property; } @@ -145,7 +148,7 @@ class Variables { } getValueFromSelf(variableString) { - let valueToPopulate = _.cloneDeep(this.service); + let valueToPopulate = this.service; const deepProperties = variableString.split(':')[1].split('.'); valueToPopulate = this.getDeepValue(deepProperties, valueToPopulate); return valueToPopulate; @@ -216,7 +219,7 @@ class Variables { deepProperties.forEach(subProperty => { if (typeof valueToPopulate === 'undefined') { valueToPopulate = {}; - } else { + } else if (subProperty !== '') { valueToPopulate = valueToPopulate[subProperty]; } if (typeof valueToPopulate === 'string' && valueToPopulate.match(this.variableSyntax)) { diff --git a/lib/classes/Variables.test.js b/lib/classes/Variables.test.js index 6d9290082..bbec75173 100644 --- a/lib/classes/Variables.test.js +++ b/lib/classes/Variables.test.js @@ -361,6 +361,19 @@ describe('Variables', () => { const valueToPopulate = serverless.variables.getValueFromSelf('self:provider'); expect(valueToPopulate).to.be.equal('testProvider'); }); + it('should handle self-references to the root of the serverless.yml file', () => { + const serverless = new Serverless(); + serverless.variables.service = { + service: 'testService', + provider: 'testProvider', + defaults: serverless.service.defaults, + }; + + serverless.variables.loadVariableSyntax(); + + const valueToPopulate = serverless.variables.getValueFromSelf('self:').provider; + expect(valueToPopulate).to.be.equal('testProvider'); + }); }); describe('#getValueFromFile()', () => {