UNPKG

9.77 kBJavaScriptView Raw
1'use strict';
2
3const debug = require('debug')('fun:common');
4
5const _ = require('lodash');
6const { green, red } = require('colors');
7
8const { promptForFunctionSelection } = require('./init/prompt');
9
10const SERVICE_RESOURCE = 'Aliyun::Serverless::Service';
11const FUNCTION_RESOURCE = 'Aliyun::Serverless::Function';
12
13/* eslint-disable */
14function iterateResources(resources, resType, callback) {
15 for (const [name, res] of Object.entries(resources)) {
16 if (res.Type === resType) {
17 callback(name, res);
18 }
19 }
20}
21/* eslint-enable */
22
23function findServices(resources) {
24 const services = [];
25
26 iterateResources(resources, SERVICE_RESOURCE, (serviceName, serviceRes) => {
27 services.push({
28 serviceName,
29 serviceRes
30 });
31 });
32
33 return services;
34}
35
36
37function iterateFunctions(tplContent, callback) {
38 if (tplContent.Resources) {
39 const resources = tplContent.Resources;
40
41 iterateResources(resources, SERVICE_RESOURCE, (serviceName, serviceRes) => {
42 iterateResources(serviceRes, FUNCTION_RESOURCE, (functionName, functionRes) => {
43 callback(
44 serviceName,
45 serviceRes,
46 functionName,
47 functionRes
48 );
49 });
50 });
51 }
52}
53
54function findFunctions(serviceRes) {
55
56 const functions = [];
57
58 iterateResources(serviceRes, FUNCTION_RESOURCE, (functionName, functionRes) => {
59 functions.push({
60 functionName,
61 functionRes
62 });
63 });
64
65 return functions;
66}
67
68function findHttpTriggersInFunction(functionRes) {
69 const triggers = [];
70
71 if (functionRes.Events) {
72 iterateResources(functionRes.Events, 'HTTP', (triggerName, triggerRes) => {
73 triggers.push({
74 triggerName,
75 triggerRes
76 });
77 });
78 }
79
80 return triggers;
81}
82
83function findFunctionByServiceAndFunctionName(resources, serviceName, functionName) {
84 debug('begin search serviceName and functionName');
85
86 let serviceRes = resources[serviceName];
87
88 if (!serviceRes || !serviceName || serviceRes.Type !== SERVICE_RESOURCE) {
89
90 throw new Error(`could not found service: ${serviceName}`);
91 }
92
93 let functionRes = serviceRes[functionName];
94
95 if (functionRes && functionRes.Type !== FUNCTION_RESOURCE) {
96 functionRes = null;
97 }
98
99 return {
100 serviceName,
101 serviceRes,
102 functionName,
103 functionRes
104 };
105}
106
107function findFunctionInService(funcName, serviceRes) {
108
109 debug('find function ' + funcName + ' definition in service: ' + JSON.stringify(serviceRes));
110
111 for (let { functionName, functionRes } of findFunctions(serviceRes)) {
112 debug(`functionName is ${functionName}, compare with ${functionName}`);
113 if (functionName === funcName) {
114 debug(`found function ${functionName}, functionRes is ${functionRes}`);
115
116 return functionRes;
117 }
118 }
119
120 return null;
121}
122
123function findFunctionByFunctionName(resources, functionName) {
124 // iterator all services and functions
125 for (let { serviceName, serviceRes } of findServices(resources)) {
126 debug('servicename: ' + serviceName);
127 const functionRes = findFunctionInService(functionName, serviceRes);
128
129 if (functionRes) {
130 return {
131 serviceName,
132 serviceRes,
133 functionName,
134 functionRes
135 };
136 }
137 }
138
139 return {};
140}
141
142function parseFunctionPath(funcPath) {
143 let serviceName = null;
144 let functionName = null;
145
146 if (!funcPath) { return []; }
147
148 const index = funcPath.indexOf('/');
149
150 if (index < 0) {
151 functionName = funcPath;
152 } else {
153 serviceName = funcPath.substring(0, index);
154 functionName = funcPath.substring(index + 1);
155 }
156
157 debug(`invoke service: ${serviceName}`);
158
159 debug(`invoke function: ${functionName}`);
160
161 return [serviceName, functionName];
162}
163
164/**
165 * funcPath : functionName or serviceName/functionName
166 */
167function findFunctionInTpl(funcPath, tpl) {
168 const [serviceName, functionName] = parseFunctionPath(funcPath);
169 return doFindFunctionInTpl(serviceName, functionName, tpl);
170}
171
172// return first if only provide functionName
173function doFindFunctionInTpl(serviceName, functionName, tpl) {
174
175 const resources = tpl.Resources;
176
177 if (serviceName) {
178 // invokeName is serviceName/functionName
179 return findFunctionByServiceAndFunctionName(resources, serviceName, functionName);
180 }
181 // invokeName is functionName
182 return findFunctionByFunctionName(resources, functionName);
183}
184
185function findFunctionsInTpl(tpl, filter) {
186 const functions = [];
187
188 const resources = tpl.Resources;
189
190 for (let { serviceName, serviceRes } of findServices(resources)) {
191 for (let { functionName, functionRes } of findFunctions(serviceRes)) {
192
193 if (filter && !filter(functionName, functionRes)) { continue; }
194
195 functions.push({
196 serviceName,
197 serviceRes,
198 functionName,
199 functionRes
200 });
201 }
202 }
203
204 return functions;
205}
206
207function findNasConfigInService(serviceRes) {
208 if (!serviceRes) { return null; }
209
210 const serviceProps = serviceRes.Properties;
211
212 if (!serviceProps) { return null; }
213
214 return serviceProps.NasConfig;
215}
216
217function findHttpTriggersInTpl(tpl) {
218 const resources = tpl.Resources;
219
220 const httpTriggers = [];
221
222 for (let { serviceName, serviceRes } of findServices(resources)) {
223 for (let { functionName, functionRes } of findFunctions(serviceRes)) {
224 for (let { triggerName, triggerRes } of findHttpTriggersInFunction(functionRes)) {
225 httpTriggers.push({
226 serviceName,
227 serviceRes,
228 functionName,
229 functionRes,
230 triggerName,
231 triggerRes
232 });
233 }
234 }
235 }
236
237 return httpTriggers;
238}
239
240function findFirstFunctionName(tpl) {
241 const resources = tpl.Resources;
242
243 var firstInvokeName;
244
245 for (let { serviceName, serviceRes } of findServices(resources)) {
246 for (let { functionName } of findFunctions(serviceRes)) {
247 firstInvokeName = serviceName + '/' + functionName;
248 break;
249 }
250 }
251
252 if (!firstInvokeName) {
253 throw new Error(red(`Missing function definition in template.yml`));
254 }
255 return firstInvokeName;
256}
257
258// find the first service in resoueces
259function findServiceByServiceName (resources, name) {
260
261 for (let { serviceName, serviceRes } of findServices(resources)) {
262
263 if (serviceName === name) {
264 return {
265 serviceName,
266 serviceRes
267 };
268 }
269 }
270 return {};
271}
272
273function findAllFunctionsByFunctionName(resources, functionName) {
274
275 let functions = [];
276
277 for (let { serviceName, serviceRes } of findServices(resources)) {
278 debug('servicename: ' + serviceName);
279 const functionRes = findFunctionInService(functionName, serviceRes);
280
281 if (functionRes) {
282
283 functions.push({
284 serviceName,
285 serviceRes,
286 functionName,
287 functionRes
288 });
289 }
290 }
291 return functions;
292}
293
294async function matchingFuntionUnderServiceBySourceName(resources, sourceName) {
295
296 const serviceObj = findServiceByServiceName(resources, sourceName);
297
298 if (!_.isEmpty(serviceObj)) {
299
300 return {
301 serviceName: serviceObj.serviceName,
302 serviceRes: serviceObj.serviceRes
303 };
304 }
305
306 const functions = findAllFunctionsByFunctionName(resources, sourceName);
307
308 if (functions.length === 0) {
309
310 throw new Error(`could not found sourceName: ${sourceName}`);
311
312 } else if (functions.length > 1) {
313
314 const { serviceName, functionName } = await promptForFunctionSelection(functions);
315
316 const selectionFunction = functions.find(funcObj => {
317
318 return funcObj.serviceName === serviceName && funcObj.functionName === functionName;
319 });
320
321 // delete unmatch functions under a serviceRes
322 const serviceRes = deleteUnmatchFunctionsUnderServiceRes(selectionFunction);
323
324 return {
325 serviceName: selectionFunction.serviceName,
326 serviceRes
327 };
328 }
329
330 const serviceName = _.first(functions).serviceName;
331 let serviceRes = _.first(functions).serviceRes;
332
333 serviceRes = deleteUnmatchFunctionsUnderServiceRes({
334 serviceName,
335 serviceRes,
336 functionName: sourceName
337 });
338
339 return {
340 serviceName,
341 serviceRes
342 };
343}
344
345// delete unmatch functions under a serviceRes
346function deleteUnmatchFunctionsUnderServiceRes({
347 serviceName,
348 serviceRes,
349 functionName
350}) {
351
352 const functionNamesInService = findFunctions(serviceRes).map(funRes => {
353 return funRes.functionName;
354 });
355
356 if (!_.includes(functionNamesInService, functionName)) {
357
358 throw new Error(`could not found service/function:` + green(`${serviceName}`) + `/` + red(`${functionName}`));
359 }
360
361 for (let functions of findFunctions(serviceRes)) {
362
363 if (functions.functionName !== functionName) {
364
365 serviceRes = _.omit(serviceRes, functions.functionName);
366 }
367 }
368
369 return serviceRes;
370}
371
372function findServiceByCertainServiceAndFunctionName(resources, certainServiceName, certainFunctionName) {
373
374 for (let { serviceName, serviceRes } of findServices(resources)) {
375
376 if (serviceName === certainServiceName) {
377
378 serviceRes = deleteUnmatchFunctionsUnderServiceRes({
379 serviceName,
380 serviceRes,
381 functionName: certainFunctionName
382 });
383
384 return {
385 serviceName,
386 serviceRes
387 };
388 }
389 }
390
391 throw new Error(`could not found service: ${certainServiceName}`);
392}
393
394function isNasAutoConfig(nasConfig) {
395 if (nasConfig === 'Auto') { return true; }
396 return false;
397}
398
399function isVpcAutoConfig(vpcConfig) {
400 if (vpcConfig === 'Auto') { return true; }
401 return false;
402}
403
404module.exports = {
405 findFunctionInTpl, findHttpTriggersInTpl,
406 findFunctionsInTpl, findNasConfigInService,
407 findHttpTriggersInFunction, findServices,
408 findFunctions, findFirstFunctionName, matchingFuntionUnderServiceBySourceName,
409 findServiceByCertainServiceAndFunctionName, deleteUnmatchFunctionsUnderServiceRes,
410 isNasAutoConfig, isVpcAutoConfig, parseFunctionPath, iterateFunctions
411};
\No newline at end of file