1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | module.exports = function (babel) {
|
8 | var logger = console.log.bind(console);
|
9 | var nodent = require('nodent');
|
10 | var compiler = null;
|
11 | var compilerOpts = {};
|
12 | var shouldIncludeRuntime = false;
|
13 | var defaultEnv = {
|
14 | log:logger,
|
15 | dontInstallRequireHook:true,
|
16 | dontMapStackTraces:true,
|
17 | extension:null
|
18 | };
|
19 |
|
20 | function getRuntime(symbol, fn, opts, compiler) {
|
21 | var runtime = symbol + '=' + fn.toString().replace(/[\s]+/g, ' ') + ';\n';
|
22 | opts.parser.ranges = false;
|
23 | opts.parser.locations = false;
|
24 |
|
25 | var ast = babel.transform(runtime).ast.program.body[0];
|
26 |
|
27 |
|
28 | ast = JSON.parse(JSON.stringify(ast, function replacer(key, value) {
|
29 | return (key === 'start' || key === 'end' ? undefined : value);
|
30 | }));
|
31 | return ast;
|
32 | }
|
33 |
|
34 | return {
|
35 |
|
36 |
|
37 | manipulateOptions: function manipulateOptions(opts, parserOpts) {
|
38 | parserOpts.plugins.push('asyncFunctions');
|
39 | },
|
40 |
|
41 | visitor: {
|
42 | Program: {
|
43 | enter: function(path, state){
|
44 | shouldIncludeRuntime = false;
|
45 | },
|
46 | exit: function (path, state) {
|
47 |
|
48 | if (!shouldIncludeRuntime)
|
49 | return ;
|
50 |
|
51 | state.opts = state.opts || {} ;
|
52 | var envOpts = state.opts.env || {};
|
53 | Object.keys(defaultEnv).forEach(function(k){
|
54 | if (!(k in envOpts))
|
55 | envOpts[k] = defaultEnv[k] ;
|
56 | }) ;
|
57 |
|
58 | compiler = nodent(envOpts);
|
59 | compilerOpts = compiler.parseCompilerOptions('"use nodent-promises";', compiler.log);
|
60 |
|
61 | var defCompilerOpts = state.opts.compiler ;
|
62 | if (state.opts.spec) {
|
63 | defCompilerOpts = {
|
64 | promises:true,
|
65 | wrapAwait:true,
|
66 | noRuntime:true
|
67 | }
|
68 | }
|
69 |
|
70 | if (defCompilerOpts && typeof defCompilerOpts==="object") {
|
71 | Object.keys(defCompilerOpts).forEach(function(k){
|
72 | compilerOpts[k] = defCompilerOpts[k] ;
|
73 | }) ;
|
74 | }
|
75 | compilerOpts.babelTree = true;
|
76 |
|
77 | var pr = { origCode: state.file.code, filename: '', ast: path.node };
|
78 | compiler.asynchronize(pr, undefined, compilerOpts, compiler.log);
|
79 |
|
80 | var runtime ;
|
81 | if (!compilerOpts.noRuntime) {
|
82 | if (compilerOpts.generators) {
|
83 | runtime = getRuntime('Function.prototype.$asyncspawn', Function.prototype.$asyncspawn, compilerOpts, compiler);
|
84 | } else {
|
85 | runtime = getRuntime('Function.prototype.$asyncbind', Function.prototype.$asyncbind, compilerOpts, compiler);
|
86 | }
|
87 |
|
88 | if (state.opts.useRuntimeModule) {
|
89 | state.addImport(state.opts.useRuntimeModule === true ? 'nodent-runtime' : state.opts.useRuntimeModule, 'default');
|
90 | }
|
91 | else if (!state.opts.runtimePattern) {
|
92 | path.unshiftContainer('body', runtime);
|
93 | }
|
94 | else if (state.opts.runtimePattern === 'directive') {
|
95 | var hasRuntime = false;
|
96 | for (var index = 0; index < path.node.directives.length; index++) {
|
97 | if (path.node.directives[index].value.value === 'use runtime-nodent') {
|
98 | if (!hasRuntime) {
|
99 | path.unshiftContainer('body', runtime);
|
100 | hasRuntime = true;
|
101 | }
|
102 | path.node.directives.splice(index, 1);
|
103 | }
|
104 | }
|
105 | }
|
106 | else {
|
107 | var pattern = new RegExp(state.opts.runtimePattern);
|
108 | var parserOpts = state.file.parserOpts;
|
109 |
|
110 |
|
111 | var sourceFileName = parserOpts.filename || parserOpts.sourceFileName;
|
112 | if (sourceFileName.match(pattern)) {
|
113 | path.unshiftContainer('body', runtime);
|
114 | }
|
115 | }
|
116 | }
|
117 | }
|
118 | },
|
119 |
|
120 | AwaitExpression: function Function(path, state) {
|
121 | shouldIncludeRuntime = true;
|
122 | },
|
123 |
|
124 | Function: function Function(path, state) {
|
125 | if (path.node.async) {
|
126 | shouldIncludeRuntime = true;
|
127 | }
|
128 | }
|
129 | }
|
130 | };
|
131 | };
|