Skip to content

Commit

Permalink
Update Sass URI
Browse files Browse the repository at this point in the history
  • Loading branch information
bgriffith committed Nov 18, 2016
1 parent 5d422ae commit 410d1a8
Show file tree
Hide file tree
Showing 36 changed files with 1,619 additions and 80 deletions.
302 changes: 227 additions & 75 deletions src/sass/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,21 +181,6 @@ function throwError(opt_i) {
throw {line: ln, syntax: 'sass'};
}

/**
* @param {!Object} exclude
* @param {number} i Token's index number
* @return {number}
*/
function checkExcluding(exclude, i) {
var start = i;

while (i < tokensLength) {
if (exclude[tokens[i++].type]) break;
}

return i - start - 2;
}

/**
* @param {number} start
* @param {number} finish
Expand Down Expand Up @@ -4508,107 +4493,274 @@ function _checkUnicodeWildcard(i) {
return i - start;
}


/**
* Check if token is part of URI (e.g. `url('/css/styles.css')`)
* Check if token is part of URI, e.g. `url('/css/styles.css')`
* @param {number} i Token's index number
* @return {number} Length of URI
* @returns {number} Length of URI
*/
function checkUri(i) {
var start = i;
const start = i;
let l;

if (i >= tokensLength || tokens[i++].value !== 'url' ||
i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis)
return 0;
if (i >= tokensLength || tokens[i].value !== 'url') return 0;

return tokens[i].right - start + 1;
// Skip `url`
i++;

if (i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis)
return 0;

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

// Skip `(`
i++;

// Determine the type of URI
while (i < leftParenthesis.right) {
if (l = checkUri1(i)) {
i += l;
tokens[start].uriType = 1; // Raw based URI (without quotes)
} else if (l = checkUri2(i)) {
i += l;
tokens[start].uriType = 2; // Non-raw based URI (with quotes)
} else return 0;
}

return i - start;
}

/**
* Get node with URI
* @return {Array} `['uri', x]` where `x` is URI's nodes (without `url`
* and braces, e.g. `['string', ''/css/styles.css'']`).
* Get specific type of URI node
* @returns {Node} Specific type of URI node
*/
function getUri() {
let startPos = pos;
let uriExcluding = {};
let uri;
let token;
const uriType = tokens[pos].uriType;

if (uriType === 1) return getUri1();
else if (uriType === 2) return getUri2();
else return 0;
}

