Skip to content

Commit 4b1d83d

Browse files
authored
Sanitize JS code to avoid Babel helpers (#142)
1 parent 516ff8e commit 4b1d83d

File tree

2 files changed

+113
-3
lines changed

2 files changed

+113
-3
lines changed

tools/builder/prepare-gh-pages.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ const execute = utils.promisify(exec);
77
const archiver = require("archiver");
88
const fg = require('fast-glob');
99

10+
const sanitize = require("./sanitze");
11+
1012
const cwd = process.cwd();
1113

1214
function zipDirectory(sourceDir, outPath) {
@@ -127,9 +129,7 @@ function zipDirectory(sourceDir, outPath) {
127129
mkdirSync(dirname(targetJS), { recursive: true });
128130
// rewrite content of the JS file
129131
let content = readFileSync(sourceJS, { encoding: "utf8" });
130-
content = content.replaceAll(/\/\*\*.*[\n\s]+\* @namespace.*[\n\s]+\*\/[\n\s]+/g, "");
131-
content = content.replaceAll(/\/\*\*.*[\n\s]+\* @name.*[\n\s]+\*\/[\n\s]+/g, "");
132-
content = content.replaceAll(/\/\/# sourceMappingURL=.*[\n\s]+/g, "");
132+
content = sanitize(content);
133133
writeFileSync(targetJS, content, { encoding: "utf8" });
134134
} else {
135135
console.error("No JS file found for", source);

tools/builder/sanitze.js

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
const removeFunction = function removeFunction(code, functionName) {
2+
if (!code || !functionName) {
3+
return code;
4+
}
5+
6+
// match the function start
7+
const fnStartRegex = new RegExp(
8+
`^[ \t\f\v]*function\\s+${functionName}\\s*\\([^)]*\\)\\s*\\{`,
9+
"gm"
10+
);
11+
12+
// find the closing brace for the function and remove the function
13+
let match;
14+
while ((match = fnStartRegex.exec(code)) !== null) {
15+
let startIndex = match.index;
16+
let braceIndex = code.indexOf("{", match.index);
17+
let depth = 0;
18+
let i = braceIndex;
19+
for (; i < code.length; i++) {
20+
if (code[i] === "{") {
21+
depth++;
22+
} else if (code[i] === "}") {
23+
depth--;
24+
}
25+
if (depth === 0) {
26+
// found the matching }
27+
break;
28+
}
29+
}
30+
if (depth === 0 && i > braceIndex) {
31+
// also include trailing whitespace / newlines after function
32+
let endIndex = i + 1;
33+
while (endIndex < code.length && /\n/.test(code[endIndex])) {
34+
endIndex++;
35+
}
36+
code = code.slice(0, startIndex) + code.slice(endIndex);
37+
fnStartRegex.lastIndex = startIndex;
38+
}
39+
}
40+
41+
return code;
42+
}
43+
44+
/**
45+
* the code sanitization function is used to remove the _interopRequireDefault function
46+
* and replace the parameters in the sap.ui.define function with the variables that were
47+
* assigned using _interopRequireDefault.
48+
* It also removes the __ui5_require_async function and replaces it with sap.ui.require.
49+
* @param {string} code the code to sanitize
50+
* @returns sanitized code
51+
*/
52+
module.exports = function sanitze(code = "") {
53+
54+
// remove all comments related to UI5 TypeScript generation (namespaces, names)
55+
code = code.replaceAll(/\/\*\*.*[\n\s]+\* @namespace.*[\n\s]+\*\/[\n\s]+/g, "");
56+
code = code.replaceAll(/\/\*\*.*[\n\s]+\* @name.*[\n\s]+\*\/[\n\s]+/g, "");
57+
58+
// remove all comments related to source maps
59+
code = code.replaceAll(/\/\/# sourceMappingURL=.*[\n\s]+/g, "");
60+
61+
// remove _interopRequireDefault function
62+
code = removeFunction(code, "_interopRequireDefault");
63+
64+
// find which variables are assigned using _interopRequireDefault
65+
let matchedVars;
66+
code = code.replace(/^(\s*)(?:var|const|let)\s+(\w+)\s*=\s*_interopRequireDefault\((\w+)\);\s*(.*)\n/gm, (all, spacing, varName, requiredVarName, comment) => {
67+
matchedVars ??= {};
68+
matchedVars[requiredVarName] = varName;
69+
return comment?.trim() ? `${spacing}${comment}\n` : "";
70+
});
71+
72+
// selectively rename only these parameters
73+
if (matchedVars) {
74+
code = code.replace(
75+
/sap\.ui\.define\(\s*(\[[^\]]*\])\s*,\s*function\s*\(([^)]*)\)/g,
76+
(all, deps, params) => {
77+
const newParams = params
78+
.split(",")
79+
.map((param) => {
80+
return matchedVars[param.trim()] || param.trim();
81+
})
82+
.join(", ");
83+
return `sap.ui.define(${deps}, function (${newParams})`;
84+
}
85+
);
86+
}
87+
88+
// remove the __ui5_require_async function
89+
code = removeFunction(code, "__ui5_require_async");
90+
91+
// replace __ui5_require_async calls with sap.ui.require
92+
code = code.replace(
93+
/__ui5_require_async\s*\(\s*("[^"]+")\s*\);/g,
94+
"sap.ui.require([$1]);"
95+
);
96+
97+
// replace the class member function classic syntax with the shorthand syntax
98+
code = code.replace(/(\w+)\s*:\s*function\s+\w+\s*\(/g, '$1(');
99+
100+
// replace the async class member function classic syntax with the shorthand syntax
101+
code = code.replace(/(\w+)\s*:\s*async\s+function\s+\w+\s*\(/g, 'async $1(');
102+
103+
// remove the __exports variable and return the exports directly
104+
code = code.replace(/(?:var|const|let)\s+__exports\s*=\s*({[\s\S]*?});\s*return\s+__exports\s*;/g, 'return $1;');
105+
106+
// remove empty lines
107+
code = code.replace(/^\s*;\s*\n/gm, "");
108+
109+
return code;
110+
};

0 commit comments

Comments
 (0)