trullock / NUglify

NUglify is a HTML, JavaScript and CSS minification Library for .NET (fork of AjaxMin + new features)
Other
395 stars 78 forks source link

Uglify.Js generate a javascript code without the same behavior due to variables conflict #285

Closed miraks31 closed 2 years ago

miraks31 commented 2 years ago

If you launch Uglify.Js (version 1.16.1) on the following code:

document.manualCostingTableRenderer = function (data, type, full, meta) {
    let id = 'aaaa';
    if ((type === 'display' || type === 'filter') && data.length > 0 && data[0] === '=') {
        // This is a formula
        let toeval = document.getResolvedFormular(id, data.substring(1), document.manual_costing_template_info),
            rawVal = '',
            newval = 'TO COMPUTE',
            tooltip = id + data + "=",
            addon = '',
            format = document.manual_costing_template_info.cols_formats[meta.col];
        try {
            if (toeval === '') newval = '';
            else {
                if (type === 'display' && (full[1].toLowerCase() === 'total' || full[0].toLowerCase() === 'total') &&
                    ['COP_WO', 'COP', 'UNIT_SHOULD_PRICE_USD'].indexOf(document.manual_costing_template_info.cols[meta.col]) !== -1) {
                    toeval = document.replaceKeyValuesInFunction(toeval, true, document.tds, document.additional_columns);
                    let simu_f = toeval.split('[').join('[CTX:' + document.thisItem.getProperty('_context', '') + ':'),
                        f = {};
                    try { f = JSON.parse(document.thisItem.getProperty('_functions', '{}')); } catch { }
                    f[id + '_F'] = simu_f;
                    document.thisItem.setProperty('_functions', JSON.stringify(f));
                }
                toeval = document.replaceKeyValuesInFunction(toeval, false, document.tds, document.additional_columns);
                newval = eval(toeval);
                rawVal = newval;
            }
            if (format !== '') newval = document.format(newval, format);
            tooltip += document.stripHtml(newval);

            let v1 = (document.manual_costing_for_compare !== undefined ? document.manual_costing_for_compare[id] || newval : newval);
            if (v1 === undefined || v1 === null) v1 = '';
            if (format !== '') v1 = document.format(v1, format);
            if (v1.toString() !== newval.toString()) {
                addon += document.diffString(document.stripHtml(v1) + " ", document.stripHtml(newval) + " ");
            }
        }
        catch (e) {
            newval = 'hello';
            tooltip += toeval + "=ERROR. " + e;
        }
        document.manualCostingTable[id] = newval;
        let displayedValue;
        if (document.displayMode === displayModes.NORMAL || document.displayMode === displayModes.TIME) {
            if (document.displayMode === displayModes.TIME && format === 'H' && full[0].indexOf('material') === -1)
                displayedValue = document.formatTimestamp(rawVal);
            else
                displayedValue = newval;
        }
        else
            displayedValue = rawVal;
        return type === 'filter' ? displayedValue : '<div class="tocompute" id="' + id + '"><a title="' + document.htmlEntities(tooltip) + '" onclick="document.CopyTextToClipboard(this.getAttribute(\'oldtitle\'))">' + displayedValue + '</a></div>' + addon;
    }
    return data;
};

You will get this:

document.manualCostingTableRenderer=function(n,t,i,r){let u="aaaa";if((t==="display"||t==="filter")&&n.length>0&&n[0]==="="){let e=document.getResolvedFormular(u,n.substring(1),document.manual_costing_template_info),s="",f="TO COMPUTE",h=u+n+"=",l="",o=document.manual_costing_template_info.cols_formats[r.col];try{if(e==="")f="";else{if(t==="display"&&(i[1].toLowerCase()==="total"||i[0].toLowerCase()==="total")&&["COP_WO","COP","UNIT_SHOULD_PRICE_USD"].indexOf(document.manual_costing_template_info.cols[r.col])!==-1){e=document.replaceKeyValuesInFunction(e,!0,document.tds,document.additional_columns);let t=e.split("[").join("[CTX:"+document.thisItem.getProperty("_context","")+":"),n={};try{n=JSON.parse(document.thisItem.getProperty("_functions","{}"))}catch{}n[u+"_F"]=t;document.thisItem.setProperty("_functions",JSON.stringify(n))}e=document.replaceKeyValuesInFunction(e,!1,document.tds,document.additional_columns);f=eval(e);s=f}o!==""&&(f=document.format(f,o));h+=document.stripHtml(f);let n=document.manual_costing_for_compare!==undefined?document.manual_costing_for_compare[u]||f:f;(n===undefined||n===null)&&(n="");o!==""&&(n=document.format(n,o));n.toString()!==f.toString()&&(l+=document.diffString(document.stripHtml(n)+" ",document.stripHtml(f)+" "))}catch(f){f="hello";h+=e+"=ERROR. "+f}document.manualCostingTable[u]=f;let c;return c=document.displayMode===displayModes.NORMAL||document.displayMode===displayModes.TIME?document.displayMode===displayModes.TIME&&o==="H"&&i[0].indexOf("material")===-1?document.formatTimestamp(s):f:s,t==="filter"?c:'<div class="tocompute" id="'+u+'"><a title="'+document.htmlEntities(h)+'" onclick="document.CopyTextToClipboard(this.getAttribute(\'oldtitle\'))">'+c+"<\/a><\/div>"+l}return n}

As you can see, the code:

        catch (e) {
            newval = 'hello';
            tooltip += toeval + "=ERROR. " + e;
        }

is converted in : catch(f){f="hello";h+=e+"=ERROR. "+f}

There is a mismatch in the variables mapping for e =>f and newval => f.

trullock commented 2 years ago

Can you reduce the input code a bit to a minimum repro? Thanks

miraks31 commented 2 years ago

I tried during 2h but without success that's why I published this.

trullock commented 2 years ago

OK I'll take a look asap

trullock commented 2 years ago

This is a minimum repo:

fff = function () {
    if (true) {
        let aaa = 1;
        try {
        }
        catch (bbb) {
            return aaa + bbb;
        }
    }
};

Looks like lets declared inside a non function block confuse catch declarations

trullock commented 2 years ago

I think the bug is to do with how the lexical scoping of the catch parameter is treated

trullock commented 2 years ago

Fixed in 1.16.5