/**
* Check if token type is valid URI character
* @param {number} i Token's index number
* @returns {number} Length of raw node
*/
function checkUriRawCharacters(i) {
const start = i;
let l;
let raw;

pos += 2;
if (l = checkIdent(i)) i += l;
else if (l = checkNumber(i)) i += l;
else {
switch (tokens[i].type) {
case TokenType.ExclamationMark:
case TokenType.NumberSign:
case TokenType.DollarSign:
case TokenType.PercentSign:
case TokenType.Ampersand:
case TokenType.Asterisk:
case TokenType.PlusSign:
case TokenType.Comma:
case TokenType.HyphenMinus:
case TokenType.FullStop:
case TokenType.Solidus:
case TokenType.Colon:
case TokenType.Semicolon:
case TokenType.LessThanSign:
case TokenType.EqualsSign:
case TokenType.GreaterThanSign:
case TokenType.QuotationMark:
case TokenType.CommercialAt:
case TokenType.LeftSquareBracket:
case TokenType.RightSquareBracket:
case TokenType.CircumflexAccent:
case TokenType.LowLine:
case TokenType.LeftCurlyBracket:
case TokenType.VerticalLine:
case TokenType.RightCurlyBracket:
case TokenType.Tilde:
i += 1;
break;

default:
return 0;
}
}

uriExcluding[TokenType.Space] = 1;
uriExcluding[TokenType.Tab] = 1;
uriExcluding[TokenType.Newline] = 1;
uriExcluding[TokenType.LeftParenthesis] = 1;
uriExcluding[TokenType.RightParenthesis] = 1;

if (checkUriContent(pos)) {
uri = []
.concat(getSC())
.concat(getUriContent())
.concat(getSC());
} else {
uri = [].concat(getSC());
l = checkExcluding(uriExcluding, pos);
token = tokens[pos];
raw = newNode(NodeType.RawType, joinValues(pos, pos + l), token.ln,
token.col);
return i - start;
}

/**
* Check if content of URI can be contained within a raw node
* @param {number} i Token's index number
* @returns {number} Length of raw node
*/
function checkUriRaw(i) {
const start = i;
let l;

while (i < tokensLength) {
if (checkInterpolation(i) || checkVariable(i)) break;
else if (l = checkUriRawCharacters(i)) i += l;
else break;
}

uri.push(raw);
tokens[start].uri_raw_end = i;

pos += l + 1;
return i - start;
}

uri = uri.concat(getSC());
/**
* Get a raw node
* @returns {Node}
*/
function getUriRaw() {
const startPos = pos;
const type = NodeType.RawType;
const token = tokens[startPos];
const line = token.ln;
const column = token.col;
let content = [];
let l;

while (pos < tokens[startPos].uri_raw_end) {
if (checkInterpolation(pos) || checkVariable(pos)) break;
else if (l = checkUriRawCharacters(pos)) pos += l;
else break;
}

token = tokens[startPos];
var line = token.ln;
var column = token.col;
var end = getLastPosition(uri, line, column, 1);
pos++;
content = joinValues(startPos, pos - 1);

return newNode(NodeType.UriType, uri, token.ln, token.col, end);
return newNode(type, content, line, column);
}

/**
* Check for a raw (without quotes) URI
* (1) http://foo.com/bar.png
* (2) http://foo.com/#{$bar}.png
* (3) #{$foo}/bar.png
* (4) #{$foo}
* @param {number} i Token's index number
* @return {number}
* @returns {number} Length of URI node
*/
function checkUriContent(i) {
return checkUri1(i) ||
checkFunction(i);
function checkUri1(i) {
const start = i;
let l;

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

while (i < tokensLength) {
if (l = checkInterpolation(i) || checkUriRaw(i)) i += l;
else break;
}

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

// Check that we are at the end of the uri
if (i < tokens[start - 1].right) return 0;

tokens[start].uri_end = i;

return i - start;
}

/**
* @return {Array}
* Get a raw (without quotes) URI
node
* @returns {Node}
*/
function getUriContent() {
if (checkUri1(pos)) return getString();
else if (checkFunction(pos)) return getFunction();
function getUri1() {
const startPos = pos;
const type = NodeType.UriType;
const token = tokens[startPos];
const line = token.ln;
const column = token.col;
let content = [];
let end;

// Skip url and (
pos += 2;

if (checkSC(pos)) content = content.concat(getSC());

while (pos < tokens[startPos + 2].uri_end) {
if (checkInterpolation(pos)) content.push(getInterpolation());
else if (checkUriRaw(pos)) content.push(getUriRaw());
else break;
}

if (checkSC(pos)) content = content.concat(getSC());

// Check that we are at the end of the uri
if (pos < tokens[startPos + 1].right) return 0;

end = getLastPosition(content, line, column, 1);

// Skip )
pos++;

return newNode(type, content, line, column, end);
}

/**
* Check for a non-raw (with quotes) URI
* (1) 'http://foo.com/bar.png'
* (2) 'http://foo.com/'#{$bar}.png
* (3) #{$foo}'/bar.png'
* @param {number} i Token's index number
* @return {number}
* @returns {number} Length of URI node
*/
function checkUri1(i) {
let start = i;
function checkUri2(i) {
const start = i;
let l;

if (i >= tokensLength) return 0;
while (i < tokensLength) {
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;
else if (l = checkIdentOrInterpolation(i)) i += l;
else if (l = checkVariable(i)) i += l;
else break;
}

if (l = checkSC(i)) i += l;
tokens[start].uri_end = i;

if (tokens[i].type !== TokenType.StringDQ &&
tokens[i].type !== TokenType.StringSQ) return 0;
return i - start;
}

i++;
/**
* Get a non-raw (with quotes) URI node
* @returns {Node}
*/
function getUri2() {
const startPos = pos;
const token = tokens[startPos];
const line = token.ln;
const column = token.col;
let content = [];
let end;

if (l = checkSC(i)) i += l;
// Skip `url` and `(`
pos += 2;

return i - start;
while (pos < tokens[startPos + 2].uri_end) {
if (checkSC(pos)) content = content.concat(getSC());
else if (checkUnary(pos)) content.push(getUnary());
else if (_checkValue(pos)) content.push(_getValue());
else break;
}

end = getLastPosition(content, line, column, 1);

// Skip `)`
pos++;

return newNode(NodeType.UriType, content, line, column, end);
}

/**
Expand Down
22 changes: 18 additions & 4 deletions test/sass/uri/3.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,30 @@
"type": "uri",
"content": [
{
"type": "raw",
"content": "$v1",
"type": "variable",
"content": [
{
"type": "ident",
"content": "foo",
"syntax": "sass",
"start": {
"line": 1,
"column": 6
},
"end": {
"line": 1,
"column": 8
}
}
],
"syntax": "sass",
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 7
"column": 8
}
}
],
Expand All @@ -22,6 +36,6 @@
},
"end": {
"line": 1,
"column": 8
"column": 9
}
}
Loading

0 comments on commit 410d1a8

Please sign in to comment.