mirror of
https://github.com/idanoo/GoScrobble
synced 2025-07-01 05:32:18 +00:00
0.2.0 - Mid migration
This commit is contained in:
parent
139e6a915e
commit
7e38fdbd7d
42393 changed files with 5358157 additions and 62 deletions
36
web/node_modules/postcss-values-parser/.github/ISSUE_TEMPLATE.md
generated
vendored
Normal file
36
web/node_modules/postcss-values-parser/.github/ISSUE_TEMPLATE.md
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
<!--
|
||||
Please note: This template is *not* optional. Please fill in all fields and
|
||||
questions, otherwise *the issue may be closed*. Please provide actual technical
|
||||
information about errors, if an error has occurred.
|
||||
-->
|
||||
|
||||
* Node Version:
|
||||
* NPM Version:
|
||||
* postcss-values-parser Version:
|
||||
|
||||
This issue is regarding a problem with:
|
||||
- [ ] Standard CSS
|
||||
- [ ] LESS
|
||||
- [ ] SCSS
|
||||
- [ ] SASS
|
||||
|
||||
If you have a large amount of code to share which demonstrates the problem you're experiencing, please provide a link to your
|
||||
repository rather than pasting code. Otherwise, please paste relevant short snippets below.
|
||||
|
||||
```css
|
||||
// offending or problematic css
|
||||
```
|
||||
|
||||
```js
|
||||
// any js you'd like to add. this section can be removed if none
|
||||
```
|
||||
|
||||
```
|
||||
// actual error output, if error was thrown
|
||||
```
|
||||
|
||||
### Expected Behavior
|
||||
|
||||
### Actual Behavior
|
||||
|
||||
### How can we reproduce the behavior?
|
14
web/node_modules/postcss-values-parser/.github/PULL_REQUEST_TEMPLATE.md
generated
vendored
Normal file
14
web/node_modules/postcss-values-parser/.github/PULL_REQUEST_TEMPLATE.md
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
<!-- This template is *not* optional. If you remove this template or choose
|
||||
not to complete it, your PR may be closed without review -->
|
||||
|
||||
**Which issue #** if any, does this resolve?
|
||||
|
||||
<!-- PRs must be accompanied by related tests -->
|
||||
|
||||
Please check one:
|
||||
- [ ] New tests created for this change
|
||||
- [ ] Tests updated for this change
|
||||
|
||||
---
|
||||
|
||||
<!-- add additional comments here -->
|
585
web/node_modules/postcss-values-parser/API.md
generated
vendored
Normal file
585
web/node_modules/postcss-values-parser/API.md
generated
vendored
Normal file
|
@ -0,0 +1,585 @@
|
|||
# API Documentation
|
||||
|
||||
*Please use only this documented API when working with the parser. Methods
|
||||
not documented here are subject to change at any point.*
|
||||
|
||||
<!-- toc -->
|
||||
|
||||
- [`parser` function](#parser-function)
|
||||
* [`parser.atword([props])`](#parseratwordprops)
|
||||
* [`parser.colon([props])`](#parsercolonprops)
|
||||
* [`parser.comma([props])`](#parsercommaprops)
|
||||
* [`parser.comment([props])`](#parsercommentprops)
|
||||
* [`parser.func([props])`](#parserfuncprops)
|
||||
* [`parser.number([props])`](#parsernumberprops)
|
||||
* [`parser.operator([props])`](#parseroperatorprops)
|
||||
* [`parser.paren([props])`](#parserparenprops)
|
||||
* [`parser.string([props])`](#parserstringprops)
|
||||
* [`parser.value([props])`](#parservalueprops)
|
||||
* [`parser.word([props])`](#parserwordprops)
|
||||
* [`parser.unicodeRange([props])`](#parserunicoderangeprops)
|
||||
- [Node types](#node-types)
|
||||
* [`node.type`](#nodetype)
|
||||
* [`node.parent`](#nodeparent)
|
||||
* [`node.toString()`, `String(node)`, or `'' + node`](#nodetostring-stringnode-or---node)
|
||||
* [`node.next()` & `node.prev()`](#nodenext--nodeprev)
|
||||
* [`node.replaceWith(node)`](#nodereplacewithnode)
|
||||
* [`node.remove()`](#noderemove)
|
||||
* [`node.clone()`](#nodeclone)
|
||||
* [`node.raws`](#noderaws)
|
||||
* [`node.source`](#nodesource)
|
||||
* [`node.sourceIndex`](#nodesourceindex)
|
||||
- [Container types](#container-types)
|
||||
* [`container.nodes`](#containernodes)
|
||||
* [`container.first` & `container.last`](#containerfirst--containerlast)
|
||||
* [`container.at(index)`](#containeratindex)
|
||||
* [`container.index(node)`](#containerindexnode)
|
||||
* [`container.length`](#containerlength)
|
||||
* [`container.each(callback)`](#containereachcallback)
|
||||
* [`container.walk(callback)`](#containerwalkcallback)
|
||||
* [`container.walk` proxies](#containerwalk-proxies)
|
||||
* [`container.prepend(node)` & `container.append(node)`](#containerprependnode--containerappendnode)
|
||||
* [`container.insertBefore(old, new)` & `container.insertAfter(old, new)`](#containerinsertbeforeold-new--containerinsertafterold-new)
|
||||
* [`container.removeChild(node)`](#containerremovechildnode)
|
||||
* [`container.removeAll()` or `container.empty()`](#containerremoveall-or-containerempty)
|
||||
- [Root nodes`](#root-nodes)
|
||||
- [Value nodes](#value-nodes)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
## `parser` function
|
||||
|
||||
This is the module's main entry point, and returns a `new Parser`.
|
||||
|
||||
```js
|
||||
let parser = require('postcss-values-parser');
|
||||
|
||||
let ast = parser(source) // tokenizes the source string
|
||||
.parse(); // parses the tokens and returns an AST
|
||||
```
|
||||
|
||||
### `parser.atword([props])`
|
||||
|
||||
Creates a new AtWord value.
|
||||
|
||||
```js
|
||||
parser.atword({ value: '@foo' });
|
||||
// → @foo
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `props (object)`: The new node's properties.
|
||||
|
||||
### `parser.colon([props])`
|
||||
|
||||
Creates a new colon Node.
|
||||
|
||||
```js
|
||||
parser.colon({ value: ':' });
|
||||
// → :
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `props (object)`: The new node's properties. If no properties are specified,
|
||||
the default value of `:` will be used. It's not recommended to deviate from this.
|
||||
|
||||
### `parser.comma([props])`
|
||||
|
||||
Creates a new comma Node.
|
||||
|
||||
```js
|
||||
parser.comma({ value: ',' });
|
||||
// → ,
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `props (object)`: The new node's properties. If no properties are specified,
|
||||
the default value of `,` will be used. It's not recommended to deviate from this.
|
||||
|
||||
### `parser.comment([props])`
|
||||
|
||||
Creates a new comment.
|
||||
|
||||
```js
|
||||
parser.comment({ value: 'Affirmative, Dave. I read you.' });
|
||||
// → /* Affirmative, Dave. I read you. */
|
||||
```
|
||||
|
||||
```js
|
||||
parser.comment({ value: 'Affirmative, Dave. I read you.', inline: true });
|
||||
// → // Affirmative, Dave. I read you.
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `props (object)`: The new node's properties.
|
||||
|
||||
### `parser.func([props])`
|
||||
|
||||
Creates a new function value Container node.
|
||||
|
||||
```js
|
||||
let func = parser.func({ value: 'calc' });
|
||||
|
||||
func.append(parser.paren());
|
||||
func.append(parser.paren({ value: ')' }));
|
||||
|
||||
func.toString();
|
||||
// → calc()
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `props (object)`: The new node's properties.
|
||||
|
||||
### `parser.number([props])`
|
||||
|
||||
Creates a new number Node.
|
||||
|
||||
```js
|
||||
parser.number({ value: 10, unit: 'px' });
|
||||
// → 10px
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `props (object)`: The new node's properties.
|
||||
|
||||
### `parser.operator([props])`
|
||||
|
||||
Creates a new operator Node.
|
||||
|
||||
```js
|
||||
parser.operator({ value: '+' });
|
||||
// → +
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `props (object)`: The new node's properties.
|
||||
|
||||
### `parser.paren([props])`
|
||||
|
||||
Creates a new parenthesis Node.
|
||||
|
||||
```js
|
||||
parser.paren();
|
||||
// → (
|
||||
|
||||
parser.paren({ value: ')' });
|
||||
// → )
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `props (object)`: The new node's properties. If no value is specified, the
|
||||
default value of `(` will be used.
|
||||
|
||||
### `parser.string([props])`
|
||||
|
||||
Creates a new string node.
|
||||
|
||||
```js
|
||||
parser.string();
|
||||
// → (empty)
|
||||
|
||||
parser.string({ value: 'hello', quote: '"' });
|
||||
// → "hello"
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `props (object)`: The new node's properties. Note: If no `quote` property is
|
||||
specified, the default value of `'` will be used.
|
||||
|
||||
### `parser.value([props])`
|
||||
|
||||
Creates a new value Node. This node acts as the container for all values within
|
||||
the Root node, but can be created for convenience.
|
||||
|
||||
### `parser.word([props])`
|
||||
|
||||
Creates a new word Node. A `Word` is anything that doesn't fall into one of the
|
||||
other node types.
|
||||
|
||||
```js
|
||||
let word = parser.word({ value: '#fff' });
|
||||
// → #fff
|
||||
|
||||
word.isHex;
|
||||
// → true
|
||||
|
||||
word.isColor;
|
||||
// → true
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `props (object)`: The new node's properties.
|
||||
|
||||
### `parser.unicodeRange([props])`
|
||||
|
||||
Creates a new unicode range Node.
|
||||
|
||||
```js
|
||||
parser.unicodeRange({ value: 'U+26' });
|
||||
// → U+26
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `props (object)`: The new node's properties.
|
||||
|
||||
## Node types
|
||||
|
||||
### `node.type`
|
||||
|
||||
A string representation of the node type. It can be one of the following;
|
||||
`atword`, `colon`, `comma`, `comment`, `func`, `number`, `operator`,
|
||||
`paren`, `string`, `unicoderange`, `value`, `word`.
|
||||
|
||||
```js
|
||||
parser.word({ value: '#fff' }).type;
|
||||
// → 'word'
|
||||
```
|
||||
|
||||
### `node.parent`
|
||||
|
||||
Returns the parent node.
|
||||
|
||||
```js
|
||||
root.nodes[0].parent === root;
|
||||
```
|
||||
|
||||
### `node.toString()`, `String(node)`, or `'' + node`
|
||||
|
||||
Returns a string representation of the node.
|
||||
|
||||
```js
|
||||
let color = parser.word({ value: '#fff' });
|
||||
console.log(String(color));
|
||||
// → #fff
|
||||
```
|
||||
|
||||
### `node.next()` & `node.prev()`
|
||||
|
||||
Returns the next/previous child of the parent node.
|
||||
|
||||
```js
|
||||
let next = func.next();
|
||||
if (next && next.type !== 'paren') {
|
||||
throw new Error('Unclosed function parenthesis!');
|
||||
}
|
||||
```
|
||||
|
||||
### `node.replaceWith(node)`
|
||||
|
||||
Replace a node with another.
|
||||
|
||||
```js
|
||||
let ast = parser('#fff').parse();
|
||||
let word = ast.first.first;
|
||||
let atword = parser.atword({ value: '@purple' });
|
||||
|
||||
word.replaceWith(atword);
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `node`: The node to substitute the original with.
|
||||
|
||||
### `node.remove()`
|
||||
|
||||
Removes the node from its parent node.
|
||||
|
||||
```js
|
||||
if (node.type === 'word') {
|
||||
node.remove();
|
||||
}
|
||||
```
|
||||
|
||||
### `node.clone()`
|
||||
|
||||
Returns a copy of a node, detached from any parent containers that the
|
||||
original might have had.
|
||||
|
||||
```js
|
||||
let word = parser.word({ value: '#fff' });
|
||||
let cloned = word.clone();
|
||||
|
||||
cloned.value = '#fff';
|
||||
String(cloned);
|
||||
// → #000
|
||||
|
||||
String(word);
|
||||
// → #fff
|
||||
```
|
||||
|
||||
### `node.raws`
|
||||
|
||||
Extra whitespaces around the node will be assigned to `node.raws.before` and
|
||||
`node.raws.after`. Spaces in this context have no semantic meaning, but may
|
||||
be useful for inspection:
|
||||
|
||||
```css
|
||||
1px solid black
|
||||
```
|
||||
|
||||
Any space following a node/segement is assigned to the next node's
|
||||
`raws.before` property, unless the node with the trailing space is the only
|
||||
node in the set.
|
||||
|
||||
```js
|
||||
let source = 'calc(something about mary)';
|
||||
let ast = parser(source).parse();
|
||||
let func = ast.first.first;
|
||||
|
||||
let something = func.first.next();
|
||||
let about = something.next();
|
||||
|
||||
something.raws.after;
|
||||
// → (empty)
|
||||
|
||||
about.raws.before;
|
||||
// → ' '
|
||||
```
|
||||
|
||||
Additionally, any space remaining after the last node in a
|
||||
set will be assigned to the last non-symbol child's `raws.after` property.
|
||||
For example:
|
||||
|
||||
```js
|
||||
let source = 'calc(something )';
|
||||
let ast = parser(source).parse();
|
||||
let func = ast.first.first;
|
||||
|
||||
let something = func.first.next();
|
||||
something.raws.after;
|
||||
// → ' '
|
||||
```
|
||||
|
||||
### `node.source`
|
||||
|
||||
An object describing the node's start/end, line/column source position.
|
||||
|
||||
Within the following CSS, the `.bar` class node ...
|
||||
|
||||
```css
|
||||
.foo,
|
||||
.bar {}
|
||||
```
|
||||
|
||||
... will contain the following `source` object.
|
||||
|
||||
```js
|
||||
source: {
|
||||
start: {
|
||||
line: 2,
|
||||
column: 3
|
||||
},
|
||||
end: {
|
||||
line: 2,
|
||||
column: 6
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `node.sourceIndex`
|
||||
|
||||
The zero-based index of the node within the original source string.
|
||||
|
||||
Within the following CSS, the `.baz` class node will have a `sourceIndex` of `12`.
|
||||
|
||||
```css
|
||||
.foo, .bar, .baz {}
|
||||
```
|
||||
|
||||
## Container types
|
||||
|
||||
The `root`, `node`, and `pseudo` nodes have some helper methods for working
|
||||
with their children.
|
||||
|
||||
### `container.nodes`
|
||||
|
||||
An array of the container's children.
|
||||
|
||||
```js
|
||||
// Input: h1 h2
|
||||
nodes.at(0).nodes.length // → 3
|
||||
nodes.at(0).nodes[0].value // → 'h1'
|
||||
nodes.at(0).nodes[1].value // → ' '
|
||||
```
|
||||
|
||||
### `container.first` & `container.last`
|
||||
|
||||
The first/last child of the container.
|
||||
|
||||
```js
|
||||
node.first === node.nodes[0];
|
||||
node.last === node.nodes[node.nodes.length - 1];
|
||||
```
|
||||
|
||||
### `container.at(index)`
|
||||
|
||||
Returns the node at position `index`.
|
||||
|
||||
```js
|
||||
node.at(0) === node.first;
|
||||
node.at(0) === node.nodes[0];
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `index`: The index of the node to return.
|
||||
|
||||
### `container.index(node)`
|
||||
|
||||
Return the index of the node within its container.
|
||||
|
||||
```js
|
||||
node.index(node.nodes[2]) // → 2
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `node`: A node within the current container.
|
||||
|
||||
### `container.length`
|
||||
|
||||
Proxy to the length of the container's nodes.
|
||||
|
||||
```js
|
||||
container.length === container.nodes.length
|
||||
```
|
||||
|
||||
### `container.each(callback)`
|
||||
|
||||
Iterate the container's immediate children, calling `callback` for each child.
|
||||
You may return `false` within the callback to break the iteration.
|
||||
|
||||
```js
|
||||
let className;
|
||||
nodes.each(function (node, index) {
|
||||
if (node.type === 'class') {
|
||||
className = node.value;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Note that unlike `Array#forEach()`, this iterator is safe to use whilst adding
|
||||
or removing nodes from the container.
|
||||
|
||||
Arguments:
|
||||
|
||||
* `callback (function)`: A function to call for each node, which receives `node`
|
||||
and `index` arguments.
|
||||
|
||||
### `container.walk(callback)`
|
||||
|
||||
Like `container#each`, but will also iterate child nodes as long as they are
|
||||
`container` types.
|
||||
|
||||
```js
|
||||
nodes.walk(function (node, index) {
|
||||
// all nodes
|
||||
});
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `callback (function)`: A function to call for each node, which receives `node`
|
||||
and `index` arguments.
|
||||
|
||||
This iterator is safe to use whilst mutating `container.nodes`,
|
||||
like `container#each`.
|
||||
|
||||
### `container.walk` proxies
|
||||
|
||||
The container class provides proxy methods for iterating over types of nodes,
|
||||
so that it is easier to write modules that target specific nodes. Those
|
||||
methods are:
|
||||
|
||||
* `container.walkAtWords`
|
||||
* `container.walkColons`
|
||||
* `container.walkCommas`
|
||||
* `container.walkComments`
|
||||
* `container.walkFunctionNodes`
|
||||
* `container.walkNumberNodes`
|
||||
* `container.walkOperators`
|
||||
* `container.walkParenthesis`
|
||||
* `container.walkStringNodes`
|
||||
* `container.walkUnicodeRanges`
|
||||
* `container.walkWords`
|
||||
|
||||
### `container.prepend(node)` & `container.append(node)`
|
||||
|
||||
Add a node to the start/end of the container. Note that doing so will set
|
||||
the parent property of the node to this container.
|
||||
|
||||
```js
|
||||
let color = parser.word({ value: '#fff' });
|
||||
node.append(color);
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `node`: The node to add.
|
||||
|
||||
### `container.insertBefore(old, new)` & `container.insertAfter(old, new)`
|
||||
|
||||
Add a node before or after an existing node in a container:
|
||||
|
||||
```js
|
||||
nodes.walk(function (node) {
|
||||
if (node.type !== 'word') {
|
||||
let colon = parser.colon();
|
||||
node.parent.insertAfter(node, colon);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `old`: The existing node in the container.
|
||||
* `new`: The new node to add before/after the existing node.
|
||||
|
||||
### `container.removeChild(node)`
|
||||
|
||||
Remove the node from the container. Note that you can also use
|
||||
`node.remove()` if you would like to remove just a single node.
|
||||
|
||||
```js
|
||||
node.length // → 2
|
||||
node.remove(word)
|
||||
node.length // → 1;
|
||||
word.parent // undefined
|
||||
```
|
||||
|
||||
Arguments:
|
||||
|
||||
* `node`: The node to remove.
|
||||
|
||||
### `container.removeAll()` or `container.empty()`
|
||||
|
||||
Remove all children from the container.
|
||||
|
||||
```js
|
||||
node.removeAll();
|
||||
node.length // → 0
|
||||
```
|
||||
|
||||
## Root nodes`
|
||||
|
||||
A root node represents the top-level Container for Value nodes. Indeed, all
|
||||
a root's `toString()` method does is join its node children with a ','.
|
||||
Other than this, it has no special functionality and acts like a container.
|
||||
|
||||
## Value nodes
|
||||
|
||||
A Value node represents a single compound node. For example, this
|
||||
node string `1px solid black`, is represented as three distinct nodes.
|
||||
It has no special functionality of its own.
|
22
web/node_modules/postcss-values-parser/LICENSE
generated
vendored
Normal file
22
web/node_modules/postcss-values-parser/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
Copyright (c) Andrew Powell <andrew@shellscape.org>
|
||||
|
||||
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.
|
110
web/node_modules/postcss-values-parser/README.md
generated
vendored
Normal file
110
web/node_modules/postcss-values-parser/README.md
generated
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
# postcss-values-parser [](https://travis-ci.org/shellscape/postcss-values-parser)
|
||||
|
||||
<img align="right" width="95" height="95"
|
||||
title="Philosopher’s stone, logo of PostCSS"
|
||||
src="http://postcss.github.io/postcss/logo.svg">
|
||||
|
||||
A CSS property value parser for use with [PostCSS](https://github.com/postcss/postcss),
|
||||
following the same node, container, and traversal patterns as PostCSS.
|
||||
|
||||
##
|
||||
<p align="center">
|
||||
<b>:rocket: Are you ready to tackle ES6 and hone your JavaScript Skills?</b> :rocket:<br/>
|
||||
Check out these outstanding <a href="https://es6.io/">ES6 courses</a> by <a href="https://github.com/wesbos">@wesbos</a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
As with PostCSS and postcss-selector-parser, this parser generates an
|
||||
[Abstract Syntax Tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree),
|
||||
(aka "AST") which allows for ease of traversal and granular inspection of each
|
||||
part of a property's value.
|
||||
|
||||
## postcss-values-parser vs. postcss-value-parser
|
||||
|
||||
Yeah, it's a tad confusing. The [Lesshint](https://github.com/lesshint/lesshint)
|
||||
project needed a parser that would allow detailed inspection of property values
|
||||
to the same degree that PostCSS and [postcss-selector-parser](https://github.com/postcss/postcss-selector-parser)
|
||||
provided. This was especailly important for the Lesshint project, as it provides
|
||||
for very granular rules for linting LESS.
|
||||
|
||||
[postcss-value-parser](https://github.com/TrySound/postcss-value-parser)
|
||||
makes a lot of assumption about how values should be parsed and how the resulting
|
||||
AST should be organized. It was also fairly out of sync with the tokenzing and
|
||||
traversal patterns and convenience methods found in PostCSS and
|
||||
postcss-selector-parser.
|
||||
|
||||
So we needed an alternative, and drew upon all three projects to put together a
|
||||
value parser that met and exceeded our needs. The improvements include:
|
||||
|
||||
- Written using ES6
|
||||
- Uses the same Gulp toolchain as PostCSS
|
||||
- Doesn't strip characters; eg. parenthesis
|
||||
- Full AST traversal
|
||||
- AST traversal based on node type
|
||||
- Simple methods to derive strings from the parsed result
|
||||
- Follows PostCSS patterns for whitespace between Nodes
|
||||
- Provides convenience properties for number units, colors, etc.
|
||||
|
||||
## Usage
|
||||
|
||||
Please see the [API Documentation](API.md) for full usage information.
|
||||
|
||||
As with any NPM module, start with the install:
|
||||
|
||||
```
|
||||
npm install postcss-values-parser
|
||||
```
|
||||
|
||||
Using this parser is straightforward and doesn't require callbacks:
|
||||
|
||||
```js
|
||||
const parser = require('postcss-values-parser');
|
||||
const ast = parser('#fff').parse();
|
||||
|
||||
let color = ast // the Root node
|
||||
.first // the Value node
|
||||
.first; // a Word node, containing the color value.
|
||||
```
|
||||
|
||||
## Loose Mode
|
||||
|
||||
Loose mode was introduced to support adherence to the W3C CSS Specification as
|
||||
well as the ability to parse noncompliant CSS for variants like LESS, SCSS, and
|
||||
CSSNext. If you're working with a noncompliant or CSS-like variant, then loose
|
||||
mode is for you.
|
||||
|
||||
For example, the parser
|
||||
will throw an error by default if `calc` parameters [don't adhere to the spec](https://www.w3.org/TR/css-values/#calc-syntax).
|
||||
However, with loose mode enabled, the parse will ignore spec rules and succeed.
|
||||
|
||||
In-draft features, or CSS features in modules not yet finalized, often cause parser
|
||||
errors. eg. `url(var(--somevar))`. Loose mode supports parsing of these features.
|
||||
|
||||
Loose Mode is enabled by passing an option of `loose: true` to the `parser` method.
|
||||
|
||||
```js
|
||||
const less = 'calc(2+2)'; // not valid per spec, but valid in LESS
|
||||
const cssnext = 'url(var(--somevar))'; // not valid per spec, but in spec draft
|
||||
|
||||
const parser = require('postcss-values-parser');
|
||||
const ast = parser(less, { loose: true }).parse();
|
||||
|
||||
// parse will succeed
|
||||
```
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
This project was heavily influenced by [postcss-selector-parser](https://github.com/postcss/postcss-selector-parser)
|
||||
and utilized many patterns and logical constructs from the project.
|
||||
|
||||
Tests and some tokenizing techniques found in [postcss-value-parser](https://github.com/TrySound/postcss-value-parser)
|
||||
were used.
|
||||
|
||||
## Contributing
|
||||
|
||||
- `git fork/clone`
|
||||
- `npm i`
|
||||
- Before PR'ing, make sure `npm test` still pass. Add test if you're adding features.
|
||||
|
||||
When you tweak [API.md](API.md), please run `npm run toc` before PR'ing.
|
26
web/node_modules/postcss-values-parser/lib/atword.js
generated
vendored
Normal file
26
web/node_modules/postcss-values-parser/lib/atword.js
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
'use strict';
|
||||
|
||||
const Container = require('./container');
|
||||
|
||||
class AtWord extends Container {
|
||||
constructor (opts) {
|
||||
super(opts);
|
||||
this.type = 'atword';
|
||||
}
|
||||
|
||||
toString () {
|
||||
let quote = this.quoted ? this.raws.quote : '';
|
||||
return [
|
||||
this.raws.before,
|
||||
'@',
|
||||
// we can't use String() here because it'll try using itself
|
||||
// as the constructor
|
||||
String.prototype.toString.call(this.value),
|
||||
this.raws.after
|
||||
].join('');
|
||||
}
|
||||
}
|
||||
|
||||
Container.registerWalker(AtWord);
|
||||
|
||||
module.exports = AtWord;
|
15
web/node_modules/postcss-values-parser/lib/colon.js
generated
vendored
Normal file
15
web/node_modules/postcss-values-parser/lib/colon.js
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
'use strict';
|
||||
|
||||
const Container = require('./container');
|
||||
const Node = require('./node');
|
||||
|
||||
class Colon extends Node {
|
||||
constructor (opts) {
|
||||
super(opts);
|
||||
this.type = 'colon';
|
||||
}
|
||||
}
|
||||
|
||||
Container.registerWalker(Colon);
|
||||
|
||||
module.exports = Colon;
|
15
web/node_modules/postcss-values-parser/lib/comma.js
generated
vendored
Normal file
15
web/node_modules/postcss-values-parser/lib/comma.js
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
'use strict';
|
||||
|
||||
const Container = require('./container');
|
||||
const Node = require('./node');
|
||||
|
||||
class Comma extends Node {
|
||||
constructor (opts) {
|
||||
super(opts);
|
||||
this.type = 'comma';
|
||||
}
|
||||
}
|
||||
|
||||
Container.registerWalker(Comma);
|
||||
|
||||
module.exports = Comma;
|
26
web/node_modules/postcss-values-parser/lib/comment.js
generated
vendored
Normal file
26
web/node_modules/postcss-values-parser/lib/comment.js
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
'use strict';
|
||||
|
||||
const Container = require('./container');
|
||||
const Node = require('./node');
|
||||
|
||||
class Comment extends Node {
|
||||
constructor (opts) {
|
||||
super(opts);
|
||||
this.type = 'comment';
|
||||
this.inline = Object(opts).inline || false;
|
||||
}
|
||||
|
||||
toString () {
|
||||
return [
|
||||
this.raws.before,
|
||||
this.inline ? '//' : '/*',
|
||||
String(this.value),
|
||||
this.inline ? '' : '*/',
|
||||
this.raws.after
|
||||
].join('');
|
||||
}
|
||||
};
|
||||
|
||||
Container.registerWalker(Comment);
|
||||
|
||||
module.exports = Comment;
|
210
web/node_modules/postcss-values-parser/lib/container.js
generated
vendored
Normal file
210
web/node_modules/postcss-values-parser/lib/container.js
generated
vendored
Normal file
|
@ -0,0 +1,210 @@
|
|||
'use strict';
|
||||
|
||||
const Node = require('./node');
|
||||
|
||||
class Container extends Node {
|
||||
|
||||
constructor (opts) {
|
||||
super(opts);
|
||||
|
||||
if (!this.nodes) {
|
||||
this.nodes = [];
|
||||
}
|
||||
}
|
||||
|
||||
push (child) {
|
||||
child.parent = this;
|
||||
this.nodes.push(child);
|
||||
return this;
|
||||
}
|
||||
|
||||
each (callback) {
|
||||
if (!this.lastEach) this.lastEach = 0;
|
||||
if (!this.indexes) this.indexes = { };
|
||||
|
||||
this.lastEach += 1;
|
||||
|
||||
let id = this.lastEach,
|
||||
index,
|
||||
result;
|
||||
|
||||
this.indexes[id] = 0;
|
||||
|
||||
if (!this.nodes) return undefined;
|
||||
|
||||
while (this.indexes[id] < this.nodes.length) {
|
||||
index = this.indexes[id];
|
||||
result = callback(this.nodes[index], index);
|
||||
if (result === false) break;
|
||||
|
||||
this.indexes[id] += 1;
|
||||
}
|
||||
|
||||
delete this.indexes[id];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
walk (callback) {
|
||||
return this.each((child, i) => {
|
||||
let result = callback(child, i);
|
||||
if (result !== false && child.walk) {
|
||||
result = child.walk(callback);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
walkType (type, callback) {
|
||||
if (!type || !callback) {
|
||||
throw new Error('Parameters {type} and {callback} are required.');
|
||||
}
|
||||
|
||||
// allow users to pass a constructor, or node type string; eg. Word.
|
||||
const isTypeCallable = typeof type === 'function';
|
||||
|
||||
return this.walk((node, index) => {
|
||||
if (isTypeCallable && node instanceof type || !isTypeCallable && node.type === type) {
|
||||
return callback.call(this, node, index);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
append (node) {
|
||||
node.parent = this;
|
||||
this.nodes.push(node);
|
||||
return this;
|
||||
}
|
||||
|
||||
prepend (node) {
|
||||
node.parent = this;
|
||||
this.nodes.unshift(node);
|
||||
return this;
|
||||
}
|
||||
|
||||
cleanRaws (keepBetween) {
|
||||
super.cleanRaws(keepBetween);
|
||||
if (this.nodes) {
|
||||
for (let node of this.nodes) node.cleanRaws(keepBetween);
|
||||
}
|
||||
}
|
||||
|
||||
insertAfter (oldNode, newNode) {
|
||||
let oldIndex = this.index(oldNode),
|
||||
index;
|
||||
|
||||
this.nodes.splice(oldIndex + 1, 0, newNode);
|
||||
|
||||
for (let id in this.indexes) {
|
||||
index = this.indexes[id];
|
||||
if (oldIndex <= index) {
|
||||
this.indexes[id] = index + this.nodes.length;
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
insertBefore (oldNode, newNode) {
|
||||
let oldIndex = this.index(oldNode),
|
||||
index;
|
||||
|
||||
this.nodes.splice(oldIndex, 0, newNode);
|
||||
|
||||
for (let id in this.indexes) {
|
||||
index = this.indexes[id];
|
||||
if (oldIndex <= index) {
|
||||
this.indexes[id] = index + this.nodes.length;
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
removeChild (child) {
|
||||
child = this.index(child);
|
||||
this.nodes[child].parent = undefined;
|
||||
this.nodes.splice(child, 1);
|
||||
|
||||
let index;
|
||||
for (let id in this.indexes) {
|
||||
index = this.indexes[id];
|
||||
if (index >= child) {
|
||||
this.indexes[id] = index - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
removeAll () {
|
||||
for (let node of this.nodes) node.parent = undefined;
|
||||
this.nodes = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
every (condition) {
|
||||
return this.nodes.every(condition);
|
||||
}
|
||||
|
||||
some (condition) {
|
||||
return this.nodes.some(condition);
|
||||
}
|
||||
|
||||
index (child) {
|
||||
if (typeof child === 'number') {
|
||||
return child;
|
||||
}
|
||||
else {
|
||||
return this.nodes.indexOf(child);
|
||||
}
|
||||
}
|
||||
|
||||
get first () {
|
||||
if (!this.nodes) return undefined;
|
||||
return this.nodes[0];
|
||||
}
|
||||
|
||||
get last () {
|
||||
if (!this.nodes) return undefined;
|
||||
return this.nodes[this.nodes.length - 1];
|
||||
}
|
||||
|
||||
toString () {
|
||||
let result = this.nodes.map(String).join('');
|
||||
|
||||
if (this.value) {
|
||||
result = this.value + result;
|
||||
}
|
||||
|
||||
if (this.raws.before) {
|
||||
result = this.raws.before + result;
|
||||
}
|
||||
|
||||
if (this.raws.after) {
|
||||
result += this.raws.after;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Container.registerWalker = (constructor) => {
|
||||
let walkerName = 'walk' + constructor.name;
|
||||
|
||||
// plural sugar
|
||||
if (walkerName.lastIndexOf('s') !== walkerName.length - 1) {
|
||||
walkerName += 's';
|
||||
}
|
||||
|
||||
if (Container.prototype[walkerName]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we need access to `this` so we can't use an arrow function
|
||||
Container.prototype[walkerName] = function (callback) {
|
||||
return this.walkType(constructor, callback);
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = Container;
|
19
web/node_modules/postcss-values-parser/lib/errors/ParserError.js
generated
vendored
Normal file
19
web/node_modules/postcss-values-parser/lib/errors/ParserError.js
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
'use strict';
|
||||
|
||||
class ParserError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
|
||||
this.name = this.constructor.name;
|
||||
this.message = message || 'An error ocurred while parsing.';
|
||||
|
||||
if (typeof Error.captureStackTrace === 'function') {
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
}
|
||||
else {
|
||||
this.stack = (new Error(message)).stack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ParserError;
|
19
web/node_modules/postcss-values-parser/lib/errors/TokenizeError.js
generated
vendored
Normal file
19
web/node_modules/postcss-values-parser/lib/errors/TokenizeError.js
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
'use strict';
|
||||
|
||||
class TokenizeError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
|
||||
this.name = this.constructor.name;
|
||||
this.message = message || 'An error ocurred while tokzenizing.';
|
||||
|
||||
if (typeof Error.captureStackTrace === 'function') {
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
}
|
||||
else {
|
||||
this.stack = (new Error(message)).stack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TokenizeError;
|
16
web/node_modules/postcss-values-parser/lib/function.js
generated
vendored
Normal file
16
web/node_modules/postcss-values-parser/lib/function.js
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
'use strict';
|
||||
|
||||
const Container = require('./container');
|
||||
|
||||
class FunctionNode extends Container {
|
||||
constructor (opts) {
|
||||
super(opts);
|
||||
this.type = 'func';
|
||||
// start off at -1 so we know there haven't been any parens added
|
||||
this.unbalanced = -1;
|
||||
}
|
||||
};
|
||||
|
||||
Container.registerWalker(FunctionNode);
|
||||
|
||||
module.exports = FunctionNode;
|
69
web/node_modules/postcss-values-parser/lib/index.js
generated
vendored
Normal file
69
web/node_modules/postcss-values-parser/lib/index.js
generated
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
'use strict';
|
||||
|
||||
const Parser = require('./parser');
|
||||
const AtWord = require('./atword');
|
||||
const Colon = require('./colon');
|
||||
const Comma = require('./comma');
|
||||
const Comment = require('./comment');
|
||||
const Func = require('./function');
|
||||
const Num = require('./number');
|
||||
const Operator = require('./operator');
|
||||
const Paren = require('./paren');
|
||||
const Str = require('./string');
|
||||
const UnicodeRange = require('./unicode-range');
|
||||
const Value = require('./value');
|
||||
const Word = require('./word');
|
||||
|
||||
let parser = function (source, options) {
|
||||
return new Parser(source, options);
|
||||
};
|
||||
|
||||
parser.atword = function (opts) {
|
||||
return new AtWord(opts);
|
||||
};
|
||||
|
||||
parser.colon = function (opts) {
|
||||
return new Colon(Object.assign({ value: ':' }, opts));
|
||||
};
|
||||
|
||||
parser.comma = function (opts) {
|
||||
return new Comma(Object.assign({ value: ',' }, opts));
|
||||
};
|
||||
|
||||
parser.comment = function (opts) {
|
||||
return new Comment(opts);
|
||||
};
|
||||
|
||||
parser.func = function (opts) {
|
||||
return new Func(opts);
|
||||
};
|
||||
|
||||
parser.number = function (opts) {
|
||||
return new Num(opts);
|
||||
};
|
||||
|
||||
parser.operator = function (opts) {
|
||||
return new Operator(opts);
|
||||
};
|
||||
|
||||
parser.paren = function (opts) {
|
||||
return new Paren(Object.assign({ value: '(' }, opts));
|
||||
};
|
||||
|
||||
parser.string = function (opts) {
|
||||
return new Str(Object.assign({ quote: '\'' }, opts));
|
||||
};
|
||||
|
||||
parser.value = function (opts) {
|
||||
return new Value(opts);
|
||||
};
|
||||
|
||||
parser.word = function (opts) {
|
||||
return new Word(opts);
|
||||
};
|
||||
|
||||
parser.unicodeRange = function (opts) {
|
||||
return new UnicodeRange(opts);
|
||||
};
|
||||
|
||||
module.exports = parser;
|
214
web/node_modules/postcss-values-parser/lib/node.js
generated
vendored
Normal file
214
web/node_modules/postcss-values-parser/lib/node.js
generated
vendored
Normal file
|
@ -0,0 +1,214 @@
|
|||
'use strict';
|
||||
|
||||
let cloneNode = function (obj, parent) {
|
||||
let cloned = new obj.constructor();
|
||||
|
||||
for (let i in obj) {
|
||||
if (!obj.hasOwnProperty(i)) continue;
|
||||
|
||||
let value = obj[i],
|
||||
type = typeof value;
|
||||
|
||||
if (i === 'parent' && type === 'object') {
|
||||
if (parent) cloned[i] = parent;
|
||||
}
|
||||
else if (i === 'source') {
|
||||
cloned[i] = value;
|
||||
}
|
||||
else if (value instanceof Array) {
|
||||
cloned[i] = value.map(j => cloneNode(j, cloned));
|
||||
}
|
||||
else if (i !== 'before' && i !== 'after' && i !== 'between' && i !== 'semicolon') {
|
||||
if (type === 'object' && value !== null) value = cloneNode(value);
|
||||
cloned[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return cloned;
|
||||
};
|
||||
|
||||
module.exports = class Node {
|
||||
|
||||
constructor (defaults) {
|
||||
defaults = defaults || {};
|
||||
this.raws = { before: '', after: '' };
|
||||
|
||||
for (let name in defaults) {
|
||||
this[name] = defaults[name];
|
||||
}
|
||||
}
|
||||
|
||||
remove () {
|
||||
if (this.parent) {
|
||||
this.parent.removeChild(this);
|
||||
}
|
||||
|
||||
this.parent = undefined;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
toString () {
|
||||
return [
|
||||
this.raws.before,
|
||||
String(this.value),
|
||||
this.raws.after
|
||||
].join('');
|
||||
}
|
||||
|
||||
clone (overrides) {
|
||||
overrides = overrides || {};
|
||||
|
||||
let cloned = cloneNode(this);
|
||||
|
||||
for (let name in overrides) {
|
||||
cloned[name] = overrides[name];
|
||||
}
|
||||
|
||||
return cloned;
|
||||
}
|
||||
|
||||
cloneBefore (overrides) {
|
||||
overrides = overrides || {};
|
||||
|
||||
let cloned = this.clone(overrides);
|
||||
|
||||
this.parent.insertBefore(this, cloned);
|
||||
return cloned;
|
||||
}
|
||||
|
||||
cloneAfter (overrides) {
|
||||
overrides = overrides || {};
|
||||
|
||||
let cloned = this.clone(overrides);
|
||||
|
||||
this.parent.insertAfter(this, cloned);
|
||||
return cloned;
|
||||
}
|
||||
|
||||
replaceWith () {
|
||||
let nodes = Array.prototype.slice.call(arguments);
|
||||
|
||||
if (this.parent) {
|
||||
for (let node of nodes) {
|
||||
this.parent.insertBefore(this, node);
|
||||
}
|
||||
|
||||
this.remove();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
moveTo (container) {
|
||||
this.cleanRaws(this.root() === container.root());
|
||||
this.remove();
|
||||
|
||||
container.append(this);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
moveBefore (node) {
|
||||
this.cleanRaws(this.root() === node.root());
|
||||
this.remove();
|
||||
|
||||
node.parent.insertBefore(node, this);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
moveAfter (node) {
|
||||
this.cleanRaws(this.root() === node.root());
|
||||
this.remove();
|
||||
node.parent.insertAfter(node, this);
|
||||
return this;
|
||||
}
|
||||
|
||||
next () {
|
||||
let index = this.parent.index(this);
|
||||
|
||||
return this.parent.nodes[index + 1];
|
||||
}
|
||||
|
||||
prev () {
|
||||
let index = this.parent.index(this);
|
||||
|
||||
return this.parent.nodes[index - 1];
|
||||
}
|
||||
|
||||
toJSON () {
|
||||
let fixed = { };
|
||||
|
||||
for (let name in this) {
|
||||
if (!this.hasOwnProperty(name)) continue;
|
||||
if (name === 'parent') continue;
|
||||
let value = this[name];
|
||||
|
||||
if (value instanceof Array) {
|
||||
fixed[name] = value.map(i => {
|
||||
if (typeof i === 'object' && i.toJSON) {
|
||||
return i.toJSON();
|
||||
}
|
||||
else {
|
||||
return i;
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (typeof value === 'object' && value.toJSON) {
|
||||
fixed[name] = value.toJSON();
|
||||
}
|
||||
else {
|
||||
fixed[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return fixed;
|
||||
}
|
||||
|
||||
root () {
|
||||
let result = this;
|
||||
|
||||
while (result.parent) result = result.parent;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cleanRaws (keepBetween) {
|
||||
delete this.raws.before;
|
||||
delete this.raws.after;
|
||||
if (!keepBetween) delete this.raws.between;
|
||||
}
|
||||
|
||||
positionInside (index) {
|
||||
let string = this.toString(),
|
||||
column = this.source.start.column,
|
||||
line = this.source.start.line;
|
||||
|
||||
for (let i = 0; i < index; i++) {
|
||||
if (string[i] === '\n') {
|
||||
column = 1;
|
||||
line += 1;
|
||||
}
|
||||
else {
|
||||
column += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return { line, column };
|
||||
}
|
||||
|
||||
positionBy (opts) {
|
||||
let pos = this.source.start;
|
||||
|
||||
if (Object(opts).index) {
|
||||
pos = this.positionInside(opts.index);
|
||||
}
|
||||
else if (Object(opts).word) {
|
||||
let index = this.toString().indexOf(opts.word);
|
||||
if (index !== -1) pos = this.positionInside(index);
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
};
|
25
web/node_modules/postcss-values-parser/lib/number.js
generated
vendored
Normal file
25
web/node_modules/postcss-values-parser/lib/number.js
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
'use strict';
|
||||
|
||||
const Container = require('./container');
|
||||
const Node = require('./node');
|
||||
|
||||
class NumberNode extends Node {
|
||||
constructor (opts) {
|
||||
super(opts);
|
||||
this.type = 'number';
|
||||
this.unit = Object(opts).unit || '';
|
||||
}
|
||||
|
||||
toString () {
|
||||
return [
|
||||
this.raws.before,
|
||||
String(this.value),
|
||||
this.unit,
|
||||
this.raws.after
|
||||
].join('');
|
||||
}
|
||||
};
|
||||
|
||||
Container.registerWalker(NumberNode);
|
||||
|
||||
module.exports = NumberNode;
|
15
web/node_modules/postcss-values-parser/lib/operator.js
generated
vendored
Normal file
15
web/node_modules/postcss-values-parser/lib/operator.js
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
'use strict';
|
||||
|
||||
const Container = require('./container');
|
||||
const Node = require('./node');
|
||||
|
||||
class Operator extends Node {
|
||||
constructor (opts) {
|
||||
super(opts);
|
||||
this.type = 'operator';
|
||||
}
|
||||
}
|
||||
|
||||
Container.registerWalker(Operator);
|
||||
|
||||
module.exports = Operator;
|
16
web/node_modules/postcss-values-parser/lib/paren.js
generated
vendored
Normal file
16
web/node_modules/postcss-values-parser/lib/paren.js
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
'use strict';
|
||||
|
||||
const Container = require('./container');
|
||||
const Node = require('./node');
|
||||
|
||||
class Parenthesis extends Node {
|
||||
constructor (opts) {
|
||||
super(opts);
|
||||
this.type = 'paren';
|
||||
this.parenType = '';
|
||||
}
|
||||
}
|
||||
|
||||
Container.registerWalker(Parenthesis);
|
||||
|
||||
module.exports = Parenthesis;
|
576
web/node_modules/postcss-values-parser/lib/parser.js
generated
vendored
Normal file
576
web/node_modules/postcss-values-parser/lib/parser.js
generated
vendored
Normal file
|
@ -0,0 +1,576 @@
|
|||
'use strict';
|
||||
|
||||
const Root = require('./root');
|
||||
const Value = require('./value');
|
||||
|
||||
const AtWord = require('./atword');
|
||||
const Colon = require('./colon');
|
||||
const Comma = require('./comma');
|
||||
const Comment = require('./comment');
|
||||
const Func = require('./function');
|
||||
const Numbr = require('./number');
|
||||
const Operator = require('./operator');
|
||||
const Paren = require('./paren');
|
||||
const Str = require('./string');
|
||||
const Word = require('./word');
|
||||
const UnicodeRange = require('./unicode-range');
|
||||
|
||||
const tokenize = require('./tokenize');
|
||||
|
||||
const flatten = require('flatten');
|
||||
const indexesOf = require('indexes-of');
|
||||
const uniq = require('uniq');
|
||||
const ParserError = require('./errors/ParserError');
|
||||
|
||||
function sortAscending (list) {
|
||||
return list.sort((a, b) => a - b);
|
||||
}
|
||||
|
||||
module.exports = class Parser {
|
||||
constructor (input, options) {
|
||||
const defaults = { loose: false };
|
||||
|
||||
// cache needs to be an array for values with more than 1 level of function nesting
|
||||
this.cache = [];
|
||||
this.input = input;
|
||||
this.options = Object.assign({}, defaults, options);
|
||||
this.position = 0;
|
||||
// we'll use this to keep track of the paren balance
|
||||
this.unbalanced = 0;
|
||||
this.root = new Root();
|
||||
|
||||
let value = new Value();
|
||||
|
||||
this.root.append(value);
|
||||
|
||||
this.current = value;
|
||||
this.tokens = tokenize(input, this.options);
|
||||
}
|
||||
|
||||
parse () {
|
||||
return this.loop();
|
||||
}
|
||||
|
||||
colon () {
|
||||
let token = this.currToken;
|
||||
|
||||
this.newNode(new Colon({
|
||||
value: token[1],
|
||||
source: {
|
||||
start: {
|
||||
line: token[2],
|
||||
column: token[3]
|
||||
},
|
||||
end: {
|
||||
line: token[4],
|
||||
column: token[5]
|
||||
}
|
||||
},
|
||||
sourceIndex: token[6]
|
||||
}));
|
||||
|
||||
this.position ++;
|
||||
}
|
||||
|
||||
comma () {
|
||||
let token = this.currToken;
|
||||
|
||||
this.newNode(new Comma({
|
||||
value: token[1],
|
||||
source: {
|
||||
start: {
|
||||
line: token[2],
|
||||
column: token[3]
|
||||
},
|
||||
end: {
|
||||
line: token[4],
|
||||
column: token[5]
|
||||
}
|
||||
},
|
||||
sourceIndex: token[6]
|
||||
}));
|
||||
|
||||
this.position ++;
|
||||
}
|
||||
|
||||
comment () {
|
||||
let inline = false,
|
||||
value = this.currToken[1].replace(/\/\*|\*\//g, ''),
|
||||
node;
|
||||
|
||||
if (this.options.loose && value.startsWith("//")) {
|
||||
value = value.substring(2);
|
||||
inline = true;
|
||||
}
|
||||
|
||||
node = new Comment({
|
||||
value: value,
|
||||
inline: inline,
|
||||
source: {
|
||||
start: {
|
||||
line: this.currToken[2],
|
||||
column: this.currToken[3]
|
||||
},
|
||||
end: {
|
||||
line: this.currToken[4],
|
||||
column: this.currToken[5]
|
||||
}
|
||||
},
|
||||
sourceIndex: this.currToken[6]
|
||||
});
|
||||
|
||||
this.newNode(node);
|
||||
this.position++;
|
||||
}
|
||||
|
||||
error (message, token) {
|
||||
throw new ParserError(message + ` at line: ${token[2]}, column ${token[3]}`);
|
||||
}
|
||||
|
||||
loop () {
|
||||
while (this.position < this.tokens.length) {
|
||||
this.parseTokens();
|
||||
}
|
||||
|
||||
if (!this.current.last && this.spaces) {
|
||||
this.current.raws.before += this.spaces;
|
||||
}
|
||||
else if (this.spaces) {
|
||||
this.current.last.raws.after += this.spaces;
|
||||
}
|
||||
|
||||
this.spaces = '';
|
||||
|
||||
return this.root;
|
||||
}
|
||||
|
||||
operator () {
|
||||
|
||||
// if a +|- operator is followed by a non-word character (. is allowed) and
|
||||
// is preceded by a non-word character. (5+5)
|
||||
let char = this.currToken[1],
|
||||
node;
|
||||
|
||||
if (char === '+' || char === '-') {
|
||||
// only inspect if the operator is not the first token, and we're only
|
||||
// within a calc() function: the only spec-valid place for math expressions
|
||||
if (!this.options.loose) {
|
||||
if (this.position > 0) {
|
||||
if (this.current.type === 'func' && this.current.value === 'calc') {
|
||||
// allow operators to be proceeded by spaces and opening parens
|
||||
if (this.prevToken[0] !== 'space' && this.prevToken[0] !== '(') {
|
||||
this.error('Syntax Error', this.currToken);
|
||||
}
|
||||
// valid: calc(1 - +2)
|
||||
// invalid: calc(1 -+2)
|
||||
else if (this.nextToken[0] !== 'space' && this.nextToken[0] !== 'word') {
|
||||
this.error('Syntax Error', this.currToken);
|
||||
}
|
||||
// valid: calc(1 - +2)
|
||||
// valid: calc(-0.5 + 2)
|
||||
// invalid: calc(1 -2)
|
||||
else if (this.nextToken[0] === 'word' && this.current.last.type !== 'operator' &&
|
||||
this.current.last.value !== '(') {
|
||||
this.error('Syntax Error', this.currToken);
|
||||
}
|
||||
}
|
||||
// if we're not in a function and someone has doubled up on operators,
|
||||
// or they're trying to perform a calc outside of a calc
|
||||
// eg. +-4px or 5+ 5, throw an error
|
||||
else if (this.nextToken[0] === 'space'
|
||||
|| this.nextToken[0] === 'operator'
|
||||
|| this.prevToken[0] === 'operator') {
|
||||
this.error('Syntax Error', this.currToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.options.loose) {
|
||||
if (this.nextToken[0] === 'word') {
|
||||
return this.word();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((!this.current.nodes.length || (this.current.last && this.current.last.type === 'operator')) && this.nextToken[0] === 'word') {
|
||||
return this.word();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node = new Operator({
|
||||
value: this.currToken[1],
|
||||
source: {
|
||||
start: {
|
||||
line: this.currToken[2],
|
||||
column: this.currToken[3]
|
||||
},
|
||||
end: {
|
||||
line: this.currToken[2],
|
||||
column: this.currToken[3]
|
||||
}
|
||||
},
|
||||
sourceIndex: this.currToken[4]
|
||||
});
|
||||
|
||||
this.position ++;
|
||||
|
||||
return this.newNode(node);
|
||||
}
|
||||
|
||||
parseTokens () {
|
||||
switch (this.currToken[0]) {
|
||||
case 'space':
|
||||
this.space();
|
||||
break;
|
||||
case 'colon':
|
||||
this.colon();
|
||||
break;
|
||||
case 'comma':
|
||||
this.comma();
|
||||
break;
|
||||
case 'comment':
|
||||
this.comment();
|
||||
break;
|
||||
case '(':
|
||||
this.parenOpen();
|
||||
break;
|
||||
case ')':
|
||||
this.parenClose();
|
||||
break;
|
||||
case 'atword':
|
||||
case 'word':
|
||||
this.word();
|
||||
break;
|
||||
case 'operator':
|
||||
this.operator();
|
||||
break;
|
||||
case 'string':
|
||||
this.string();
|
||||
break;
|
||||
case 'unicoderange':
|
||||
this.unicodeRange();
|
||||
break;
|
||||
default:
|
||||
this.word();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
parenOpen () {
|
||||
let unbalanced = 1,
|
||||
pos = this.position + 1,
|
||||
token = this.currToken,
|
||||
last;
|
||||
|
||||
// check for balanced parens
|
||||
while (pos < this.tokens.length && unbalanced) {
|
||||
let tkn = this.tokens[pos];
|
||||
|
||||
if (tkn[0] === '(') {
|
||||
unbalanced++;
|
||||
}
|
||||
if (tkn[0] === ')') {
|
||||
unbalanced--;
|
||||
}
|
||||
pos ++;
|
||||
}
|
||||
|
||||
if (unbalanced) {
|
||||
this.error('Expected closing parenthesis', token);
|
||||
}
|
||||
|
||||
// ok, all parens are balanced. continue on
|
||||
|
||||
last = this.current.last;
|
||||
|
||||
if (last && last.type === 'func' && last.unbalanced < 0) {
|
||||
last.unbalanced = 0; // ok we're ready to add parens now
|
||||
this.current = last;
|
||||
}
|
||||
|
||||
this.current.unbalanced ++;
|
||||
|
||||
this.newNode(new Paren({
|
||||
value: token[1],
|
||||
source: {
|
||||
start: {
|
||||
line: token[2],
|
||||
column: token[3]
|
||||
},
|
||||
end: {
|
||||
line: token[4],
|
||||
column: token[5]
|
||||
}
|
||||
},
|
||||
sourceIndex: token[6]
|
||||
}));
|
||||
|
||||
this.position ++;
|
||||
|
||||
// url functions get special treatment, and anything between the function
|
||||
// parens get treated as one word, if the contents aren't not a string.
|
||||
if (this.current.type === 'func' && this.current.unbalanced &&
|
||||
this.current.value === 'url' && this.currToken[0] !== 'string' &&
|
||||
this.currToken[0] !== ')' && !this.options.loose) {
|
||||
|
||||
let nextToken = this.nextToken,
|
||||
value = this.currToken[1],
|
||||
start = {
|
||||
line: this.currToken[2],
|
||||
column: this.currToken[3]
|
||||
};
|
||||
|
||||
while (nextToken && nextToken[0] !== ')' && this.current.unbalanced) {
|
||||
this.position ++;
|
||||
value += this.currToken[1];
|
||||
nextToken = this.nextToken;
|
||||
}
|
||||
|
||||
if (this.position !== this.tokens.length - 1) {
|
||||
// skip the following word definition, or it'll be a duplicate
|
||||
this.position ++;
|
||||
|
||||
this.newNode(new Word({
|
||||
value,
|
||||
source: {
|
||||
start,
|
||||
end: {
|
||||
line: this.currToken[4],
|
||||
column: this.currToken[5]
|
||||
}
|
||||
},
|
||||
sourceIndex: this.currToken[6]
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parenClose () {
|
||||
let token = this.currToken;
|
||||
|
||||
this.newNode(new Paren({
|
||||
value: token[1],
|
||||
source: {
|
||||
start: {
|
||||
line: token[2],
|
||||
column: token[3]
|
||||
},
|
||||
end: {
|
||||
line: token[4],
|
||||
column: token[5]
|
||||
}
|
||||
},
|
||||
sourceIndex: token[6]
|
||||
}));
|
||||
|
||||
this.position ++;
|
||||
|
||||
if (this.position >= this.tokens.length - 1 && !this.current.unbalanced) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.current.unbalanced --;
|
||||
|
||||
if (this.current.unbalanced < 0) {
|
||||
this.error('Expected opening parenthesis', token);
|
||||
}
|
||||
|
||||
if (!this.current.unbalanced && this.cache.length) {
|
||||
this.current = this.cache.pop();
|
||||
}
|
||||
}
|
||||
|
||||
space () {
|
||||
let token = this.currToken;
|
||||
// Handle space before and after the selector
|
||||
if (this.position === (this.tokens.length - 1) || this.nextToken[0] === ',' || this.nextToken[0] === ')') {
|
||||
this.current.last.raws.after += token[1];
|
||||
this.position ++;
|
||||
}
|
||||
else {
|
||||
this.spaces = token[1];
|
||||
this.position ++;
|
||||
}
|
||||
}
|
||||
|
||||
unicodeRange () {
|
||||
let token = this.currToken;
|
||||
|
||||
this.newNode(new UnicodeRange({
|
||||
value: token[1],
|
||||
source: {
|
||||
start: {
|
||||
line: token[2],
|
||||
column: token[3]
|
||||
},
|
||||
end: {
|
||||
line: token[4],
|
||||
column: token[5]
|
||||
}
|
||||
},
|
||||
sourceIndex: token[6]
|
||||
}));
|
||||
|
||||
this.position ++;
|
||||
}
|
||||
|
||||
splitWord () {
|
||||
let nextToken = this.nextToken,
|
||||
word = this.currToken[1],
|
||||
rNumber = /^[\+\-]?((\d+(\.\d*)?)|(\.\d+))([eE][\+\-]?\d+)?/,
|
||||
|
||||
// treat css-like groupings differently so they can be inspected,
|
||||
// but don't address them as anything but a word, but allow hex values
|
||||
// to pass through.
|
||||
rNoFollow = /^(?!\#([a-z0-9]+))[\#\{\}]/gi,
|
||||
|
||||
hasAt, indices;
|
||||
|
||||
if (!rNoFollow.test(word)) {
|
||||
while (nextToken && nextToken[0] === 'word') {
|
||||
this.position ++;
|
||||
|
||||
let current = this.currToken[1];
|
||||
word += current;
|
||||
|
||||
nextToken = this.nextToken;
|
||||
}
|
||||
}
|
||||
|
||||
hasAt = indexesOf(word, '@');
|
||||
indices = sortAscending(uniq(flatten([[0], hasAt])));
|
||||
|
||||
indices.forEach((ind, i) => {
|
||||
let index = indices[i + 1] || word.length,
|
||||
value = word.slice(ind, index),
|
||||
node;
|
||||
|
||||
if (~hasAt.indexOf(ind)) {
|
||||
node = new AtWord({
|
||||
value: value.slice(1),
|
||||
source: {
|
||||
start: {
|
||||
line: this.currToken[2],
|
||||
column: this.currToken[3] + ind
|
||||
},
|
||||
end: {
|
||||
line: this.currToken[4],
|
||||
column: this.currToken[3] + (index - 1)
|
||||
}
|
||||
},
|
||||
sourceIndex: this.currToken[6] + indices[i]
|
||||
});
|
||||
}
|
||||
else if (rNumber.test(this.currToken[1])) {
|
||||
let unit = value.replace(rNumber, '');
|
||||
|
||||
node = new Numbr({
|
||||
value: value.replace(unit, ''),
|
||||
source: {
|
||||
start: {
|
||||
line: this.currToken[2],
|
||||
column: this.currToken[3] + ind
|
||||
},
|
||||
end: {
|
||||
line: this.currToken[4],
|
||||
column: this.currToken[3] + (index - 1)
|
||||
}
|
||||
},
|
||||
sourceIndex: this.currToken[6] + indices[i],
|
||||
unit
|
||||
});
|
||||
}
|
||||
else {
|
||||
node = new (nextToken && nextToken[0] === '(' ? Func : Word)({
|
||||
value,
|
||||
source: {
|
||||
start: {
|
||||
line: this.currToken[2],
|
||||
column: this.currToken[3] + ind
|
||||
},
|
||||
end: {
|
||||
line: this.currToken[4],
|
||||
column: this.currToken[3] + (index - 1)
|
||||
}
|
||||
},
|
||||
sourceIndex: this.currToken[6] + indices[i]
|
||||
});
|
||||
|
||||
if (node.constructor.name === 'Word') {
|
||||
node.isHex = /^#(.+)/.test(value);
|
||||
node.isColor = /^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(value);
|
||||
}
|
||||
else {
|
||||
this.cache.push(this.current);
|
||||
}
|
||||
}
|
||||
|
||||
this.newNode(node);
|
||||
|
||||
});
|
||||
|
||||
this.position ++;
|
||||
}
|
||||
|
||||
string () {
|
||||
let token = this.currToken,
|
||||
value = this.currToken[1],
|
||||
rQuote = /^(\"|\')/,
|
||||
quoted = rQuote.test(value),
|
||||
quote = '',
|
||||
node;
|
||||
|
||||
if (quoted) {
|
||||
quote = value.match(rQuote)[0];
|
||||
// set value to the string within the quotes
|
||||
// quotes are stored in raws
|
||||
value = value.slice(1, value.length - 1);
|
||||
}
|
||||
|
||||
node = new Str({
|
||||
value,
|
||||
source: {
|
||||
start: {
|
||||
line: token[2],
|
||||
column: token[3]
|
||||
},
|
||||
end: {
|
||||
line: token[4],
|
||||
column: token[5]
|
||||
}
|
||||
},
|
||||
sourceIndex: token[6],
|
||||
quoted
|
||||
});
|
||||
|
||||
node.raws.quote = quote;
|
||||
|
||||
this.newNode(node);
|
||||
this.position++;
|
||||
}
|
||||
|
||||
word () {
|
||||
return this.splitWord();
|
||||
}
|
||||
|
||||
newNode (node) {
|
||||
if (this.spaces) {
|
||||
node.raws.before += this.spaces;
|
||||
this.spaces = '';
|
||||
}
|
||||
|
||||
return this.current.append(node);
|
||||
}
|
||||
|
||||
get currToken () {
|
||||
return this.tokens[this.position];
|
||||
}
|
||||
|
||||
get nextToken () {
|
||||
return this.tokens[this.position + 1];
|
||||
}
|
||||
|
||||
get prevToken () {
|
||||
return this.tokens[this.position - 1];
|
||||
}
|
||||
};
|
10
web/node_modules/postcss-values-parser/lib/root.js
generated
vendored
Normal file
10
web/node_modules/postcss-values-parser/lib/root.js
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
'use strict';
|
||||
|
||||
const Container = require('./container');
|
||||
|
||||
module.exports = class Root extends Container {
|
||||
constructor (opts) {
|
||||
super(opts);
|
||||
this.type = 'root';
|
||||
}
|
||||
};
|
28
web/node_modules/postcss-values-parser/lib/string.js
generated
vendored
Normal file
28
web/node_modules/postcss-values-parser/lib/string.js
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
'use strict';
|
||||
|
||||
const Container = require('./container');
|
||||
const Node = require('./node');
|
||||
|
||||
class StringNode extends Node {
|
||||
constructor (opts) {
|
||||
super(opts);
|
||||
this.type = 'string';
|
||||
}
|
||||
|
||||
toString () {
|
||||
let quote = this.quoted ? this.raws.quote : '';
|
||||
return [
|
||||
this.raws.before,
|
||||
quote,
|
||||
// we can't use String() here because it'll try using itself
|
||||
// as the constructor
|
||||
this.value + '',
|
||||
quote,
|
||||
this.raws.after
|
||||
].join('');
|
||||
}
|
||||
}
|
||||
|
||||
Container.registerWalker(StringNode);
|
||||
|
||||
module.exports = StringNode;
|
394
web/node_modules/postcss-values-parser/lib/tokenize.js
generated
vendored
Normal file
394
web/node_modules/postcss-values-parser/lib/tokenize.js
generated
vendored
Normal file
|
@ -0,0 +1,394 @@
|
|||
'use strict';
|
||||
|
||||
const openBracket = '{'.charCodeAt(0);
|
||||
const closeBracket = '}'.charCodeAt(0);
|
||||
const openParen = '('.charCodeAt(0);
|
||||
const closeParen = ')'.charCodeAt(0);
|
||||
const singleQuote = '\''.charCodeAt(0);
|
||||
const doubleQuote = '"'.charCodeAt(0);
|
||||
const backslash = '\\'.charCodeAt(0);
|
||||
const slash = '/'.charCodeAt(0);
|
||||
const period = '.'.charCodeAt(0);
|
||||
const comma = ','.charCodeAt(0);
|
||||
const colon = ':'.charCodeAt(0);
|
||||
const asterisk = '*'.charCodeAt(0);
|
||||
const minus = '-'.charCodeAt(0);
|
||||
const plus = '+'.charCodeAt(0);
|
||||
const pound = '#'.charCodeAt(0);
|
||||
const newline = '\n'.charCodeAt(0);
|
||||
const space = ' '.charCodeAt(0);
|
||||
const feed = '\f'.charCodeAt(0);
|
||||
const tab = '\t'.charCodeAt(0);
|
||||
const cr = '\r'.charCodeAt(0);
|
||||
const at = '@'.charCodeAt(0);
|
||||
const lowerE = 'e'.charCodeAt(0);
|
||||
const upperE = 'E'.charCodeAt(0);
|
||||
const digit0 = '0'.charCodeAt(0);
|
||||
const digit9 = '9'.charCodeAt(0);
|
||||
const lowerU = 'u'.charCodeAt(0);
|
||||
const upperU = 'U'.charCodeAt(0);
|
||||
const atEnd = /[ \n\t\r\{\(\)'"\\;,/]/g;
|
||||
const wordEnd = /[ \n\t\r\(\)\{\}\*:;@!&'"\+\|~>,\[\]\\]|\/(?=\*)/g;
|
||||
const wordEndNum = /[ \n\t\r\(\)\{\}\*:;@!&'"\-\+\|~>,\[\]\\]|\//g;
|
||||
const alphaNum = /^[a-z0-9]/i;
|
||||
const unicodeRange = /^[a-f0-9?\-]/i;
|
||||
|
||||
const util = require('util');
|
||||
const TokenizeError = require('./errors/TokenizeError');
|
||||
|
||||
module.exports = function tokenize (input, options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
let tokens = [],
|
||||
css = input.valueOf(),
|
||||
length = css.length,
|
||||
offset = -1,
|
||||
line = 1,
|
||||
pos = 0,
|
||||
parentCount = 0,
|
||||
isURLArg = null,
|
||||
|
||||
code, next, quote, lines, last, content, escape, nextLine, nextOffset,
|
||||
escaped, escapePos, nextChar;
|
||||
|
||||
function unclosed (what) {
|
||||
let message = util.format('Unclosed %s at line: %d, column: %d, token: %d', what, line, pos - offset, pos);
|
||||
throw new TokenizeError(message);
|
||||
}
|
||||
|
||||
function tokenizeError () {
|
||||
let message = util.format('Syntax error at line: %d, column: %d, token: %d', line, pos - offset, pos);
|
||||
throw new TokenizeError(message);
|
||||
}
|
||||
|
||||
while (pos < length) {
|
||||
code = css.charCodeAt(pos);
|
||||
|
||||
if (code === newline) {
|
||||
offset = pos;
|
||||
line += 1;
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
case newline:
|
||||
case space:
|
||||
case tab:
|
||||
case cr:
|
||||
case feed:
|
||||
next = pos;
|
||||
do {
|
||||
next += 1;
|
||||
code = css.charCodeAt(next);
|
||||
if (code === newline) {
|
||||
offset = next;
|
||||
line += 1;
|
||||
}
|
||||
} while (code === space ||
|
||||
code === newline ||
|
||||
code === tab ||
|
||||
code === cr ||
|
||||
code === feed);
|
||||
|
||||
tokens.push(['space', css.slice(pos, next),
|
||||
line, pos - offset,
|
||||
line, next - offset,
|
||||
pos
|
||||
]);
|
||||
|
||||
pos = next - 1;
|
||||
break;
|
||||
|
||||
case colon:
|
||||
next = pos + 1;
|
||||
tokens.push(['colon', css.slice(pos, next),
|
||||
line, pos - offset,
|
||||
line, next - offset,
|
||||
pos
|
||||
]);
|
||||
|
||||
pos = next - 1;
|
||||
break;
|
||||
|
||||
case comma:
|
||||
next = pos + 1;
|
||||
tokens.push(['comma', css.slice(pos, next),
|
||||
line, pos - offset,
|
||||
line, next - offset,
|
||||
pos
|
||||
]);
|
||||
|
||||
pos = next - 1;
|
||||
break;
|
||||
|
||||
case openBracket:
|
||||
tokens.push(['{', '{',
|
||||
line, pos - offset,
|
||||
line, next - offset,
|
||||
pos
|
||||
]);
|
||||
break;
|
||||
|
||||
case closeBracket:
|
||||
tokens.push(['}', '}',
|
||||
line, pos - offset,
|
||||
line, next - offset,
|
||||
pos
|
||||
]);
|
||||
break;
|
||||
|
||||
case openParen:
|
||||
parentCount++;
|
||||
isURLArg = !isURLArg && parentCount === 1 &&
|
||||
tokens.length > 0 &&
|
||||
tokens[tokens.length - 1][0] === "word" &&
|
||||
tokens[tokens.length - 1][1] === "url";
|
||||
tokens.push(['(', '(',
|
||||
line, pos - offset,
|
||||
line, next - offset,
|
||||
pos
|
||||
]);
|
||||
break;
|
||||
|
||||
case closeParen:
|
||||
parentCount--;
|
||||
isURLArg = isURLArg && parentCount > 0;
|
||||
tokens.push([')', ')',
|
||||
line, pos - offset,
|
||||
line, next - offset,
|
||||
pos
|
||||
]);
|
||||
break;
|
||||
|
||||
case singleQuote:
|
||||
case doubleQuote:
|
||||
quote = code === singleQuote ? '\'' : '"';
|
||||
next = pos;
|
||||
do {
|
||||
escaped = false;
|
||||
next = css.indexOf(quote, next + 1);
|
||||
if (next === -1) {
|
||||
unclosed('quote', quote);
|
||||
}
|
||||
escapePos = next;
|
||||
while (css.charCodeAt(escapePos - 1) === backslash) {
|
||||
escapePos -= 1;
|
||||
escaped = !escaped;
|
||||
}
|
||||
} while (escaped);
|
||||
|
||||
tokens.push(['string', css.slice(pos, next + 1),
|
||||
line, pos - offset,
|
||||
line, next - offset,
|
||||
pos
|
||||
]);
|
||||
pos = next;
|
||||
break;
|
||||
|
||||
case at:
|
||||
atEnd.lastIndex = pos + 1;
|
||||
atEnd.test(css);
|
||||
|
||||
if (atEnd.lastIndex === 0) {
|
||||
next = css.length - 1;
|
||||
}
|
||||
else {
|
||||
next = atEnd.lastIndex - 2;
|
||||
}
|
||||
|
||||
tokens.push(['atword', css.slice(pos, next + 1),
|
||||
line, pos - offset,
|
||||
line, next - offset,
|
||||
pos
|
||||
]);
|
||||
pos = next;
|
||||
break;
|
||||
|
||||
case backslash:
|
||||
next = pos;
|
||||
code = css.charCodeAt(next + 1);
|
||||
|
||||
if (escape && (code !== slash && code !== space &&
|
||||
code !== newline && code !== tab &&
|
||||
code !== cr && code !== feed)) {
|
||||
next += 1;
|
||||
}
|
||||
|
||||
tokens.push(['word', css.slice(pos, next + 1),
|
||||
line, pos - offset,
|
||||
line, next - offset,
|
||||
pos
|
||||
]);
|
||||
|
||||
pos = next;
|
||||
break;
|
||||
|
||||
case plus:
|
||||
case minus:
|
||||
case asterisk:
|
||||
next = pos + 1;
|
||||
nextChar = css.slice(pos + 1, next + 1);
|
||||
|
||||
let prevChar = css.slice(pos - 1, pos);
|
||||
|
||||
// if the operator is immediately followed by a word character, then we
|
||||
// have a prefix of some kind, and should fall-through. eg. -webkit
|
||||
|
||||
// look for --* for custom variables
|
||||
if (code === minus && nextChar.charCodeAt(0) === minus) {
|
||||
next++;
|
||||
|
||||
tokens.push(['word', css.slice(pos, next),
|
||||
line, pos - offset,
|
||||
line, next - offset,
|
||||
pos
|
||||
]);
|
||||
|
||||
pos = next - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
tokens.push(['operator', css.slice(pos, next),
|
||||
line, pos - offset,
|
||||
line, next - offset,
|
||||
pos
|
||||
]);
|
||||
|
||||
pos = next - 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (code === slash && (css.charCodeAt(pos + 1) === asterisk || (options.loose && !isURLArg && css.charCodeAt(pos + 1) === slash))) {
|
||||
const isStandardComment = css.charCodeAt(pos + 1) === asterisk;
|
||||
|
||||
if (isStandardComment) {
|
||||
next = css.indexOf('*/', pos + 2) + 1;
|
||||
if (next === 0) {
|
||||
unclosed('comment', '*/');
|
||||
}
|
||||
}
|
||||
else {
|
||||
const newlinePos = css.indexOf('\n', pos + 2);
|
||||
|
||||
next = newlinePos !== -1 ? newlinePos - 1 : length;
|
||||
}
|
||||
|
||||
content = css.slice(pos, next + 1);
|
||||
lines = content.split('\n');
|
||||
last = lines.length - 1;
|
||||
|
||||
if (last > 0) {
|
||||
nextLine = line + last;
|
||||
nextOffset = next - lines[last].length;
|
||||
}
|
||||
else {
|
||||
nextLine = line;
|
||||
nextOffset = offset;
|
||||
}
|
||||
|
||||
tokens.push(['comment', content,
|
||||
line, pos - offset,
|
||||
nextLine, next - nextOffset,
|
||||
pos
|
||||
]);
|
||||
|
||||
offset = nextOffset;
|
||||
line = nextLine;
|
||||
pos = next;
|
||||
|
||||
}
|
||||
else if (code === pound && !alphaNum.test(css.slice(pos + 1, pos + 2))) {
|
||||
next = pos + 1;
|
||||
|
||||
tokens.push(['#', css.slice(pos, next),
|
||||
line, pos - offset,
|
||||
line, next - offset,
|
||||
pos
|
||||
]);
|
||||
|
||||
pos = next - 1;
|
||||
}
|
||||
else if ((code === lowerU || code === upperU) && css.charCodeAt(pos + 1) === plus) {
|
||||
next = pos + 2;
|
||||
|
||||
do {
|
||||
next += 1;
|
||||
code = css.charCodeAt(next);
|
||||
} while (next < length && unicodeRange.test(css.slice(next, next + 1)));
|
||||
|
||||
tokens.push(['unicoderange', css.slice(pos, next),
|
||||
line, pos - offset,
|
||||
line, next - offset,
|
||||
pos
|
||||
]);
|
||||
pos = next - 1;
|
||||
}
|
||||
// catch a regular slash, that isn't a comment
|
||||
else if (code === slash) {
|
||||
next = pos + 1;
|
||||
|
||||
tokens.push(['operator', css.slice(pos, next),
|
||||
line, pos - offset,
|
||||
line, next - offset,
|
||||
pos
|
||||
]);
|
||||
|
||||
pos = next - 1;
|
||||
}
|
||||
else {
|
||||
let regex = wordEnd;
|
||||
|
||||
// we're dealing with a word that starts with a number
|
||||
// those get treated differently
|
||||
if (code >= digit0 && code <= digit9) {
|
||||
regex = wordEndNum;
|
||||
}
|
||||
|
||||
regex.lastIndex = pos + 1;
|
||||
regex.test(css);
|
||||
|
||||
if (regex.lastIndex === 0) {
|
||||
next = css.length - 1;
|
||||
}
|
||||
else {
|
||||
next = regex.lastIndex - 2;
|
||||
}
|
||||
|
||||
// Exponential number notation with minus or plus: 1e-10, 1e+10
|
||||
if (regex === wordEndNum || code === period) {
|
||||
let ncode = css.charCodeAt(next),
|
||||
ncode1 = css.charCodeAt(next + 1),
|
||||
ncode2 = css.charCodeAt(next + 2);
|
||||
|
||||
if (
|
||||
(ncode === lowerE || ncode === upperE) &&
|
||||
(ncode1 === minus || ncode1 === plus) &&
|
||||
(ncode2 >= digit0 && ncode2 <= digit9)
|
||||
) {
|
||||
wordEndNum.lastIndex = next + 2;
|
||||
wordEndNum.test(css);
|
||||
|
||||
if (wordEndNum.lastIndex === 0) {
|
||||
next = css.length - 1;
|
||||
}
|
||||
else {
|
||||
next = wordEndNum.lastIndex - 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tokens.push(['word', css.slice(pos, next + 1),
|
||||
line, pos - offset,
|
||||
line, next - offset,
|
||||
pos
|
||||
]);
|
||||
pos = next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
pos ++;
|
||||
}
|
||||
|
||||
return tokens;
|
||||
};
|
15
web/node_modules/postcss-values-parser/lib/unicode-range.js
generated
vendored
Normal file
15
web/node_modules/postcss-values-parser/lib/unicode-range.js
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
'use strict';
|
||||
|
||||
const Container = require('./container');
|
||||
const Node = require('./node');
|
||||
|
||||
class UnicodeRange extends Node {
|
||||
constructor (opts) {
|
||||
super(opts);
|
||||
this.type = 'unicode-range';
|
||||
}
|
||||
}
|
||||
|
||||
Container.registerWalker(UnicodeRange);
|
||||
|
||||
module.exports = UnicodeRange;
|
11
web/node_modules/postcss-values-parser/lib/value.js
generated
vendored
Normal file
11
web/node_modules/postcss-values-parser/lib/value.js
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
'use strict';
|
||||
|
||||
const Container = require('./container');
|
||||
|
||||
module.exports = class Value extends Container {
|
||||
constructor (opts) {
|
||||
super(opts);
|
||||
this.type = 'value';
|
||||
this.unbalanced = 0;
|
||||
}
|
||||
};
|
15
web/node_modules/postcss-values-parser/lib/word.js
generated
vendored
Normal file
15
web/node_modules/postcss-values-parser/lib/word.js
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
'use strict';
|
||||
|
||||
const Container = require('./container');
|
||||
const Node = require('./node');
|
||||
|
||||
class Word extends Node {
|
||||
constructor (opts) {
|
||||
super(opts);
|
||||
this.type = 'word';
|
||||
}
|
||||
}
|
||||
|
||||
Container.registerWalker(Word);
|
||||
|
||||
module.exports = Word;
|
48
web/node_modules/postcss-values-parser/old-lib/container.js
generated
vendored
Normal file
48
web/node_modules/postcss-values-parser/old-lib/container.js
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
const Node = require('./node');
|
||||
|
||||
class Container extends Node {
|
||||
walk(callback) {
|
||||
return this.each((child, i) => {
|
||||
let result = callback(child, i);
|
||||
if (result !== false && child.walk) {
|
||||
result = child.walk(callback);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
walkType(type, callback) {
|
||||
if (!type || !callback) {
|
||||
throw new Error('Parameters {type} and {callback} are required.');
|
||||
}
|
||||
|
||||
// allow users to pass a constructor, or node type string; eg. Word.
|
||||
const isTypeCallable = typeof type === 'function';
|
||||
|
||||
return this.walk((node, index) => {
|
||||
if ((isTypeCallable && node instanceof type) || (!isTypeCallable && node.type === type)) {
|
||||
return callback.call(this, node, index);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Container.registerWalker = (constructor) => {
|
||||
let walkerName = `walk${constructor.name}`;
|
||||
|
||||
// plural sugar
|
||||
if (walkerName.lastIndexOf('s') !== walkerName.length - 1) {
|
||||
walkerName += 's';
|
||||
}
|
||||
|
||||
if (Container.prototype[walkerName]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we need access to `this` so we can't use an arrow function
|
||||
Container.prototype[walkerName] = function(callback) {
|
||||
return this.walkType(constructor, callback);
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = Container;
|
576
web/node_modules/postcss-values-parser/old-lib/parser.js
generated
vendored
Normal file
576
web/node_modules/postcss-values-parser/old-lib/parser.js
generated
vendored
Normal file
|
@ -0,0 +1,576 @@
|
|||
'use strict';
|
||||
|
||||
const Root = require('./root');
|
||||
const Value = require('./value');
|
||||
|
||||
const AtWord = require('./atword');
|
||||
const Colon = require('./colon');
|
||||
const Comma = require('./comma');
|
||||
const Comment = require('./comment');
|
||||
const Func = require('./function');
|
||||
const Numbr = require('./number');
|
||||
const Operator = require('./operator');
|
||||
const Paren = require('./paren');
|
||||
const Str = require('./string');
|
||||
const Word = require('./word');
|
||||
const UnicodeRange = require('./unicode-range');
|
||||
|
||||
const tokenize = require('./tokenize');
|
||||
|
||||
const flatten = require('flatten');
|
||||
const indexesOf = require('indexes-of');
|
||||
const uniq = require('uniq');
|
||||
const ParserError = require('./errors/ParserError');
|
||||
|
||||
function sortAscending (list) {
|
||||
return list.sort((a, b) => a - b);
|
||||
}
|
||||
|
||||
module.exports = class Parser {
|
||||
constructor (input, options) {
|
||||
const defaults = { loose: false };
|
||||
|
||||
// cache needs to be an array for values with more than 1 level of function nesting
|
||||
this.cache = [];
|
||||
this.input = input;
|
||||
this.options = Object.assign({}, defaults, options);
|
||||
this.position = 0;
|
||||
// we'll use this to keep track of the paren balance
|
||||
this.unbalanced = 0;
|
||||
this.root = new Root();
|
||||
|
||||
let value = new Value();
|
||||
|
||||
this.root.append(value);
|
||||
|
||||
this.current = value;
|
||||
this.tokens = tokenize(input, this.options);
|
||||
}
|
||||
|
||||
parse () {
|
||||
return this.loop();
|
||||
}
|
||||
|
||||
colon () {
|
||||
let token = this.currToken;
|
||||
|
||||
this.newNode(new Colon({
|
||||
value: token[1],
|
||||
source: {
|
||||
start: {
|
||||
line: token[2],
|
||||
column: token[3]
|
||||
},
|
||||
end: {
|
||||
line: token[4],
|
||||
column: token[5]
|
||||
}
|
||||
},
|
||||
sourceIndex: token[6]
|
||||
}));
|
||||
|
||||
this.position ++;
|
||||
}
|
||||
|
||||
comma () {
|
||||
let token = this.currToken;
|
||||
|
||||
this.newNode(new Comma({
|
||||
value: token[1],
|
||||
source: {
|
||||
start: {
|
||||
line: token[2],
|
||||
column: token[3]
|
||||
},
|
||||
end: {
|
||||
line: token[4],
|
||||
column: token[5]
|
||||
}
|
||||
},
|
||||
sourceIndex: token[6]
|
||||
}));
|
||||
|
||||
this.position ++;
|
||||
}
|
||||
|
||||
comment () {
|
||||
let inline = false,
|
||||
value = this.currToken[1].replace(/\/\*|\*\//g, ''),
|
||||
node;
|
||||
|
||||
if (this.options.loose && value.startsWith("//")) {
|
||||
value = value.substring(2);
|
||||
inline = true;
|
||||
}
|
||||
|
||||
node = new Comment({
|
||||
value: value,
|
||||
inline: inline,
|
||||
source: {
|
||||
start: {
|
||||
line: this.currToken[2],
|
||||
column: this.currToken[3]
|
||||
},
|
||||
end: {
|
||||
line: this.currToken[4],
|
||||
column: this.currToken[5]
|
||||
}
|
||||
},
|
||||
sourceIndex: this.currToken[6]
|
||||
});
|
||||
|
||||
this.newNode(node);
|
||||
this.position++;
|
||||
}
|
||||
|
||||
error (message, token) {
|
||||
throw new ParserError(message + ` at line: ${token[2]}, column ${token[3]}`);
|
||||
}
|
||||
|
||||
loop () {
|
||||
while (this.position < this.tokens.length) {
|
||||
this.parseTokens();
|
||||
}
|
||||
|
||||
if (!this.current.last && this.spaces) {
|
||||
this.current.raws.before += this.spaces;
|
||||
}
|
||||
else if (this.spaces) {
|
||||
this.current.last.raws.after += this.spaces;
|
||||
}
|
||||
|
||||
this.spaces = '';
|
||||
|
||||
return this.root;
|
||||
}
|
||||
|
||||
operator () {
|
||||
|
||||
// if a +|- operator is followed by a non-word character (. is allowed) and
|
||||
// is preceded by a non-word character. (5+5)
|
||||
let char = this.currToken[1],
|
||||
node;
|
||||
|
||||
if (char === '+' || char === '-') {
|
||||
// only inspect if the operator is not the first token, and we're only
|
||||
// within a calc() function: the only spec-valid place for math expressions
|
||||
if (!this.options.loose) {
|
||||
if (this.position > 0) {
|
||||
if (this.current.type === 'func' && this.current.value === 'calc') {
|
||||
// allow operators to be proceeded by spaces and opening parens
|
||||
if (this.prevToken[0] !== 'space' && this.prevToken[0] !== '(') {
|
||||
this.error('Syntax Error', this.currToken);
|
||||
}
|
||||
// valid: calc(1 - +2)
|
||||
// invalid: calc(1 -+2)
|
||||
else if (this.nextToken[0] !== 'space' && this.nextToken[0] !== 'word') {
|
||||
this.error('Syntax Error', this.currToken);
|
||||
}
|
||||
// valid: calc(1 - +2)
|
||||
// valid: calc(-0.5 + 2)
|
||||
// invalid: calc(1 -2)
|
||||
else if (this.nextToken[0] === 'word' && this.current.last.type !== 'operator' &&
|
||||
this.current.last.value !== '(') {
|
||||
this.error('Syntax Error', this.currToken);
|
||||
}
|
||||
}
|
||||
// if we're not in a function and someone has doubled up on operators,
|
||||
// or they're trying to perform a calc outside of a calc
|
||||
// eg. +-4px or 5+ 5, throw an error
|
||||
else if (this.nextToken[0] === 'space'
|
||||
|| this.nextToken[0] === 'operator'
|
||||
|| this.prevToken[0] === 'operator') {
|
||||
this.error('Syntax Error', this.currToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.options.loose) {
|
||||
if (this.nextToken[0] === 'word') {
|
||||
return this.word();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((!this.current.nodes.length || (this.current.last && this.current.last.type === 'operator')) && this.nextToken[0] === 'word') {
|
||||
return this.word();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node = new Operator({
|
||||
value: this.currToken[1],
|
||||
source: {
|
||||
start: {
|
||||
line: this.currToken[2],
|
||||
column: this.currToken[3]
|
||||
},
|
||||
end: {
|
||||
line: this.currToken[2],
|
||||
column: this.currToken[3]
|
||||
}
|
||||
},
|
||||
sourceIndex: this.currToken[4]
|
||||
});
|
||||
|
||||
this.position ++;
|
||||
|
||||
return this.newNode(node);
|
||||
}
|
||||
|
||||
parseTokens () {
|
||||
switch (this.currToken[0]) {
|
||||
case 'space':
|
||||
this.space();
|
||||
break;
|
||||
case 'colon':
|
||||
this.colon();
|
||||
break;
|
||||
case 'comma':
|
||||
this.comma();
|
||||
break;
|
||||
case 'comment':
|
||||
this.comment();
|
||||
break;
|
||||
case '(':
|
||||
this.parenOpen();
|
||||
break;
|
||||
case ')':
|
||||
this.parenClose();
|
||||
break;
|
||||
case 'atword':
|
||||
case 'word':
|
||||
this.word();
|
||||
break;
|
||||
case 'operator':
|
||||
this.operator();
|
||||
break;
|
||||
case 'string':
|
||||
this.string();
|
||||
break;
|
||||
case 'unicoderange':
|
||||
this.unicodeRange();
|
||||
break;
|
||||
default:
|
||||
this.word();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
parenOpen () {
|
||||
let unbalanced = 1,
|
||||
pos = this.position + 1,
|
||||
token = this.currToken,
|
||||
last;
|
||||
|
||||
// check for balanced parens
|
||||
while (pos < this.tokens.length && unbalanced) {
|
||||
let tkn = this.tokens[pos];
|
||||
|
||||
if (tkn[0] === '(') {
|
||||
unbalanced++;
|
||||
}
|
||||
if (tkn[0] === ')') {
|
||||
unbalanced--;
|
||||
}
|
||||
pos ++;
|
||||
}
|
||||
|
||||
if (unbalanced) {
|
||||
this.error('Expected closing parenthesis', token);
|
||||
}
|
||||
|
||||
// ok, all parens are balanced. continue on
|
||||
|
||||
last = this.current.last;
|
||||
|
||||
if (last && last.type === 'func' && last.unbalanced < 0) {
|
||||
last.unbalanced = 0; // ok we're ready to add parens now
|
||||
this.current = last;
|
||||
}
|
||||
|
||||
this.current.unbalanced ++;
|
||||
|
||||
this.newNode(new Paren({
|
||||
value: token[1],
|
||||
source: {
|
||||
start: {
|
||||
line: token[2],
|
||||
column: token[3]
|
||||
},
|
||||
end: {
|
||||
line: token[4],
|
||||
column: token[5]
|
||||
}
|
||||
},
|
||||
sourceIndex: token[6]
|
||||
}));
|
||||
|
||||
this.position ++;
|
||||
|
||||
// url functions get special treatment, and anything between the function
|
||||
// parens get treated as one word, if the contents aren't not a string.
|
||||
if (this.current.type === 'func' && this.current.unbalanced &&
|
||||
this.current.value === 'url' && this.currToken[0] !== 'string' &&
|
||||
this.currToken[0] !== ')' && !this.options.loose) {
|
||||
|
||||
let nextToken = this.nextToken,
|
||||
value = this.currToken[1],
|
||||
start = {
|
||||
line: this.currToken[2],
|
||||
column: this.currToken[3]
|
||||
};
|
||||
|
||||
while (nextToken && nextToken[0] !== ')' && this.current.unbalanced) {
|
||||
this.position ++;
|
||||
value += this.currToken[1];
|
||||
nextToken = this.nextToken;
|
||||
}
|
||||
|
||||
if (this.position !== this.tokens.length - 1) {
|
||||
// skip the following word definition, or it'll be a duplicate
|
||||
this.position ++;
|
||||
|
||||
this.newNode(new Word({
|
||||
value,
|
||||
source: {
|
||||
start,
|
||||
end: {
|
||||
line: this.currToken[4],
|
||||
column: this.currToken[5]
|
||||
}
|
||||
},
|
||||
sourceIndex: this.currToken[6]
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parenClose () {
|
||||
let token = this.currToken;
|
||||
|
||||
this.newNode(new Paren({
|
||||
value: token[1],
|
||||
source: {
|
||||
start: {
|
||||
line: token[2],
|
||||
column: token[3]
|
||||
},
|
||||
end: {
|
||||
line: token[4],
|
||||
column: token[5]
|
||||
}
|
||||
},
|
||||
sourceIndex: token[6]
|
||||
}));
|
||||
|
||||
this.position ++;
|
||||
|
||||
if (this.position >= this.tokens.length - 1 && !this.current.unbalanced) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.current.unbalanced --;
|
||||
|
||||
if (this.current.unbalanced < 0) {
|
||||
this.error('Expected opening parenthesis', token);
|
||||
}
|
||||
|
||||
if (!this.current.unbalanced && this.cache.length) {
|
||||
this.current = this.cache.pop();
|
||||
}
|
||||
}
|
||||
|
||||
space () {
|
||||
let token = this.currToken;
|
||||
// Handle space before and after the selector
|
||||
if (this.position === (this.tokens.length - 1) || this.nextToken[0] === ',' || this.nextToken[0] === ')') {
|
||||
this.current.last.raws.after += token[1];
|
||||
this.position ++;
|
||||
}
|
||||
else {
|
||||
this.spaces = token[1];
|
||||
this.position ++;
|
||||
}
|
||||
}
|
||||
|
||||
unicodeRange () {
|
||||
let token = this.currToken;
|
||||
|
||||
this.newNode(new UnicodeRange({
|
||||
value: token[1],
|
||||
source: {
|
||||
start: {
|
||||
line: token[2],
|
||||
column: token[3]
|
||||
},
|
||||
end: {
|
||||
line: token[4],
|
||||
column: token[5]
|
||||
}
|
||||
},
|
||||
sourceIndex: token[6]
|
||||
}));
|
||||
|
||||
this.position ++;
|
||||
}
|
||||
|
||||
splitWord () {
|
||||
let nextToken = this.nextToken,
|
||||
word = this.currToken[1],
|
||||
rNumber = /^[\+\-]?((\d+(\.\d*)?)|(\.\d+))([eE][\+\-]?\d+)?/,
|
||||
|
||||
// treat css-like groupings differently so they can be inspected,
|
||||
// but don't address them as anything but a word, but allow hex values
|
||||
// to pass through.
|
||||
rNoFollow = /^(?!\#([a-z0-9]+))[\#\{\}]/gi,
|
||||
|
||||
hasAt, indices;
|
||||
|
||||
if (!rNoFollow.test(word)) {
|
||||
while (nextToken && nextToken[0] === 'word') {
|
||||
this.position ++;
|
||||
|
||||
let current = this.currToken[1];
|
||||
word += current;
|
||||
|
||||
nextToken = this.nextToken;
|
||||
}
|
||||
}
|
||||
|
||||
hasAt = indexesOf(word, '@');
|
||||
indices = sortAscending(uniq(flatten([[0], hasAt])));
|
||||
|
||||
indices.forEach((ind, i) => {
|
||||
let index = indices[i + 1] || word.length,
|
||||
value = word.slice(ind, index),
|
||||
node;
|
||||
|
||||
if (~hasAt.indexOf(ind)) {
|
||||
node = new AtWord({
|
||||
value: value.slice(1),
|
||||
source: {
|
||||
start: {
|
||||
line: this.currToken[2],
|
||||
column: this.currToken[3] + ind
|
||||
},
|
||||
end: {
|
||||
line: this.currToken[4],
|
||||
column: this.currToken[3] + (index - 1)
|
||||
}
|
||||
},
|
||||
sourceIndex: this.currToken[6] + indices[i]
|
||||
});
|
||||
}
|
||||
else if (rNumber.test(this.currToken[1])) {
|
||||
let unit = value.replace(rNumber, '');
|
||||
|
||||
node = new Numbr({
|
||||
value: value.replace(unit, ''),
|
||||
source: {
|
||||
start: {
|
||||
line: this.currToken[2],
|
||||
column: this.currToken[3] + ind
|
||||
},
|
||||
end: {
|
||||
line: this.currToken[4],
|
||||
column: this.currToken[3] + (index - 1)
|
||||
}
|
||||
},
|
||||
sourceIndex: this.currToken[6] + indices[i],
|
||||
unit
|
||||
});
|
||||
}
|
||||
else {
|
||||
node = new (nextToken && nextToken[0] === '(' ? Func : Word)({
|
||||
value,
|
||||
source: {
|
||||
start: {
|
||||
line: this.currToken[2],
|
||||
column: this.currToken[3] + ind
|
||||
},
|
||||
end: {
|
||||
line: this.currToken[4],
|
||||
column: this.currToken[3] + (index - 1)
|
||||
}
|
||||
},
|
||||
sourceIndex: this.currToken[6] + indices[i]
|
||||
});
|
||||
|
||||
if (node.constructor.name === 'Word') {
|
||||
node.isHex = /^#(.+)/.test(value);
|
||||
node.isColor = /^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(value);
|
||||
}
|
||||
else {
|
||||
this.cache.push(this.current);
|
||||
}
|
||||
}
|
||||
|
||||
this.newNode(node);
|
||||
|
||||
});
|
||||
|
||||
this.position ++;
|
||||
}
|
||||
|
||||
string () {
|
||||
let token = this.currToken,
|
||||
value = this.currToken[1],
|
||||
rQuote = /^(\"|\')/,
|
||||
quoted = rQuote.test(value),
|
||||
quote = '',
|
||||
node;
|
||||
|
||||
if (quoted) {
|
||||
quote = value.match(rQuote)[0];
|
||||
// set value to the string within the quotes
|
||||
// quotes are stored in raws
|
||||
value = value.slice(1, value.length - 1);
|
||||
}
|
||||
|
||||
node = new Str({
|
||||
value,
|
||||
source: {
|
||||
start: {
|
||||
line: token[2],
|
||||
column: token[3]
|
||||
},
|
||||
end: {
|
||||
line: token[4],
|
||||
column: token[5]
|
||||
}
|
||||
},
|
||||
sourceIndex: token[6],
|
||||
quoted
|
||||
});
|
||||
|
||||
node.raws.quote = quote;
|
||||
|
||||
this.newNode(node);
|
||||
this.position++;
|
||||
}
|
||||
|
||||
word () {
|
||||
return this.splitWord();
|
||||
}
|
||||
|
||||
newNode (node) {
|
||||
if (this.spaces) {
|
||||
node.raws.before += this.spaces;
|
||||
this.spaces = '';
|
||||
}
|
||||
|
||||
return this.current.append(node);
|
||||
}
|
||||
|
||||
get currToken () {
|
||||
return this.tokens[this.position];
|
||||
}
|
||||
|
||||
get nextToken () {
|
||||
return this.tokens[this.position + 1];
|
||||
}
|
||||
|
||||
get prevToken () {
|
||||
return this.tokens[this.position - 1];
|
||||
}
|
||||
};
|
416
web/node_modules/postcss-values-parser/old-lib/tokenize.js
generated
vendored
Normal file
416
web/node_modules/postcss-values-parser/old-lib/tokenize.js
generated
vendored
Normal file
|
@ -0,0 +1,416 @@
|
|||
const openBracket = '{'.charCodeAt(0);
|
||||
const closeBracket = '}'.charCodeAt(0);
|
||||
const openParen = '('.charCodeAt(0);
|
||||
const closeParen = ')'.charCodeAt(0);
|
||||
const singleQuote = "'".charCodeAt(0);
|
||||
const doubleQuote = '"'.charCodeAt(0);
|
||||
const backslash = '\\'.charCodeAt(0);
|
||||
const slash = '/'.charCodeAt(0);
|
||||
const period = '.'.charCodeAt(0);
|
||||
const comma = ','.charCodeAt(0);
|
||||
const colon = ':'.charCodeAt(0);
|
||||
const asterisk = '*'.charCodeAt(0);
|
||||
const minus = '-'.charCodeAt(0);
|
||||
const plus = '+'.charCodeAt(0);
|
||||
const pound = '#'.charCodeAt(0);
|
||||
const newline = '\n'.charCodeAt(0);
|
||||
const space = ' '.charCodeAt(0);
|
||||
const feed = '\f'.charCodeAt(0);
|
||||
const tab = '\t'.charCodeAt(0);
|
||||
const cr = '\r'.charCodeAt(0);
|
||||
const at = '@'.charCodeAt(0);
|
||||
const lowerE = 'e'.charCodeAt(0);
|
||||
const upperE = 'E'.charCodeAt(0);
|
||||
const digit0 = '0'.charCodeAt(0);
|
||||
const digit9 = '9'.charCodeAt(0);
|
||||
const lowerU = 'u'.charCodeAt(0);
|
||||
const upperU = 'U'.charCodeAt(0);
|
||||
const atEnd = /[ \n\t\r\{\(\)'"\\;,/]/g;
|
||||
const wordEnd = /[ \n\t\r\(\)\{\}\*:;@!&'"\+\|~>,\[\]\\]|\/(?=\*)/g;
|
||||
const wordEndNum = /[ \n\t\r\(\)\{\}\*:;@!&'"\-\+\|~>,\[\]\\]|\//g;
|
||||
const alphaNum = /^[a-z0-9]/i;
|
||||
const unicodeRange = /^[a-f0-9?\-]/i;
|
||||
|
||||
const util = require('util');
|
||||
|
||||
const TokenizeError = require('./errors/TokenizeError');
|
||||
|
||||
module.exports = function tokenize(input, options) {
|
||||
options = options || {};
|
||||
|
||||
const tokens = [];
|
||||
|
||||
const css = input.valueOf();
|
||||
|
||||
const length = css.length;
|
||||
|
||||
let offset = -1;
|
||||
|
||||
let line = 1;
|
||||
|
||||
let pos = 0;
|
||||
|
||||
let parentCount = 0;
|
||||
|
||||
let isURLArg = null;
|
||||
|
||||
let code;
|
||||
let next;
|
||||
let quote;
|
||||
let lines;
|
||||
let last;
|
||||
let content;
|
||||
let escape;
|
||||
let nextLine;
|
||||
let nextOffset;
|
||||
|
||||
let escaped;
|
||||
let escapePos;
|
||||
let nextChar;
|
||||
|
||||
function unclosed(what) {
|
||||
const message = util.format(
|
||||
'Unclosed %s at line: %d, column: %d, token: %d',
|
||||
what,
|
||||
line,
|
||||
pos - offset,
|
||||
pos
|
||||
);
|
||||
throw new TokenizeError(message);
|
||||
}
|
||||
|
||||
function tokenizeError() {
|
||||
const message = util.format(
|
||||
'Syntax error at line: %d, column: %d, token: %d',
|
||||
line,
|
||||
pos - offset,
|
||||
pos
|
||||
);
|
||||
throw new TokenizeError(message);
|
||||
}
|
||||
|
||||
while (pos < length) {
|
||||
code = css.charCodeAt(pos);
|
||||
|
||||
if (code === newline) {
|
||||
offset = pos;
|
||||
line += 1;
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
case newline:
|
||||
case space:
|
||||
case tab:
|
||||
case cr:
|
||||
case feed:
|
||||
next = pos;
|
||||
do {
|
||||
next += 1;
|
||||
code = css.charCodeAt(next);
|
||||
if (code === newline) {
|
||||
offset = next;
|
||||
line += 1;
|
||||
}
|
||||
} while (
|
||||
code === space ||
|
||||
code === newline ||
|
||||
code === tab ||
|
||||
code === cr ||
|
||||
code === feed
|
||||
);
|
||||
|
||||
tokens.push(['space', css.slice(pos, next), line, pos - offset, line, next - offset, pos]);
|
||||
|
||||
pos = next - 1;
|
||||
break;
|
||||
|
||||
case colon:
|
||||
next = pos + 1;
|
||||
tokens.push(['colon', css.slice(pos, next), line, pos - offset, line, next - offset, pos]);
|
||||
|
||||
pos = next - 1;
|
||||
break;
|
||||
|
||||
case comma:
|
||||
next = pos + 1;
|
||||
tokens.push(['comma', css.slice(pos, next), line, pos - offset, line, next - offset, pos]);
|
||||
|
||||
pos = next - 1;
|
||||
break;
|
||||
|
||||
case openBracket:
|
||||
tokens.push(['{', '{', line, pos - offset, line, next - offset, pos]);
|
||||
break;
|
||||
|
||||
case closeBracket:
|
||||
tokens.push(['}', '}', line, pos - offset, line, next - offset, pos]);
|
||||
break;
|
||||
|
||||
case openParen:
|
||||
parentCount++;
|
||||
isURLArg =
|
||||
!isURLArg &&
|
||||
parentCount === 1 &&
|
||||
tokens.length > 0 &&
|
||||
tokens[tokens.length - 1][0] === 'word' &&
|
||||
tokens[tokens.length - 1][1] === 'url';
|
||||
tokens.push(['(', '(', line, pos - offset, line, next - offset, pos]);
|
||||
break;
|
||||
|
||||
case closeParen:
|
||||
parentCount--;
|
||||
isURLArg = !isURLArg && parentCount === 1;
|
||||
tokens.push([')', ')', line, pos - offset, line, next - offset, pos]);
|
||||
break;
|
||||
|
||||
case singleQuote:
|
||||
case doubleQuote:
|
||||
quote = code === singleQuote ? "'" : '"';
|
||||
next = pos;
|
||||
do {
|
||||
escaped = false;
|
||||
next = css.indexOf(quote, next + 1);
|
||||
if (next === -1) {
|
||||
unclosed('quote', quote);
|
||||
}
|
||||
escapePos = next;
|
||||
while (css.charCodeAt(escapePos - 1) === backslash) {
|
||||
escapePos -= 1;
|
||||
escaped = !escaped;
|
||||
}
|
||||
} while (escaped);
|
||||
|
||||
tokens.push([
|
||||
'string',
|
||||
css.slice(pos, next + 1),
|
||||
line,
|
||||
pos - offset,
|
||||
line,
|
||||
next - offset,
|
||||
pos
|
||||
]);
|
||||
pos = next;
|
||||
break;
|
||||
|
||||
case at:
|
||||
atEnd.lastIndex = pos + 1;
|
||||
atEnd.test(css);
|
||||
|
||||
if (atEnd.lastIndex === 0) {
|
||||
next = css.length - 1;
|
||||
} else {
|
||||
next = atEnd.lastIndex - 2;
|
||||
}
|
||||
|
||||
tokens.push([
|
||||
'atword',
|
||||
css.slice(pos, next + 1),
|
||||
line,
|
||||
pos - offset,
|
||||
line,
|
||||
next - offset,
|
||||
pos
|
||||
]);
|
||||
pos = next;
|
||||
break;
|
||||
|
||||
case backslash:
|
||||
next = pos;
|
||||
code = css.charCodeAt(next + 1);
|
||||
|
||||
if (
|
||||
escape &&
|
||||
(code !== slash &&
|
||||
code !== space &&
|
||||
code !== newline &&
|
||||
code !== tab &&
|
||||
code !== cr &&
|
||||
code !== feed)
|
||||
) {
|
||||
next += 1;
|
||||
}
|
||||
|
||||
tokens.push([
|
||||
'word',
|
||||
css.slice(pos, next + 1),
|
||||
line,
|
||||
pos - offset,
|
||||
line,
|
||||
next - offset,
|
||||
pos
|
||||
]);
|
||||
|
||||
pos = next;
|
||||
break;
|
||||
|
||||
case plus:
|
||||
case minus:
|
||||
case asterisk:
|
||||
next = pos + 1;
|
||||
nextChar = css.slice(pos + 1, next + 1);
|
||||
|
||||
const prevChar = css.slice(pos - 1, pos);
|
||||
|
||||
// if the operator is immediately followed by a word character, then we
|
||||
// have a prefix of some kind, and should fall-through. eg. -webkit
|
||||
|
||||
// look for --* for custom variables
|
||||
if (code === minus && nextChar.charCodeAt(0) === minus) {
|
||||
next++;
|
||||
|
||||
tokens.push(['word', css.slice(pos, next), line, pos - offset, line, next - offset, pos]);
|
||||
|
||||
pos = next - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
tokens.push([
|
||||
'operator',
|
||||
css.slice(pos, next),
|
||||
line,
|
||||
pos - offset,
|
||||
line,
|
||||
next - offset,
|
||||
pos
|
||||
]);
|
||||
|
||||
pos = next - 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (
|
||||
code === slash &&
|
||||
(css.charCodeAt(pos + 1) === asterisk ||
|
||||
(options.loose && !isURLArg && css.charCodeAt(pos + 1) === slash))
|
||||
) {
|
||||
const isStandardComment = css.charCodeAt(pos + 1) === asterisk;
|
||||
|
||||
if (isStandardComment) {
|
||||
next = css.indexOf('*/', pos + 2) + 1;
|
||||
if (next === 0) {
|
||||
unclosed('comment', '*/');
|
||||
}
|
||||
} else {
|
||||
const newlinePos = css.indexOf('\n', pos + 2);
|
||||
|
||||
next = newlinePos !== -1 ? newlinePos - 1 : length;
|
||||
}
|
||||
|
||||
content = css.slice(pos, next + 1);
|
||||
lines = content.split('\n');
|
||||
last = lines.length - 1;
|
||||
|
||||
if (last > 0) {
|
||||
nextLine = line + last;
|
||||
nextOffset = next - lines[last].length;
|
||||
} else {
|
||||
nextLine = line;
|
||||
nextOffset = offset;
|
||||
}
|
||||
|
||||
tokens.push(['comment', content, line, pos - offset, nextLine, next - nextOffset, pos]);
|
||||
|
||||
offset = nextOffset;
|
||||
line = nextLine;
|
||||
pos = next;
|
||||
} else if (code === pound && !alphaNum.test(css.slice(pos + 1, pos + 2))) {
|
||||
next = pos + 1;
|
||||
|
||||
tokens.push(['#', css.slice(pos, next), line, pos - offset, line, next - offset, pos]);
|
||||
|
||||
pos = next - 1;
|
||||
} else if ((code === lowerU || code === upperU) && css.charCodeAt(pos + 1) === plus) {
|
||||
next = pos + 2;
|
||||
|
||||
do {
|
||||
next += 1;
|
||||
code = css.charCodeAt(next);
|
||||
} while (next < length && unicodeRange.test(css.slice(next, next + 1)));
|
||||
|
||||
tokens.push([
|
||||
'unicoderange',
|
||||
css.slice(pos, next),
|
||||
line,
|
||||
pos - offset,
|
||||
line,
|
||||
next - offset,
|
||||
pos
|
||||
]);
|
||||
pos = next - 1;
|
||||
}
|
||||
// catch a regular slash, that isn't a comment
|
||||
else if (code === slash) {
|
||||
next = pos + 1;
|
||||
|
||||
tokens.push([
|
||||
'operator',
|
||||
css.slice(pos, next),
|
||||
line,
|
||||
pos - offset,
|
||||
line,
|
||||
next - offset,
|
||||
pos
|
||||
]);
|
||||
|
||||
pos = next - 1;
|
||||
} else {
|
||||
let regex = wordEnd;
|
||||
|
||||
// we're dealing with a word that starts with a number
|
||||
// those get treated differently
|
||||
if (code >= digit0 && code <= digit9) {
|
||||
regex = wordEndNum;
|
||||
}
|
||||
|
||||
regex.lastIndex = pos + 1;
|
||||
regex.test(css);
|
||||
|
||||
if (regex.lastIndex === 0) {
|
||||
next = css.length - 1;
|
||||
} else {
|
||||
next = regex.lastIndex - 2;
|
||||
}
|
||||
|
||||
// Exponential number notation with minus or plus: 1e-10, 1e+10
|
||||
if (regex === wordEndNum || code === period) {
|
||||
const ncode = css.charCodeAt(next);
|
||||
|
||||
const ncode1 = css.charCodeAt(next + 1);
|
||||
|
||||
const ncode2 = css.charCodeAt(next + 2);
|
||||
|
||||
if (
|
||||
(ncode === lowerE || ncode === upperE) &&
|
||||
(ncode1 === minus || ncode1 === plus) &&
|
||||
(ncode2 >= digit0 && ncode2 <= digit9)
|
||||
) {
|
||||
wordEndNum.lastIndex = next + 2;
|
||||
wordEndNum.test(css);
|
||||
|
||||
if (wordEndNum.lastIndex === 0) {
|
||||
next = css.length - 1;
|
||||
} else {
|
||||
next = wordEndNum.lastIndex - 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tokens.push([
|
||||
'word',
|
||||
css.slice(pos, next + 1),
|
||||
line,
|
||||
pos - offset,
|
||||
line,
|
||||
next - offset,
|
||||
pos
|
||||
]);
|
||||
pos = next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
pos++;
|
||||
}
|
||||
|
||||
return tokens;
|
||||
};
|
43
web/node_modules/postcss-values-parser/package.json
generated
vendored
Normal file
43
web/node_modules/postcss-values-parser/package.json
generated
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"name": "postcss-values-parser",
|
||||
"version": "2.0.1",
|
||||
"description": "A CSS property value parser for use with PostCSS",
|
||||
"main": "lib/index.js",
|
||||
"repository": "lesshint/postcss-values-parser",
|
||||
"author": {
|
||||
"name": "Andrew Powell (shellscape)",
|
||||
"email": "andrew@shellscape.org",
|
||||
"url": "http://shellscape.org"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.14.4"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "gulp"
|
||||
},
|
||||
"keywords": [
|
||||
"css",
|
||||
"less",
|
||||
"ast",
|
||||
"postcss",
|
||||
"value",
|
||||
"values",
|
||||
"parser",
|
||||
"parsing",
|
||||
"properties"
|
||||
],
|
||||
"dependencies": {
|
||||
"flatten": "^1.0.2",
|
||||
"indexes-of": "^1.0.1",
|
||||
"uniq": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^4.1.2",
|
||||
"chai-shallow-deep-equal": "^1.4.0",
|
||||
"eslint": "^5.6.0",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-eslint": "^5.0.0",
|
||||
"gulp-mocha": "^6.0.0"
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue