forked from mike-engel/babel-plugin-bucklescript
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
128 lines (97 loc) · 3.29 KB
/
index.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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import { dirname, join, relative, resolve } from "path";
import debugConstructor from "debug";
import { execFileSync, spawn } from "child_process";
import { StringLiteral } from "babel-types";
const debug = debugConstructor("babel-plugin-bucklescript");
const watching =
process.argv.indexOf("-w") + process.argv.indexOf("--watch") >= -1;
const globalPath = process.cwd();
const compileDir = "lib";
const fileRegex = /\.(re|ml)$/;
let bsb;
try {
bsb = require.resolve("bs-platform/lib/bsb.exe");
} catch (_) {
/* istanbul ignore next */
bsb = "bsb";
}
/* istanbul ignore next */
debug(`Spawning bsb ${watching ? "watch " : "make world"}process`);
/* istanbul ignore next */
const watcher = spawn(bsb, watching ? ["-w", "-make-world"] : ["-make-world"]);
/* istanbul ignore next */
process.on("exit", () => {
if (watching) {
/* istanbul ignore next */
debug("Terminating bsb process");
watcher.kill();
}
});
export const isBuckleScriptFile = path => {
/* istanbul ignore next */
debug(`Checking if the file is a bs file: " ${path}"`);
return fileRegex.test(path);
};
export const traverseExpression = (t, arg) => {
/* istanbul ignore next */
debug("Traversing the AST expression");
if (t.isStringLiteral(arg)) {
/* istanbul ignore next */
debug("AST expression is a string");
return arg;
}
return null;
};
export const getModuleType = state => {
debug("Checking configured module type");
return state.opts.module || "js";
};
export const getNewPath = (path, state) => {
debug("Generating new path");
const sourcePath = dirname(state.file.opts.filenameRelative);
const requirePath = resolve(sourcePath, path);
const rootPath = requirePath.replace(globalPath, "");
const newPath = join(globalPath, compileDir, getModuleType(state), rootPath);
return newPath.replace(fileRegex, ".js");
};
export default babel => {
return {
visitor: {
CallExpression(path, state) {
debug("Evaluating call expression");
if (path.node.callee.name !== "require") return;
debug("Call expression is a require call");
const args = path.node.arguments;
/* istanbul ignore next */
if (!args.length) return;
debug("Call expression has at least one argument");
const firstArg = traverseExpression(babel.types, args[0]);
/* istanbul ignore next */
if (!firstArg) return;
debug("Call expression has a valid first argument");
if (!isBuckleScriptFile(firstArg.value)) return;
debug("Path is a bucklescript file");
const newPath = getNewPath(firstArg.value, state);
debug(`Setting new path: "${newPath}"`);
path.replaceWith(
babel.types.callExpression(path.node.callee, [
babel.types.stringLiteral(newPath)
])
);
},
ImportDeclaration(path, state) {
debug("Evaluating import declaration");
if (!isBuckleScriptFile(path.node.source.value)) return;
debug("Path is a bucklescript file");
const newPath = getNewPath(path.node.source.value, state);
debug(`Setting new path: "${newPath}"`);
path.replaceWith(
babel.types.importDeclaration(
path.node.specifiers,
babel.types.stringLiteral(newPath)
)
);
}
}
};
};