cocos-enhance-kit/engine/gulp/util/inline-prop.js
2022-06-25 00:23:03 +08:00

110 lines
3.8 KiB
JavaScript

// Force inline const enum.
// We don't use terser >= 4.2.1 to do this because it obsoleted `reduce_funcs` option.
//
// Replace:
// /*@__DROP_PURE_EXPORT__*/
// var aa = {
// bb: 0,
// cc: 1,
// };
// const UPPER_CASE = 2;
// console.log(aa.bb, aa.cc, UPPER_CASE);
//
// As:
// /*@__DROP_PURE_EXPORT__*/
// var aa = {
// bb: 0,
// cc: 1,
// };
// const UPPER_CASE = 2;
// console.log(0, 1, 2);
const es = require('event-stream');
const stream = require('stream');
const COMMENT_ANNOTATION = `/*@__DROP_PURE_EXPORT__*/`;
const CONST_OBJ_REG = /^[ \t]*\/\*@__DROP_PURE_EXPORT__\*\/[\w\s]*?\s+([A-Za-z_$][0-9A-Za-z_$]*)\s*=\s*({[\n\s\S]*?})/gm;
const CONST_NUM_REG = /^[ \t]*const[ \t]+([A-Z_$][0-9A-Z_$]*)[ \t]*=[ \t]*(\d{1,2});?$/gm;
function matchAll (str, reg, callback) {
// the easiest matchAll polyfill ; )
if (!reg.global) {
throw new Error('Can not matchAll if the global property is false.');
}
str.replace(reg, function (m) {
callback.apply(null, arguments);
return m;
});
}
exports.inlineEnum = function (filename) {
if (filename.endsWith('.js') || filename.endsWith('.ts')) {
return es.map(function (data, callback) {
var content = data.toString();
if (content.includes(COMMENT_ANNOTATION)) { // fast test
let error = null;
matchAll(content, CONST_OBJ_REG, function (match, obj, body) {
try {
body = Function(`return ${body}`)();
}
catch (e) {
error = new Error(`Failed to inline property "${obj}" in "${filename}", ${e}`);
return;
}
for (const key in body) {
let reg = new RegExp(`\\b${obj}\\.${key}\\b`, 'g');
let replaced = content.replace(reg, body[key]);
if (replaced !== content) {
content = replaced;
console.log(`[inline-prop] '${obj}.${key}' is inlined with ${body[key]}`);
}
}
});
if (error) {
return callback(error);
}
data = new Buffer(content);
}
callback(null, data);
});
}
else {
return stream.PassThrough();
}
};
exports.inlineConst = function (filename) {
if (filename.endsWith('.js') || filename.endsWith('.ts')) {
return es.map(function (data, callback) {
var content = data.toString();
if (content.includes(COMMENT_ANNOTATION)) { // fast test
let error = null;
matchAll(content, CONST_NUM_REG, function (match, name, value) {
let reg = new RegExp(`([{,]\\s*|\\btypeof[ \\t]+)?(\\b${name}\\b)(?![ \\t]*=)`, 'g'); // not support negative lookbehind...
let replaced = content.replace(reg, function (m, g1, g2) {
if (m === g2) {
return value;
}
else {
return m;
}
});
if (replaced !== content) {
content = replaced;
console.log(`[inline-prop] '${name}' is inlined with ${value}`);
}
});
if (error) {
return callback(error);
}
data = new Buffer(content);
}
callback(null, data);
});
}
else {
return stream.PassThrough();
}
};