trullock / NUglify

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

Incorrect output when minifying code produced from typescript compilation of null chaining #402

Open ig-jb opened 4 months ago

ig-jb commented 4 months ago

Are you using the latest verion of NUglify, especially if used through BunderMinifier? Update before raising a bug as your issue is probably already fixed Yes - V1.21.9

Describe the bug Typescript compiles null chaining in a similar manner to the below: Typescript input:

for (let myOption of collection) {
    if (myOption.purpose === purpose) {
        return myOption;
    }

    if (myOption.subItems?.length > 0 ?? false) {
        myNextCollection.push(...myOption.subItems);
    }
}

Typescript output:

for (var _i = 0, collection_1 = collection; _i < collection_1.length; _i++) {
            var myOption = collection_1[_i];
            if (myOption.purpose === purpose ) {
                return myOption;
            }
            if ((_b = ((_a = myOption.subItems) === null || _a === void 0 ? void 0 : _a.length) > 0) !== null && _b !== void 0 ? _b : false) {
                myNextCollection.push.apply(myNextCollection, myOption.subItems);
            }
        }

When minified with NUglify, we end up with this:

for (var r, f, i = [], u = 0, e = n; u < e.length; u++) {
        if (r = e[u],
            r.purpose === t)
            return r;
        (!0 && f !== void 0 ? f : !1) && i.push.apply(i, r.subItems)
    }

f is never assigned, so the condition to recurse through the subItems object is never executed.

To Reproduce I have produced a small sample based on the real example above (typescript compilation removed from the picture):

using NUglify;

string myCode = @"
const findByCriteriaRecursive = function (collection, criteria) {
        var _a,
        _b;
        var myNextCollection = [];
        for (var _i = 0, collection_1 = collection; _i < collection_1.length; _i++) {
            var myOption = collection_1[_i];
            if (myOption.criteria === criteria) {
                return myOption;
            }
            if ((_b = ((_a = myOption.subItems) === null || _a === void 0 ? void 0 : _a.length) > 0) !== null && _b !== void 0 ? _b : false) {
                myNextCollection.push.apply(myNextCollection, myOption.subItems);
            }
        }
        if (myNextCollection.length > 0) {
            return findByCriteriaRecursive(myNextCollection, criteria);
        }
        return null;
    };

const myTestItem = [
    { id: 1, criteria: ""Not this one"", subItems: [] },
    { id: 2, criteria: ""Not this one either"", subItems: [{ id: 3, criteria: ""Nor this one"" , subItems:[]}] },
    { id: 4, criteria: ""It's in here"", subItems: [{ id: 5, criteria: ""HelloWorld"" , subItems:[]}] },
];

console.log(findByCriteriaRecursive(myTestItem, ""HelloWorld""));
";

string myResult = Uglify.Js(myCode, new NUglify.JavaScript.CodeSettings()).Code;

Minified output or stack trace

const findByCriteriaRecursive=function(n,t){for(var r,f,i=[],u=0,e=n;u<e.length;u++){if(r=e[u],r.criteria===t)return r;(!0&&f!==void 0?f:!1)&&i.push.apply(i,r.subItems)}return i.length>0?findByCriteriaRecursive(i,t):null},myTestItem=[{id:1,criteria:"Not this one",subItems:[]},{id:2,criteria:"Not this one either",subItems:[{id:3,criteria:"Nor this one",subItems:[]}]},{id:4,criteria:"It's in here",subItems:[{id:5,criteria:"HelloWorld",subItems:[]}]},];console.log(findByCriteriaRecursive(myTestItem,"HelloWorld"))

Excepted output code

const findByCriteriaRecursive=function(n,t){for(var r,f,i=[],u=0,e=n;u<e.length;u++){if(r=e[u],f=r.subItems,r.criteria===t)return r;(!0&&f!==void 0?f:!1)&&i.push.apply(i,r.subItems)}return i.length>0?findByCriteriaRecursive(i,t):null},myTestItem=[{id:1,criteria:"Not this one",subItems:[]},{id:2,criteria:"Not this one either",subItems:[{id:3,criteria:"Nor this one",subItems:[]}]},{id:4,criteria:"It's in here",subItems:[{id:5,criteria:"HelloWorld",subItems:[]}]},];console.log(findByCriteriaRecursive(myTestItem,"HelloWorld"))