'use strict'; /** * Serverless State Class */ const SError = require('./ServerlessError'), SUtils = require('./utils/index'), _ = require('lodash'), path = require('path'), fs = require('fs'); class ServerlessState { /** * Constructor */ constructor(Serverless) { this._S = Serverless; this.meta = new this._S.classes.Meta(this._S); this.project = new this._S.classes.Project(this._S); // If project path, load state if (Serverless.config.projectPath) this.load(); } /** * Load * - Load from source (i.e., file system); * - Returns promise */ load() { let _this = this; return _this.project.load() .then(function() { return _this.meta.load(); }); } /** * Save * - Load from source (i.e., file system); */ save() { let _this = this; return _this.project.save({ deep: true }) .then(function() { return _this.meta.save({ deep: true }); }); } /** * Set * - Set data */ set(data) { this.meta = data.meta ? this.meta.set(data.meta) : this.meta; this.project = data.project ? this.project.set(data.project, { deep: true }) : this.project; return this; } /** * Get * - Returns clone of data */ get() { return { meta: this.meta.get(), project: this.project.get() } } /** * Get Populated * - Returns clone of data */ getPopulated(options) { options = options || {}; // Validate: Check Stage & Region if (!options.stage || !options.region) throw new SError('Both "stage" and "region" params are required'); let populatedData = { meta: this.meta.get(), project: {} }; return this.project.getPopulated(options) .then(function(data) { populatedData.project = data; return populatedData; }); } /** * Get Meta * - Returns meta data from state */ getMeta() { return this.meta; } /** * Get Project * - Returns project data from state */ getProject() { return this.project; } /** * Get Resources * - Get project resources */ getResources(options) { options = options || {}; if (options.populate) { return this.getPopulated(options) .then(function(populatedData) { return SUtils.getResources(populatedData.project); }); } else { return Promise.resolve(SUtils.getResources(this.project.get())); } } /** * Get Stages * - Returns array of stages in project */ getStages() { return this.meta.getStages(); } /** * Get Regions (in stage) * - Returns array of regions in a stage */ getRegions(stage) { return this.meta.getRegions(stage); } /** * Get Components * - Returns an array of this state's project component instances * - Options: component * - options.paths is an array of serverless paths like this: ['component', 'component'] */ getComponents(options) { let _this = this, allComponents = [], foundComponents = []; // Get all for (let i = 0; i < Object.keys(_this.project.components).length; i++) { allComponents.push(_this.project.components[Object.keys(_this.project.components)[i]]); } // Return if no options specified if (!options) return allComponents; // If options specified, loop through and find the ones specified for (let i = 0; i < allComponents.length; i++) { let component = allComponents[i]; if (options.component) { if (component._config.component == options.component) { foundComponents.push(component); } continue; } if (options.paths && options.paths.indexOf(component._config.sPath) !== -1) { foundComponents.push(component); continue; } } if (!foundComponents.length) { throw new SError('No components found via the options you provided'); } return foundComponents; } /** * Get Modules * - Returns an array of this state's modules instances * - Options: component, module * - options.paths is an array of serverless paths like this: ['component/moduleOne', 'component/moduleTwo'] */ getModules(options) { let _this = this, allModules = [], foundModules = []; // Get all for (let i = 0; i < Object.keys(_this.project.components).length; i++) { let component = _this.project.components[Object.keys(_this.project.components)[i]]; if (!component.modules) continue; for (let j = 0; j < Object.keys(component.modules).length; j++) { allModules.push(component.modules[Object.keys(component.modules)[j]]); } } // Return if no options specified if (!options) return allModules; // If options specified, loop through and find the ones specified for (let i = 0; i < allModules.length; i++) { let module = allModules[i]; if (options.component && options.module) { if (module._config.component == options.component && module._config.module == options.module) { foundModules.push(module); } continue; } if (options.component) { if (module._config.component == options.component) { foundModules.push(module); } continue; } if (options.paths && options.paths.indexOf(module._config.sPath) !== -1) { foundModules.push(module); continue; } } if (!foundModules.length) { throw new SError('No modules found via the options you provided'); } return foundModules; } /** * Get Functions * - Returns an array of this state's function instances * - Options: paths, component, module, function * - options.paths is an array of Serverless paths like this: ['component/moduleOne/functionOne', 'component/moduleOne/functionOne'] */ getFunctions(options) { let _this = this, allFunctions = [], foundFunctions = []; // Get all for (let i = 0; i < Object.keys(_this.project.components).length; i++) { let component = _this.project.components[Object.keys(_this.project.components)[i]]; if (!component.modules) continue; for (let j = 0; j < Object.keys(component.modules).length; j++) { let module = component.modules[Object.keys(component.modules)[j]]; if (!module.functions) continue; for (let k = 0; k < Object.keys(module.functions).length; k++) { allFunctions.push(module.functions[Object.keys(module.functions)[k]]); } } } // Return if no options specified if (!options) return allFunctions; // If options specified, loop through and find the ones specified for (let i = 0; i < allFunctions.length; i++) { let func = allFunctions[i]; if (options.component && options.module && options.function) { if (func._config.component == options.component && func._config.module == options.module && func.name == options.function) { foundFunctions.push(func); } continue; } if (options.component && options.module) { if (func._config.component == options.component && func._config.module == options.module) { foundFunctions.push(func); } continue; } if (options.component) { if (func._config.component == options.component) { foundFunctions.push(func); } continue; } if (options.paths && options.paths.indexOf(func._config.sPath) !== -1) { foundFunctions.push(func); continue; } } if (!foundFunctions.length) { throw new SError('No functions found via the options you provided'); } return foundFunctions; } /** * Get Endpoints * - Returns an array of this state's function instances * - Options: paths, component, module, function, endpointPath, endpointMethod * - options.paths is an array of Serverless paths like this: ['component/moduleOne/functionOne@moduleOne/functionOne~GET'] */ getEndpoints(options) { let _this = this, allEndpoints = [], foundEndpoints = []; // Get all functions for (let i = 0; i < Object.keys(_this.project.components).length; i++) { let component = _this.project.components[Object.keys(_this.project.components)[i]]; if (!component.modules) continue; for (let j = 0; j < Object.keys(component.modules).length; j++) { let module = component.modules[Object.keys(component.modules)[j]]; if (!module.functions) continue; for (let k = 0; k < Object.keys(module.functions).length; k++) { let func = module.functions[Object.keys(module.functions)[k]]; for (let l = 0; l < func.endpoints.length; l++) { allEndpoints.push(func.endpoints[l]); } } } } // Return if no options specified if (!options) return allEndpoints; // If options specified, loop through functions and find the ones specified for (let i = 0; i < allEndpoints.length; i++) { let endpoint = allEndpoints[i]; if (options.component && options.module && options.function && options.endpointPath && options.endpointMethod) { if (endpoint._config.component == options.component && endpoint._config.module == options.module && endpoint._config.function == options.function && endpoint.path == options.endpointPath && endpoint.method == options.endpointMethod) { foundEndpoints.push(endpoint); } continue; } if (options.component && options.module && options.function && options.endpointPath && !options.endpointMethod) { if (endpoint._config.component == options.component && endpoint._config.module == options.module && endpoint._config.function == options.function && endpoint.path == options.endpointPath) { foundEndpoints.push(endpoint); } continue; } if (options.component && options.module && options.function && options.endpointMethod && !options.endpointPath) { if (endpoint._config.component == options.component && endpoint._config.module == options.module && endpoint._config.function == options.function && endpoint.method == options.endpointMethod) { foundEndpoints.push(endpoint); } continue; } if (options.component && options.module && options.function && !options.endpointPath && !options.endpointMethod) { if (endpoint._config.component == options.component && endpoint._config.module == options.module && endpoint._config.function == options.function) { foundEndpoints.push(endpoint); } continue; } if (options.component && options.module && options.endpointMethod && !options.function && !options.endpointPath) { if (endpoint._config.component == options.component && endpoint._config.module == options.module && endpoint.method == options.endpointMethod) { foundEndpoints.push(endpoint); } continue; } if (options.component && options.module && !options.function && !options.endpointPath && !options.endpointMethod) { if (endpoint._config.component == options.component && endpoint._config.module == options.module) { foundEndpoints.push(endpoint); } continue; } if (options.component && options.endpointMethod && !options.module && !options.function && !options.endpointPath) { if (endpoint._config.component == options.component && endpoint.method == options.endpointMethod) { foundEndpoints.push(endpoint); } continue; } if (options.component && !options.module && !options.function && !options.endpointPath && !options.endpointMethod) { if (endpoint._config.component == options.component) { foundEndpoints.push(endpoint); } continue; } if (options.paths && options.paths.indexOf(endpoint._config.sPath) !== -1) { foundEndpoints.push(endpoint); continue; } } if (!foundEndpoints.length) { throw new SError('No endpoints found via the options you provided'); } return foundEndpoints; } /** * Validate Stage Exists * - Checks to see if a stage exists in your project */ validateStageExists(stage) { return this.meta.validateStageExists(stage); } /** * Validate Region Exists * - Checks to see if a stage exists in your project */ validateRegionExists(stage, region) { return this.meta.validateRegionExists(stage, region); } } module.exports = ServerlessState;