pax_global_header00006660000000000000000000000064126614010400014504gustar00rootroot0000000000000052 comment=c2738fbc73bf1162481862ddce7d011cc0a57b15 postcss-value-parser-3.3.0/000077500000000000000000000000001266140104000156115ustar00rootroot00000000000000postcss-value-parser-3.3.0/.editorconfig000066400000000000000000000002531266140104000202660ustar00rootroot00000000000000root = true [*] charset = utf-8 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true indent_style = space indent_size = 2 [*.js] indent_size = 4 postcss-value-parser-3.3.0/.gitignore000066400000000000000000000000151266140104000175750ustar00rootroot00000000000000node_modules postcss-value-parser-3.3.0/.travis.yml000066400000000000000000000000631266140104000177210ustar00rootroot00000000000000language: node_js node_js: - 'stable' - '0.12' postcss-value-parser-3.3.0/LICENSE000066400000000000000000000020621266140104000166160ustar00rootroot00000000000000Copyright (c) Bogdan Chadkin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. postcss-value-parser-3.3.0/README.md000066400000000000000000000163451266140104000171010ustar00rootroot00000000000000# postcss-value-parser [![Travis CI](https://travis-ci.org/TrySound/postcss-value-parser.svg)](https://travis-ci.org/TrySound/postcss-value-parser) Transforms CSS declaration values and at-rule parameters into a tree of nodes, and provides a simple traversal API. ## Usage ```js var valueParser = require('postcss-value-parser'); var cssBackgroundValue = 'url(foo.png) no-repeat 40px 73%'; var parsedValue = valueParser(cssBackgroundValue); // parsedValue exposes an API described below, // e.g. parsedValue.walk(..), parsedValue.toString(), etc. ``` For example, parsing the value `rgba(233, 45, 66, .5)` will return the following: ```js { nodes: [ { type: 'function', value: 'rgba', before: '', after: '', nodes: [ { type: 'word', value: '233' }, { type: 'div', value: ',', before: '', after: ' ' }, { type: 'word', value: '45' }, { type: 'div', value: ',', before: '', after: ' ' }, { type: 'word', value: '66' }, { type: 'div', value: ',', before: ' ', after: '' }, { type: 'word', value: '.5' } ] } ] } ``` If you wanted to convert each `rgba()` value in `sourceCSS` to a hex value, you could do so like this: ```js var valueParser = require('postcss-value-parser'); var parsed = valueParser(sourceCSS); // walk() will visit all the of the nodes in the tree, // invoking the callback for each. parsed.walk(function (node) { // Since we only want to transform rgba() values, // we can ignore anything else. if (node.type !== 'function' && node.value !== 'rgba') return; // We can make an array of the rgba() arguments to feed to a // convertToHex() function var color = node.nodes.filter(function (node) { return node.type === 'word'; }).map(function (node) { return Number(node.value); }); // [233, 45, 66, .5] // Now we will transform the existing rgba() function node // into a word node with the hex value node.type = 'word'; node.value = convertToHex(color); }) parsed.toString(); // #E92D42 ``` ## Nodes Each node is an object with these common properties: - **type**: The type of node (`word`, `string`, `div`, `space`, `comment`, or `function`). Each type is documented below. - **value**: Each node has a `value` property; but what exactly `value` means is specific to the node type. Details are documented for each type below. - **sourceIndex**: The starting index of the node within the original source string. For example, given the source string `10px 20px`, the `word` node whose value is `20px` will have a `sourceIndex` of `5`. ### word The catch-all node type that includes keywords (e.g. `no-repeat`), quantities (e.g. `20px`, `75%`, `1.5`), and hex colors (e.g. `#e6e6e6`). Node-specific properties: - **value**: The "word" itself. ### string A quoted string value, e.g. `"something"` in `content: "something";`. Node-specific properties: - **value**: The text content of the string. - **quote**: The quotation mark surrounding the string, either `"` or `'`. - **unclosed**: `true` if the string was not closed properly. e.g. `"unclosed string `. ### div A divider, for example - `,` in `animation-duration: 1s, 2s, 3s` - `/` in `border-radius: 10px / 23px` - `:` in `(min-width: 700px)` Node-specific properties: - **value**: The divider character. Either `,`, `/`, or `:` (see examples above). - **before**: Whitespace before the divider. - **after**: Whitespace after the divider. ### space Whitespace used as a separator, e.g. ` ` occurring twice in `border: 1px solid black;`. Node-specific properties: - **value**: The whitespace itself. ### comment A CSS comment starts with `/*` and ends with `*/` Node-specific properties: - **value**: The comment value without `/*` and `*/` - **unclosed**: `true` if the comment was not closed properly. e.g. `/* comment without an end `. ### function A CSS function, e.g. `rgb(0,0,0)` or `url(foo.bar)`. Function nodes have nodes nested within them: the function arguments. Additional properties: - **value**: The name of the function, e.g. `rgb` in `rgb(0,0,0)`. - **before**: Whitespace after the opening parenthesis and before the first argument, e.g. ` ` in `rgb( 0,0,0)`. - **after**: Whitespace before the closing parenthesis and after the last argument, e.g. ` ` in `rgb(0,0,0 )`. - **nodes**: More nodes representing the arguments to the function. - **unclosed**: `true` if the parentheses was not closed properly. e.g. `( unclosed-function `. Media features surrounded by parentheses are considered functions with an empty value. For example, `(min-width: 700px)` parses to these nodes: ```js [ { type: 'function', value: '', before: '', after: '', nodes: [ { type: 'word', value: 'min-width' }, { type: 'div', value: ':', before: '', after: ' ' }, { type: 'word', value: '700px' } ] } ] ``` `url()` functions can be parsed a little bit differently depending on whether the first character in the argument is a quotation mark. `url( /gfx/img/bg.jpg )` parses to: ```js { type: 'function', sourceIndex: 0, value: 'url', before: ' ', after: ' ', nodes: [ { type: 'word', sourceIndex: 5, value: '/gfx/img/bg.jpg' } ] } ``` `url( "/gfx/img/bg.jpg" )`, on the other hand, parses to: ```js { type: 'function', sourceIndex: 0, value: 'url', before: ' ', after: ' ', nodes: [ type: 'string', sourceIndex: 5, quote: '"', value: '/gfx/img/bg.jpg' }, ] } ``` ## API ``` var valueParser = require('postcss-value-parser'); ``` ### valueParser.unit(quantity) Parses `quantity`, distinguishing the number from the unit. Returns an object like the following: ```js // Given 2rem { number: '2', unit: 'rem' } ``` If the `quantity` argument cannot be parsed as a number, returns `false`. *This function does not parse complete values*: you cannot pass it `1px solid black` and expect `px` as the unit. Instead, you should pass it single quantities only. Parse `1px solid black`, then pass it the stringified `1px` node (a `word` node) to parse the number and unit. ### valueParser.stringify(nodes[, custom]) Stringifies a node or array of nodes. The `custom` function is called for each `node`; return a string to override the default behaviour. ### valueParser.walk(nodes, callback[, bubble]) Walks each provided node, recursively walking all descendent nodes within functions. Returning `false` in the `callback` will prevent traversal of descendent nodes (within functions). You can use this feature to for shallow iteration, walking over only the *immediate* children. *Note: This only applies if `bubble` is `false` (which is the default).* By default, the tree is walked from the outermost node inwards. To reverse the direction, pass `true` for the `bubble` argument. The `callback` is invoked with three arguments: `callback(node, index, nodes)`. - `node`: The current node. - `index`: The index of the current node. - `nodes`: The complete nodes array passed to `walk()`. Returns the `valueParser` instance. ### var parsed = valueParser(value) Returns the parsed node tree. ### parsed.nodes The array of nodes. ### parsed.toString() Stringifies the node tree. ### parsed.walk(callback[, bubble]) Walks each node inside `parsed.nodes`. See the documentation for `valueParser.walk()` above. # License MIT © [Bogdan Chadkin](mailto:trysound@yandex.ru) postcss-value-parser-3.3.0/lib/000077500000000000000000000000001266140104000163575ustar00rootroot00000000000000postcss-value-parser-3.3.0/lib/index.js000066400000000000000000000011651266140104000200270ustar00rootroot00000000000000var parse = require('./parse'); var walk = require('./walk'); var stringify = require('./stringify'); function ValueParser(value) { if (this instanceof ValueParser) { this.nodes = parse(value); return this; } return new ValueParser(value); } ValueParser.prototype.toString = function () { return Array.isArray(this.nodes) ? stringify(this.nodes) : ''; }; ValueParser.prototype.walk = function (cb, bubble) { walk(this.nodes, cb, bubble); return this; }; ValueParser.unit = require('./unit'); ValueParser.walk = walk; ValueParser.stringify = stringify; module.exports = ValueParser; postcss-value-parser-3.3.0/lib/parse.js000066400000000000000000000165551266140104000200430ustar00rootroot00000000000000var openParentheses = '('.charCodeAt(0); var closeParentheses = ')'.charCodeAt(0); var singleQuote = '\''.charCodeAt(0); var doubleQuote = '"'.charCodeAt(0); var backslash = '\\'.charCodeAt(0); var slash = '/'.charCodeAt(0); var comma = ','.charCodeAt(0); var colon = ':'.charCodeAt(0); var star = '*'.charCodeAt(0); module.exports = function (input) { var tokens = []; var value = input; var next, quote, prev, token, escape, escapePos, whitespacePos; var pos = 0; var code = value.charCodeAt(pos); var max = value.length; var stack = [{ nodes: tokens }]; var balanced = 0; var parent; var name = ''; var before = ''; var after = ''; while (pos < max) { // Whitespaces if (code <= 32) { next = pos; do { next += 1; code = value.charCodeAt(next); } while (code <= 32); token = value.slice(pos, next); prev = tokens[tokens.length - 1]; if (code === closeParentheses && balanced) { after = token; } else if (prev && prev.type === 'div') { prev.after = token; } else if (code === comma || code === colon || code === slash && value.charCodeAt(next + 1) !== star) { before = token; } else { tokens.push({ type: 'space', sourceIndex: pos, value: token }); } pos = next; // Quotes } else if (code === singleQuote || code === doubleQuote) { next = pos; quote = code === singleQuote ? '\'' : '"'; token = { type: 'string', sourceIndex: pos, quote: quote }; do { escape = false; next = value.indexOf(quote, next + 1); if (~next) { escapePos = next; while (value.charCodeAt(escapePos - 1) === backslash) { escapePos -= 1; escape = !escape; } } else { value += quote; next = value.length - 1; token.unclosed = true; } } while (escape); token.value = value.slice(pos + 1, next); tokens.push(token); pos = next + 1; code = value.charCodeAt(pos); // Comments } else if (code === slash && value.charCodeAt(pos + 1) === star) { token = { type: 'comment', sourceIndex: pos }; next = value.indexOf('*/', pos); if (next === -1) { token.unclosed = true; next = value.length; } token.value = value.slice(pos + 2, next); tokens.push(token); pos = next + 2; code = value.charCodeAt(pos); // Dividers } else if (code === slash || code === comma || code === colon) { token = value[pos]; tokens.push({ type: 'div', sourceIndex: pos - before.length, value: token, before: before, after: '' }); before = ''; pos += 1; code = value.charCodeAt(pos); // Open parentheses } else if (openParentheses === code) { // Whitespaces after open parentheses next = pos; do { next += 1; code = value.charCodeAt(next); } while (code <= 32); token = { type: 'function', sourceIndex: pos - name.length, value: name, before: value.slice(pos + 1, next) }; pos = next; if (name === 'url' && code !== singleQuote && code !== doubleQuote) { next -= 1; do { escape = false; next = value.indexOf(')', next + 1); if (~next) { escapePos = next; while (value.charCodeAt(escapePos - 1) === backslash) { escapePos -= 1; escape = !escape; } } else { value += ')'; next = value.length - 1; token.unclosed = true; } } while (escape); // Whitespaces before closed whitespacePos = next; do { whitespacePos -= 1; code = value.charCodeAt(whitespacePos); } while (code <= 32); if (pos !== whitespacePos + 1) { token.nodes = [{ type: 'word', sourceIndex: pos, value: value.slice(pos, whitespacePos + 1) }]; } else { token.nodes = []; } if (token.unclosed && whitespacePos + 1 !== next) { token.after = ''; token.nodes.push({ type: 'space', sourceIndex: whitespacePos + 1, value: value.slice(whitespacePos + 1, next) }); } else { token.after = value.slice(whitespacePos + 1, next); } pos = next + 1; code = value.charCodeAt(pos); tokens.push(token); } else { balanced += 1; token.after = ''; tokens.push(token); stack.push(token); tokens = token.nodes = []; parent = token; } name = ''; // Close parentheses } else if (closeParentheses === code && balanced) { pos += 1; code = value.charCodeAt(pos); parent.after = after; after = ''; balanced -= 1; stack.pop(); parent = stack[balanced]; tokens = parent.nodes; // Words } else { next = pos; do { if (code === backslash) { next += 1; } next += 1; code = value.charCodeAt(next); } while (next < max && !( code <= 32 || code === singleQuote || code === doubleQuote || code === comma || code === colon || code === slash || code === openParentheses || code === closeParentheses && balanced )); token = value.slice(pos, next); if (openParentheses === code) { name = token; } else { tokens.push({ type: 'word', sourceIndex: pos, value: token }); } pos = next; } } for (pos = stack.length - 1; pos; pos -= 1) { stack[pos].unclosed = true; } return stack[0].nodes; }; postcss-value-parser-3.3.0/lib/stringify.js000066400000000000000000000023211266140104000207310ustar00rootroot00000000000000function stringifyNode(node, custom) { var type = node.type; var value = node.value; var buf; var customResult; if (custom && (customResult = custom(node)) !== undefined) { return customResult; } else if (type === 'word' || type === 'space') { return value; } else if (type === 'string') { buf = node.quote || ''; return buf + value + (node.unclosed ? '' : buf); } else if (type === 'comment') { return '/*' + value + (node.unclosed ? '' : '*/'); } else if (type === 'div') { return (node.before || '') + value + (node.after || ''); } else if (Array.isArray(node.nodes)) { buf = stringify(node.nodes); if (type !== 'function') { return buf; } return value + '(' + (node.before || '') + buf + (node.after || '') + (node.unclosed ? '' : ')'); } return value; } function stringify(nodes, custom) { var result, i; if (Array.isArray(nodes)) { result = ''; for (i = nodes.length - 1; ~i; i -= 1) { result = stringifyNode(nodes[i], custom) + result; } return result; } return stringifyNode(nodes, custom); } module.exports = stringify; postcss-value-parser-3.3.0/lib/unit.js000066400000000000000000000016451266140104000177020ustar00rootroot00000000000000var minus = '-'.charCodeAt(0); var plus = '+'.charCodeAt(0); var dot = '.'.charCodeAt(0); module.exports = function (value) { var pos = 0; var length = value.length; var dotted = false; var containsNumber = false; var code; var number = ''; while (pos < length) { code = value.charCodeAt(pos); if (code >= 48 && code <= 57) { number += value[pos]; containsNumber = true; } else if (code === dot) { if (dotted) { break; } dotted = true; number += value[pos]; } else if (code === plus || code === minus) { if (pos !== 0) { break; } number += value[pos]; } else { break; } pos += 1; } return containsNumber ? { number: number, unit: value.slice(pos) } : false; }; postcss-value-parser-3.3.0/lib/walk.js000066400000000000000000000007051266140104000176550ustar00rootroot00000000000000module.exports = function walk(nodes, cb, bubble) { var i, max, node, result; for (i = 0, max = nodes.length; i < max; i += 1) { node = nodes[i]; if (!bubble) { result = cb(node, i, nodes); } if (result !== false && node.type === 'function' && Array.isArray(node.nodes)) { walk(node.nodes, cb, bubble); } if (bubble) { cb(node, i, nodes); } } }; postcss-value-parser-3.3.0/package.json000066400000000000000000000017631266140104000201060ustar00rootroot00000000000000{ "name": "postcss-value-parser", "version": "3.3.0", "description": "Transforms css values and at-rule params into the tree", "main": "lib/index.js", "files": [ "lib" ], "devDependencies": { "eslint": "^2.1.0", "eslint-config-postcss": "^2.0.0", "tap-spec": "^4.1.0", "tape": "^4.2.0" }, "scripts": { "test": "tape test/*.js | tap-spec", "posttest": "eslint ." }, "eslintConfig": { "extends": "postcss/es5", "rules": { "max-len": 0, "no-bitwise": 0, "complexity": 0, "no-use-before-define": 0, "consistent-return": 0 } }, "author": "Bogdan Chadkin ", "license": "MIT", "homepage": "https://github.com/TrySound/postcss-value-parser", "repository": { "type": "git", "url": "https://github.com/TrySound/postcss-value-parser.git" }, "keywords": [ "postcss", "value", "parser" ], "bugs": { "url": "https://github.com/TrySound/postcss-value-parser/issues" } } postcss-value-parser-3.3.0/test/000077500000000000000000000000001266140104000165705ustar00rootroot00000000000000postcss-value-parser-3.3.0/test/index.js000066400000000000000000000062321266140104000202400ustar00rootroot00000000000000var test = require('tape'); var parser = require('..'); test('ValueParser', function (tp) { tp.test('i/o', function (t) { var tests = [ ' rgba( 34 , 45 , 54, .5 ) ', 'w1 w2 w6 \n f(4) ( ) () \t "s\'t" \'st\\"2\'' ]; t.plan(tests.length); tests.forEach(function (item) { t.equal(item, parser(item).walk(function () {}).toString(), JSON.stringify(item)); }); }); tp.test('walk', function (t) { t.plan(4); var result; result = []; parser('fn( ) fn2( fn3())').walk(function (node) { if (node.type === 'function') { result.push(node); } }); t.deepEqual(result, [ { type: 'function', sourceIndex: 0, value: 'fn', before: ' ', after: '', nodes: [] }, { type: 'function', sourceIndex: 6, value: 'fn2', before: ' ', after: '', nodes: [ { type: 'function', sourceIndex: 11, value: 'fn3', before: '', after: '', nodes: [] } ] }, { type: 'function', sourceIndex: 11, value: 'fn3', before: '', after: '', nodes: [] } ], 'should process all functions'); result = []; parser('fn( ) fn2( fn3())').walk(function (node) { if (node.type === 'function') { result.push(node); if (node.value === 'fn2') { return false; } } return true; }); t.deepEqual(result, [ { type: 'function', sourceIndex: 0, value: 'fn', before: ' ', after: '', nodes: [] }, { type: 'function', sourceIndex: 6, value: 'fn2', before: ' ', after: '', nodes: [ { type: 'function', sourceIndex: 11, value: 'fn3', before: '', after: '', nodes: [] } ] } ], 'shouldn\'t process functions after falsy callback'); result = []; parser('fn( ) fn2( fn3())').walk(function (node) { if (node.type === 'function' && node.value === 'fn2') { node.type = 'word'; } result.push(node); }); t.deepEqual(result, [ { type: 'function', sourceIndex: 0, value: 'fn', before: ' ', after: '', nodes: [] }, { type: 'space', sourceIndex: 5, value: ' ' }, { type: 'word', sourceIndex: 6, value: 'fn2', before: ' ', after: '', nodes: [ { type: 'function', sourceIndex: 11, value: 'fn3', before: '', after: '', nodes: [] } ] } ], 'shouldn\'t process nodes with defined non-function type'); result = []; parser('fn2( fn3())').walk(function (node) { if (node.type === 'function') { result.push(node); } }, true); t.deepEqual(result, [ { type: 'function', sourceIndex: 5, value: 'fn3', before: '', after: '', nodes: [] }, { type: 'function', sourceIndex: 0, value: 'fn2', before: ' ', after: '', nodes: [ { type: 'function', sourceIndex: 5, value: 'fn3', before: '', after: '', nodes: [] } ] } ], 'should process all functions with reverse mode'); }); }); postcss-value-parser-3.3.0/test/parse.js000066400000000000000000000451371266140104000202520ustar00rootroot00000000000000var test = require('tape'); var parse = require('../lib/parse'); var tests = [{ message: 'should correctly process empty input', fixture: '', expected: [] }, { message: 'should process escaped parentheses (open)', fixture: '\\(', expected: [ { type: 'word', sourceIndex: 0, value: '\\(' } ] }, { message: 'should process escaped parentheses (close)', fixture: '\\)', expected: [ { type: 'word', sourceIndex: 0, value: '\\)' } ] }, { message: 'should process escaped parentheses (both)', fixture: '\\(\\)', expected: [ { type: 'word', sourceIndex: 0, value: '\\(\\)' } ] }, { message: 'should process escaped parentheses (both)', fixture: '\\( \\)', expected: [ { type: 'word', sourceIndex: 0, value: '\\(' }, { type: 'space', sourceIndex: 2, value: ' ' }, { type: 'word', sourceIndex: 3, value: '\\)' } ] }, { message: 'should process unopened parentheses as word', fixture: '() )wo)rd)', expected: [ { type: 'function', sourceIndex: 0, value: '', before: '', after: '', nodes: [] }, { type: 'space', sourceIndex: 2, value: ' ' }, { type: 'word', sourceIndex: 3, value: ')wo)rd)' } ] }, { message: 'should add before prop', fixture: '( )', expected: [ { type: 'function', sourceIndex: 0, value: '', before: ' ', after: '', nodes: [] } ] }, { message: 'should add before and after prop', fixture: '( | )', expected: [ { type: 'function', sourceIndex: 0, value: '', before: ' ', after: ' ', nodes: [ { type: 'word', sourceIndex: 2, value: '|' } ] } ] }, { message: 'should add value prop', fixture: 'name()', expected: [ { type: 'function', sourceIndex: 0, value: 'name', before: '', after: '', nodes: [] } ] }, { message: 'should process nested functions', fixture: '((()))', expected: [ { type: 'function', sourceIndex: 0, value: '', before: '', after: '', nodes: [ { type: 'function', sourceIndex: 1, value: '', before: '', after: '', nodes: [ { type: 'function', sourceIndex: 2, value: '', before: '', after: '', nodes: [] } ] } ] } ] }, { message: 'should process advanced nested functions', fixture: '( calc(( ) ))word', expected: [ { type: 'function', sourceIndex: 0, value: '', before: ' ', after: '', nodes: [ { type: 'function', sourceIndex: 2, value: 'calc', before: '', after: ' ', nodes: [ { type: 'function', sourceIndex: 7, value: '', before: ' ', after: '', nodes: [] } ] } ] }, { type: 'word', sourceIndex: 13, value: 'word' } ] }, { message: 'should process divider (/)', fixture: '/', expected: [ { type: 'div', sourceIndex: 0, value: '/', before: '', after: '' } ] }, { message: 'should process divider (:)', fixture: ':', expected: [ { type: 'div', sourceIndex: 0, value: ':', before: '', after: '' } ] }, { message: 'should process divider (,)', fixture: ',', expected: [ { type: 'div', sourceIndex: 0, value: ',', before: '', after: '' } ] }, { message: 'should process complex divider', fixture: ' , ', expected: [ { type: 'div', sourceIndex: 0, value: ',', before: ' ', after: ' ' } ] }, { message: 'should process divider in function', fixture: '( , )', expected: [ { type: 'function', sourceIndex: 0, value: '', before: ' ', after: ' ', nodes: [ { type: 'div', sourceIndex: 2, value: ',', before: '', after: '' } ] } ] }, { message: 'should process two spaced divider', fixture: ' , : ', expected: [ { type: 'div', sourceIndex: 0, value: ',', before: ' ', after: ' ' }, { type: 'div', sourceIndex: 3, value: ':', before: '', after: ' ' } ] }, { message: 'should process empty quoted strings (")', fixture: '""', expected: [ { type: 'string', sourceIndex: 0, value: '', quote: '"' } ] }, { message: 'should process empty quoted strings (\')', fixture: '\'\'', expected: [ { type: 'string', sourceIndex: 0, value: '', quote: '\'' } ] }, { message: 'should process escaped quotes (\')', fixture: '\'word\\\'word\'', expected: [ { type: 'string', sourceIndex: 0, value: 'word\\\'word', quote: '\'' } ] }, { message: 'should process escaped quotes (\')', fixture: '"word\\"word"', expected: [ { type: 'string', sourceIndex: 0, value: 'word\\"word', quote: '"' } ] }, { message: 'should process single quotes inside double quotes (\')', fixture: '"word\'word"', expected: [ { type: 'string', sourceIndex: 0, value: 'word\'word', quote: '"' } ] }, { message: 'should process double quotes inside single quotes (\')', fixture: '\'word"word\'', expected: [ { type: 'string', sourceIndex: 0, value: 'word"word', quote: '\'' } ] }, { message: 'should process unclosed quotes', fixture: '"word', expected: [ { type: 'string', sourceIndex: 0, value: 'word', quote: '"', unclosed: true } ] }, { message: 'should process unclosed quotes with ended backslash', fixture: '"word\\', expected: [ { type: 'string', sourceIndex: 0, value: 'word\\', quote: '"', unclosed: true } ] }, { message: 'should process quoted strings', fixture: '"string"', expected: [ { type: 'string', sourceIndex: 0, value: 'string', quote: '"' } ] }, { message: 'should process quoted strings and words', fixture: 'word1"string"word2', expected: [ { type: 'word', sourceIndex: 0, value: 'word1' }, { type: 'string', sourceIndex: 5, value: 'string', quote: '"' }, { type: 'word', sourceIndex: 13, value: 'word2' } ] }, { message: 'should process quoted strings and spaces', fixture: ' "string" ', expected: [ { type: 'space', sourceIndex: 0, value: ' ' }, { type: 'string', sourceIndex: 1, value: 'string', quote: '"' }, { type: 'space', sourceIndex: 9, value: ' ' } ] }, { message: 'should process escaped symbols as words', fixture: ' \\"word\\\'\\ \\\t ', expected: [ { type: 'space', sourceIndex: 0, value: ' ' }, { type: 'word', sourceIndex: 1, value: '\\"word\\\'\\ \\\t' }, { type: 'space', sourceIndex: 13, value: ' ' } ] }, { message: 'should correctly proceess font value', fixture: 'bold italic 12px \t /3 \'Open Sans\', Arial, "Helvetica Neue", sans-serif', expected: [ { type: 'word', sourceIndex: 0, value: 'bold' }, { type: 'space', sourceIndex: 4, value: ' ' }, { type: 'word', sourceIndex: 5, value: 'italic' }, { type: 'space', sourceIndex: 11, value: ' ' }, { type: 'word', sourceIndex: 12, value: '12px' }, { type: 'div', sourceIndex: 16, value: '/', before: ' \t ', after: '' }, { type: 'word', sourceIndex: 20, value: '3' }, { type: 'space', sourceIndex: 21, value: ' ' }, { type: 'string', sourceIndex: 22, value: 'Open Sans', quote: '\'' }, { type: 'div', sourceIndex: 33, value: ',', before: '', after: ' ' }, { type: 'word', sourceIndex: 35, value: 'Arial' }, { type: 'div', sourceIndex: 40, value: ',', before: '', after: ' ' }, { type: 'string', sourceIndex: 42, value: 'Helvetica Neue', quote: '"' }, { type: 'div', sourceIndex: 58, value: ',', before: '', after: ' ' }, { type: 'word', sourceIndex: 60, value: 'sans-serif' } ] }, { message: 'should correctly proceess color value', fixture: 'rgba( 29, 439 , 29 )', expected: [ { type: 'function', sourceIndex: 0, value: 'rgba', before: ' ', after: ' ', nodes: [ { type: 'word', sourceIndex: 6, value: '29' }, { type: 'div', sourceIndex: 8, value: ',', before: '', after: ' ' }, { type: 'word', sourceIndex: 10, value: '439' }, { type: 'div', sourceIndex: 13, value: ',', before: ' ', after: ' ' }, { type: 'word', sourceIndex: 16, value: '29' } ] } ] }, { message: 'should correctly process url function', fixture: 'url( /gfx/img/bg.jpg )', expected: [ { type: 'function', sourceIndex: 0, value: 'url', before: ' ', after: ' ', nodes: [ { type: 'word', sourceIndex: 5, value: '/gfx/img/bg.jpg' } ] } ] }, { message: 'should add unclosed: true prop for url function', fixture: 'url( /gfx/img/bg.jpg ', expected: [ { type: 'function', sourceIndex: 0, value: 'url', before: ' ', after: '', unclosed: true, nodes: [ { type: 'word', sourceIndex: 5, value: '/gfx/img/bg.jpg' }, { type: 'space', sourceIndex: 20, value: ' ' } ] } ] }, { message: 'should correctly process url function with quoted first argument', fixture: 'url( "/gfx/img/bg.jpg" hello )', expected: [ { type: 'function', sourceIndex: 0, value: 'url', before: ' ', after: ' ', nodes: [ { type: 'string', sourceIndex: 5, quote: '"', value: '/gfx/img/bg.jpg' }, { type: 'space', sourceIndex: 22, value: ' ' }, { type: 'word', sourceIndex: 23, value: 'hello' } ] } ] }, { message: 'should correctly process nested calc functions', fixture: 'calc(((768px - 100vw) / 2) - 15px)', expected: [ { type: 'function', sourceIndex: 0, value: 'calc', before: '', after: '', nodes: [ { type: 'function', sourceIndex: 5, value: '', before: '', after: '', nodes: [ { type: 'function', sourceIndex: 6, value: '', before: '', after: '', nodes: [ { type: 'word', sourceIndex: 7, value: '768px' }, { type: 'space', sourceIndex: 12, value: ' ' }, { type: 'word', sourceIndex: 13, value: '-' }, { type: 'space', sourceIndex: 14, value: ' ' }, { type: 'word', sourceIndex: 15, value: '100vw' } ] }, { type: 'div', sourceIndex: 21, value: '/', before: ' ', after: ' ' }, { type: 'word', sourceIndex: 24, value: '2' } ] }, { type: 'space', sourceIndex: 26, value: ' ' }, { type: 'word', sourceIndex: 27, value: '-' }, { type: 'space', sourceIndex: 28, value: ' ' }, { type: 'word', sourceIndex: 29, value: '15px' } ] } ] }, { message: 'should process colons with params', fixture: '(min-width: 700px) and (orientation: \\$landscape)', expected: [ { type: 'function', sourceIndex: 0, value: '', before: '', after: '', nodes: [ { type: 'word', sourceIndex: 1, value: 'min-width' }, { type: 'div', sourceIndex: 10, value: ':', before: '', after: ' ' }, { type: 'word', sourceIndex: 12, value: '700px' } ] }, { type: 'space', sourceIndex: 18, value: ' ' }, { type: 'word', sourceIndex: 19, value: 'and' }, { type: 'space', sourceIndex: 22, value: ' ' }, { type: 'function', sourceIndex: 23, value: '', before: '', after: '', nodes: [ { type: 'word', sourceIndex: 24, value: 'orientation' }, { type: 'div', sourceIndex: 35, value: ':', before: '', after: ' ' }, { type: 'word', sourceIndex: 37, value: '\\$landscape' } ] } ] }, { message: 'should escape parentheses with backslash', fixture: 'url( http://website.com/assets\\)_test )', expected: [ { type: 'function', sourceIndex: 0, value: 'url', before: ' ', after: ' ', nodes: [ { type: 'word', sourceIndex: 5, value: 'http://website.com/assets\\)_test' } ] } ] }, { message: 'should parse parentheses correctly', fixture: 'fn1(fn2(255), fn3(.2)), fn4(fn5(255,.2), fn6)', expected: [ { type: 'function', sourceIndex: 0, value: 'fn1', before: '', after: '', nodes: [ { type: 'function', sourceIndex: 4, value: 'fn2', before: '', after: '', nodes: [ { type: 'word', sourceIndex: 8, value: '255' } ] }, { type: 'div', sourceIndex: 12, value: ',', before: '', after: ' ' }, { type: 'function', sourceIndex: 14, value: 'fn3', before: '', after: '', nodes: [ { type: 'word', sourceIndex: 18, value: '.2' } ] } ] }, { type: 'div', sourceIndex: 22, value: ',', before: '', after: ' ' }, { type: 'function', sourceIndex: 24, value: 'fn4', before: '', after: '', nodes: [ { type: 'function', sourceIndex: 28, value: 'fn5', before: '', after: '', nodes: [ { type: 'word', sourceIndex: 32, value: '255' }, { type: 'div', sourceIndex: 35, value: ',', before: '', after: '' }, { type: 'word', sourceIndex: 36, value: '.2' } ] }, { type: 'div', sourceIndex: 39, value: ',', before: '', after: ' ' }, { type: 'word', sourceIndex: 41, value: 'fn6' } ] } ] }, { message: 'shouldn\'t throw an error on unclosed function', fixture: '(0 32 word ', expected: [ { type: 'function', sourceIndex: 0, value: '', before: '', after: '', unclosed: true, nodes: [ { type: 'word', sourceIndex: 1, value: '0' }, { type: 'space', sourceIndex: 2, value: ' ' }, { type: 'word', sourceIndex: 3, value: '32' }, { type: 'space', sourceIndex: 5, value: ' ' }, { type: 'word', sourceIndex: 6, value: 'word' }, { type: 'space', sourceIndex: 10, value: ' ' } ] } ] }, { message: 'should add unclosed: true prop for every unclosed function', fixture: '( ( ( ) ', expected: [ { type: 'function', sourceIndex: 0, value: '', before: ' ', after: '', unclosed: true, nodes: [ { type: 'function', sourceIndex: 2, value: '', before: ' ', after: '', unclosed: true, nodes: [ { type: 'function', sourceIndex: 4, value: '', before: ' ', after: '', nodes: [] }, { type: 'space', sourceIndex: 7, value: ' ' } ] } ] } ] }, { message: 'shouldn\'t throw an error on unopened function', fixture: '0 32 word ) ', expected: [ { type: 'word', sourceIndex: 0, value: '0' }, { type: 'space', sourceIndex: 1, value: ' ' }, { type: 'word', sourceIndex: 2, value: '32' }, { type: 'space', sourceIndex: 4, value: ' ' }, { type: 'word', sourceIndex: 5, value: 'word' }, { type: 'space', sourceIndex: 9, value: ' ' }, { type: 'word', sourceIndex: 10, value: ')' }, { type: 'space', sourceIndex: 11, value: ' ' } ] }, { message: 'should process escaped spaces as word in fonts', fixture: 'Bond\\ 007', expected: [ { type: 'word', sourceIndex: 0, value: 'Bond\\ 007' } ] }, { message: 'should parse double url and comma', fixture: 'url(foo/bar.jpg), url(http://website.com/img.jpg)', expected: [ { type: 'function', sourceIndex: 0, value: 'url', before: '', after: '', nodes: [ { type: 'word', sourceIndex: 4, value: 'foo/bar.jpg' } ] }, { type: 'div', sourceIndex: 16, value: ',', before: '', after: ' ' }, { type: 'function', sourceIndex: 18, value: 'url', before: '', after: '', nodes: [ { type: 'word', sourceIndex: 22, value: 'http://website.com/img.jpg' } ] } ] }, { message: 'should parse empty url', fixture: 'url()', expected: [ { type: 'function', sourceIndex: 0, value: 'url', before: '', after: '', nodes: [] } ] }, { message: 'should parse comments', fixture: '/*before*/ 1px /*between*/ 1px /*after*/', expected: [ { type: 'comment', sourceIndex: 0, value: 'before' }, { type: 'space', sourceIndex: 10, value: ' ' }, { type: 'word', sourceIndex: 11, value: '1px' }, { type: 'space', sourceIndex: 14, value: ' ' }, { type: 'comment', sourceIndex: 15, value: 'between' }, { type: 'space', sourceIndex: 26, value: ' ' }, { type: 'word', sourceIndex: 27, value: '1px' }, { type: 'space', sourceIndex: 30, value: ' ' }, { type: 'comment', sourceIndex: 31, value: 'after' } ] }, { message: 'should parse comments inside functions', fixture: 'rgba( 0, 55/55, 0/*,.5*/ )', expected: [ { type: 'function', sourceIndex: 0, value: 'rgba', before: ' ', after: ' ', nodes: [ { type: 'word', sourceIndex: 6, value: '0' }, { type: 'div', sourceIndex: 7, value: ',', before:'', after: ' ' }, { type: 'word', sourceIndex: 9, value: '55' }, { type: 'div', sourceIndex: 11, value: '/', before:'', after: '' }, { type: 'word', sourceIndex: 12, value: '55' }, { type: 'div', sourceIndex: 14, value: ',', before:'', after: ' ' }, { type: 'word', sourceIndex: 16, value: '0' }, { type: 'comment', sourceIndex: 17, value: ',.5' } ] } ] }, { message: 'should parse comments at the end of url functions with quoted first argument', fixture: 'url( "/demo/bg.png" /*comment*/ )', expected: [ { type: 'function', sourceIndex: 0, value: 'url', before: ' ', after: ' ', nodes: [ { type: 'string', sourceIndex: 5, value: '/demo/bg.png', quote:'"' }, { type: 'space', sourceIndex: 19, value: ' ' }, { type: 'comment', sourceIndex: 20, value: 'comment' } ] } ] }, { message: 'should not parse comments at the start of url function with unquoted first argument', fixture: 'url( /*comment*/ /demo/bg.png )', expected: [ { type: 'function', sourceIndex: 0, value: 'url', before: ' ', after: ' ', nodes: [ { type: 'word', sourceIndex: 5, value: '/*comment*/ /demo/bg.png' } ] } ] }, { message: 'should not parse comments at the end of url function with unquoted first argument', fixture: 'url( /demo/bg.png /*comment*/ )', expected: [ { type: 'function', sourceIndex: 0, value: 'url', before: ' ', after: ' ', nodes: [ { type: 'word', sourceIndex: 5, value: '/demo/bg.png /*comment*/' } ] } ] }, { message: 'should parse unclosed comments', fixture: '/*comment*/ 1px /* unclosed ', expected: [ { type: 'comment', sourceIndex: 0, value: 'comment' }, { type: 'space', sourceIndex: 11, value: ' ' }, { type: 'word', sourceIndex: 12, value: '1px' }, { type: 'space', sourceIndex: 15, value: ' ' }, { type: 'comment', sourceIndex: 16, value: ' unclosed ', unclosed:true } ] }]; test('Parse', function (t) { t.plan(tests.length); tests.forEach(function (opts) { t.deepEqual(parse(opts.fixture), opts.expected, opts.message); }); }); postcss-value-parser-3.3.0/test/stringify.js000066400000000000000000000042331266140104000211460ustar00rootroot00000000000000var test = require('tape'); var parse = require('../lib/parse'); var stringify = require('../lib/stringify'); var tests = [ { message: 'Should correctly add quotes', fixture: 'bold italic 12px/3 \'Open Sans\', Arial, "Helvetica Neue", sans-serif' }, { message: 'Should not close unclosed strings', fixture: '" 12, 54, 65 ' }, { message: 'Should correctly add brackets', fixture: ' rgba( 12, 54, 65) ' }, { message: 'Should not close unclosed functions', fixture: ' rgba( 12, 54, 65 ' }, { message: 'Should correctly process advanced gradients', fixture: 'background-image:linear-gradient(45deg,transparent 25%,hsla(0,0%,100%,.2) 25%,hsla(0,0%,100%,.2) 75%,transparent 75%,transparent 25%,hsla(0,0%,100%,.2) 75%,transparent 75%,transparent),linear-gradient(45deg,transparent 25%,hsla(0,0%,100%,.2))' }, { message: 'Should correctly add comments', fixture: '/*comment*/ 1px /* unclosed ' }, { message: 'Should correctly process comments inside functions', fixture: '/*before*/ rgb( /*red component*/ 12, 54 /*green component*/, /* blue */ 65)/* after */ ' } ]; test('Stringify', function (t) { t.plan(tests.length + 3); tests.forEach(function (opts) { t.equal(stringify(parse(opts.fixture)), opts.fixture, opts.message); }); var tokens = parse(' rgba(12, 54, 65 ) '); t.equal(stringify(tokens, function (node) { if (node.type === 'function') { return node.value + '[' + [ node.nodes[0].value, node.nodes[2].value, node.nodes[4].value ].join(',') + ']'; } }), ' rgba[12,54,65] '); t.equal(stringify(tokens[1], function (node) { if (node.type === 'function') { return node.value + '[' + [ node.nodes[0].value, node.nodes[2].value, node.nodes[4].value ].join(',') + ']'; } }), 'rgba[12,54,65]'); tokens[1].type = 'word'; t.equal(stringify(tokens), ' rgba ', 'Shouldn\'t process nodes of work type'); }); postcss-value-parser-3.3.0/test/unit.js000066400000000000000000000013201266140104000201010ustar00rootroot00000000000000var test = require('tape'); var unit = require('../lib/unit'); var tests = [{ fixture: '.23rem', expected: { number: '.23', unit: 'rem' } }, { fixture: '.2.3rem', expected: { number: '.2', unit: '.3rem' } }, { fixture: '2.', expected: { number: '2.', unit: '' } }, { fixture: '+2.', expected: { number: '+2.', unit: '' } }, { fixture: '-2.', expected: { number: '-2.', unit: '' } }, { fixture: '+-2.', expected: false }, { fixture: '.', expected: false }, { fixture: '.rem', expected: false }]; test('Unit', function (t) { t.plan(tests.length); tests.forEach(function (item) { t.deepEqual(unit(item.fixture), item.expected); }); });