2

My Goal:
I'm trying to parse css string to retrieve different parts like css rules, imports, comments, ...

What I've done:
My function starts by retrieving comments, then it retrieves the imports and finally it retrieves the rules blocks.
Once these parts are retrieved, each parts is logged to the console.

My Problem:
My problem is when I test it, it seems like my code generates random numbers when the rules blocks part is logged to the console.

My Code:

function output(css) {
    if(typeof css === 'string') {
        var current = css;
        // remove comments
        var comments = [];
        current = current.replace(/\s*\/\*[^*]*\*+([^/*][^*]*\*+)*\/|^\/\/[^\n]*\n?/gim, c=>comments.push(c.trim()));

        // retrieve @ imports
        var imports = [];
        current = current.replace(/@[^;{]+;/gi, imp => imports.push(imp.trim()));

        // retrieve rules blocks
        var rulesBlocks = [];
        current = current.replace(/[^};]+{[^{]*}/gi, block => {
            rulesBlocks.push(block.trim());
        });
        console.log(comments, imports, rulesBlocks);
    }
}

var css = document.getElementById('css').innerText;

output(css);
<pre id="css"><code>
#id, .class {
	#id {
	}
}
/**
*/
@import url('http://www.test.com/test.min.js/');
/*
@import url('http://www.test.com/test.min.js/');
*/
/***/
//#id, .class {
#id, .class {
	#id {
		& {
		}
	}
}
#id, .class {
	#id {
	}
}
declaration {
    data: test;
}
declaration2 declaration {
    data
}

@font-face {
    font-family: myFirstFont;
    src: url(sansation_light.woff);
}
@font-face {
    font-family: myFirstFont;
    src: url(sansation_light.woff);
}
</code></pre>

As you can see if you run it, the console shows random numbers in this line:
"1\n123\n4#id, .class {\n\t#id {\n\t\t& {\n\t\t}\n\t}\n}"
Why it generates random numbers? Why the console shows 1, 123 and 4?

4
  • 1
    It is because the Array.push() method returns the array's length, your replaces are doing it. You can add &&''; after the push method, then it will work as expected. Commented Jun 19, 2017 at 17:08
  • 1
    Don't parse CSS with regexp. Use a CSS parser. Commented Jun 19, 2017 at 17:20
  • 1
    @torazaburo Why should I use a CSS parser rather than regex? and what is a CSS parser? Commented Jun 19, 2017 at 17:22
  • Google "CSS parser". Commented Jun 19, 2017 at 18:49

1 Answer 1

2

Because array push returns the new length of the array, and you are using that return value as the replacement.

You can specify a function as the second parameter. In this case, the function will be invoked after the match has been performed. The function's result (return value) will be used as the replacement string.

So:

current = current.replace(/@[^;{]+;/gi, imp => imports.push(imp.trim()));

will replace every instance of the expression with the new length of imports.

If you want to avoid the problem, you could use Washington Guedes' suggestion in the comments of adding &&''; after the push, or just return imp (etc.) in the replace function, or rewrite the function to use the more idiomatic exec method.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.