-
-
Notifications
You must be signed in to change notification settings - Fork 65
Expand file tree
/
Copy pathcolocated-babel-plugin.js
More file actions
100 lines (91 loc) · 3.51 KB
/
colocated-babel-plugin.js
File metadata and controls
100 lines (91 loc) · 3.51 KB
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
// For ease of debuggin / tweaking:
// https://astexplorer.net/#/gist/bcca584efdab6c981a75618642c76a22/1e1d262eaeb47b7da66150e0781a02b96e597b25
module.exports = function (babel) {
let t = babel.types;
function makeSetComponentTemplateMemberExpression() {
return t.memberExpression(t.identifier('Ember'), t.identifier('_setComponentTemplate'));
}
function makeColocatedTemplateIdentifier() {
return t.identifier('__COLOCATED_TEMPLATE__');
}
return {
name: 'ember-cli-htmlbars-colocation-template',
visitor: {
VariableDeclarator(path, state) {
if (path.node.id.name === '__COLOCATED_TEMPLATE__') {
state.colocatedTemplateFound = true;
}
},
ExportDefaultDeclaration(path, state) {
if (state.colocatedTemplateFound !== true || state.setComponentTemplateInjected === true) {
let colocatedFlagIndex = path.parent.body.findIndex((node) => {
if (node.type === 'VariableDeclaration') {
if (
node.declarations.findIndex((declaration) => {
if (declaration.id.name === '__COLOCATED_TEMPLATE__') return true;
return false;
}) >= 0
)
return true;
return false;
}
});
if (colocatedFlagIndex < 0) return;
}
state.setComponentTemplateInjected = true;
let defaultExportDeclaration = path.node.declaration;
let setComponentTemplateMemberExpression = makeSetComponentTemplateMemberExpression();
let colocatedTemplateIdentifier = makeColocatedTemplateIdentifier();
if (defaultExportDeclaration.type === 'ClassDeclaration') {
// when the default export is a ClassDeclaration with an `id`,
// wrapping it in a CallExpression would remove that class from the
// local scope which would cause issues for folks using the declared
// name _after_ the export
if (defaultExportDeclaration.id !== null) {
path.parent.body.push(
t.expressionStatement(
t.callExpression(setComponentTemplateMemberExpression, [
colocatedTemplateIdentifier,
defaultExportDeclaration.id,
])
)
);
} else {
path.node.declaration = t.callExpression(setComponentTemplateMemberExpression, [
colocatedTemplateIdentifier,
t.classExpression(
null,
defaultExportDeclaration.superClass,
defaultExportDeclaration.body
),
]);
}
} else {
path.node.declaration = t.callExpression(setComponentTemplateMemberExpression, [
colocatedTemplateIdentifier,
defaultExportDeclaration,
]);
}
},
ExportNamedDeclaration(path, state) {
if (state.colocatedTemplateFound !== true || state.setComponentTemplateInjected === true) {
return;
}
let defaultSpecifier = path.node.specifiers.find(
(spec) => spec.exported.name === 'default'
);
if (defaultSpecifier) {
state.setComponentTemplateInjected = true;
path.parent.body.push(
t.expressionStatement(
t.callExpression(makeSetComponentTemplateMemberExpression(), [
makeColocatedTemplateIdentifier(),
defaultSpecifier.local,
])
)
);
}
},
},
};
};