-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathwrapper.js
More file actions
201 lines (177 loc) · 5.93 KB
/
wrapper.js
File metadata and controls
201 lines (177 loc) · 5.93 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
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
import { types as t } from "@babel/core";
import * as eh from "./exports";
import * as th from "../../utils/templates";
import * as ast from "../../utils/ast";
export function wrap(visitor, programNode, opts) {
let {
defaultExport,
exportGlobal,
firstImportMarked,
imports,
namedExports,
ignoredImports,
injectDynamicImportHelper,
} = visitor;
const needsWrap = !!(
defaultExport ||
imports.length ||
namedExports.length ||
injectDynamicImportHelper
);
if (!needsWrap) {
// cleanup the program node if it's empty (just having empty imports)
programNode.body = programNode.body.filter((node) => {
if (t.isExportNamedDeclaration(node)) {
return node.declaration != null;
}
return true;
});
return;
}
let { body } = programNode;
// find the copyright comment from the original program body and remove it there
// since it need to be put around the new program body (which is sap.ui.define)
let copyright = body?.[0]?.leadingComments?.find((comment, idx, arr) => {
if (comment.value.startsWith("!")) {
arr.splice(idx, 1);
return true;
}
});
// in case of TypeScript transpiling taking place upfront, the copyright comment
// is associcated with the program and not the program body, so we need to find it
// and move it to the new program body (which is sap.ui.define)
if (!copyright) {
copyright = visitor.parent?.comments?.find((comment, idx, arr) => {
if (comment.value.startsWith("!")) {
arr.splice(idx, 1);
return true;
}
});
}
let allExportHelperAdded = false;
let extendAdded = false;
opts.collapse = !opts.noExportCollapse;
// opts.extend = !opts.noExportExtend
// Before adding anything, see if the named exports can be collapsed into the default export.
if (defaultExport && namedExports.length && opts.collapse) {
let { filteredExports, conflictingExports, newDefaultExportIdentifier } =
eh.collapseNamedExports(programNode, defaultExport, namedExports, opts);
if (filteredExports.length && !opts.allowUnsafeMixedExports) {
throw new Error(
`Unsafe mixing of conflicting default and named exports. The following named exports are conflicting: (${ast
.getPropNames(conflictingExports)
.join(", ")}).`
);
} else {
namedExports = filteredExports;
}
// The default export may have changed if the collapse logic needed to assign a prop when the default export was previously anonymous.
if (newDefaultExportIdentifier) {
extendAdded = true; // If an anonymous default export needed to be assigned to a a variable, it uses the exports name for convenience.
defaultExport = newDefaultExportIdentifier;
}
}
const preDefine = [...ignoredImports];
// If the noWrapBeforeImport opt is set, split any code before the first import and afterwards into separate arrays.
// This should be done before any interops or other vars are injected.
if (opts.noWrapBeforeImport && firstImportMarked) {
let reachedFirstImport = false;
const fullBody = body;
const newBody = [];
for (const item of fullBody) {
if (reachedFirstImport) {
newBody.push(item);
} else {
preDefine.push(item);
}
if (item.lastBeforeWrapping) {
reachedFirstImport = true;
}
}
if (
!opts.neverUseStrict &&
preDefine.length &&
!hasUseStrict(programNode)
) {
programNode.directives = [
t.directive(t.directiveLiteral("use strict")),
...(programNode.directives || []),
];
}
body = newBody;
}
if (injectDynamicImportHelper) {
// import() to sap.ui.require() w/ promise and interop
body.unshift(th.buildDynamicImportHelper());
}
if (!namedExports.length && defaultExport) {
// If there's no named exports, return the default export
body.push(t.returnStatement(defaultExport));
} else if (namedExports.length) {
if (!extendAdded) {
body.push(th.buildDeclareExports()); // i.e. const __exports = {__esModule: true};
}
for (const namedExport of namedExports) {
if (namedExport.all) {
if (!allExportHelperAdded) {
body.push(th.buildAllExportHelper());
allExportHelperAdded = true;
}
body.push(
th.buildAllExport({
LOCAL: namedExport.value,
})
);
} else {
body.push(th.buildNamedExport(namedExport));
}
}
if (defaultExport) {
body.push(
th.buildNamedExport({
key: t.identifier("default"),
value: defaultExport,
})
);
}
body.push(th.buildReturnExports());
}
if (imports.some((imp) => imp.interop)) {
body.unshift(th.buildDefaultImportInterop());
}
const define = generateDefine(
body,
imports,
exportGlobal || opts.exportAllGlobal,
hasUseStrict(programNode)
);
// add the "use strict" directive if not on program node
if (!opts.neverUseStrict && !hasUseStrict(programNode)) {
const defineFnBody = define.expression.arguments[1].body;
defineFnBody.directives = [
t.directive(t.directiveLiteral("use strict")),
...(defineFnBody.directives || []),
];
}
programNode.body = [...preDefine, define];
// if a copyright comment is present we append it to the new program node
if (copyright && visitor.parent) {
visitor.parent.leadingComments = visitor.parent.leadingComments || [];
visitor.parent.leadingComments.unshift(copyright);
}
}
function hasUseStrict(node) {
return (node.directives || []).some(
(directive) => directive.value.value === "use strict"
);
}
function generateDefine(body, imports, exportGlobal) {
const defineOpts = {
SOURCES: t.arrayExpression(imports.map((i) => t.stringLiteral(i.src))),
PARAMS: imports.map((i) => t.identifier(i.tmpName)),
BODY: body,
};
return exportGlobal
? th.buildDefineGlobal(defineOpts)
: th.buildDefine(defineOpts);
}