-
Notifications
You must be signed in to change notification settings - Fork 2
/
plugin.js
93 lines (83 loc) · 3.56 KB
/
plugin.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import awsAnnotations from "./aws/annotations.js";
import { initConfig, writeConfig, getConfig } from "./utils/serverless.js";
let postFunctions = [];
const buildVisitor = (babel, annotations) => {
const visitor = {};
[...new Set(annotations.filter(a => a.handlers !== undefined).map(a => Object.keys(a.handlers)).flat())].map(visitorMethod => {
visitor[visitorMethod] = (path, state) => {
if (path.node.leadingComments) {
// parse annotations
const parsedAnnotations = parseAnnotations(path.node.leadingComments);
if (parsedAnnotations.length !== 0) {
// process parsed annotations
annotations.filter(a => parsedAnnotations.map(pa => pa.name).includes(a.name) && Object.keys(a.handlers).includes(visitorMethod)).map(annotation => {
// check dependencies
if (annotation.dependsOn && !(parsedAnnotations.filter(a => a.name === annotation.dependsOn)[0])) {
console.warn(`(${state.file.opts.filename}, ${path.node.loc.start.line}:${path.node.loc.start.column}) ${annotation.name} depends on ${annotation.dependsOn}, which is not defined. ${annotation.name} will be skipped.`);
return;
}
// call handler
const parsedAnnotation = parsedAnnotations.filter(a => a.name === annotation.name)[0];
annotation.handlers[visitorMethod](parsedAnnotation, path, state, babel, postFunctions);
});
}
}
}
});
[...new Set(annotations.filter(a => a.genericHandlers !== undefined).map(a => Object.keys(a.genericHandlers)).flat())].map(visitorMethod => {
if (Object.keys(visitor).includes(visitorMethod)) {
console.warn(`Visitor method "${visitorMethod}" has already been declared as an annotation-specific visitor method. Generic handler functions associated with this visitor method will be skipped.`);
} else {
visitor[visitorMethod] = (path, state) => {
annotations.filter(a => a.genericHandlers !== undefined && Object.keys(a.genericHandlers).includes(visitorMethod)).map(annotation => {
annotation.genericHandlers[visitorMethod](path, state, babel, postFunctions);
});
}
}
});
return visitor;
}
const plugin = (babel) => {
initConfig();
const config = getConfig();
let visitor = {}
switch (config.provider.name) {
case "aws":
visitor = buildVisitor(babel, awsAnnotations);
break;
default:
visitor = buildVisitor(babel, awsAnnotations);
break;
}
return {
pre() {
postFunctions = [];
},
visitor,
post(state) {
[...new Set(postFunctions)].map(f => f(state, babel.template, config));
writeConfig();
}
};
}
const parseAnnotations = (comments) => {
const regex = /\@\w+(\(( *\w+ *\= *\S+ *)?(\, *\w+ *\= *\S+ *)*\))?/g
const rawAnnotations = comments.map(comment => comment.value).join(' ').match(regex);
let annotations = [];
if (rawAnnotations !== null) {
rawAnnotations.map(rawAnnotation => {
let params = {};
const name = rawAnnotation.substring(0, rawAnnotation.indexOf('(') !== -1 ? rawAnnotation.indexOf('(') : rawAnnotation.length).toLowerCase();
const rawParams = rawAnnotation.substring(rawAnnotation.indexOf('(') + 1, rawAnnotation.indexOf(')'));
if (rawParams) {
rawParams.split(',').map(rawParam => {
rawParam = rawParam.split('=');
params = { ...params, [rawParam[0].trim().toLowerCase()]: rawParam[1].trim() };
});
}
annotations.push({ name: name, params: params });
});
}
return annotations;
}
export default plugin;