'use strict'; const SError = require('./Error'), SerializerFileSystem = require('./SerializerFileSystem'), BbPromise = require('bluebird'), async = require('async'), path = require('path'), fs = BbPromise.promisifyAll(require('fs')), _ = require('lodash'); let SUtils; class Function extends SerializerFileSystem { constructor(S, data, filePath) { super(S); SUtils = S.utils; this._S = S; this._class = 'Function'; this._config = config || {}; this._filePath = filePath; this.name = data.name || 'function' + SUtils.generateShortId(6); this.setRuntime(data.runtime || 'nodejs'); this.customName = false; this.customRole = false; this.handler = 'handler.handler'; this.timeout = 6; this.memorySize = 1024; this.authorizer = {}; this.custom = { excludePatterns: [], envVars: [] }; this.endpoints = []; this.events = []; this.environment = { SERVERLESS_PROJECT: this.getProject().getName(), SERVERLESS_STAGE: "${stage}", SERVERLESS_REGION: "${region}" }; this.vpc = { securityGroupIds: [], subnetIds: [] }; this.templates = new this._S.classes.Templates(this._S, {}, this.getRootPath('s-templates.json')); if (data) this.fromObject(data); } updateConfig(config) { this._config = _.merge(this._config, config || {}); } load() { return this.deserialize(this); } save(options) { return this.serialize(this, options); } toObject() { return SUtils.exportObject(_.cloneDeep(this)); } toObjectPopulated(options) { options = options || {}; // Validate: Check project path is set if (!this._S.hasProject()) throw new SError('Function could not be populated because no project path has been set on Serverless instance'); // Merge templates let templates = _.merge( this.getProject().getTemplates().toObject(), this.getTemplates().toObject()); // Populate return SUtils.populate(this.getProject(), templates, this.toObject(), options.stage, options.region); } fromObject(data) { // Clear Data this.endpoints = []; this.events = []; if(data.runtime) { this.setRuntime(data.runtime); delete data.runtime; } if (data.endpoints) { for (let i = 0; i < data.endpoints.length; i++) { this.setEndpoint(new this._S.classes.Endpoint(this._S, this, data.endpoints[i])); } delete data.endpoints; } if (data.events) { for (let i = 0; i < data.events.length; i++) { this.setEvent(new this._S.classes.Event(this._S, this, data.events[i])); } delete data.events; } if (data.templates) { this.templates.fromObject(data.templates); delete data.templates; } _.assign(this, data); return this; } setEndpoint(endpoint) { let _this = this, added = false; for (let i = 0; i < _this.endpoints.length; i++){ let e = _this.endpoints[i]; if (!added && e.path == endpoint.path && e.method == endpoint.method) { let instance = new _this._S.classes.Endpoint(_this._S, _this); _this.endpoints[i] = instance.fromObject(endpoint); added = true; } } if (!added) { let instance = new _this._S.classes.Endpoint(_this._S, _this); _this.endpoints.push(instance.fromObject(endpoint)); } } setEvent(event) { let _this = this, added = false; for (let i = 0; i < _this.events.length; i++){ let e = _this.events[i]; if (!added && e.name == event.name) { let instance = new _this._S.classes.Event(_this._S, _this); _this.events[i] = instance.fromObject(event); added = true; } } if (!added) { let instance = new _this._S.classes.Event(_this._S, _this); _this.events.push(instance.fromObject(event)); } } setRuntime( runtimeName ) { let runtime = this._S.getRuntime(runtimeName); if (runtime) { this.runtime = runtimeName; } else { throw new SError( `Runtime ${runtimeName} is not supported!` ); } } /** * Get Deployed Name * - Uses Lambda name or template name * - Stage and Region are required since customName could use variables */ getDeployedName(options) { // Validate: options.state and options.region are required if (!options.stage || !options.region) { throw new SError(`Stage and region options are required`); } // Add function name let name = this.getProject().getName() + '-' + this.name; // If customName, use that if (options.stage && options.region && this.customName) { name = this.toObjectPopulated({ stage: options.stage, region: options.region }).customName; } return name; } getName() { return this.name; } getAllEvents() { return this.events; } getAllEndpoints() { return this.endpoints; } getProject() { return this._S.getProject(); } getTemplates() { return this.templates || {}; } setTemplate(template) { this.templates = template; } getRuntime() { return this._S.getRuntime(this.runtime); } getFilePath() { return this._filePath; } getRootPath() { let args = _.toArray( arguments ); args.unshift(path.dirname(this.getFilePath())); return path.join.apply( path, args ); } static validateName(name) { return /^[a-zA-Z\d]+$/.test(name); } scaffold() { return this.getRuntime().scaffold(this); } run() { return this.getRuntime().run(this); } build(pathDist, stage, region) { return this.getRuntime().build(this, pathDist, stage, region); } } module.exports = Function;