Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SCSS] Fixes issues with URIs when handling interp and unary #217

Merged
merged 2 commits into from
Nov 18, 2016

Conversation

bgriffith
Copy link
Collaborator

This PR rewrites the way we handle URI nodes by allowing either a raw uri or non-raw uri that can be made up of multiple nodes (interps, numbers, idents, unary etc)

It solves issues highlighted in #85

Only implement in SCSS but if approved I'll add it into Sass too.

Copy link
Owner

@tonyganch tonyganch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please explain to me what's the proposed difference between "raw" and "non-raw" types, and what "raw" is supposed to mean now? Comments for checkUri1 and checkUri2 functions seem to be the same :)


// Store the opening parenthesis token as we will reference it's `right`
// property to determine when the parentheses close
token = tokens[i];
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't reassign token anywhere later so you can move let from line 4032 here and rename variable to something like leftParenthesis

@bgriffith
Copy link
Collaborator Author

@tonyganch From a quick look checkUri1 is looking for non-string url url(image.png) and checkUri2 is looking for string based urls url('image.png')

@bgriffith
Copy link
Collaborator Author

@tonyganch Updated the code. Any further thoughts?

@tonyganch
Copy link
Owner

@bgriffith, I'm researching grammar and use cases, will get back to you shortly

case TokenType.LeftSquareBracket:
case TokenType.RightSquareBracket:
case TokenType.LowLine:
case TokenType.Tilde:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe there should be a different set of valid tokens.
According to css spec, any of the characters from this regexp are valid: [!#$%&*-\[\]-~]. Note that there are two groups, so the full list of valid characters is: !, #, $, %, &, *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, ], ^, _, {, |, }, plus backtick, digits and letters. Both " and ' are invalid.

raw = newNode(NodeType.RawType, joinValues(pos, pos + l), token.ln,
token.col);
if (l = checkIdent(i)) i += l;
else if (l = checkNumber(i)) i += l;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think both ident and number checks should be moved to checkUriRawCharacters, since all those characters are just part of raw and I see not much sense in trying to parse them differently from other 26 token types.

else if (l = checkNumber(i)) i += l;
else if (l = _checkUriRawCharacters(i)) i += l;
// As comments are not allowed within the uri token, include as part of node
else if (l = checkCommentML(i)) i += l;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check for comment should be removed and more tokens should be added to checkUriRawCharacters instead: not every comment is valid inside uri, for example, this is invalid code according to css spec: url(a/*(*/) (note ( inside the comment).


uri.push(raw);
return i - start;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can store position of final token as uri_end, for example, in which case getUriRaw will not need to loop through characters again to find it.

* Check for a raw URI
* (1) `url(http://foo/bar.png)`
* (2) `url(http://foo/#{bar}.png)`
* (3) `url(#{foo}/bar.png)`
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please either update examples or clarify description, that "raw" in that case means "without quotes" and that we only check inner part, without url and parentheses?

if (l = checkSC(i)) i += l;

while (i < tokensLength) {
if (checkVariable(i) || checkFunction(i)) return 0;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this line can be removed. We don't need to check for function because parentheses are invalid raw tokens. Plus we should not break on variables because url($a) is a perfectly valid piece of css code where $a is just part of uri and not a variable.

Copy link
Collaborator Author

@bgriffith bgriffith Nov 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tonyganch - So are you ok with parsing the $a in url($a) always as raw and not variable?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For css syntax = definitely :) What will compiler assume? That this is variable in any case?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking out loud - #{$a} would always parse as raw too right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah guess it HAS to be, incase we end up breaking up a totally legit url into many incorrect nodes.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked with both css validator and sassmeister. CSS validator treats url(#{$a}) as a valid url thus parsing it as "raw", and sassmeister interprets it strongly as interpolation.
So I guess the logic for css and scss/sass should be different here.

Copy link
Collaborator Author

@bgriffith bgriffith Nov 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll have to check but I think the current implementation for the CSS parser is problem free.

So on the SCSS/Sass front, where would you stop? Would you parse url($a) as variable?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, for SCSS/Sass those should be variables and interpolations.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I've removed checkFunction but left checkVariable due to the above.

// Determine the type of URI
if (checkUri1(i)) tokens[start].uriType = 1; // Raw based URI
else if (checkUri2(i)) tokens[start].uriType = 2; // Non-raw based URI
else return 0;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current implementation doesn't guarantee that those checkUri checks will go through all characters between parentheses because we don't compare token position with a matching right parenthesis anywhere. In checkUri1 for example we check for i < tokensLength in while loop. I suppose that will parse the following example as valid even though it is not: url(abc(()

if (l = checkSC(i)) i += l;

// Check if URI contains a raw node
if (!isRaw) return 0;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually need that? Consider url(#{abc}), even though there is no raw node besides a lonely interpolation, it still can be parsed inside this check without need to call checkUri2

if (l = checkSC(i)) i += l;
else if (l = checkString(i)) i += l;
else if (l = checkFunction(i)) i += l;
else if (l = checkUnary(i)) i += l;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unary operator is the one that gives sign to a number, for example, -3 or +8. I think it can't be applied to uris but I guess there isn't anything more suitable in the code now :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha yeah I know, just wasn't one for just a plus sign 😛

@tonyganch
Copy link
Owner

Related issue which should be fixed with this PR: #210

@bgriffith
Copy link
Collaborator Author

Awesome feedback @tonyganch - thanks a lot! I'll go through it and implement the changes.

@bgriffith bgriffith self-assigned this Nov 2, 2016
@bgriffith
Copy link
Collaborator Author

@tonyganch Updated the PR! Let me know what you think - if it's all good I'll port the changes to Sass syntax

@bgriffith
Copy link
Collaborator Author

bgriffith commented Nov 4, 2016

Few issues have cropped up and I noticed some bugs in my code! Hold yer horses 🐴

@bgriffith
Copy link
Collaborator Author

@tonyganch Ok! So I've cleaned up the loops, and fixed a few issues. Give me a shout if there's anything not quite right.

@tonyganch
Copy link
Owner

I'm okay with this PR, can you please port the changes to Sass and merge it?

@bgriffith bgriffith merged commit 2c3c49d into tonyganch:dev Nov 18, 2016
@bgriffith
Copy link
Collaborator Author

bgriffith commented Nov 18, 2016

@tonyganch Ported and merged! Glad to get that one in! 😁

@tonyganch
Copy link
Owner

Cool, thanks, will publish it tonight or tomorrow.

On 18 Nov 2016, at 15:47, Ben Griffith [email protected] wrote:

Ported and merged 😁


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants