Import python-tinycss2_0.6.1.orig.tar.gz
[dgit import orig python-tinycss2_0.6.1.orig.tar.gz]
This commit is contained in:
commit
33bf61345e
|
@ -0,0 +1,10 @@
|
||||||
|
[run]
|
||||||
|
branch = True
|
||||||
|
|
||||||
|
[report]
|
||||||
|
exclude_lines =
|
||||||
|
pragma: no cover
|
||||||
|
def __repr__
|
||||||
|
raise NotImplementedError
|
||||||
|
omit =
|
||||||
|
.*
|
|
@ -0,0 +1,8 @@
|
||||||
|
*.pyc
|
||||||
|
*.egg-info
|
||||||
|
.cache
|
||||||
|
.coverage
|
||||||
|
.eggs
|
||||||
|
/htmlcov
|
||||||
|
/dist
|
||||||
|
/build
|
|
@ -0,0 +1,30 @@
|
||||||
|
language: python
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
git:
|
||||||
|
submodules: false
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: linux
|
||||||
|
python: 2.7
|
||||||
|
- os: linux
|
||||||
|
python: 3.3
|
||||||
|
- os: linux
|
||||||
|
python: 3.4
|
||||||
|
- os: linux
|
||||||
|
python: 3.5
|
||||||
|
- os: linux
|
||||||
|
python: 3.6
|
||||||
|
- os: osx
|
||||||
|
language: generic
|
||||||
|
env: PYTHON_VERSION=3
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install python3; fi
|
||||||
|
|
||||||
|
install:
|
||||||
|
- pip$PYTHON_VERSION install --upgrade -e.[test]
|
||||||
|
|
||||||
|
script:
|
||||||
|
- python$PYTHON_VERSION setup.py test
|
|
@ -0,0 +1,83 @@
|
||||||
|
tinycss2 changelog
|
||||||
|
==================
|
||||||
|
|
||||||
|
|
||||||
|
Version 0.6.1
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Released on 2017-10-02.
|
||||||
|
|
||||||
|
* Update documentation.
|
||||||
|
|
||||||
|
|
||||||
|
Version 0.6.0
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Released on 2017-08-16.
|
||||||
|
|
||||||
|
* Don't allow identifiers starting with two dashes.
|
||||||
|
* Don't use Tox for tests.
|
||||||
|
* Follow semantic versioning.
|
||||||
|
|
||||||
|
|
||||||
|
Version 0.5
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Released on 2014-08-19.
|
||||||
|
|
||||||
|
* Update for spec changes.
|
||||||
|
* Add a :attr:`~tinycss2.ast.WhitespaceToken.value` attribute
|
||||||
|
to :class:`~tinycss2.ast.WhitespaceToken`.
|
||||||
|
* **Breaking change**: CSS comments are now preserved
|
||||||
|
as :class:`~tinycss2.ast.Comment` objects by default.
|
||||||
|
Pass ``skip_comments=True`` to parsing functions to get the old behavior.
|
||||||
|
* **Breaking change**: Top-level comments and whitespace are now preserved
|
||||||
|
when parsing a stylesheet, rule list, or declaration list.
|
||||||
|
Pass ``skip_comments=True`` and ``skip_whitespace=True``
|
||||||
|
to get the old behavior.
|
||||||
|
* Test on Python 3.4 and PyPy3.
|
||||||
|
* Set up continous integration on Travis-CI.
|
||||||
|
|
||||||
|
|
||||||
|
Version 0.4
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Released on 2014-01-04.
|
||||||
|
|
||||||
|
* Fix :class:`~tinycss2.ast.HashToken` starting with a non-ASCII character.
|
||||||
|
* Fix :func:`repr` on AST nodes.
|
||||||
|
|
||||||
|
|
||||||
|
Version 0.3
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Released on 2013-12-27.
|
||||||
|
|
||||||
|
* Document all the things!
|
||||||
|
* Add :ref:`serialization`
|
||||||
|
* Merge :func:`tinycss2.color3.parse_color_string` behavior into
|
||||||
|
:func:`~tinycss2.color3.parse_color`.
|
||||||
|
* Fix and test parsing form bytes and tokenization of <unicode-range>.
|
||||||
|
|
||||||
|
|
||||||
|
Version 0.2
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Released on 2013-09-02.
|
||||||
|
|
||||||
|
Add parsing for <An+B>,
|
||||||
|
as in ``:nth-child()`` and related Selectors pseudo-classes.
|
||||||
|
|
||||||
|
|
||||||
|
Version 0.1
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Released on 2013-08-31.
|
||||||
|
|
||||||
|
First PyPI release. Contains:
|
||||||
|
|
||||||
|
* Decoding from bytes (``@charset``, etc.)
|
||||||
|
* Tokenization
|
||||||
|
* Parsing for "generic" rules and declarations
|
||||||
|
* Parsing for CSS Color Level 3
|
||||||
|
* Tests for all of the above, except for decoding from bytes.
|
|
@ -0,0 +1,31 @@
|
||||||
|
Copyright (c) 2013 by Simon Sapin.
|
||||||
|
|
||||||
|
Some rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following
|
||||||
|
disclaimer in the documentation and/or other materials provided
|
||||||
|
with the distribution.
|
||||||
|
|
||||||
|
* The names of the contributors may not be used to endorse or
|
||||||
|
promote products derived from this software without specific
|
||||||
|
prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,4 @@
|
||||||
|
include CHANGES
|
||||||
|
include LICENSE
|
||||||
|
include docs/*
|
||||||
|
include tinycss2/css-parsing-tests/*
|
|
@ -0,0 +1,41 @@
|
||||||
|
Metadata-Version: 1.1
|
||||||
|
Name: tinycss2
|
||||||
|
Version: 0.6.1
|
||||||
|
Summary: Low-level CSS parser for Python
|
||||||
|
Home-page: UNKNOWN
|
||||||
|
Author: Simon Sapin
|
||||||
|
Author-email: simon.sapin@exyr.org
|
||||||
|
License: BSD
|
||||||
|
Description-Content-Type: UNKNOWN
|
||||||
|
Description: tinycss2: Low-level CSS parser for Python
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
tinycss2 is a rewrite of tinycss_ with a simpler API,
|
||||||
|
based on the more recent `CSS Syntax Level 3`_ specification.
|
||||||
|
|
||||||
|
.. _tinycss: http://pythonhosted.org/tinycss/
|
||||||
|
.. _CSS Syntax Level 3: http://dev.w3.org/csswg/css-syntax-3/
|
||||||
|
|
||||||
|
* BSD licensed
|
||||||
|
* For Python 2.7 or 3.3+ (tested on CPython)
|
||||||
|
* Latest documentation: http://tinycss2.readthedocs.io/
|
||||||
|
* Source code and issue tracker: https://github.com/Kozea/tinycss2
|
||||||
|
* PyPI releases: https://pypi.python.org/pypi/tinycss2/
|
||||||
|
* Continuous integration: |travis|
|
||||||
|
|
||||||
|
.. |travis| image:: https://travis-ci.org/Kozea/tinycss2.svg?branch=master
|
||||||
|
:target: https://travis-ci.org/Kozea/tinycss2
|
||||||
|
:alt: https://travis-ci.org/Kozea/tinycss2
|
||||||
|
|
||||||
|
Platform: UNKNOWN
|
||||||
|
Classifier: Development Status :: 5 - Production/Stable
|
||||||
|
Classifier: Intended Audience :: Developers
|
||||||
|
Classifier: License :: OSI Approved :: BSD License
|
||||||
|
Classifier: Programming Language :: Python :: 2
|
||||||
|
Classifier: Programming Language :: Python :: 2.7
|
||||||
|
Classifier: Programming Language :: Python :: 3
|
||||||
|
Classifier: Programming Language :: Python :: 3.3
|
||||||
|
Classifier: Programming Language :: Python :: 3.4
|
||||||
|
Classifier: Programming Language :: Python :: 3.5
|
||||||
|
Classifier: Programming Language :: Python :: 3.6
|
||||||
|
Classifier: Topic :: Text Processing
|
|
@ -0,0 +1,19 @@
|
||||||
|
tinycss2: Low-level CSS parser for Python
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
tinycss2 is a rewrite of tinycss_ with a simpler API,
|
||||||
|
based on the more recent `CSS Syntax Level 3`_ specification.
|
||||||
|
|
||||||
|
.. _tinycss: http://pythonhosted.org/tinycss/
|
||||||
|
.. _CSS Syntax Level 3: http://dev.w3.org/csswg/css-syntax-3/
|
||||||
|
|
||||||
|
* BSD licensed
|
||||||
|
* For Python 2.7 or 3.3+ (tested on CPython)
|
||||||
|
* Latest documentation: http://tinycss2.readthedocs.io/
|
||||||
|
* Source code and issue tracker: https://github.com/Kozea/tinycss2
|
||||||
|
* PyPI releases: https://pypi.python.org/pypi/tinycss2/
|
||||||
|
* Continuous integration: |travis|
|
||||||
|
|
||||||
|
.. |travis| image:: https://travis-ci.org/Kozea/tinycss2.svg?branch=master
|
||||||
|
:target: https://travis-ci.org/Kozea/tinycss2
|
||||||
|
:alt: https://travis-ci.org/Kozea/tinycss2
|
|
@ -0,0 +1,4 @@
|
||||||
|
Test preserve_comments=True
|
||||||
|
|
||||||
|
Test declaration corner cases: top-level ! and ;
|
||||||
|
… once that is all figured out in the spec
|
|
@ -0,0 +1,84 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# tinycss2 documentation build configuration file.
|
||||||
|
|
||||||
|
import codecs
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
|
||||||
|
sys.path.append(path.dirname(path.abspath(__file__)))
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
|
extensions = [
|
||||||
|
'sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'css_diagram_role']
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
# The suffix of source filenames.
|
||||||
|
source_suffix = '.rst'
|
||||||
|
|
||||||
|
# The master toctree document.
|
||||||
|
master_doc = 'index'
|
||||||
|
|
||||||
|
# General information about the project.
|
||||||
|
project = 'tinycss2'
|
||||||
|
copyright = '2013-2017, Simon Sapin'
|
||||||
|
|
||||||
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
|
# |version| and |release|, also used in various other places throughout the
|
||||||
|
# built documents.
|
||||||
|
#
|
||||||
|
# The full version, including alpha/beta/rc tags.
|
||||||
|
release = re.search("VERSION = '([^']+)'", codecs.open(
|
||||||
|
path.join(path.dirname(path.dirname(__file__)), 'tinycss2', '__init__.py'),
|
||||||
|
encoding='utf-8',
|
||||||
|
).read().strip()).group(1)
|
||||||
|
|
||||||
|
# The short X.Y version.
|
||||||
|
version = '.'.join(release.split('.')[:2])
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
exclude_patterns = ['_build']
|
||||||
|
|
||||||
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
|
pygments_style = 'sphinx'
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
|
# a list of builtin themes.
|
||||||
|
html_theme = 'sphinx_rtd_theme'
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ['_static']
|
||||||
|
|
||||||
|
# Output file base name for HTML help builder.
|
||||||
|
htmlhelp_basename = 'tinycss2doc'
|
||||||
|
|
||||||
|
# One entry per manual page. List of tuples
|
||||||
|
# (source start file, name, description, authors, manual section).
|
||||||
|
man_pages = [
|
||||||
|
('index', 'tinycss2', 'tinycss2 Documentation',
|
||||||
|
['Simon Sapin'], 1)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Grouping the document tree into Texinfo files. List of tuples
|
||||||
|
# (source start file, target name, title, author,
|
||||||
|
# dir menu entry, description, category)
|
||||||
|
texinfo_documents = [
|
||||||
|
('index', 'tinycss2', 'tinycss2 Documentation',
|
||||||
|
'Simon Sapin', 'tinycss2', 'One line description of project.',
|
||||||
|
'Miscellaneous'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Example configuration for intersphinx: refer to the Python standard library.
|
||||||
|
intersphinx_mapping = {
|
||||||
|
'py2': ('http://docs.python.org/2', None),
|
||||||
|
'py3': ('http://docs.python.org/3', None),
|
||||||
|
'webencodings': ('http://pythonhosted.org/webencodings/', None)}
|
|
@ -0,0 +1,21 @@
|
||||||
|
# coding: utf8
|
||||||
|
"""
|
||||||
|
A Sphinx extension adding a 'css' role creating links to
|
||||||
|
the spec’s railroad diagrams.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from docutils import nodes
|
||||||
|
|
||||||
|
|
||||||
|
def role_fn(_name, rawtext, text, lineno, inliner, options={}, content=()):
|
||||||
|
ref = 'http://dev.w3.org/csswg/css-syntax-3/#%s-diagram' % text.replace(
|
||||||
|
' ', '-')
|
||||||
|
if text.endswith(('-token', '-block')):
|
||||||
|
text = '<%s>' % text
|
||||||
|
ref = nodes.reference(rawtext, text, refuri=ref, **options)
|
||||||
|
return [ref], []
|
||||||
|
|
||||||
|
|
||||||
|
def setup(app):
|
||||||
|
app.add_role_to_domain('py', 'diagram', role_fn)
|
|
@ -0,0 +1,157 @@
|
||||||
|
:tocdepth: 3
|
||||||
|
|
||||||
|
.. include:: ../README.rst
|
||||||
|
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
Installing tinycss2 with pip_ should Just Work::
|
||||||
|
|
||||||
|
pip install tinycss2
|
||||||
|
|
||||||
|
This will also automatically install tinycss2’s only dependency, webencodings_.
|
||||||
|
tinycss2 and webencodings both only contain Python code and should work on any
|
||||||
|
Python implementation, although they’re only tested on CPython.
|
||||||
|
|
||||||
|
.. _pip: http://pip-installer.org/
|
||||||
|
.. _webencodings: http://pythonhosted.org/webencodings/
|
||||||
|
|
||||||
|
|
||||||
|
.. _parsing:
|
||||||
|
|
||||||
|
Parsing
|
||||||
|
=======
|
||||||
|
|
||||||
|
tinycss2 is “low-level” in that it doesn’t parse all of CSS:
|
||||||
|
it doesn’t know about the syntax of any specific properties or at-rules.
|
||||||
|
Instead, it provides a set of functions that can be composed
|
||||||
|
to support exactly the parts of CSS you’re interested in,
|
||||||
|
including new or non-standard rules or properties,
|
||||||
|
without modifying tinycss or having a complex hook/plugin system.
|
||||||
|
|
||||||
|
In many cases, parts of the parsed values
|
||||||
|
(such as the :attr:`~tinycss2.ast.AtRule.content`
|
||||||
|
of a :class:`~tinycss2.ast.AtRule`)
|
||||||
|
is given as :term:`component values` that can be parsed further
|
||||||
|
with other functions.
|
||||||
|
|
||||||
|
.. module:: tinycss2
|
||||||
|
.. autofunction:: parse_stylesheet_bytes
|
||||||
|
.. autofunction:: parse_stylesheet
|
||||||
|
.. autofunction:: parse_rule_list
|
||||||
|
.. autofunction:: parse_one_rule
|
||||||
|
.. autofunction:: parse_declaration_list
|
||||||
|
.. autofunction:: parse_one_declaration
|
||||||
|
.. autofunction:: parse_component_value_list
|
||||||
|
.. autofunction:: parse_one_component_value
|
||||||
|
|
||||||
|
|
||||||
|
.. _serialization:
|
||||||
|
|
||||||
|
Serialization
|
||||||
|
=============
|
||||||
|
|
||||||
|
In addition to each node’s a :meth:`~tinycss2.ast.Node.serialize` method,
|
||||||
|
some serialization-related functions are available:
|
||||||
|
|
||||||
|
.. autofunction:: serialize
|
||||||
|
.. autofunction:: serialize_identifier
|
||||||
|
|
||||||
|
|
||||||
|
.. module:: tinycss2.color3
|
||||||
|
|
||||||
|
Color
|
||||||
|
=====
|
||||||
|
|
||||||
|
.. autofunction:: parse_color
|
||||||
|
.. autoclass:: RGBA
|
||||||
|
|
||||||
|
|
||||||
|
.. module:: tinycss2.nth
|
||||||
|
|
||||||
|
<An+B>
|
||||||
|
======
|
||||||
|
|
||||||
|
.. autofunction:: parse_nth
|
||||||
|
|
||||||
|
|
||||||
|
.. module:: tinycss2.ast
|
||||||
|
|
||||||
|
AST nodes
|
||||||
|
=========
|
||||||
|
|
||||||
|
Various parsing functions return a **node** or a list of nodes.
|
||||||
|
Some types of nodes contain nested nodes which may in turn contain more nodes,
|
||||||
|
forming together an **abstract syntax tree**.
|
||||||
|
|
||||||
|
Although you typically don’t need to import it,
|
||||||
|
the :mod:`tinycss2.ast` module defines a class for every type of node.
|
||||||
|
|
||||||
|
.. autoclass:: Node()
|
||||||
|
|
||||||
|
.. autoclass:: QualifiedRule()
|
||||||
|
.. autoclass:: AtRule()
|
||||||
|
.. autoclass:: Declaration()
|
||||||
|
|
||||||
|
|
||||||
|
Component values
|
||||||
|
----------------
|
||||||
|
|
||||||
|
.. autoclass:: ParseError()
|
||||||
|
.. autoclass:: Comment()
|
||||||
|
.. autoclass:: WhitespaceToken()
|
||||||
|
.. autoclass:: LiteralToken()
|
||||||
|
.. autoclass:: IdentToken()
|
||||||
|
.. autoclass:: AtKeywordToken()
|
||||||
|
.. autoclass:: HashToken()
|
||||||
|
.. autoclass:: StringToken()
|
||||||
|
.. autoclass:: URLToken()
|
||||||
|
.. autoclass:: UnicodeRangeToken()
|
||||||
|
.. autoclass:: NumberToken()
|
||||||
|
.. autoclass:: PercentageToken()
|
||||||
|
.. autoclass:: DimensionToken()
|
||||||
|
.. autoclass:: ParenthesesBlock()
|
||||||
|
.. autoclass:: SquareBracketsBlock()
|
||||||
|
.. autoclass:: CurlyBracketsBlock()
|
||||||
|
.. autoclass:: FunctionBlock()
|
||||||
|
|
||||||
|
|
||||||
|
Glossary
|
||||||
|
========
|
||||||
|
|
||||||
|
.. currentmodule:: tinycss2.ast
|
||||||
|
.. glossary::
|
||||||
|
|
||||||
|
String
|
||||||
|
In this documentation “a string” means an Unicode string:
|
||||||
|
:func:`unicode <py2:unicode>` on Python 2.x and
|
||||||
|
:class:`py3:str` on Python 3.x.
|
||||||
|
On 2.x,
|
||||||
|
a byte string (:func:`str <py2:str>`) that only contains ASCII bytes
|
||||||
|
is also accepted and implicitly decoded.
|
||||||
|
|
||||||
|
Component value
|
||||||
|
Component values
|
||||||
|
A :class:`ParseError`,
|
||||||
|
:class:`WhitespaceToken`,
|
||||||
|
:class:`LiteralToken`,
|
||||||
|
:class:`IdentToken`,
|
||||||
|
:class:`AtKeywordToken`,
|
||||||
|
:class:`HashToken`,
|
||||||
|
:class:`StringToken`,
|
||||||
|
:class:`URLToken`,
|
||||||
|
:class:`NumberToken`,
|
||||||
|
:class:`PercentageToken`,
|
||||||
|
:class:`DimensionToken`,
|
||||||
|
:class:`UnicodeRangeToken`,
|
||||||
|
:class:`ParenthesesBlock`,
|
||||||
|
:class:`SquareBracketsBlock`,
|
||||||
|
:class:`CurlyBracketsBlock`,
|
||||||
|
:class:`FunctionBlock`,
|
||||||
|
or :class:`Comment`
|
||||||
|
object.
|
||||||
|
|
||||||
|
|
||||||
|
.. currentmodule:: tinycss2
|
||||||
|
.. include:: ../CHANGES
|
|
@ -0,0 +1,14 @@
|
||||||
|
[aliases]
|
||||||
|
test = pytest
|
||||||
|
|
||||||
|
[bdist_wheel]
|
||||||
|
universal = 1
|
||||||
|
|
||||||
|
[tool:pytest]
|
||||||
|
addopts = --cov=tinycss2 --flake8 --isort tinycss2/test.py
|
||||||
|
norecursedirs = dist .cache .git build *.egg-info .eggs venv
|
||||||
|
|
||||||
|
[egg_info]
|
||||||
|
tag_build =
|
||||||
|
tag_date = 0
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# coding: utf8
|
||||||
|
|
||||||
|
import codecs
|
||||||
|
import os.path
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
|
||||||
|
VERSION = re.search("VERSION = '([^']+)'", codecs.open(
|
||||||
|
os.path.join(os.path.dirname(__file__), 'tinycss2', '__init__.py'),
|
||||||
|
encoding='utf-8',
|
||||||
|
).read().strip()).group(1)
|
||||||
|
|
||||||
|
README = codecs.open(
|
||||||
|
os.path.join(os.path.dirname(__file__), 'README.rst'),
|
||||||
|
encoding='utf-8',
|
||||||
|
).read()
|
||||||
|
|
||||||
|
needs_pytest = {'pytest', 'test', 'ptr'}.intersection(sys.argv)
|
||||||
|
pytest_runner = ['pytest-runner'] if needs_pytest else []
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='tinycss2',
|
||||||
|
version=VERSION,
|
||||||
|
description='Low-level CSS parser for Python',
|
||||||
|
long_description=README,
|
||||||
|
license='BSD',
|
||||||
|
author='Simon Sapin',
|
||||||
|
author_email='simon.sapin@exyr.org',
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 5 - Production/Stable',
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
'License :: OSI Approved :: BSD License',
|
||||||
|
'Programming Language :: Python :: 2',
|
||||||
|
'Programming Language :: Python :: 2.7',
|
||||||
|
'Programming Language :: Python :: 3',
|
||||||
|
'Programming Language :: Python :: 3.3',
|
||||||
|
'Programming Language :: Python :: 3.4',
|
||||||
|
'Programming Language :: Python :: 3.5',
|
||||||
|
'Programming Language :: Python :: 3.6',
|
||||||
|
'Topic :: Text Processing',
|
||||||
|
],
|
||||||
|
packages=['tinycss2'],
|
||||||
|
install_requires=['webencodings>=0.4'],
|
||||||
|
package_data={'tinycss2': ['css-parsing-tests/*']},
|
||||||
|
setup_requires=pytest_runner,
|
||||||
|
test_suite='tinycss2.test',
|
||||||
|
tests_require=[
|
||||||
|
'pytest-runner', 'pytest-cov', 'pytest-flake8', 'pytest-isort'],
|
||||||
|
extras_require={'test': [
|
||||||
|
'pytest-runner', 'pytest-cov', 'pytest-flake8', 'pytest-isort']},
|
||||||
|
)
|
|
@ -0,0 +1,41 @@
|
||||||
|
Metadata-Version: 1.1
|
||||||
|
Name: tinycss2
|
||||||
|
Version: 0.6.1
|
||||||
|
Summary: Low-level CSS parser for Python
|
||||||
|
Home-page: UNKNOWN
|
||||||
|
Author: Simon Sapin
|
||||||
|
Author-email: simon.sapin@exyr.org
|
||||||
|
License: BSD
|
||||||
|
Description-Content-Type: UNKNOWN
|
||||||
|
Description: tinycss2: Low-level CSS parser for Python
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
tinycss2 is a rewrite of tinycss_ with a simpler API,
|
||||||
|
based on the more recent `CSS Syntax Level 3`_ specification.
|
||||||
|
|
||||||
|
.. _tinycss: http://pythonhosted.org/tinycss/
|
||||||
|
.. _CSS Syntax Level 3: http://dev.w3.org/csswg/css-syntax-3/
|
||||||
|
|
||||||
|
* BSD licensed
|
||||||
|
* For Python 2.7 or 3.3+ (tested on CPython)
|
||||||
|
* Latest documentation: http://tinycss2.readthedocs.io/
|
||||||
|
* Source code and issue tracker: https://github.com/Kozea/tinycss2
|
||||||
|
* PyPI releases: https://pypi.python.org/pypi/tinycss2/
|
||||||
|
* Continuous integration: |travis|
|
||||||
|
|
||||||
|
.. |travis| image:: https://travis-ci.org/Kozea/tinycss2.svg?branch=master
|
||||||
|
:target: https://travis-ci.org/Kozea/tinycss2
|
||||||
|
:alt: https://travis-ci.org/Kozea/tinycss2
|
||||||
|
|
||||||
|
Platform: UNKNOWN
|
||||||
|
Classifier: Development Status :: 5 - Production/Stable
|
||||||
|
Classifier: Intended Audience :: Developers
|
||||||
|
Classifier: License :: OSI Approved :: BSD License
|
||||||
|
Classifier: Programming Language :: Python :: 2
|
||||||
|
Classifier: Programming Language :: Python :: 2.7
|
||||||
|
Classifier: Programming Language :: Python :: 3
|
||||||
|
Classifier: Programming Language :: Python :: 3.3
|
||||||
|
Classifier: Programming Language :: Python :: 3.4
|
||||||
|
Classifier: Programming Language :: Python :: 3.5
|
||||||
|
Classifier: Programming Language :: Python :: 3.6
|
||||||
|
Classifier: Topic :: Text Processing
|
|
@ -0,0 +1,44 @@
|
||||||
|
.coveragerc
|
||||||
|
.gitignore
|
||||||
|
.travis.yml
|
||||||
|
CHANGES
|
||||||
|
LICENSE
|
||||||
|
MANIFEST.in
|
||||||
|
README.rst
|
||||||
|
TODO
|
||||||
|
setup.cfg
|
||||||
|
setup.py
|
||||||
|
docs/conf.py
|
||||||
|
docs/css_diagram_role.py
|
||||||
|
docs/index.rst
|
||||||
|
tinycss2/__init__.py
|
||||||
|
tinycss2/_compat.py
|
||||||
|
tinycss2/ast.py
|
||||||
|
tinycss2/bytes.py
|
||||||
|
tinycss2/color3.py
|
||||||
|
tinycss2/nth.py
|
||||||
|
tinycss2/parser.py
|
||||||
|
tinycss2/serializer.py
|
||||||
|
tinycss2/test.py
|
||||||
|
tinycss2/tokenizer.py
|
||||||
|
tinycss2.egg-info/PKG-INFO
|
||||||
|
tinycss2.egg-info/SOURCES.txt
|
||||||
|
tinycss2.egg-info/dependency_links.txt
|
||||||
|
tinycss2.egg-info/requires.txt
|
||||||
|
tinycss2.egg-info/top_level.txt
|
||||||
|
tinycss2/css-parsing-tests/An+B.json
|
||||||
|
tinycss2/css-parsing-tests/LICENSE
|
||||||
|
tinycss2/css-parsing-tests/README.rst
|
||||||
|
tinycss2/css-parsing-tests/color3.json
|
||||||
|
tinycss2/css-parsing-tests/color3_hsl.json
|
||||||
|
tinycss2/css-parsing-tests/color3_keywords.json
|
||||||
|
tinycss2/css-parsing-tests/component_value_list.json
|
||||||
|
tinycss2/css-parsing-tests/declaration_list.json
|
||||||
|
tinycss2/css-parsing-tests/make_color3_hsl.py
|
||||||
|
tinycss2/css-parsing-tests/make_color3_keywords.py
|
||||||
|
tinycss2/css-parsing-tests/one_component_value.json
|
||||||
|
tinycss2/css-parsing-tests/one_declaration.json
|
||||||
|
tinycss2/css-parsing-tests/one_rule.json
|
||||||
|
tinycss2/css-parsing-tests/rule_list.json
|
||||||
|
tinycss2/css-parsing-tests/stylesheet.json
|
||||||
|
tinycss2/css-parsing-tests/stylesheet_bytes.json
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
webencodings>=0.4
|
||||||
|
|
||||||
|
[test]
|
||||||
|
pytest-runner
|
||||||
|
pytest-cov
|
||||||
|
pytest-flake8
|
||||||
|
pytest-isort
|
|
@ -0,0 +1 @@
|
||||||
|
tinycss2
|
|
@ -0,0 +1,9 @@
|
||||||
|
VERSION = '0.6.1'
|
||||||
|
|
||||||
|
|
||||||
|
from .tokenizer import parse_component_value_list # noqa
|
||||||
|
from .parser import ( # noqa
|
||||||
|
parse_one_component_value, parse_one_declaration, parse_declaration_list,
|
||||||
|
parse_one_rule, parse_rule_list, parse_stylesheet)
|
||||||
|
from .bytes import parse_stylesheet_bytes # noqa
|
||||||
|
from .serializer import serialize, serialize_identifier # noqa
|
|
@ -0,0 +1,6 @@
|
||||||
|
if str is bytes: # pragma: no cover
|
||||||
|
unichr = unichr # noqa
|
||||||
|
basestring = basestring # noqa
|
||||||
|
else: # pragma: no cover
|
||||||
|
unichr = chr # noqa
|
||||||
|
basestring = str # noqa
|
|
@ -0,0 +1,871 @@
|
||||||
|
# coding: utf8
|
||||||
|
"""
|
||||||
|
|
||||||
|
Data structures for the CSS abstract syntax tree.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from webencodings import ascii_lower
|
||||||
|
|
||||||
|
from .serializer import (_serialize_to, serialize_identifier, serialize_name,
|
||||||
|
serialize_string_value)
|
||||||
|
|
||||||
|
|
||||||
|
class Node(object):
|
||||||
|
"""Every node type inherits from this class,
|
||||||
|
which is never instantiated directly.
|
||||||
|
|
||||||
|
.. attribute:: type
|
||||||
|
|
||||||
|
Each child class has a :attr:`type` class attribute
|
||||||
|
with an unique string value.
|
||||||
|
This allows checking for the node type with code like:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
if node.type == 'whitespace':
|
||||||
|
|
||||||
|
instead of the more verbose:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from tinycss2.ast import WhitespaceToken
|
||||||
|
if isinstance(node, WhitespaceToken):
|
||||||
|
|
||||||
|
Every node also has these attributes and methods,
|
||||||
|
which are not repeated for brevity:
|
||||||
|
|
||||||
|
.. attribute:: source_line
|
||||||
|
|
||||||
|
The line number of the start of the node in the CSS source.
|
||||||
|
Starts at 1.
|
||||||
|
|
||||||
|
.. attribute:: source_column
|
||||||
|
|
||||||
|
The column number within :attr:`source_line` of the start of the node
|
||||||
|
in the CSS source.
|
||||||
|
Starts at 1.
|
||||||
|
|
||||||
|
.. automethod:: serialize
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['source_line', 'source_column']
|
||||||
|
|
||||||
|
def __init__(self, source_line, source_column):
|
||||||
|
self.source_line = source_line
|
||||||
|
self.source_column = source_column
|
||||||
|
|
||||||
|
if str is bytes: # pragma: no cover
|
||||||
|
def __repr__(self):
|
||||||
|
return self.repr_format.format(self=self).encode('utf8')
|
||||||
|
else: # pragma: no cover
|
||||||
|
def __repr__(self):
|
||||||
|
return self.repr_format.format(self=self)
|
||||||
|
|
||||||
|
def serialize(self):
|
||||||
|
"""Serialize this node to CSS syntax and return an Unicode string."""
|
||||||
|
chunks = []
|
||||||
|
self._serialize_to(chunks.append)
|
||||||
|
return ''.join(chunks)
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
"""Serialize this node to CSS syntax, writing chunks as Unicode string
|
||||||
|
by calling the provided :obj:`write` callback.
|
||||||
|
|
||||||
|
"""
|
||||||
|
raise NotImplementedError # pragma: no cover
|
||||||
|
|
||||||
|
|
||||||
|
class ParseError(Node):
|
||||||
|
"""A syntax error of some sort. May occur anywhere in the tree.
|
||||||
|
|
||||||
|
Syntax errors are not fatal in the parser
|
||||||
|
to allow for different error handling behaviors.
|
||||||
|
For example, an error in a Selector list makes the whole rule invalid,
|
||||||
|
but an error in a Media Query list only replaces one comma-separated query
|
||||||
|
with ``not all``.
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: kind
|
||||||
|
|
||||||
|
Machine-readable string indicating the type of error.
|
||||||
|
Example: ``'bad-url'``.
|
||||||
|
|
||||||
|
.. attribute:: message
|
||||||
|
|
||||||
|
Human-readable explanation of the error, as a string.
|
||||||
|
Could be translated, expanded to include details, etc.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['kind', 'message']
|
||||||
|
type = 'error'
|
||||||
|
repr_format = '<{self.__class__.__name__} {self.kind}>'
|
||||||
|
|
||||||
|
def __init__(self, line, column, kind, message):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.kind = kind
|
||||||
|
self.message = message
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
if self.kind == 'bad-string':
|
||||||
|
write('"[bad string]\n')
|
||||||
|
elif self.kind == 'bad-url':
|
||||||
|
write('url([bad url])')
|
||||||
|
elif self.kind in ')]}':
|
||||||
|
write(self.kind)
|
||||||
|
else: # pragma: no cover
|
||||||
|
raise TypeError('Can not serialize %r' % self)
|
||||||
|
|
||||||
|
|
||||||
|
class Comment(Node):
|
||||||
|
"""A CSS comment.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
'/*' <value> '*/'
|
||||||
|
|
||||||
|
Comments can be ignored by passing ``skip_comments=True``
|
||||||
|
to functions such as :func:`~tinycss2.parse_component_value_list`.
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
.. attribute:: value
|
||||||
|
|
||||||
|
The content of the comment, between ``/*`` and ``*/``, as a string.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['value']
|
||||||
|
type = 'comment'
|
||||||
|
repr_format = '<{self.__class__.__name__} {self.value}>'
|
||||||
|
|
||||||
|
def __init__(self, line, column, value):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write('/*')
|
||||||
|
write(self.value)
|
||||||
|
write('*/')
|
||||||
|
|
||||||
|
|
||||||
|
class WhitespaceToken(Node):
|
||||||
|
"""A :diagram:`whitespace-token`.
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
.. attribute:: value
|
||||||
|
|
||||||
|
The whitespace sequence, as a string, as in the original CSS source.
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['value']
|
||||||
|
type = 'whitespace'
|
||||||
|
repr_format = '<{self.__class__.__name__}>'
|
||||||
|
|
||||||
|
def __init__(self, line, column, value):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write(self.value)
|
||||||
|
|
||||||
|
|
||||||
|
class LiteralToken(Node):
|
||||||
|
r"""Token that represents one or more characters as in the CSS source.
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: value
|
||||||
|
|
||||||
|
A string of one to four characters.
|
||||||
|
|
||||||
|
Instances compare equal to their :attr:`value`,
|
||||||
|
so that these are equivalent:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
if node == ';':
|
||||||
|
if node.type == 'literal' and node.value == ';':
|
||||||
|
|
||||||
|
This regroups what `the specification`_ defines as separate token types:
|
||||||
|
|
||||||
|
.. _the specification: http://dev.w3.org/csswg/css-syntax-3/
|
||||||
|
|
||||||
|
* *<colon-token>* ``:``
|
||||||
|
* *<semicolon-token>* ``;``
|
||||||
|
* *<comma-token>* ``,``
|
||||||
|
* *<cdc-token>* ``-->``
|
||||||
|
* *<cdo-token>* ``<!--``
|
||||||
|
* *<include-match-token>* ``~=``
|
||||||
|
* *<dash-match-token>* ``|=``
|
||||||
|
* *<prefix-match-token>* ``^=``
|
||||||
|
* *<suffix-match-token>* ``$=``
|
||||||
|
* *<substring-match-token>* ``*=``
|
||||||
|
* *<column-token>* ``||``
|
||||||
|
* *<delim-token>* (a single ASCII character not part of any another token)
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['value']
|
||||||
|
type = 'literal'
|
||||||
|
repr_format = '<{self.__class__.__name__} {self.value}>'
|
||||||
|
|
||||||
|
def __init__(self, line, column, value):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.value == other or self is other
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return not self == other
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write(self.value)
|
||||||
|
|
||||||
|
|
||||||
|
class IdentToken(Node):
|
||||||
|
"""An :diagram:`ident-token`.
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: value
|
||||||
|
|
||||||
|
The unescaped value, as an Unicode string.
|
||||||
|
|
||||||
|
.. attribute:: lower_value
|
||||||
|
|
||||||
|
Same as :attr:`value` but normalized to *ASCII lower case*,
|
||||||
|
see :func:`~webencodings.ascii_lower`.
|
||||||
|
This is the value to use when comparing to a CSS keyword.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['value', 'lower_value']
|
||||||
|
type = 'ident'
|
||||||
|
repr_format = '<{self.__class__.__name__} {self.value}>'
|
||||||
|
|
||||||
|
def __init__(self, line, column, value):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.value = value
|
||||||
|
self.lower_value = ascii_lower(value)
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write(serialize_identifier(self.value))
|
||||||
|
|
||||||
|
|
||||||
|
class AtKeywordToken(Node):
|
||||||
|
"""An :diagram:`at-keyword-token`.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
'@' <value>
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: value
|
||||||
|
|
||||||
|
The unescaped value, as an Unicode string, without the preceding ``@``.
|
||||||
|
|
||||||
|
.. attribute:: lower_value
|
||||||
|
|
||||||
|
Same as :attr:`value` but normalized to *ASCII lower case*,
|
||||||
|
see :func:`~webencodings.ascii_lower`.
|
||||||
|
This is the value to use when comparing to a CSS at-keyword.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
if node.type == 'at-keyword' and node.lower_value == 'import':
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['value', 'lower_value']
|
||||||
|
type = 'at-keyword'
|
||||||
|
repr_format = '<{self.__class__.__name__} @{self.value}>'
|
||||||
|
|
||||||
|
def __init__(self, line, column, value):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.value = value
|
||||||
|
self.lower_value = ascii_lower(value)
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write('@')
|
||||||
|
write(serialize_identifier(self.value))
|
||||||
|
|
||||||
|
|
||||||
|
class HashToken(Node):
|
||||||
|
r"""A :diagram:`hash-token`.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
'#' <value>
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: value
|
||||||
|
|
||||||
|
The unescaped value, as an Unicode string, without the preceding ``#``.
|
||||||
|
|
||||||
|
.. attribute:: is_identifier
|
||||||
|
|
||||||
|
A boolean, true if the CSS source for this token
|
||||||
|
was ``#`` followed by a valid identifier.
|
||||||
|
(Only such hash tokens are valid ID selectors.)
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['value', 'is_identifier']
|
||||||
|
type = 'hash'
|
||||||
|
repr_format = '<{self.__class__.__name__} #{self.value}>'
|
||||||
|
|
||||||
|
def __init__(self, line, column, value, is_identifier):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.value = value
|
||||||
|
self.is_identifier = is_identifier
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write('#')
|
||||||
|
if self.is_identifier:
|
||||||
|
write(serialize_identifier(self.value))
|
||||||
|
else:
|
||||||
|
write(serialize_name(self.value))
|
||||||
|
|
||||||
|
|
||||||
|
class StringToken(Node):
|
||||||
|
"""A :diagram:`string-token`.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
'"' <value> '"'
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: value
|
||||||
|
|
||||||
|
The unescaped value, as an Unicode string, without the quotes.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['value']
|
||||||
|
type = 'string'
|
||||||
|
repr_format = '<{self.__class__.__name__} "{self.value}">'
|
||||||
|
|
||||||
|
def __init__(self, line, column, value):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write('"')
|
||||||
|
write(serialize_string_value(self.value))
|
||||||
|
write('"')
|
||||||
|
|
||||||
|
|
||||||
|
class URLToken(Node):
|
||||||
|
"""An :diagram:`url-token`.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
'url("' <value> '")'
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: value
|
||||||
|
|
||||||
|
The unescaped URL, as an Unicode string,
|
||||||
|
without the ``url(`` and ``)`` markers or the optional quotes.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['value']
|
||||||
|
type = 'url'
|
||||||
|
repr_format = '<{self.__class__.__name__} url({self.value})>'
|
||||||
|
|
||||||
|
def __init__(self, line, column, value):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write('url("')
|
||||||
|
write(serialize_string_value(self.value))
|
||||||
|
write('")')
|
||||||
|
|
||||||
|
|
||||||
|
class UnicodeRangeToken(Node):
|
||||||
|
"""An :diagram:`unicode-range-token`.
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: start
|
||||||
|
|
||||||
|
The start of the range, as an integer between 0 and 1114111.
|
||||||
|
|
||||||
|
.. attribute:: end
|
||||||
|
|
||||||
|
The end of the range, as an integer between 0 and 1114111.
|
||||||
|
Same as :attr:`start` if the source only specified one value.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['start', 'end']
|
||||||
|
type = 'unicode-range'
|
||||||
|
repr_format = '<{self.__class__.__name__} {self.start} {self.end}>'
|
||||||
|
|
||||||
|
def __init__(self, line, column, start, end):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.start = start
|
||||||
|
self.end = end
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
if self.end == self.start:
|
||||||
|
write('U+%X' % self.start)
|
||||||
|
else:
|
||||||
|
write('U+%X-%X' % (self.start, self.end))
|
||||||
|
|
||||||
|
|
||||||
|
class NumberToken(Node):
|
||||||
|
"""A :diagram:`numer-token`.
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: value
|
||||||
|
|
||||||
|
The numeric value as a :class:`float`.
|
||||||
|
|
||||||
|
.. attribute:: int_value
|
||||||
|
|
||||||
|
The numeric value as an :class:`int`
|
||||||
|
if :attr:`is_integer` is true, :obj:`None` otherwise.
|
||||||
|
|
||||||
|
.. attribute:: is_integer
|
||||||
|
|
||||||
|
Whether the token was syntactically an integer, as a boolean.
|
||||||
|
|
||||||
|
.. attribute:: representation
|
||||||
|
|
||||||
|
The CSS representation of the value, as an Unicode string.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['value', 'int_value', 'is_integer', 'representation']
|
||||||
|
type = 'number'
|
||||||
|
repr_format = '<{self.__class__.__name__} {self.representation}>'
|
||||||
|
|
||||||
|
def __init__(self, line, column, value, int_value, representation):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.value = value
|
||||||
|
self.int_value = int_value
|
||||||
|
self.is_integer = int_value is not None
|
||||||
|
self.representation = representation
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write(self.representation)
|
||||||
|
|
||||||
|
|
||||||
|
class PercentageToken(Node):
|
||||||
|
"""A :diagram:`percentage-token`.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
<representation> '%'
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: value
|
||||||
|
|
||||||
|
The value numeric as a :class:`float`.
|
||||||
|
|
||||||
|
.. attribute:: int_value
|
||||||
|
|
||||||
|
The numeric value as an :class:`int`
|
||||||
|
if the token was syntactically an integer,
|
||||||
|
or :obj:`None`.
|
||||||
|
|
||||||
|
.. attribute:: is_integer
|
||||||
|
|
||||||
|
Whether the token’s value was syntactically an integer, as a boolean.
|
||||||
|
|
||||||
|
.. attribute:: representation
|
||||||
|
|
||||||
|
The CSS representation of the value without the unit,
|
||||||
|
as an Unicode string.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['value', 'int_value', 'is_integer', 'representation']
|
||||||
|
type = 'percentage'
|
||||||
|
repr_format = '<{self.__class__.__name__} {self.representation}%>'
|
||||||
|
|
||||||
|
def __init__(self, line, column, value, int_value, representation):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.value = value
|
||||||
|
self.int_value = int_value
|
||||||
|
self.is_integer = int_value is not None
|
||||||
|
self.representation = representation
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write(self.representation)
|
||||||
|
write('%')
|
||||||
|
|
||||||
|
|
||||||
|
class DimensionToken(Node):
|
||||||
|
"""A :diagram:`dimension-token`.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
<representation> <unit>
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: value
|
||||||
|
|
||||||
|
The value numeric as a :class:`float`.
|
||||||
|
|
||||||
|
.. attribute:: int_value
|
||||||
|
|
||||||
|
The numeric value as an :class:`int`
|
||||||
|
if the token was syntactically an integer,
|
||||||
|
or :obj:`None`.
|
||||||
|
|
||||||
|
.. attribute:: is_integer
|
||||||
|
|
||||||
|
Whether the token’s value was syntactically an integer, as a boolean.
|
||||||
|
|
||||||
|
.. attribute:: representation
|
||||||
|
|
||||||
|
The CSS representation of the value without the unit,
|
||||||
|
as an Unicode string.
|
||||||
|
|
||||||
|
.. attribute:: unit
|
||||||
|
|
||||||
|
The unescaped unit, as an Unicode string.
|
||||||
|
|
||||||
|
.. attribute:: lower_unit
|
||||||
|
|
||||||
|
Same as :attr:`unit` but normalized to *ASCII lower case*,
|
||||||
|
see :func:`~webencodings.ascii_lower`.
|
||||||
|
This is the value to use when comparing to a CSS unit.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
if node.type == 'dimension' and node.lower_unit == 'px':
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['value', 'int_value', 'is_integer', 'representation',
|
||||||
|
'unit', 'lower_unit']
|
||||||
|
type = 'dimension'
|
||||||
|
repr_format = ('<{self.__class__.__name__} '
|
||||||
|
'{self.representation}{self.unit}>')
|
||||||
|
|
||||||
|
def __init__(self, line, column, value, int_value, representation, unit):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.value = value
|
||||||
|
self.int_value = int_value
|
||||||
|
self.is_integer = int_value is not None
|
||||||
|
self.representation = representation
|
||||||
|
self.unit = unit
|
||||||
|
self.lower_unit = ascii_lower(unit)
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write(self.representation)
|
||||||
|
# Disambiguate with scientific notation
|
||||||
|
unit = self.unit
|
||||||
|
if unit in ('e', 'E') or unit.startswith(('e-', 'E-')):
|
||||||
|
write('\\65 ')
|
||||||
|
write(serialize_name(unit[1:]))
|
||||||
|
else:
|
||||||
|
write(serialize_identifier(unit))
|
||||||
|
|
||||||
|
|
||||||
|
class ParenthesesBlock(Node):
|
||||||
|
"""A :diagram:`()-block`.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
'(' <content> ')'
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: content
|
||||||
|
|
||||||
|
The content of the block, as list of :term:`component values`.
|
||||||
|
The ``(`` and ``)`` markers themselves are not represented in the list.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['content']
|
||||||
|
type = '() block'
|
||||||
|
repr_format = '<{self.__class__.__name__} ( … )>'
|
||||||
|
|
||||||
|
def __init__(self, line, column, content):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.content = content
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write('(')
|
||||||
|
_serialize_to(self.content, write)
|
||||||
|
write(')')
|
||||||
|
|
||||||
|
|
||||||
|
class SquareBracketsBlock(Node):
|
||||||
|
"""A :diagram:`[]-block`.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
'[' <content> ']'
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: content
|
||||||
|
|
||||||
|
The content of the block, as list of :term:`component values`.
|
||||||
|
The ``[`` and ``]`` markers themselves are not represented in the list.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['content']
|
||||||
|
type = '[] block'
|
||||||
|
repr_format = '<{self.__class__.__name__} [ … ]>'
|
||||||
|
|
||||||
|
def __init__(self, line, column, content):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.content = content
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write('[')
|
||||||
|
_serialize_to(self.content, write)
|
||||||
|
write(']')
|
||||||
|
|
||||||
|
|
||||||
|
class CurlyBracketsBlock(Node):
|
||||||
|
"""A :diagram:`{}-block`.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
'{' <content> '}'
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: content
|
||||||
|
|
||||||
|
The content of the block, as list of :term:`component values`.
|
||||||
|
The ``[`` and ``]`` markers themselves are not represented in the list.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['content']
|
||||||
|
type = '{} block'
|
||||||
|
repr_format = '<{self.__class__.__name__} {{ … }}>'
|
||||||
|
|
||||||
|
def __init__(self, line, column, content):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.content = content
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write('{')
|
||||||
|
_serialize_to(self.content, write)
|
||||||
|
write('}')
|
||||||
|
|
||||||
|
|
||||||
|
class FunctionBlock(Node):
|
||||||
|
"""A :diagram:`function-block`.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
<name> '(' <arguments> ')'
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: name
|
||||||
|
|
||||||
|
The unescaped name of the function, as an Unicode string.
|
||||||
|
|
||||||
|
.. attribute:: lower_name
|
||||||
|
|
||||||
|
Same as :attr:`name` but normalized to *ASCII lower case*,
|
||||||
|
see :func:`~webencodings.ascii_lower`.
|
||||||
|
This is the value to use when comparing to a CSS function name.
|
||||||
|
|
||||||
|
.. attribute:: arguments
|
||||||
|
|
||||||
|
The arguments of the function, as list of :term:`component values`.
|
||||||
|
The ``(`` and ``)`` markers themselves are not represented in the list.
|
||||||
|
Commas are not special, but represented as :obj:`LiteralToken` objects
|
||||||
|
in the list.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['name', 'lower_name', 'arguments']
|
||||||
|
type = 'function'
|
||||||
|
repr_format = '<{self.__class__.__name__} {self.name}( … )>'
|
||||||
|
|
||||||
|
def __init__(self, line, column, name, arguments):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.name = name
|
||||||
|
self.lower_name = ascii_lower(name)
|
||||||
|
self.arguments = arguments
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write(serialize_identifier(self.name))
|
||||||
|
write('(')
|
||||||
|
_serialize_to(self.arguments, write)
|
||||||
|
write(')')
|
||||||
|
|
||||||
|
|
||||||
|
class Declaration(Node):
|
||||||
|
"""A (property or descriptor) :diagram:`declaration`.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
<name> ':' <value>
|
||||||
|
<name> ':' <value> '!important'
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: name
|
||||||
|
|
||||||
|
The unescaped name, as an Unicode string.
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: lower_name
|
||||||
|
|
||||||
|
Same as :attr:`name` but normalized to *ASCII lower case*,
|
||||||
|
see :func:`~webencodings.ascii_lower`.
|
||||||
|
This is the value to use when comparing to
|
||||||
|
a CSS property or descriptor name.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
if node.type == 'declaration' and node.lower_name == 'color':
|
||||||
|
|
||||||
|
.. attribute:: value
|
||||||
|
|
||||||
|
The declaration value as a list of :term:`component values`:
|
||||||
|
anything between ``:`` and
|
||||||
|
the end of the declaration, or ``!important``.
|
||||||
|
|
||||||
|
.. attribute:: important
|
||||||
|
|
||||||
|
A boolean, true if the declaration had an ``!important`` marker.
|
||||||
|
It is up to the consumer to reject declarations that do not accept
|
||||||
|
this flag, such as non-property descriptor declarations.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['name', 'lower_name', 'value', 'important']
|
||||||
|
type = 'declaration'
|
||||||
|
repr_format = '<{self.__class__.__name__} {self.name}: …>'
|
||||||
|
|
||||||
|
def __init__(self, line, column, name, lower_name, value, important):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.name = name
|
||||||
|
self.lower_name = lower_name
|
||||||
|
self.value = value
|
||||||
|
self.important = important
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write(serialize_identifier(self.name))
|
||||||
|
write(':')
|
||||||
|
_serialize_to(self.value, write)
|
||||||
|
if self.important:
|
||||||
|
write('!important')
|
||||||
|
|
||||||
|
|
||||||
|
class QualifiedRule(Node):
|
||||||
|
"""A :diagram:`qualified rule`.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
<prelude> '{' <content> '}'
|
||||||
|
|
||||||
|
The interpretation of qualified rules depend on their context.
|
||||||
|
At the top-level of a stylesheet
|
||||||
|
or in a conditional rule such as ``@media``,
|
||||||
|
they are **style rules** where the :attr:`prelude` is Selectors list
|
||||||
|
and the :attr:`content` is a list of property declarations.
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: prelude
|
||||||
|
|
||||||
|
The rule’s prelude, the part before the {} block,
|
||||||
|
as a list of :term:`component values`.
|
||||||
|
|
||||||
|
.. attribute:: content
|
||||||
|
|
||||||
|
The rule’s content, the part inside the {} block,
|
||||||
|
as a list of :term:`component values`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['prelude', 'content']
|
||||||
|
type = 'qualified-rule'
|
||||||
|
repr_format = ('<{self.__class__.__name__} '
|
||||||
|
'… {{ … }}>')
|
||||||
|
|
||||||
|
def __init__(self, line, column, prelude, content):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.prelude = prelude
|
||||||
|
self.content = content
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
_serialize_to(self.prelude, write)
|
||||||
|
write('{')
|
||||||
|
_serialize_to(self.content, write)
|
||||||
|
write('}')
|
||||||
|
|
||||||
|
|
||||||
|
class AtRule(Node):
|
||||||
|
"""An :diagram:`at-rule`.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
@<at_keyword> <prelude> '{' <content> '}'
|
||||||
|
@<at_keyword> <prelude> ';'
|
||||||
|
|
||||||
|
The interpretation of at-rules depend on their at-keyword
|
||||||
|
as well as their context.
|
||||||
|
Most types of at-rules (ie. at-keyword values)
|
||||||
|
are only allowed in some context,
|
||||||
|
and must either end with a {} block or a semicolon.
|
||||||
|
|
||||||
|
.. autoattribute:: type
|
||||||
|
|
||||||
|
.. attribute:: at_keyword
|
||||||
|
|
||||||
|
The unescaped value of the rule’s at-keyword,
|
||||||
|
without the ``@`` symbol, as an Unicode string.
|
||||||
|
|
||||||
|
.. attribute:: lower_at_keyword
|
||||||
|
|
||||||
|
Same as :attr:`at_keyword` but normalized to *ASCII lower case*,
|
||||||
|
see :func:`~webencodings.ascii_lower`.
|
||||||
|
This is the value to use when comparing to a CSS at-keyword.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
if node.type == 'at-rule' and node.lower_at_keyword == 'import':
|
||||||
|
|
||||||
|
.. attribute:: prelude
|
||||||
|
|
||||||
|
The rule’s prelude, the part before the {} block or semicolon,
|
||||||
|
as a list of :term:`component values`.
|
||||||
|
|
||||||
|
.. attribute:: content
|
||||||
|
|
||||||
|
The rule’s content, if any.
|
||||||
|
The block’s content as a list of :term:`component values`
|
||||||
|
for at-rules with a {} block,
|
||||||
|
or :obj:`None` for at-rules ending with a semicolon.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ['at_keyword', 'lower_at_keyword', 'prelude', 'content']
|
||||||
|
type = 'at-rule'
|
||||||
|
repr_format = ('<{self.__class__.__name__} '
|
||||||
|
'@{self.at_keyword} … {{ … }}>')
|
||||||
|
|
||||||
|
def __init__(self, line, column,
|
||||||
|
at_keyword, lower_at_keyword, prelude, content):
|
||||||
|
Node.__init__(self, line, column)
|
||||||
|
self.at_keyword = at_keyword
|
||||||
|
self.lower_at_keyword = lower_at_keyword
|
||||||
|
self.prelude = prelude
|
||||||
|
self.content = content
|
||||||
|
|
||||||
|
def _serialize_to(self, write):
|
||||||
|
write('@')
|
||||||
|
write(serialize_identifier(self.at_keyword))
|
||||||
|
_serialize_to(self.prelude, write)
|
||||||
|
if self.content is None:
|
||||||
|
write(';')
|
||||||
|
else:
|
||||||
|
write('{')
|
||||||
|
_serialize_to(self.content, write)
|
||||||
|
write('}')
|
|
@ -0,0 +1,112 @@
|
||||||
|
from webencodings import UTF8, decode, lookup
|
||||||
|
|
||||||
|
from .parser import parse_stylesheet
|
||||||
|
|
||||||
|
|
||||||
|
def decode_stylesheet_bytes(css_bytes, protocol_encoding=None,
|
||||||
|
environment_encoding=None):
|
||||||
|
"""Determine the character encoding of a CSS stylesheet and decode it.
|
||||||
|
|
||||||
|
This is based on the presence of a ,
|
||||||
|
an ``@charset`` rule,
|
||||||
|
and encoding meta-information.
|
||||||
|
|
||||||
|
:param css_bytes: A byte string.
|
||||||
|
:param protocol_encoding:
|
||||||
|
The encoding label, if any, defined by HTTP or equivalent protocol.
|
||||||
|
(e.g. via the ``charset`` parameter of the ``Content-Type`` header.)
|
||||||
|
:param environment_encoding:
|
||||||
|
A :class:`webencodings.Encoding` object
|
||||||
|
for the `environment encoding
|
||||||
|
<http://www.w3.org/TR/css-syntax/#environment-encoding>`_,
|
||||||
|
if any.
|
||||||
|
:returns:
|
||||||
|
A 2-tuple of a decoded Unicode string
|
||||||
|
and the :class:`webencodings.Encoding` object that was used.
|
||||||
|
|
||||||
|
"""
|
||||||
|
# http://dev.w3.org/csswg/css-syntax/#the-input-byte-stream
|
||||||
|
if protocol_encoding:
|
||||||
|
fallback = lookup(protocol_encoding)
|
||||||
|
if fallback:
|
||||||
|
return decode(css_bytes, fallback)
|
||||||
|
if css_bytes.startswith(b'@charset "'):
|
||||||
|
# 10 is len(b'@charset "')
|
||||||
|
# 100 is arbitrary so that no encoding label is more than 100-10 bytes.
|
||||||
|
end_quote = css_bytes.find(b'"', 10, 100)
|
||||||
|
if end_quote != -1 and css_bytes.startswith(b'";', end_quote):
|
||||||
|
fallback = lookup(css_bytes[10:end_quote].decode('latin1'))
|
||||||
|
if fallback:
|
||||||
|
if fallback.name in ('utf-16be', 'utf-16le'):
|
||||||
|
return decode(css_bytes, UTF8)
|
||||||
|
return decode(css_bytes, fallback)
|
||||||
|
if environment_encoding:
|
||||||
|
return decode(css_bytes, environment_encoding)
|
||||||
|
return decode(css_bytes, UTF8)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_stylesheet_bytes(css_bytes, protocol_encoding=None,
|
||||||
|
environment_encoding=None,
|
||||||
|
skip_comments=False, skip_whitespace=False):
|
||||||
|
"""Parse :diagram:`stylesheet` from bytes,
|
||||||
|
determining the character encoding as web browsers do.
|
||||||
|
|
||||||
|
This is used when reading a file or fetching an URL.
|
||||||
|
The character encoding is determined from the initial bytes
|
||||||
|
(a :abbr:`BOM (Byte Order Mark)` or an ``@charset`` rule)
|
||||||
|
as well as the parameters.
|
||||||
|
The ultimate fallback is UTF-8.
|
||||||
|
|
||||||
|
:param css_bytes: A byte string.
|
||||||
|
:param protocol_encoding:
|
||||||
|
A string.
|
||||||
|
The encoding label, if any, defined by HTTP or equivalent protocol.
|
||||||
|
(e.g. via the ``charset`` parameter of the ``Content-Type`` header.)
|
||||||
|
:param environment_encoding:
|
||||||
|
A :class:`webencodings.Encoding` object
|
||||||
|
for the `environment encoding`_,
|
||||||
|
if any.
|
||||||
|
:param skip_comments:
|
||||||
|
Ignore CSS comments at the top-level of the stylesheet.
|
||||||
|
If the input is a string, ignore all comments.
|
||||||
|
:param skip_whitespace:
|
||||||
|
Ignore whitespace at the top-level of the stylesheet.
|
||||||
|
Whitespace is still preserved
|
||||||
|
in the :attr:`~tinycss2.ast.QualifiedRule.prelude`
|
||||||
|
and the :attr:`~tinycss2.ast.QualifiedRule.content` of rules.
|
||||||
|
:returns:
|
||||||
|
A ``(rules, encoding)`` tuple.
|
||||||
|
|
||||||
|
* :obj:`rules` is a list of
|
||||||
|
:class:`~tinycss2.ast.QualifiedRule`,
|
||||||
|
:class:`~tinycss2.ast.AtRule`,
|
||||||
|
:class:`~tinycss2.ast.Comment` (if ``skip_comments`` is false),
|
||||||
|
:class:`~tinycss2.ast.WhitespaceToken`
|
||||||
|
(if ``skip_whitespace`` is false),
|
||||||
|
and :class:`~tinycss2.ast.ParseError` objects.
|
||||||
|
* :obj:`encoding` is the :class:`webencodings.Encoding` object
|
||||||
|
that was used.
|
||||||
|
If ``rules`` contains an ``@import`` rule, this is
|
||||||
|
the `environment encoding`_ for the imported stylesheet.
|
||||||
|
|
||||||
|
.. _environment encoding:
|
||||||
|
http://www.w3.org/TR/css-syntax/#environment-encoding
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
response = urlopen('http://example.net/foo.css')
|
||||||
|
rules, encoding = parse_stylesheet_bytes(
|
||||||
|
css_bytes=response.read(),
|
||||||
|
# Python 3.x
|
||||||
|
protocol_encoding=response.info().get_content_type().get_param('charset'),
|
||||||
|
# Python 2.x
|
||||||
|
protocol_encoding=response.info().gettype().getparam('charset'),
|
||||||
|
)
|
||||||
|
for rule in rules:
|
||||||
|
...
|
||||||
|
|
||||||
|
"""
|
||||||
|
css_unicode, encoding = decode_stylesheet_bytes(
|
||||||
|
css_bytes, protocol_encoding, environment_encoding)
|
||||||
|
stylesheet = parse_stylesheet(css_unicode, skip_comments, skip_whitespace)
|
||||||
|
return stylesheet, encoding
|
|
@ -0,0 +1,367 @@
|
||||||
|
from __future__ import division
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import re
|
||||||
|
|
||||||
|
from ._compat import basestring
|
||||||
|
from .parser import parse_one_component_value
|
||||||
|
|
||||||
|
|
||||||
|
class RGBA(collections.namedtuple('RGBA', ['red', 'green', 'blue', 'alpha'])):
|
||||||
|
"""An RGBA color.
|
||||||
|
|
||||||
|
A tuple of four floats in the 0..1 range: ``(red, green, blue, alpha)``.
|
||||||
|
|
||||||
|
.. attribute:: red
|
||||||
|
|
||||||
|
Convenience access to the red channel. Same as ``rgba[0]``.
|
||||||
|
|
||||||
|
.. attribute:: green
|
||||||
|
|
||||||
|
Convenience access to the green channel. Same as ``rgba[1]``.
|
||||||
|
|
||||||
|
.. attribute:: blue
|
||||||
|
|
||||||
|
Convenience access to the blue channel. Same as ``rgba[2]``.
|
||||||
|
|
||||||
|
.. attribute:: alpha
|
||||||
|
|
||||||
|
Convenience access to the alpha channel. Same as ``rgba[3]``.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def parse_color(input):
|
||||||
|
"""Parse a color value as defined in `CSS Color Level 3
|
||||||
|
<http://www.w3.org/TR/css3-color/>`_.
|
||||||
|
|
||||||
|
:param input:
|
||||||
|
A :term:`string`, or a single :term:`component value`.
|
||||||
|
:returns:
|
||||||
|
* :obj:`None` if the input is not a valid color value.
|
||||||
|
(No exception is raised.)
|
||||||
|
* The string ``'currentColor'`` for the *currentColor* keyword
|
||||||
|
* Or a :class:`RGBA` object for every other values
|
||||||
|
(including keywords, HSL and HSLA.)
|
||||||
|
The alpha channel is clipped to [0, 1]
|
||||||
|
but red, green, or blue can be out of range
|
||||||
|
(eg. ``rgb(-10%, 120%, 0%)`` is represented as
|
||||||
|
``(-0.1, 1.2, 0, 1)``.)
|
||||||
|
|
||||||
|
"""
|
||||||
|
if isinstance(input, basestring):
|
||||||
|
token = parse_one_component_value(input, skip_comments=True)
|
||||||
|
else:
|
||||||
|
token = input
|
||||||
|
if token.type == 'ident':
|
||||||
|
return _COLOR_KEYWORDS.get(token.lower_value)
|
||||||
|
elif token.type == 'hash':
|
||||||
|
for multiplier, regexp in _HASH_REGEXPS:
|
||||||
|
match = regexp(token.value)
|
||||||
|
if match:
|
||||||
|
r, g, b = [int(group * multiplier, 16) / 255
|
||||||
|
for group in match.groups()]
|
||||||
|
return RGBA(r, g, b, 1.)
|
||||||
|
elif token.type == 'function':
|
||||||
|
args = _parse_comma_separated(token.arguments)
|
||||||
|
if args:
|
||||||
|
name = token.lower_name
|
||||||
|
if name == 'rgb':
|
||||||
|
return _parse_rgb(args, alpha=1.)
|
||||||
|
elif name == 'rgba':
|
||||||
|
alpha = _parse_alpha(args[3:])
|
||||||
|
if alpha is not None:
|
||||||
|
return _parse_rgb(args[:3], alpha)
|
||||||
|
elif name == 'hsl':
|
||||||
|
return _parse_hsl(args, alpha=1.)
|
||||||
|
elif name == 'hsla':
|
||||||
|
alpha = _parse_alpha(args[3:])
|
||||||
|
if alpha is not None:
|
||||||
|
return _parse_hsl(args[:3], alpha)
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_alpha(args):
|
||||||
|
"""
|
||||||
|
If args is a list of a single INTEGER or NUMBER token,
|
||||||
|
retur its value clipped to the 0..1 range
|
||||||
|
Otherwise, return None.
|
||||||
|
"""
|
||||||
|
if len(args) == 1 and args[0].type == 'number':
|
||||||
|
return min(1, max(0, args[0].value))
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_rgb(args, alpha):
|
||||||
|
"""
|
||||||
|
If args is a list of 3 INTEGER tokens or 3 PERCENTAGE tokens,
|
||||||
|
return RGB values as a tuple of 3 floats in 0..1.
|
||||||
|
Otherwise, return None.
|
||||||
|
"""
|
||||||
|
types = [arg.type for arg in args]
|
||||||
|
if (types == ['number', 'number', 'number'] and
|
||||||
|
all(a.is_integer for a in args)):
|
||||||
|
r, g, b = [arg.int_value / 255 for arg in args[:3]]
|
||||||
|
return RGBA(r, g, b, alpha)
|
||||||
|
elif types == ['percentage', 'percentage', 'percentage']:
|
||||||
|
r, g, b = [arg.value / 100 for arg in args[:3]]
|
||||||
|
return RGBA(r, g, b, alpha)
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_hsl(args, alpha):
|
||||||
|
"""
|
||||||
|
If args is a list of 1 INTEGER token and 2 PERCENTAGE tokens,
|
||||||
|
return RGB values as a tuple of 3 floats in 0..1.
|
||||||
|
Otherwise, return None.
|
||||||
|
"""
|
||||||
|
types = [arg.type for arg in args]
|
||||||
|
if types == ['number', 'percentage', 'percentage'] and args[0].is_integer:
|
||||||
|
r, g, b = _hsl_to_rgb(args[0].int_value, args[1].value, args[2].value)
|
||||||
|
return RGBA(r, g, b, alpha)
|
||||||
|
|
||||||
|
|
||||||
|
def _hsl_to_rgb(hue, saturation, lightness):
|
||||||
|
"""
|
||||||
|
:param hue: degrees
|
||||||
|
:param saturation: percentage
|
||||||
|
:param lightness: percentage
|
||||||
|
:returns: (r, g, b) as floats in the 0..1 range
|
||||||
|
"""
|
||||||
|
hue = (hue / 360) % 1
|
||||||
|
saturation = min(1, max(0, saturation / 100))
|
||||||
|
lightness = min(1, max(0, lightness / 100))
|
||||||
|
|
||||||
|
# Translated from ABC: http://www.w3.org/TR/css3-color/#hsl-color
|
||||||
|
|
||||||
|
def hue_to_rgb(m1, m2, h):
|
||||||
|
if h < 0:
|
||||||
|
h += 1
|
||||||
|
if h > 1:
|
||||||
|
h -= 1
|
||||||
|
if h * 6 < 1:
|
||||||
|
return m1 + (m2 - m1) * h * 6
|
||||||
|
if h * 2 < 1:
|
||||||
|
return m2
|
||||||
|
if h * 3 < 2:
|
||||||
|
return m1 + (m2 - m1) * (2 / 3 - h) * 6
|
||||||
|
return m1
|
||||||
|
|
||||||
|
if lightness <= 0.5:
|
||||||
|
m2 = lightness * (saturation + 1)
|
||||||
|
else:
|
||||||
|
m2 = lightness + saturation - lightness * saturation
|
||||||
|
m1 = lightness * 2 - m2
|
||||||
|
return (
|
||||||
|
hue_to_rgb(m1, m2, hue + 1 / 3),
|
||||||
|
hue_to_rgb(m1, m2, hue),
|
||||||
|
hue_to_rgb(m1, m2, hue - 1 / 3),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_comma_separated(tokens):
|
||||||
|
"""Parse a list of tokens (typically the content of a function token)
|
||||||
|
as arguments made of a single token each, separated by mandatory commas,
|
||||||
|
with optional white space around each argument.
|
||||||
|
|
||||||
|
return the argument list without commas or white space;
|
||||||
|
or None if the function token content do not match the description above.
|
||||||
|
|
||||||
|
"""
|
||||||
|
tokens = [token for token in tokens
|
||||||
|
if token.type not in ('whitespace', 'comment')]
|
||||||
|
if not tokens:
|
||||||
|
return []
|
||||||
|
if len(tokens) % 2 == 1 and all(token == ',' for token in tokens[1::2]):
|
||||||
|
return tokens[::2]
|
||||||
|
|
||||||
|
|
||||||
|
_HASH_REGEXPS = (
|
||||||
|
(2, re.compile('^([\da-f])([\da-f])([\da-f])$', re.I).match),
|
||||||
|
(1, re.compile('^([\da-f]{2})([\da-f]{2})([\da-f]{2})$', re.I).match),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# (r, g, b) in 0..255
|
||||||
|
_BASIC_COLOR_KEYWORDS = [
|
||||||
|
('black', (0, 0, 0)),
|
||||||
|
('silver', (192, 192, 192)),
|
||||||
|
('gray', (128, 128, 128)),
|
||||||
|
('white', (255, 255, 255)),
|
||||||
|
('maroon', (128, 0, 0)),
|
||||||
|
('red', (255, 0, 0)),
|
||||||
|
('purple', (128, 0, 128)),
|
||||||
|
('fuchsia', (255, 0, 255)),
|
||||||
|
('green', (0, 128, 0)),
|
||||||
|
('lime', (0, 255, 0)),
|
||||||
|
('olive', (128, 128, 0)),
|
||||||
|
('yellow', (255, 255, 0)),
|
||||||
|
('navy', (0, 0, 128)),
|
||||||
|
('blue', (0, 0, 255)),
|
||||||
|
('teal', (0, 128, 128)),
|
||||||
|
('aqua', (0, 255, 255)),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# (r, g, b) in 0..255
|
||||||
|
_EXTENDED_COLOR_KEYWORDS = [
|
||||||
|
('aliceblue', (240, 248, 255)),
|
||||||
|
('antiquewhite', (250, 235, 215)),
|
||||||
|
('aqua', (0, 255, 255)),
|
||||||
|
('aquamarine', (127, 255, 212)),
|
||||||
|
('azure', (240, 255, 255)),
|
||||||
|
('beige', (245, 245, 220)),
|
||||||
|
('bisque', (255, 228, 196)),
|
||||||
|
('black', (0, 0, 0)),
|
||||||
|
('blanchedalmond', (255, 235, 205)),
|
||||||
|
('blue', (0, 0, 255)),
|
||||||
|
('blueviolet', (138, 43, 226)),
|
||||||
|
('brown', (165, 42, 42)),
|
||||||
|
('burlywood', (222, 184, 135)),
|
||||||
|
('cadetblue', (95, 158, 160)),
|
||||||
|
('chartreuse', (127, 255, 0)),
|
||||||
|
('chocolate', (210, 105, 30)),
|
||||||
|
('coral', (255, 127, 80)),
|
||||||
|
('cornflowerblue', (100, 149, 237)),
|
||||||
|
('cornsilk', (255, 248, 220)),
|
||||||
|
('crimson', (220, 20, 60)),
|
||||||
|
('cyan', (0, 255, 255)),
|
||||||
|
('darkblue', (0, 0, 139)),
|
||||||
|
('darkcyan', (0, 139, 139)),
|
||||||
|
('darkgoldenrod', (184, 134, 11)),
|
||||||
|
('darkgray', (169, 169, 169)),
|
||||||
|
('darkgreen', (0, 100, 0)),
|
||||||
|
('darkgrey', (169, 169, 169)),
|
||||||
|
('darkkhaki', (189, 183, 107)),
|
||||||
|
('darkmagenta', (139, 0, 139)),
|
||||||
|
('darkolivegreen', (85, 107, 47)),
|
||||||
|
('darkorange', (255, 140, 0)),
|
||||||
|
('darkorchid', (153, 50, 204)),
|
||||||
|
('darkred', (139, 0, 0)),
|
||||||
|
('darksalmon', (233, 150, 122)),
|
||||||
|
('darkseagreen', (143, 188, 143)),
|
||||||
|
('darkslateblue', (72, 61, 139)),
|
||||||
|
('darkslategray', (47, 79, 79)),
|
||||||
|
('darkslategrey', (47, 79, 79)),
|
||||||
|
('darkturquoise', (0, 206, 209)),
|
||||||
|
('darkviolet', (148, 0, 211)),
|
||||||
|
('deeppink', (255, 20, 147)),
|
||||||
|
('deepskyblue', (0, 191, 255)),
|
||||||
|
('dimgray', (105, 105, 105)),
|
||||||
|
('dimgrey', (105, 105, 105)),
|
||||||
|
('dodgerblue', (30, 144, 255)),
|
||||||
|
('firebrick', (178, 34, 34)),
|
||||||
|
('floralwhite', (255, 250, 240)),
|
||||||
|
('forestgreen', (34, 139, 34)),
|
||||||
|
('fuchsia', (255, 0, 255)),
|
||||||
|
('gainsboro', (220, 220, 220)),
|
||||||
|
('ghostwhite', (248, 248, 255)),
|
||||||
|
('gold', (255, 215, 0)),
|
||||||
|
('goldenrod', (218, 165, 32)),
|
||||||
|
('gray', (128, 128, 128)),
|
||||||
|
('green', (0, 128, 0)),
|
||||||
|
('greenyellow', (173, 255, 47)),
|
||||||
|
('grey', (128, 128, 128)),
|
||||||
|
('honeydew', (240, 255, 240)),
|
||||||
|
('hotpink', (255, 105, 180)),
|
||||||
|
('indianred', (205, 92, 92)),
|
||||||
|
('indigo', (75, 0, 130)),
|
||||||
|
('ivory', (255, 255, 240)),
|
||||||
|
('khaki', (240, 230, 140)),
|
||||||
|
('lavender', (230, 230, 250)),
|
||||||
|
('lavenderblush', (255, 240, 245)),
|
||||||
|
('lawngreen', (124, 252, 0)),
|
||||||
|
('lemonchiffon', (255, 250, 205)),
|
||||||
|
('lightblue', (173, 216, 230)),
|
||||||
|
('lightcoral', (240, 128, 128)),
|
||||||
|
('lightcyan', (224, 255, 255)),
|
||||||
|
('lightgoldenrodyellow', (250, 250, 210)),
|
||||||
|
('lightgray', (211, 211, 211)),
|
||||||
|
('lightgreen', (144, 238, 144)),
|
||||||
|
('lightgrey', (211, 211, 211)),
|
||||||
|
('lightpink', (255, 182, 193)),
|
||||||
|
('lightsalmon', (255, 160, 122)),
|
||||||
|
('lightseagreen', (32, 178, 170)),
|
||||||
|
('lightskyblue', (135, 206, 250)),
|
||||||
|
('lightslategray', (119, 136, 153)),
|
||||||
|
('lightslategrey', (119, 136, 153)),
|
||||||
|
('lightsteelblue', (176, 196, 222)),
|
||||||
|
('lightyellow', (255, 255, 224)),
|
||||||
|
('lime', (0, 255, 0)),
|
||||||
|
('limegreen', (50, 205, 50)),
|
||||||
|
('linen', (250, 240, 230)),
|
||||||
|
('magenta', (255, 0, 255)),
|
||||||
|
('maroon', (128, 0, 0)),
|
||||||
|
('mediumaquamarine', (102, 205, 170)),
|
||||||
|
('mediumblue', (0, 0, 205)),
|
||||||
|
('mediumorchid', (186, 85, 211)),
|
||||||
|
('mediumpurple', (147, 112, 219)),
|
||||||
|
('mediumseagreen', (60, 179, 113)),
|
||||||
|
('mediumslateblue', (123, 104, 238)),
|
||||||
|
('mediumspringgreen', (0, 250, 154)),
|
||||||
|
('mediumturquoise', (72, 209, 204)),
|
||||||
|
('mediumvioletred', (199, 21, 133)),
|
||||||
|
('midnightblue', (25, 25, 112)),
|
||||||
|
('mintcream', (245, 255, 250)),
|
||||||
|
('mistyrose', (255, 228, 225)),
|
||||||
|
('moccasin', (255, 228, 181)),
|
||||||
|
('navajowhite', (255, 222, 173)),
|
||||||
|
('navy', (0, 0, 128)),
|
||||||
|
('oldlace', (253, 245, 230)),
|
||||||
|
('olive', (128, 128, 0)),
|
||||||
|
('olivedrab', (107, 142, 35)),
|
||||||
|
('orange', (255, 165, 0)),
|
||||||
|
('orangered', (255, 69, 0)),
|
||||||
|
('orchid', (218, 112, 214)),
|
||||||
|
('palegoldenrod', (238, 232, 170)),
|
||||||
|
('palegreen', (152, 251, 152)),
|
||||||
|
('paleturquoise', (175, 238, 238)),
|
||||||
|
('palevioletred', (219, 112, 147)),
|
||||||
|
('papayawhip', (255, 239, 213)),
|
||||||
|
('peachpuff', (255, 218, 185)),
|
||||||
|
('peru', (205, 133, 63)),
|
||||||
|
('pink', (255, 192, 203)),
|
||||||
|
('plum', (221, 160, 221)),
|
||||||
|
('powderblue', (176, 224, 230)),
|
||||||
|
('purple', (128, 0, 128)),
|
||||||
|
('red', (255, 0, 0)),
|
||||||
|
('rosybrown', (188, 143, 143)),
|
||||||
|
('royalblue', (65, 105, 225)),
|
||||||
|
('saddlebrown', (139, 69, 19)),
|
||||||
|
('salmon', (250, 128, 114)),
|
||||||
|
('sandybrown', (244, 164, 96)),
|
||||||
|
('seagreen', (46, 139, 87)),
|
||||||
|
('seashell', (255, 245, 238)),
|
||||||
|
('sienna', (160, 82, 45)),
|
||||||
|
('silver', (192, 192, 192)),
|
||||||
|
('skyblue', (135, 206, 235)),
|
||||||
|
('slateblue', (106, 90, 205)),
|
||||||
|
('slategray', (112, 128, 144)),
|
||||||
|
('slategrey', (112, 128, 144)),
|
||||||
|
('snow', (255, 250, 250)),
|
||||||
|
('springgreen', (0, 255, 127)),
|
||||||
|
('steelblue', (70, 130, 180)),
|
||||||
|
('tan', (210, 180, 140)),
|
||||||
|
('teal', (0, 128, 128)),
|
||||||
|
('thistle', (216, 191, 216)),
|
||||||
|
('tomato', (255, 99, 71)),
|
||||||
|
('turquoise', (64, 224, 208)),
|
||||||
|
('violet', (238, 130, 238)),
|
||||||
|
('wheat', (245, 222, 179)),
|
||||||
|
('white', (255, 255, 255)),
|
||||||
|
('whitesmoke', (245, 245, 245)),
|
||||||
|
('yellow', (255, 255, 0)),
|
||||||
|
('yellowgreen', (154, 205, 50)),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# (r, g, b, a) in 0..1 or a string marker
|
||||||
|
_SPECIAL_COLOR_KEYWORDS = {
|
||||||
|
'currentcolor': 'currentColor',
|
||||||
|
'transparent': RGBA(0., 0., 0., 0.),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# RGBA namedtuples of (r, g, b, a) in 0..1 or a string marker
|
||||||
|
_COLOR_KEYWORDS = _SPECIAL_COLOR_KEYWORDS.copy()
|
||||||
|
_COLOR_KEYWORDS.update(
|
||||||
|
# 255 maps to 1, 0 to 0, the rest is linear.
|
||||||
|
(keyword, RGBA(r / 255., g / 255., b / 255., 1.))
|
||||||
|
for keyword, (r, g, b) in _BASIC_COLOR_KEYWORDS + _EXTENDED_COLOR_KEYWORDS)
|
|
@ -0,0 +1,156 @@
|
||||||
|
[
|
||||||
|
|
||||||
|
"", null,
|
||||||
|
" \n", null,
|
||||||
|
|
||||||
|
"odd", [2, 1],
|
||||||
|
"even", [2, 0],
|
||||||
|
"ödd", null,
|
||||||
|
"éven", null,
|
||||||
|
" /**/\t OdD /**/\n", [2, 1],
|
||||||
|
" /**/\t EveN /**/\n", [2, 0],
|
||||||
|
|
||||||
|
|
||||||
|
"3", [0, 3],
|
||||||
|
"+2 ", [0, 2],
|
||||||
|
" -14 ", [0, -14],
|
||||||
|
"+ 2 ", null,
|
||||||
|
"- 14 ", null,
|
||||||
|
"3.1", null,
|
||||||
|
|
||||||
|
"3N", [3, 0],
|
||||||
|
"+2N ", [2, 0],
|
||||||
|
" -14n ", [-14, 0],
|
||||||
|
"+ 2N ", null,
|
||||||
|
"- 14N ", null,
|
||||||
|
"3.1N", null,
|
||||||
|
"3 n", null,
|
||||||
|
|
||||||
|
" N", [1, 0],
|
||||||
|
" +n", [1, 0],
|
||||||
|
" -n", [-1, 0],
|
||||||
|
"+ n", null,
|
||||||
|
"- n", null,
|
||||||
|
|
||||||
|
|
||||||
|
"3N+1", [3, 1],
|
||||||
|
"+2n+1 ", [2, 1],
|
||||||
|
" -14n+1 ", [-14, 1],
|
||||||
|
"+ 2N+1 ", null,
|
||||||
|
"- 14n+1 ", null,
|
||||||
|
"3.1n+1", null,
|
||||||
|
"3 n+1", null,
|
||||||
|
|
||||||
|
" n+1", [1, 1],
|
||||||
|
" +N+1", [1, 1],
|
||||||
|
" -n+1", [-1, 1],
|
||||||
|
"+ N+1", null,
|
||||||
|
"- N+1", null,
|
||||||
|
|
||||||
|
"3n-1", [3, -1],
|
||||||
|
"+2N-1 ", [2, -1],
|
||||||
|
" -14n-1 ", [-14, -1],
|
||||||
|
"+ 2N-1 ", null,
|
||||||
|
"- 14N-1 ", null,
|
||||||
|
"3.1n-1", null,
|
||||||
|
"3 n-1", null,
|
||||||
|
"3n-1foo", null,
|
||||||
|
|
||||||
|
" n-1", [1, -1],
|
||||||
|
" +n-1", [1, -1],
|
||||||
|
" -n-1", [-1, -1],
|
||||||
|
"+ n-1", null,
|
||||||
|
"- n-1", null,
|
||||||
|
" +n-1foo", null,
|
||||||
|
" -n-1foo", null,
|
||||||
|
|
||||||
|
|
||||||
|
"3N +1", [3, 1],
|
||||||
|
"+2N +1 ", [2, 1],
|
||||||
|
" -14n +1 ", [-14, 1],
|
||||||
|
"+ 2N +1 ", null,
|
||||||
|
"- 14n +1 ", null,
|
||||||
|
"3.1N +1", null,
|
||||||
|
"3 n +1", null,
|
||||||
|
"3n foo", null,
|
||||||
|
"3n + foo", null,
|
||||||
|
|
||||||
|
" n +1", [1, 1],
|
||||||
|
" +N +1", [1, 1],
|
||||||
|
" -n +1", [-1, 1],
|
||||||
|
"+ n +1", null,
|
||||||
|
"- N +1", null,
|
||||||
|
|
||||||
|
"3N -1", [3, -1],
|
||||||
|
"+2n -1 ", [2, -1],
|
||||||
|
" -14n -1 ", [-14, -1],
|
||||||
|
"+ 2n -1 ", null,
|
||||||
|
"- 14N -1 ", null,
|
||||||
|
"3.1N -1", null,
|
||||||
|
"3 N -1", null,
|
||||||
|
|
||||||
|
" N -1", [1, -1],
|
||||||
|
" +N -1", [1, -1],
|
||||||
|
" -n -1", [-1, -1],
|
||||||
|
"+ n -1", null,
|
||||||
|
"- n -1", null,
|
||||||
|
|
||||||
|
|
||||||
|
"3n+ 1", [3, 1],
|
||||||
|
"+2n+ 1 ", [2, 1],
|
||||||
|
" -14n+ 1 ", [-14, 1],
|
||||||
|
"+ 2n+ 1 ", null,
|
||||||
|
"- 14N+ 1 ", null,
|
||||||
|
"3.1n+ 1", null,
|
||||||
|
"3 N+ 1", null,
|
||||||
|
|
||||||
|
" N+ 1", [1, 1],
|
||||||
|
" +N+ 1", [1, 1],
|
||||||
|
" -N+ 1", [-1, 1],
|
||||||
|
"+ n+ 1", null,
|
||||||
|
"- N+ 1", null,
|
||||||
|
|
||||||
|
"3n- 1", [3, -1],
|
||||||
|
"+2N- 1 ", [2, -1],
|
||||||
|
" -14N- 1 ", [-14, -1],
|
||||||
|
"+ 2N- 1 ", null,
|
||||||
|
"- 14n- 1 ", null,
|
||||||
|
"3.1n- 1", null,
|
||||||
|
"3 n- 1", null,
|
||||||
|
|
||||||
|
" N- 1", [1, -1],
|
||||||
|
" +N- 1", [1, -1],
|
||||||
|
" -n- 1", [-1, -1],
|
||||||
|
"+ n- 1", null,
|
||||||
|
"- N- 1", null,
|
||||||
|
|
||||||
|
|
||||||
|
"3N + 1", [3, 1],
|
||||||
|
"+2N + 1 ", [2, 1],
|
||||||
|
" -14n + 1 ", [-14, 1],
|
||||||
|
"+ 2n + 1 ", null,
|
||||||
|
"- 14N + 1 ", null,
|
||||||
|
"3.1n + 1", null,
|
||||||
|
"3 N + 1", null,
|
||||||
|
|
||||||
|
" n + 1", [1, 1],
|
||||||
|
" +n + 1", [1, 1],
|
||||||
|
" -N + 1", [-1, 1],
|
||||||
|
"+ N + 1", null,
|
||||||
|
"- N + 1", null,
|
||||||
|
|
||||||
|
"3N - 1", [3, -1],
|
||||||
|
"+2n - 1 ", [2, -1],
|
||||||
|
" -14n - 1 ", [-14, -1],
|
||||||
|
"+ 2N - 1 ", null,
|
||||||
|
"- 14N - 1 ", null,
|
||||||
|
"3.1N - 1", null,
|
||||||
|
"3 n - 1", null,
|
||||||
|
|
||||||
|
" N - 1", [1, -1],
|
||||||
|
" +n - 1", [1, -1],
|
||||||
|
" -n - 1", [-1, -1],
|
||||||
|
"+ N - 1", null,
|
||||||
|
"- N - 1", null
|
||||||
|
|
||||||
|
]
|
|
@ -0,0 +1,8 @@
|
||||||
|
Written in 2013 by Simon Sapin.
|
||||||
|
|
||||||
|
To the extent possible under law, the author(s) have dedicated all copyright
|
||||||
|
and related and neighboring rights to this work to the public domain worldwide.
|
||||||
|
This work is distributed without any warranty.
|
||||||
|
|
||||||
|
See the CC0 Public Domain Dedication:
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/
|
|
@ -0,0 +1,301 @@
|
||||||
|
CSS parsing tests
|
||||||
|
#################
|
||||||
|
|
||||||
|
This repository contains implementation-independent test for CSS parsers,
|
||||||
|
based on the 2013 draft of the `CSS Syntax Level 3`_ specification.
|
||||||
|
|
||||||
|
.. _CSS Syntax Level 3: http://dev.w3.org/csswg/css-syntax-3/
|
||||||
|
|
||||||
|
The upstream repository for these tests is at
|
||||||
|
https://github.com/SimonSapin/css-parsing-tests
|
||||||
|
|
||||||
|
|
||||||
|
Projects using this
|
||||||
|
===================
|
||||||
|
|
||||||
|
CSS parsers using these tests:
|
||||||
|
|
||||||
|
* `tinycss2 <https://github.com/SimonSapin/tinycss2>`_ (Python)
|
||||||
|
* `rust-cssparser <https://github.com/mozilla-servo/rust-cssparser>`_
|
||||||
|
(Rust, used in `Servo <https://github.com/mozilla/servo/>`_)
|
||||||
|
* `Crass <https://github.com/rgrove/crass/>`_ (Ruby)
|
||||||
|
|
||||||
|
|
||||||
|
Importing
|
||||||
|
=========
|
||||||
|
|
||||||
|
The recommended way to use these tests in an implementation
|
||||||
|
is to import them with git-subtree_.
|
||||||
|
|
||||||
|
.. _git-subtree: https://github.com/git/git/tree/master/contrib/subtree
|
||||||
|
|
||||||
|
To import the first time to a ``./css-parsing-tests`` sub-directory,
|
||||||
|
run this from the top-level of a git repository::
|
||||||
|
|
||||||
|
git subtree add -P css-parsing-tests https://github.com/SimonSapin/css-parsing-tests.git master
|
||||||
|
|
||||||
|
Later, to merge changes made in the upstream repository, run::
|
||||||
|
|
||||||
|
git subtree pull -P css-parsing-tests https://github.com/SimonSapin/css-parsing-tests.git master
|
||||||
|
|
||||||
|
|
||||||
|
Test files
|
||||||
|
==========
|
||||||
|
|
||||||
|
CSS Syntax specification describes a number of "functions".
|
||||||
|
Each ``.json`` file in this repository corresponds to such a function.
|
||||||
|
The files are encoded as UTF-8
|
||||||
|
and each contain a JSON array with an even number of items,
|
||||||
|
where each pair of items is one function input
|
||||||
|
associated with the expected result.
|
||||||
|
|
||||||
|
``component_value_list.json``
|
||||||
|
Tests `Parse a list of component values
|
||||||
|
<http://dev.w3.org/csswg/css-syntax-3/#parse-a-list-of-component-values>`_.
|
||||||
|
The Unicode input is represented by a JSON string,
|
||||||
|
the output as an array of `component values`_ as described below.
|
||||||
|
|
||||||
|
``component_value_list.json``
|
||||||
|
Tests `Parse a component value
|
||||||
|
<http://dev.w3.org/csswg/css-syntax-3/#parse-a-component-value>`_.
|
||||||
|
The Unicode input is represented by a JSON string,
|
||||||
|
the output as a `component value`_.
|
||||||
|
|
||||||
|
``declaration_list.json``
|
||||||
|
Tests `Parse a list of declarations
|
||||||
|
<http://dev.w3.org/csswg/css-syntax-3/#parse-a-list-of-declarations>`_.
|
||||||
|
The Unicode input is represented by a JSON string,
|
||||||
|
the output as an array of declarations_ and at-rules_.
|
||||||
|
|
||||||
|
``one_declaration.json``
|
||||||
|
Tests `Parse a declaration
|
||||||
|
<http://dev.w3.org/csswg/css-syntax-3/#parse-a-declaration>`_.
|
||||||
|
The Unicode input is represented by a JSON string,
|
||||||
|
the output as a declaration_.
|
||||||
|
|
||||||
|
``one_rule.json``
|
||||||
|
Tests `Parse a rule
|
||||||
|
<http://dev.w3.org/csswg/css-syntax-3/#parse-a-rule>`_.
|
||||||
|
The Unicode input is represented by a JSON string,
|
||||||
|
the output as a `qualified rule`_ or at-rule_.
|
||||||
|
|
||||||
|
``rule_list.json``
|
||||||
|
Tests `Parse a list of rules
|
||||||
|
<http://dev.w3.org/csswg/css-syntax-3/#parse-a-list-of-rules>`_.
|
||||||
|
The Unicode input is represented by a JSON string,
|
||||||
|
the output as a list of `qualified rules`_ or at-rules_.
|
||||||
|
|
||||||
|
``stylesheet.json``
|
||||||
|
Tests `Parse a stylesheet
|
||||||
|
<http://dev.w3.org/csswg/css-syntax-3/#parse-a-stylesheet>`_.
|
||||||
|
The Unicode input is represented by a JSON string,
|
||||||
|
the output as a list of `qualified rules`_ or at-rules_.
|
||||||
|
|
||||||
|
``stylesheet_bytes.json``
|
||||||
|
Tests `Parse a stylesheet
|
||||||
|
<http://dev.w3.org/csswg/css-syntax-3/#parse-a-stylesheet>`_
|
||||||
|
together with `The input byte stream
|
||||||
|
<http://dev.w3.org/csswg/css-syntax/#input-byte-stream>`_.
|
||||||
|
The input is represented as a JSON object containing:
|
||||||
|
|
||||||
|
* A required ``css_bytes``, the input byte string,
|
||||||
|
represented as a JSON string where code points U+0000 to U+00FF
|
||||||
|
represent bytes of the same value.
|
||||||
|
* An optional ``protocol_encoding``,
|
||||||
|
a protocol encoding label as a JSON string, or null.
|
||||||
|
* An optional ``environment_encoding``,
|
||||||
|
an environment encoding label as a JSON string, or null.
|
||||||
|
* An optional ``comment`` that is ignored.
|
||||||
|
|
||||||
|
The output is represented a list of `qualified rules`_ or at-rules_.
|
||||||
|
|
||||||
|
``color3.json``
|
||||||
|
Tests the ``<color>`` syntax `defined in CSS Color Level 3
|
||||||
|
<http://www.w3.org/TR/css3-color/#colorunits>`_.
|
||||||
|
The Unicode input is represented by a JSON string,
|
||||||
|
the output as one of:
|
||||||
|
|
||||||
|
* null if the input is not a valid color in CSS syntax
|
||||||
|
* The string "currentColor" for the currentColor keyword
|
||||||
|
* An array of length 4 for every other values:
|
||||||
|
four (floating point) numbers for the Red, Green, Blue and Alpha channel.
|
||||||
|
Each value is between 0 and 1.
|
||||||
|
|
||||||
|
``color3_hsl.json``
|
||||||
|
Same as ``color3.json``.
|
||||||
|
This file is generated by the ``make_color3_hsl.py`` Python script.
|
||||||
|
|
||||||
|
``color3_keywords.json``
|
||||||
|
Same as ``color3.json``,
|
||||||
|
except that the values for the Red, Green and Blue channel
|
||||||
|
are between 0 and 255.
|
||||||
|
This file is generated by the ``make_color3_keywords.py`` Python script.
|
||||||
|
|
||||||
|
``An+B.json``
|
||||||
|
Tests the `An+B <http://dev.w3.org/csswg/css-syntax/#the-anb-type>`_
|
||||||
|
syntax defined in CSS Syntax Level 3.
|
||||||
|
This `differs <http://dev.w3.org/csswg/css-syntax/#changes>`_ from the
|
||||||
|
`nth grammar rule <http://www.w3.org/TR/css3-selectors/#nth-child-pseudo>`_
|
||||||
|
in Selectors Level 3 only in that
|
||||||
|
``-`` charecters and digits can be escaped in some cases.
|
||||||
|
The Unicode input is represented by a JSON string,
|
||||||
|
the output as null for invalid syntax,
|
||||||
|
or an array of two integers ``[A, B]``.
|
||||||
|
|
||||||
|
|
||||||
|
Result representation
|
||||||
|
=====================
|
||||||
|
|
||||||
|
AST nodes (the results of parsing) are represented in JSON as follow.
|
||||||
|
This representation was chosen to be compact
|
||||||
|
(and thus less annoying to write by hand)
|
||||||
|
while staying unambiguous.
|
||||||
|
For example, the difference between ``@import`` and ``\@import`` is not lost:
|
||||||
|
they are represented as ``["at-keyword", "import"]`` and ``["ident", "@import"]``,
|
||||||
|
respectively.
|
||||||
|
|
||||||
|
|
||||||
|
Rules and declarations
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
.. _at-rule:
|
||||||
|
.. _at-rules:
|
||||||
|
.. _qualified rule:
|
||||||
|
.. _qualified rules:
|
||||||
|
.. _declaration:
|
||||||
|
.. _declarations:
|
||||||
|
|
||||||
|
|
||||||
|
At-rule
|
||||||
|
An array of length 4: the string ``"at-rule"``,
|
||||||
|
the name (value of the at-keyword) as a string,
|
||||||
|
the prelude as a nested array of `component values`_,
|
||||||
|
and the optional block as a nested array of component value, or null.
|
||||||
|
|
||||||
|
Qualified rule
|
||||||
|
An array of length 3: the string ``"qualified rule"``,
|
||||||
|
the prelude as a nested array of `component values`_,
|
||||||
|
and the block as a nested array of component value.
|
||||||
|
|
||||||
|
|
||||||
|
Declaration
|
||||||
|
An array of length 4: the string ``"declaration"``, the name as a string,
|
||||||
|
the value as a nested array of `component values`_,
|
||||||
|
and a the important flag as a boolean.
|
||||||
|
|
||||||
|
|
||||||
|
.. _component value:
|
||||||
|
.. _component values:
|
||||||
|
|
||||||
|
Component values
|
||||||
|
----------------
|
||||||
|
|
||||||
|
<ident>
|
||||||
|
Array of length 2: the string ``"ident"``, and the value as a string.
|
||||||
|
|
||||||
|
<at-keyword>
|
||||||
|
Array of length 2: the string ``"at-keyword"``, and the value as a string.
|
||||||
|
|
||||||
|
<hash>
|
||||||
|
Array of length 3: the string ``"hash"``, the value as a string,
|
||||||
|
and the type as the string ``"id"`` or ``"unrestricted"``.
|
||||||
|
|
||||||
|
<string>
|
||||||
|
Array of length 2: the string ``"string"``, and the value as a string.
|
||||||
|
|
||||||
|
<bad-string>
|
||||||
|
Array of length 1: the string ``"bad-string"``.
|
||||||
|
|
||||||
|
<url>
|
||||||
|
Array of length 2: the string ``"url"``, and the value as a string.
|
||||||
|
|
||||||
|
<bad-url>
|
||||||
|
Array of length 1: the string ``"bad-url"``.
|
||||||
|
|
||||||
|
<delim>
|
||||||
|
The value as a one-character string.
|
||||||
|
|
||||||
|
<number>
|
||||||
|
Array of length 4: the string ``"number"``, the representation as a string,
|
||||||
|
the value as a number, and the type as the string ``"integer"`` or ``"number"``.
|
||||||
|
|
||||||
|
<percentage>
|
||||||
|
Array of length 4: the string ``"percentage"``, the representation as a string,
|
||||||
|
the value as a number, and the type as the string ``"integer"`` or ``"number"``.
|
||||||
|
|
||||||
|
<dimension>
|
||||||
|
Array of length 4: the string ``"dimension"``, the representation as a string,
|
||||||
|
the value as a number, the type as the string ``"integer"`` or ``"number"``,
|
||||||
|
and the unit as a string.
|
||||||
|
|
||||||
|
<unicode-range>
|
||||||
|
Array of length 3: the string ``"unicode-range"``,
|
||||||
|
followed by the *start* and *end* integers as two numbers.
|
||||||
|
|
||||||
|
<include-match>
|
||||||
|
The string ``"~="``.
|
||||||
|
|
||||||
|
<dash-match>
|
||||||
|
The string ``"|="``.
|
||||||
|
|
||||||
|
<prefix-match>
|
||||||
|
The string ``"^="``.
|
||||||
|
|
||||||
|
<suffix-match>
|
||||||
|
The string ``"$="``.
|
||||||
|
|
||||||
|
<substring-match>
|
||||||
|
The string ``"*="``.
|
||||||
|
|
||||||
|
<column>
|
||||||
|
The string ``"||"``.
|
||||||
|
|
||||||
|
<whitespace>
|
||||||
|
The string ``" "`` (a single space.)
|
||||||
|
|
||||||
|
<CDO>
|
||||||
|
The string ``"<!--"``.
|
||||||
|
|
||||||
|
<CDC>
|
||||||
|
The string ``"-->"``.
|
||||||
|
|
||||||
|
<colon>
|
||||||
|
The string ``":"``.
|
||||||
|
|
||||||
|
<semicolon>
|
||||||
|
The string ``";"``.
|
||||||
|
|
||||||
|
<comma>
|
||||||
|
The string ``","``.
|
||||||
|
|
||||||
|
{} block
|
||||||
|
An array of length N+1: the string ``"{}"``
|
||||||
|
followed by the N `component values`_ of the block’s content.
|
||||||
|
|
||||||
|
[] block
|
||||||
|
An array of length N+1: the string ``"[]"``
|
||||||
|
followed by the N `component values`_ of the block’s content.
|
||||||
|
|
||||||
|
() block
|
||||||
|
An array of length N+1: the string ``"()"``
|
||||||
|
followed by the N `component values`_ of the block’s content.
|
||||||
|
|
||||||
|
Function
|
||||||
|
An array of length N+2: the string ``"function"``
|
||||||
|
and the name of the function as a string
|
||||||
|
followed by the N `component values`_ of the function’s arguments.
|
||||||
|
|
||||||
|
<bad-string>
|
||||||
|
The array of two strings ``["error", "bad-string"]``.
|
||||||
|
|
||||||
|
<bad-url>
|
||||||
|
The array of two strings ``["error", "bad-url"]``.
|
||||||
|
|
||||||
|
Unmatched <}>
|
||||||
|
The array of two strings ``["error", "}"]``.
|
||||||
|
|
||||||
|
Unmatched <]>
|
||||||
|
The array of two strings ``["error", "]"]``.
|
||||||
|
|
||||||
|
Unmatched <)>
|
||||||
|
The array of two strings ``["error", ")"]``.
|
|
@ -0,0 +1,142 @@
|
||||||
|
[
|
||||||
|
"", null,
|
||||||
|
" /* hey */\n", null,
|
||||||
|
"4", null,
|
||||||
|
"top", null,
|
||||||
|
"/**/transparent", [0, 0, 0, 0],
|
||||||
|
"transparent", [0, 0, 0, 0],
|
||||||
|
" transparent\n", [0, 0, 0, 0],
|
||||||
|
"TransParent", [0, 0, 0, 0],
|
||||||
|
"currentColor", "currentColor",
|
||||||
|
"CURRENTcolor", "currentColor",
|
||||||
|
"current-Color", null,
|
||||||
|
|
||||||
|
"black", [0, 0, 0, 1],
|
||||||
|
"white", [1, 1, 1, 1],
|
||||||
|
"fuchsia", [1, 0, 1, 1],
|
||||||
|
"cyan", [0, 1, 1, 1],
|
||||||
|
"CyAn", [0, 1, 1, 1],
|
||||||
|
|
||||||
|
"#", null,
|
||||||
|
"#f", null,
|
||||||
|
"#ff", null,
|
||||||
|
"#fff", [1, 1, 1, 1],
|
||||||
|
"#ffg", null,
|
||||||
|
"#ffff", null,
|
||||||
|
"#fffff", null,
|
||||||
|
"#ffffff", [1, 1, 1, 1],
|
||||||
|
"#fffffg", null,
|
||||||
|
"#fffffff", null,
|
||||||
|
"#ffffffff", null,
|
||||||
|
"#fffffffff", null,
|
||||||
|
|
||||||
|
"#FFCc99", [1, 0.8, 0.6, 1],
|
||||||
|
"#369", [0.2, 0.4, 0.6, 1],
|
||||||
|
|
||||||
|
"rgb(00, 51, 102)", [0, 0.2, 0.4, 1],
|
||||||
|
"r\\gb(00, 51, 102)", [0, 0.2, 0.4, 1],
|
||||||
|
"r\\67 b(00, 51, 102)", [0, 0.2, 0.4, 1],
|
||||||
|
"RGB(153, 204, 255)", [0.6, 0.8, 1, 1],
|
||||||
|
"rgB(0, 0, 0)", [0, 0, 0, 1],
|
||||||
|
"rgB(0, 51, 255)", [0, 0.2, 1, 1],
|
||||||
|
"rgb(0,51,255)", [0, 0.2, 1, 1],
|
||||||
|
"rgb(0\t, 51 ,255)", [0, 0.2, 1, 1],
|
||||||
|
"rgb(/* R */0, /* G */51, /* B */255)", [0, 0.2, 1, 1],
|
||||||
|
"rgb(-51, 306, 0)", [-0.2, 1.2, 0, 1],
|
||||||
|
|
||||||
|
"rgb(42%, 3%, 50%)", [0.42, 0.03, 0.5, 1],
|
||||||
|
"RGB(100%, 100%, 100%)", [1, 1, 1, 1],
|
||||||
|
"rgB(0%, 0%, 0%)", [0, 0, 0, 1],
|
||||||
|
"rgB(10%, 20%, 30%)", [0.1, 0.2, 0.3, 1],
|
||||||
|
"rgb(10%,20%,30%)", [0.1, 0.2, 0.3, 1],
|
||||||
|
"rgb(10%\t, 20% ,30%)", [0.1, 0.2, 0.3, 1],
|
||||||
|
"rgb(/* R */ 10%, /* G */ 20%, /* B */ 30%)", [0.1, 0.2, 0.3, 1],
|
||||||
|
"rgb(-12%, 110%, 1400%)", [-0.12, 1.1, 14, 1],
|
||||||
|
|
||||||
|
"rgb(10%, 50%, 0)", null,
|
||||||
|
"rgb(255, 50%, 0%)", null,
|
||||||
|
"rgb(0, 0 0)", null,
|
||||||
|
"rgb(0, 0, 0deg)", null,
|
||||||
|
"rgb(0, 0, light)", null,
|
||||||
|
"rgb()", null,
|
||||||
|
"rgb(0)", null,
|
||||||
|
"rgb(0, 0)", null,
|
||||||
|
"rgb(0, 0, 0, 0)", null,
|
||||||
|
"rgb(0%)", null,
|
||||||
|
"rgb(0%, 0%)", null,
|
||||||
|
"rgb(0%, 0%, 0%, 0%)", null,
|
||||||
|
"rgb(0%, 0%, 0%, 0)", null,
|
||||||
|
|
||||||
|
"rgba(0, 0, 0, 0)", [0, 0, 0, 0],
|
||||||
|
"rgba(204, 0, 102, 0.3)", [0.8, 0, 0.4, 0.3],
|
||||||
|
"RGBA(255, 255, 255, 0)", [1, 1, 1, 0],
|
||||||
|
"rgBA(0, 51, 255, 1)", [0, 0.2, 1, 1],
|
||||||
|
"rgba(0, 51, 255, 1.1)", [0, 0.2, 1, 1],
|
||||||
|
"rgba(0, 51, 255, 37)", [0, 0.2, 1, 1],
|
||||||
|
"rgba(0, 51, 255, 0.42)", [0, 0.2, 1, 0.42],
|
||||||
|
"rgba(0, 51, 255, 0)", [0, 0.2, 1, 0],
|
||||||
|
"rgba(0, 51, 255, -0.1)", [0, 0.2, 1, 0],
|
||||||
|
"rgba(0, 51, 255, -139)", [0, 0.2, 1, 0],
|
||||||
|
|
||||||
|
"rgba(42%, 3%, 50%, 0.3)", [0.42, 0.03, 0.5, 0.3],
|
||||||
|
"RGBA(100%, 100%, 100%, 0)", [1, 1, 1, 0],
|
||||||
|
"rgBA(0%, 20%, 100%, 1)", [0, 0.2, 1, 1],
|
||||||
|
"rgba(0%, 20%, 100%, 1.1)", [0, 0.2, 1, 1],
|
||||||
|
"rgba(0%, 20%, 100%, 37)", [0, 0.2, 1, 1],
|
||||||
|
"rgba(0%, 20%, 100%, 0.42)", [0, 0.2, 1, 0.42],
|
||||||
|
"rgba(0%, 20%, 100%, 0)", [0, 0.2, 1, 0],
|
||||||
|
"rgba(0%, 20%, 100%, -0.1)", [0, 0.2, 1, 0],
|
||||||
|
"rgba(0%, 20%, 100%, -139)", [0, 0.2, 1, 0],
|
||||||
|
|
||||||
|
"rgba(255, 255, 255, 0%)", null,
|
||||||
|
"rgba(10%, 50%, 0, 1)", null,
|
||||||
|
"rgba(255, 50%, 0%, 1)", null,
|
||||||
|
"rgba(0, 0, 0 0)", null,
|
||||||
|
"rgba(0, 0, 0, 0deg)", null,
|
||||||
|
"rgba(0, 0, 0, light)", null,
|
||||||
|
"rgba()", null,
|
||||||
|
"rgba(0)", null,
|
||||||
|
"rgba(0, 0, 0)", null,
|
||||||
|
"rgba(0, 0, 0, 0, 0)", null,
|
||||||
|
"rgba(0%)", null,
|
||||||
|
"rgba(0%, 0%)", null,
|
||||||
|
"rgba(0%, 0%, 0%)", null,
|
||||||
|
"rgba(0%, 0%, 0%, 0%)", null,
|
||||||
|
"rgba(0%, 0%, 0%, 0%, 0%)", null,
|
||||||
|
|
||||||
|
"HSL(0, 0%, 0%)", [0, 0, 0, 1],
|
||||||
|
"hsL(0, 100%, 50%)", [1, 0, 0, 1],
|
||||||
|
"hsl(60, 100%, 37.5%)", [0.75, 0.75, 0, 1],
|
||||||
|
"hsl(780, 100%, 37.5%)", [0.75, 0.75, 0, 1],
|
||||||
|
"hsl(-300, 100%, 37.5%)", [0.75, 0.75, 0, 1],
|
||||||
|
"hsl(300, 50%, 50%)", [0.75, 0.25, 0.75, 1],
|
||||||
|
|
||||||
|
"hsl(10, 50%, 0)", null,
|
||||||
|
"hsl(50%, 50%, 0%)", null,
|
||||||
|
"hsl(0, 0% 0%)", null,
|
||||||
|
"hsl(30deg, 100%, 100%)", null,
|
||||||
|
"hsl(0, 0%, light)", null,
|
||||||
|
"hsl()", null,
|
||||||
|
"hsl(0)", null,
|
||||||
|
"hsl(0, 0%)", null,
|
||||||
|
"hsl(0, 0%, 0%, 0%)", null,
|
||||||
|
|
||||||
|
"HSLA(-300, 100%, 37.5%, 1)", [0.75, 0.75, 0, 1],
|
||||||
|
"hsLA(-300, 100%, 37.5%, 12)", [0.75, 0.75, 0, 1],
|
||||||
|
"hsla(-300, 100%, 37.5%, 0.2)", [0.75, 0.75, 0, 0.2],
|
||||||
|
"hsla(-300, 100%, 37.5%, 0)", [0.75, 0.75, 0, 0],
|
||||||
|
"hsla(-300, 100%, 37.5%, -3)", [0.75, 0.75, 0, 0],
|
||||||
|
|
||||||
|
"hsla(10, 50%, 0, 1)", null,
|
||||||
|
"hsla(50%, 50%, 0%, 1)", null,
|
||||||
|
"hsla(0, 0% 0%, 1)", null,
|
||||||
|
"hsla(30deg, 100%, 100%, 1)", null,
|
||||||
|
"hsla(0, 0%, light, 1)", null,
|
||||||
|
"hsla()", null,
|
||||||
|
"hsla(0)", null,
|
||||||
|
"hsla(0, 0%)", null,
|
||||||
|
"hsla(0, 0%, 0%, 50%)", null,
|
||||||
|
"hsla(0, 0%, 0%, 1, 0%)", null,
|
||||||
|
|
||||||
|
"cmyk(0, 0, 0, 0)", null
|
||||||
|
]
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,803 @@
|
||||||
|
[
|
||||||
|
"transparent", [0, 0, 0, 0],
|
||||||
|
"Transparent", [0, 0, 0, 0],
|
||||||
|
"\\transparent", [0, 0, 0, 0],
|
||||||
|
"\\74 ransparent", [0, 0, 0, 0],
|
||||||
|
"ransparent", null,
|
||||||
|
"black", [0, 0, 0, 1],
|
||||||
|
"bLack", [0, 0, 0, 1],
|
||||||
|
"b\\lack", [0, 0, 0, 1],
|
||||||
|
"b\\6C ack", [0, 0, 0, 1],
|
||||||
|
"back", null,
|
||||||
|
"blacK", null,
|
||||||
|
"silver", [192, 192, 192, 1],
|
||||||
|
"siLver", [192, 192, 192, 1],
|
||||||
|
"si\\lver", [192, 192, 192, 1],
|
||||||
|
"si\\6C ver", [192, 192, 192, 1],
|
||||||
|
"siver", null,
|
||||||
|
"gray", [128, 128, 128, 1],
|
||||||
|
"graY", [128, 128, 128, 1],
|
||||||
|
"gra\\y", [128, 128, 128, 1],
|
||||||
|
"gra\\79 ", [128, 128, 128, 1],
|
||||||
|
"gra", null,
|
||||||
|
"white", [255, 255, 255, 1],
|
||||||
|
"whitE", [255, 255, 255, 1],
|
||||||
|
"whit\\65 ", [255, 255, 255, 1],
|
||||||
|
"whit", null,
|
||||||
|
"maroon", [128, 0, 0, 1],
|
||||||
|
"marooN", [128, 0, 0, 1],
|
||||||
|
"maroo\\n", [128, 0, 0, 1],
|
||||||
|
"maroo\\6E ", [128, 0, 0, 1],
|
||||||
|
"maroo", null,
|
||||||
|
"red", [255, 0, 0, 1],
|
||||||
|
"Red", [255, 0, 0, 1],
|
||||||
|
"\\red", [255, 0, 0, 1],
|
||||||
|
"\\72 ed", [255, 0, 0, 1],
|
||||||
|
"ed", null,
|
||||||
|
"purple", [128, 0, 128, 1],
|
||||||
|
"pUrple", [128, 0, 128, 1],
|
||||||
|
"p\\urple", [128, 0, 128, 1],
|
||||||
|
"p\\75 rple", [128, 0, 128, 1],
|
||||||
|
"prple", null,
|
||||||
|
"fuchsia", [255, 0, 255, 1],
|
||||||
|
"fUchsia", [255, 0, 255, 1],
|
||||||
|
"f\\uchsia", [255, 0, 255, 1],
|
||||||
|
"f\\75 chsia", [255, 0, 255, 1],
|
||||||
|
"fchsia", null,
|
||||||
|
"green", [0, 128, 0, 1],
|
||||||
|
"greeN", [0, 128, 0, 1],
|
||||||
|
"gree\\n", [0, 128, 0, 1],
|
||||||
|
"gree\\6E ", [0, 128, 0, 1],
|
||||||
|
"gree", null,
|
||||||
|
"lime", [0, 255, 0, 1],
|
||||||
|
"liMe", [0, 255, 0, 1],
|
||||||
|
"li\\me", [0, 255, 0, 1],
|
||||||
|
"li\\6D e", [0, 255, 0, 1],
|
||||||
|
"lie", null,
|
||||||
|
"olive", [128, 128, 0, 1],
|
||||||
|
"oLive", [128, 128, 0, 1],
|
||||||
|
"o\\live", [128, 128, 0, 1],
|
||||||
|
"o\\6C ive", [128, 128, 0, 1],
|
||||||
|
"oive", null,
|
||||||
|
"yellow", [255, 255, 0, 1],
|
||||||
|
"Yellow", [255, 255, 0, 1],
|
||||||
|
"\\yellow", [255, 255, 0, 1],
|
||||||
|
"\\79 ellow", [255, 255, 0, 1],
|
||||||
|
"ellow", null,
|
||||||
|
"navy", [0, 0, 128, 1],
|
||||||
|
"nAvy", [0, 0, 128, 1],
|
||||||
|
"n\\61 vy", [0, 0, 128, 1],
|
||||||
|
"nvy", null,
|
||||||
|
"blue", [0, 0, 255, 1],
|
||||||
|
"blUe", [0, 0, 255, 1],
|
||||||
|
"bl\\ue", [0, 0, 255, 1],
|
||||||
|
"bl\\75 e", [0, 0, 255, 1],
|
||||||
|
"ble", null,
|
||||||
|
"teal", [0, 128, 128, 1],
|
||||||
|
"teaL", [0, 128, 128, 1],
|
||||||
|
"tea\\l", [0, 128, 128, 1],
|
||||||
|
"tea\\6C ", [0, 128, 128, 1],
|
||||||
|
"tea", null,
|
||||||
|
"aqua", [0, 255, 255, 1],
|
||||||
|
"Aqua", [0, 255, 255, 1],
|
||||||
|
"\\61 qua", [0, 255, 255, 1],
|
||||||
|
"qua", null,
|
||||||
|
"aliceblue", [240, 248, 255, 1],
|
||||||
|
"alicebluE", [240, 248, 255, 1],
|
||||||
|
"aliceblu\\65 ", [240, 248, 255, 1],
|
||||||
|
"aliceblu", null,
|
||||||
|
"antiquewhite", [250, 235, 215, 1],
|
||||||
|
"antiquEwhite", [250, 235, 215, 1],
|
||||||
|
"antiqu\\65 white", [250, 235, 215, 1],
|
||||||
|
"antiquwhite", null,
|
||||||
|
"aqua", [0, 255, 255, 1],
|
||||||
|
"aquA", [0, 255, 255, 1],
|
||||||
|
"aqu\\61 ", [0, 255, 255, 1],
|
||||||
|
"aqu", null,
|
||||||
|
"aquamarine", [127, 255, 212, 1],
|
||||||
|
"Aquamarine", [127, 255, 212, 1],
|
||||||
|
"\\61 quamarine", [127, 255, 212, 1],
|
||||||
|
"quamarine", null,
|
||||||
|
"azure", [240, 255, 255, 1],
|
||||||
|
"aZure", [240, 255, 255, 1],
|
||||||
|
"a\\zure", [240, 255, 255, 1],
|
||||||
|
"a\\7A ure", [240, 255, 255, 1],
|
||||||
|
"aure", null,
|
||||||
|
"beige", [245, 245, 220, 1],
|
||||||
|
"beIge", [245, 245, 220, 1],
|
||||||
|
"be\\ige", [245, 245, 220, 1],
|
||||||
|
"be\\69 ge", [245, 245, 220, 1],
|
||||||
|
"bege", null,
|
||||||
|
"bisque", [255, 228, 196, 1],
|
||||||
|
"bisquE", [255, 228, 196, 1],
|
||||||
|
"bisqu\\65 ", [255, 228, 196, 1],
|
||||||
|
"bisqu", null,
|
||||||
|
"black", [0, 0, 0, 1],
|
||||||
|
"blacK", [0, 0, 0, 1],
|
||||||
|
"blac\\k", [0, 0, 0, 1],
|
||||||
|
"blac\\6B ", [0, 0, 0, 1],
|
||||||
|
"blac", null,
|
||||||
|
"blacK", null,
|
||||||
|
"blanchedalmond", [255, 235, 205, 1],
|
||||||
|
"blanchedalmOnd", [255, 235, 205, 1],
|
||||||
|
"blanchedalm\\ond", [255, 235, 205, 1],
|
||||||
|
"blanchedalm\\6F nd", [255, 235, 205, 1],
|
||||||
|
"blanchedalmnd", null,
|
||||||
|
"blue", [0, 0, 255, 1],
|
||||||
|
"blUe", [0, 0, 255, 1],
|
||||||
|
"bl\\ue", [0, 0, 255, 1],
|
||||||
|
"bl\\75 e", [0, 0, 255, 1],
|
||||||
|
"ble", null,
|
||||||
|
"blueviolet", [138, 43, 226, 1],
|
||||||
|
"bluevioLet", [138, 43, 226, 1],
|
||||||
|
"bluevio\\let", [138, 43, 226, 1],
|
||||||
|
"bluevio\\6C et", [138, 43, 226, 1],
|
||||||
|
"bluevioet", null,
|
||||||
|
"brown", [165, 42, 42, 1],
|
||||||
|
"broWn", [165, 42, 42, 1],
|
||||||
|
"bro\\wn", [165, 42, 42, 1],
|
||||||
|
"bro\\77 n", [165, 42, 42, 1],
|
||||||
|
"bron", null,
|
||||||
|
"burlywood", [222, 184, 135, 1],
|
||||||
|
"buRlywood", [222, 184, 135, 1],
|
||||||
|
"bu\\rlywood", [222, 184, 135, 1],
|
||||||
|
"bu\\72 lywood", [222, 184, 135, 1],
|
||||||
|
"bulywood", null,
|
||||||
|
"cadetblue", [95, 158, 160, 1],
|
||||||
|
"cadEtblue", [95, 158, 160, 1],
|
||||||
|
"cad\\65 tblue", [95, 158, 160, 1],
|
||||||
|
"cadtblue", null,
|
||||||
|
"chartreuse", [127, 255, 0, 1],
|
||||||
|
"cHartreuse", [127, 255, 0, 1],
|
||||||
|
"c\\hartreuse", [127, 255, 0, 1],
|
||||||
|
"c\\68 artreuse", [127, 255, 0, 1],
|
||||||
|
"cartreuse", null,
|
||||||
|
"chocolate", [210, 105, 30, 1],
|
||||||
|
"chocoLate", [210, 105, 30, 1],
|
||||||
|
"choco\\late", [210, 105, 30, 1],
|
||||||
|
"choco\\6C ate", [210, 105, 30, 1],
|
||||||
|
"chocoate", null,
|
||||||
|
"coral", [255, 127, 80, 1],
|
||||||
|
"corAl", [255, 127, 80, 1],
|
||||||
|
"cor\\61 l", [255, 127, 80, 1],
|
||||||
|
"corl", null,
|
||||||
|
"cornflowerblue", [100, 149, 237, 1],
|
||||||
|
"cornflOwerblue", [100, 149, 237, 1],
|
||||||
|
"cornfl\\owerblue", [100, 149, 237, 1],
|
||||||
|
"cornfl\\6F werblue", [100, 149, 237, 1],
|
||||||
|
"cornflwerblue", null,
|
||||||
|
"cornsilk", [255, 248, 220, 1],
|
||||||
|
"corNsilk", [255, 248, 220, 1],
|
||||||
|
"cor\\nsilk", [255, 248, 220, 1],
|
||||||
|
"cor\\6E silk", [255, 248, 220, 1],
|
||||||
|
"corsilk", null,
|
||||||
|
"cornsilK", null,
|
||||||
|
"crimson", [220, 20, 60, 1],
|
||||||
|
"cRimson", [220, 20, 60, 1],
|
||||||
|
"c\\rimson", [220, 20, 60, 1],
|
||||||
|
"c\\72 imson", [220, 20, 60, 1],
|
||||||
|
"cimson", null,
|
||||||
|
"cyan", [0, 255, 255, 1],
|
||||||
|
"cYan", [0, 255, 255, 1],
|
||||||
|
"c\\yan", [0, 255, 255, 1],
|
||||||
|
"c\\79 an", [0, 255, 255, 1],
|
||||||
|
"can", null,
|
||||||
|
"darkblue", [0, 0, 139, 1],
|
||||||
|
"darkblUe", [0, 0, 139, 1],
|
||||||
|
"darkbl\\ue", [0, 0, 139, 1],
|
||||||
|
"darkbl\\75 e", [0, 0, 139, 1],
|
||||||
|
"darkble", null,
|
||||||
|
"darKblue", null,
|
||||||
|
"darkcyan", [0, 139, 139, 1],
|
||||||
|
"darkcyaN", [0, 139, 139, 1],
|
||||||
|
"darkcya\\n", [0, 139, 139, 1],
|
||||||
|
"darkcya\\6E ", [0, 139, 139, 1],
|
||||||
|
"darkcya", null,
|
||||||
|
"darKcyan", null,
|
||||||
|
"darkgoldenrod", [184, 134, 11, 1],
|
||||||
|
"dArkgoldenrod", [184, 134, 11, 1],
|
||||||
|
"d\\61 rkgoldenrod", [184, 134, 11, 1],
|
||||||
|
"drkgoldenrod", null,
|
||||||
|
"darKgoldenrod", null,
|
||||||
|
"darkgray", [169, 169, 169, 1],
|
||||||
|
"dArkgray", [169, 169, 169, 1],
|
||||||
|
"d\\61 rkgray", [169, 169, 169, 1],
|
||||||
|
"drkgray", null,
|
||||||
|
"darKgray", null,
|
||||||
|
"darkgreen", [0, 100, 0, 1],
|
||||||
|
"darkgrEen", [0, 100, 0, 1],
|
||||||
|
"darkgr\\65 en", [0, 100, 0, 1],
|
||||||
|
"darkgren", null,
|
||||||
|
"darKgreen", null,
|
||||||
|
"darkgrey", [169, 169, 169, 1],
|
||||||
|
"darKgrey", [169, 169, 169, 1],
|
||||||
|
"dar\\kgrey", [169, 169, 169, 1],
|
||||||
|
"dar\\6B grey", [169, 169, 169, 1],
|
||||||
|
"dargrey", null,
|
||||||
|
"darKgrey", null,
|
||||||
|
"darkkhaki", [189, 183, 107, 1],
|
||||||
|
"darkkhakI", [189, 183, 107, 1],
|
||||||
|
"darkkhak\\i", [189, 183, 107, 1],
|
||||||
|
"darkkhak\\69 ", [189, 183, 107, 1],
|
||||||
|
"darkkhak", null,
|
||||||
|
"darKKhaKi", null,
|
||||||
|
"darkmagenta", [139, 0, 139, 1],
|
||||||
|
"dArkmagenta", [139, 0, 139, 1],
|
||||||
|
"d\\61 rkmagenta", [139, 0, 139, 1],
|
||||||
|
"drkmagenta", null,
|
||||||
|
"darKmagenta", null,
|
||||||
|
"darkolivegreen", [85, 107, 47, 1],
|
||||||
|
"darkOlivegreen", [85, 107, 47, 1],
|
||||||
|
"dark\\olivegreen", [85, 107, 47, 1],
|
||||||
|
"dark\\6F livegreen", [85, 107, 47, 1],
|
||||||
|
"darklivegreen", null,
|
||||||
|
"darKolivegreen", null,
|
||||||
|
"darkorange", [255, 140, 0, 1],
|
||||||
|
"darkoraNge", [255, 140, 0, 1],
|
||||||
|
"darkora\\nge", [255, 140, 0, 1],
|
||||||
|
"darkora\\6E ge", [255, 140, 0, 1],
|
||||||
|
"darkorage", null,
|
||||||
|
"darKorange", null,
|
||||||
|
"darkorchid", [153, 50, 204, 1],
|
||||||
|
"darkorchId", [153, 50, 204, 1],
|
||||||
|
"darkorch\\id", [153, 50, 204, 1],
|
||||||
|
"darkorch\\69 d", [153, 50, 204, 1],
|
||||||
|
"darkorchd", null,
|
||||||
|
"darKorchid", null,
|
||||||
|
"darkred", [139, 0, 0, 1],
|
||||||
|
"Darkred", [139, 0, 0, 1],
|
||||||
|
"\\64 arkred", [139, 0, 0, 1],
|
||||||
|
"arkred", null,
|
||||||
|
"darKred", null,
|
||||||
|
"darksalmon", [233, 150, 122, 1],
|
||||||
|
"Darksalmon", [233, 150, 122, 1],
|
||||||
|
"\\64 arksalmon", [233, 150, 122, 1],
|
||||||
|
"arksalmon", null,
|
||||||
|
"darKsalmon", null,
|
||||||
|
"darkseagreen", [143, 188, 143, 1],
|
||||||
|
"darKseagreen", [143, 188, 143, 1],
|
||||||
|
"dar\\kseagreen", [143, 188, 143, 1],
|
||||||
|
"dar\\6B seagreen", [143, 188, 143, 1],
|
||||||
|
"darseagreen", null,
|
||||||
|
"darKseagreen", null,
|
||||||
|
"darkslateblue", [72, 61, 139, 1],
|
||||||
|
"Darkslateblue", [72, 61, 139, 1],
|
||||||
|
"\\64 arkslateblue", [72, 61, 139, 1],
|
||||||
|
"arkslateblue", null,
|
||||||
|
"darKslateblue", null,
|
||||||
|
"darkslategray", [47, 79, 79, 1],
|
||||||
|
"dArkslategray", [47, 79, 79, 1],
|
||||||
|
"d\\61 rkslategray", [47, 79, 79, 1],
|
||||||
|
"drkslategray", null,
|
||||||
|
"darKslategray", null,
|
||||||
|
"darkslategrey", [47, 79, 79, 1],
|
||||||
|
"daRkslategrey", [47, 79, 79, 1],
|
||||||
|
"da\\rkslategrey", [47, 79, 79, 1],
|
||||||
|
"da\\72 kslategrey", [47, 79, 79, 1],
|
||||||
|
"dakslategrey", null,
|
||||||
|
"darKslategrey", null,
|
||||||
|
"darkturquoise", [0, 206, 209, 1],
|
||||||
|
"darKturquoise", [0, 206, 209, 1],
|
||||||
|
"dar\\kturquoise", [0, 206, 209, 1],
|
||||||
|
"dar\\6B turquoise", [0, 206, 209, 1],
|
||||||
|
"darturquoise", null,
|
||||||
|
"darKturquoise", null,
|
||||||
|
"darkviolet", [148, 0, 211, 1],
|
||||||
|
"darkviOlet", [148, 0, 211, 1],
|
||||||
|
"darkvi\\olet", [148, 0, 211, 1],
|
||||||
|
"darkvi\\6F let", [148, 0, 211, 1],
|
||||||
|
"darkvilet", null,
|
||||||
|
"darKviolet", null,
|
||||||
|
"deeppink", [255, 20, 147, 1],
|
||||||
|
"dEeppink", [255, 20, 147, 1],
|
||||||
|
"d\\65 eppink", [255, 20, 147, 1],
|
||||||
|
"deppink", null,
|
||||||
|
"deeppinK", null,
|
||||||
|
"deepskyblue", [0, 191, 255, 1],
|
||||||
|
"deePskyblue", [0, 191, 255, 1],
|
||||||
|
"dee\\pskyblue", [0, 191, 255, 1],
|
||||||
|
"dee\\70 skyblue", [0, 191, 255, 1],
|
||||||
|
"deeskyblue", null,
|
||||||
|
"deepsKyblue", null,
|
||||||
|
"dimgray", [105, 105, 105, 1],
|
||||||
|
"dimGray", [105, 105, 105, 1],
|
||||||
|
"dim\\gray", [105, 105, 105, 1],
|
||||||
|
"dim\\67 ray", [105, 105, 105, 1],
|
||||||
|
"dimray", null,
|
||||||
|
"dimgrey", [105, 105, 105, 1],
|
||||||
|
"dimgRey", [105, 105, 105, 1],
|
||||||
|
"dimg\\rey", [105, 105, 105, 1],
|
||||||
|
"dimg\\72 ey", [105, 105, 105, 1],
|
||||||
|
"dimgey", null,
|
||||||
|
"dodgerblue", [30, 144, 255, 1],
|
||||||
|
"dOdgerblue", [30, 144, 255, 1],
|
||||||
|
"d\\odgerblue", [30, 144, 255, 1],
|
||||||
|
"d\\6F dgerblue", [30, 144, 255, 1],
|
||||||
|
"ddgerblue", null,
|
||||||
|
"firebrick", [178, 34, 34, 1],
|
||||||
|
"firebricK", [178, 34, 34, 1],
|
||||||
|
"firebric\\k", [178, 34, 34, 1],
|
||||||
|
"firebric\\6B ", [178, 34, 34, 1],
|
||||||
|
"firebric", null,
|
||||||
|
"firebricK", null,
|
||||||
|
"floralwhite", [255, 250, 240, 1],
|
||||||
|
"floralwhIte", [255, 250, 240, 1],
|
||||||
|
"floralwh\\ite", [255, 250, 240, 1],
|
||||||
|
"floralwh\\69 te", [255, 250, 240, 1],
|
||||||
|
"floralwhte", null,
|
||||||
|
"forestgreen", [34, 139, 34, 1],
|
||||||
|
"forestgreEn", [34, 139, 34, 1],
|
||||||
|
"forestgre\\65 n", [34, 139, 34, 1],
|
||||||
|
"forestgren", null,
|
||||||
|
"fuchsia", [255, 0, 255, 1],
|
||||||
|
"fuChsia", [255, 0, 255, 1],
|
||||||
|
"fu\\63 hsia", [255, 0, 255, 1],
|
||||||
|
"fuhsia", null,
|
||||||
|
"gainsboro", [220, 220, 220, 1],
|
||||||
|
"gaiNsboro", [220, 220, 220, 1],
|
||||||
|
"gai\\nsboro", [220, 220, 220, 1],
|
||||||
|
"gai\\6E sboro", [220, 220, 220, 1],
|
||||||
|
"gaisboro", null,
|
||||||
|
"ghostwhite", [248, 248, 255, 1],
|
||||||
|
"ghostwhIte", [248, 248, 255, 1],
|
||||||
|
"ghostwh\\ite", [248, 248, 255, 1],
|
||||||
|
"ghostwh\\69 te", [248, 248, 255, 1],
|
||||||
|
"ghostwhte", null,
|
||||||
|
"gold", [255, 215, 0, 1],
|
||||||
|
"Gold", [255, 215, 0, 1],
|
||||||
|
"\\gold", [255, 215, 0, 1],
|
||||||
|
"\\67 old", [255, 215, 0, 1],
|
||||||
|
"old", null,
|
||||||
|
"goldenrod", [218, 165, 32, 1],
|
||||||
|
"goldenRod", [218, 165, 32, 1],
|
||||||
|
"golden\\rod", [218, 165, 32, 1],
|
||||||
|
"golden\\72 od", [218, 165, 32, 1],
|
||||||
|
"goldenod", null,
|
||||||
|
"gray", [128, 128, 128, 1],
|
||||||
|
"grAy", [128, 128, 128, 1],
|
||||||
|
"gr\\61 y", [128, 128, 128, 1],
|
||||||
|
"gry", null,
|
||||||
|
"green", [0, 128, 0, 1],
|
||||||
|
"gReen", [0, 128, 0, 1],
|
||||||
|
"g\\reen", [0, 128, 0, 1],
|
||||||
|
"g\\72 een", [0, 128, 0, 1],
|
||||||
|
"geen", null,
|
||||||
|
"greenyellow", [173, 255, 47, 1],
|
||||||
|
"greenyEllow", [173, 255, 47, 1],
|
||||||
|
"greeny\\65 llow", [173, 255, 47, 1],
|
||||||
|
"greenyllow", null,
|
||||||
|
"grey", [128, 128, 128, 1],
|
||||||
|
"gRey", [128, 128, 128, 1],
|
||||||
|
"g\\rey", [128, 128, 128, 1],
|
||||||
|
"g\\72 ey", [128, 128, 128, 1],
|
||||||
|
"gey", null,
|
||||||
|
"honeydew", [240, 255, 240, 1],
|
||||||
|
"hoNeydew", [240, 255, 240, 1],
|
||||||
|
"ho\\neydew", [240, 255, 240, 1],
|
||||||
|
"ho\\6E eydew", [240, 255, 240, 1],
|
||||||
|
"hoeydew", null,
|
||||||
|
"hotpink", [255, 105, 180, 1],
|
||||||
|
"hotpiNk", [255, 105, 180, 1],
|
||||||
|
"hotpi\\nk", [255, 105, 180, 1],
|
||||||
|
"hotpi\\6E k", [255, 105, 180, 1],
|
||||||
|
"hotpik", null,
|
||||||
|
"hotpinK", null,
|
||||||
|
"indianred", [205, 92, 92, 1],
|
||||||
|
"indiAnred", [205, 92, 92, 1],
|
||||||
|
"indi\\61 nred", [205, 92, 92, 1],
|
||||||
|
"indinred", null,
|
||||||
|
"indigo", [75, 0, 130, 1],
|
||||||
|
"indigO", [75, 0, 130, 1],
|
||||||
|
"indig\\o", [75, 0, 130, 1],
|
||||||
|
"indig\\6F ", [75, 0, 130, 1],
|
||||||
|
"indig", null,
|
||||||
|
"ivory", [255, 255, 240, 1],
|
||||||
|
"ivoRy", [255, 255, 240, 1],
|
||||||
|
"ivo\\ry", [255, 255, 240, 1],
|
||||||
|
"ivo\\72 y", [255, 255, 240, 1],
|
||||||
|
"ivoy", null,
|
||||||
|
"khaki", [240, 230, 140, 1],
|
||||||
|
"khakI", [240, 230, 140, 1],
|
||||||
|
"khak\\i", [240, 230, 140, 1],
|
||||||
|
"khak\\69 ", [240, 230, 140, 1],
|
||||||
|
"khak", null,
|
||||||
|
"KhaKi", null,
|
||||||
|
"lavender", [230, 230, 250, 1],
|
||||||
|
"Lavender", [230, 230, 250, 1],
|
||||||
|
"\\lavender", [230, 230, 250, 1],
|
||||||
|
"\\6C avender", [230, 230, 250, 1],
|
||||||
|
"avender", null,
|
||||||
|
"lavenderblush", [255, 240, 245, 1],
|
||||||
|
"lavEnderblush", [255, 240, 245, 1],
|
||||||
|
"lav\\65 nderblush", [255, 240, 245, 1],
|
||||||
|
"lavnderblush", null,
|
||||||
|
"lawngreen", [124, 252, 0, 1],
|
||||||
|
"lAwngreen", [124, 252, 0, 1],
|
||||||
|
"l\\61 wngreen", [124, 252, 0, 1],
|
||||||
|
"lwngreen", null,
|
||||||
|
"lemonchiffon", [255, 250, 205, 1],
|
||||||
|
"lemonchiffoN", [255, 250, 205, 1],
|
||||||
|
"lemonchiffo\\n", [255, 250, 205, 1],
|
||||||
|
"lemonchiffo\\6E ", [255, 250, 205, 1],
|
||||||
|
"lemonchiffo", null,
|
||||||
|
"lightblue", [173, 216, 230, 1],
|
||||||
|
"ligHtblue", [173, 216, 230, 1],
|
||||||
|
"lig\\htblue", [173, 216, 230, 1],
|
||||||
|
"lig\\68 tblue", [173, 216, 230, 1],
|
||||||
|
"ligtblue", null,
|
||||||
|
"lightcoral", [240, 128, 128, 1],
|
||||||
|
"lightCoral", [240, 128, 128, 1],
|
||||||
|
"light\\63 oral", [240, 128, 128, 1],
|
||||||
|
"lightoral", null,
|
||||||
|
"lightcyan", [224, 255, 255, 1],
|
||||||
|
"lightCyan", [224, 255, 255, 1],
|
||||||
|
"light\\63 yan", [224, 255, 255, 1],
|
||||||
|
"lightyan", null,
|
||||||
|
"lightgoldenrodyellow", [250, 250, 210, 1],
|
||||||
|
"lightgoLdenrodyellow", [250, 250, 210, 1],
|
||||||
|
"lightgo\\ldenrodyellow", [250, 250, 210, 1],
|
||||||
|
"lightgo\\6C denrodyellow", [250, 250, 210, 1],
|
||||||
|
"lightgodenrodyellow", null,
|
||||||
|
"lightgray", [211, 211, 211, 1],
|
||||||
|
"lightgrAy", [211, 211, 211, 1],
|
||||||
|
"lightgr\\61 y", [211, 211, 211, 1],
|
||||||
|
"lightgry", null,
|
||||||
|
"lightgreen", [144, 238, 144, 1],
|
||||||
|
"lightgreeN", [144, 238, 144, 1],
|
||||||
|
"lightgree\\n", [144, 238, 144, 1],
|
||||||
|
"lightgree\\6E ", [144, 238, 144, 1],
|
||||||
|
"lightgree", null,
|
||||||
|
"lightgrey", [211, 211, 211, 1],
|
||||||
|
"Lightgrey", [211, 211, 211, 1],
|
||||||
|
"\\lightgrey", [211, 211, 211, 1],
|
||||||
|
"\\6C ightgrey", [211, 211, 211, 1],
|
||||||
|
"ightgrey", null,
|
||||||
|
"lightpink", [255, 182, 193, 1],
|
||||||
|
"lIghtpink", [255, 182, 193, 1],
|
||||||
|
"l\\ightpink", [255, 182, 193, 1],
|
||||||
|
"l\\69 ghtpink", [255, 182, 193, 1],
|
||||||
|
"lghtpink", null,
|
||||||
|
"lightpinK", null,
|
||||||
|
"lightsalmon", [255, 160, 122, 1],
|
||||||
|
"lighTsalmon", [255, 160, 122, 1],
|
||||||
|
"ligh\\tsalmon", [255, 160, 122, 1],
|
||||||
|
"ligh\\74 salmon", [255, 160, 122, 1],
|
||||||
|
"lighsalmon", null,
|
||||||
|
"lightseagreen", [32, 178, 170, 1],
|
||||||
|
"liGhtseagreen", [32, 178, 170, 1],
|
||||||
|
"li\\ghtseagreen", [32, 178, 170, 1],
|
||||||
|
"li\\67 htseagreen", [32, 178, 170, 1],
|
||||||
|
"lihtseagreen", null,
|
||||||
|
"lightskyblue", [135, 206, 250, 1],
|
||||||
|
"lightskyblUe", [135, 206, 250, 1],
|
||||||
|
"lightskybl\\ue", [135, 206, 250, 1],
|
||||||
|
"lightskybl\\75 e", [135, 206, 250, 1],
|
||||||
|
"lightskyble", null,
|
||||||
|
"lightsKyblue", null,
|
||||||
|
"lightslategray", [119, 136, 153, 1],
|
||||||
|
"lightslategRay", [119, 136, 153, 1],
|
||||||
|
"lightslateg\\ray", [119, 136, 153, 1],
|
||||||
|
"lightslateg\\72 ay", [119, 136, 153, 1],
|
||||||
|
"lightslategay", null,
|
||||||
|
"lightslategrey", [119, 136, 153, 1],
|
||||||
|
"lightslategrEy", [119, 136, 153, 1],
|
||||||
|
"lightslategr\\65 y", [119, 136, 153, 1],
|
||||||
|
"lightslategry", null,
|
||||||
|
"lightsteelblue", [176, 196, 222, 1],
|
||||||
|
"lightsteelbluE", [176, 196, 222, 1],
|
||||||
|
"lightsteelblu\\65 ", [176, 196, 222, 1],
|
||||||
|
"lightsteelblu", null,
|
||||||
|
"lightyellow", [255, 255, 224, 1],
|
||||||
|
"lightyelloW", [255, 255, 224, 1],
|
||||||
|
"lightyello\\w", [255, 255, 224, 1],
|
||||||
|
"lightyello\\77 ", [255, 255, 224, 1],
|
||||||
|
"lightyello", null,
|
||||||
|
"lime", [0, 255, 0, 1],
|
||||||
|
"limE", [0, 255, 0, 1],
|
||||||
|
"lim\\65 ", [0, 255, 0, 1],
|
||||||
|
"lim", null,
|
||||||
|
"limegreen", [50, 205, 50, 1],
|
||||||
|
"lImegreen", [50, 205, 50, 1],
|
||||||
|
"l\\imegreen", [50, 205, 50, 1],
|
||||||
|
"l\\69 megreen", [50, 205, 50, 1],
|
||||||
|
"lmegreen", null,
|
||||||
|
"linen", [250, 240, 230, 1],
|
||||||
|
"lInen", [250, 240, 230, 1],
|
||||||
|
"l\\inen", [250, 240, 230, 1],
|
||||||
|
"l\\69 nen", [250, 240, 230, 1],
|
||||||
|
"lnen", null,
|
||||||
|
"magenta", [255, 0, 255, 1],
|
||||||
|
"mageNta", [255, 0, 255, 1],
|
||||||
|
"mage\\nta", [255, 0, 255, 1],
|
||||||
|
"mage\\6E ta", [255, 0, 255, 1],
|
||||||
|
"mageta", null,
|
||||||
|
"maroon", [128, 0, 0, 1],
|
||||||
|
"mAroon", [128, 0, 0, 1],
|
||||||
|
"m\\61 roon", [128, 0, 0, 1],
|
||||||
|
"mroon", null,
|
||||||
|
"mediumaquamarine", [102, 205, 170, 1],
|
||||||
|
"mediumaqUamarine", [102, 205, 170, 1],
|
||||||
|
"mediumaq\\uamarine", [102, 205, 170, 1],
|
||||||
|
"mediumaq\\75 amarine", [102, 205, 170, 1],
|
||||||
|
"mediumaqamarine", null,
|
||||||
|
"mediumblue", [0, 0, 205, 1],
|
||||||
|
"mediuMblue", [0, 0, 205, 1],
|
||||||
|
"mediu\\mblue", [0, 0, 205, 1],
|
||||||
|
"mediu\\6D blue", [0, 0, 205, 1],
|
||||||
|
"mediublue", null,
|
||||||
|
"mediumorchid", [186, 85, 211, 1],
|
||||||
|
"mediumorchId", [186, 85, 211, 1],
|
||||||
|
"mediumorch\\id", [186, 85, 211, 1],
|
||||||
|
"mediumorch\\69 d", [186, 85, 211, 1],
|
||||||
|
"mediumorchd", null,
|
||||||
|
"mediumpurple", [147, 112, 219, 1],
|
||||||
|
"mediumpurplE", [147, 112, 219, 1],
|
||||||
|
"mediumpurpl\\65 ", [147, 112, 219, 1],
|
||||||
|
"mediumpurpl", null,
|
||||||
|
"mediumseagreen", [60, 179, 113, 1],
|
||||||
|
"mediumseagReen", [60, 179, 113, 1],
|
||||||
|
"mediumseag\\reen", [60, 179, 113, 1],
|
||||||
|
"mediumseag\\72 een", [60, 179, 113, 1],
|
||||||
|
"mediumseageen", null,
|
||||||
|
"mediumslateblue", [123, 104, 238, 1],
|
||||||
|
"mediUmslateblue", [123, 104, 238, 1],
|
||||||
|
"medi\\umslateblue", [123, 104, 238, 1],
|
||||||
|
"medi\\75 mslateblue", [123, 104, 238, 1],
|
||||||
|
"medimslateblue", null,
|
||||||
|
"mediumspringgreen", [0, 250, 154, 1],
|
||||||
|
"mediumspRinggreen", [0, 250, 154, 1],
|
||||||
|
"mediumsp\\ringgreen", [0, 250, 154, 1],
|
||||||
|
"mediumsp\\72 inggreen", [0, 250, 154, 1],
|
||||||
|
"mediumspinggreen", null,
|
||||||
|
"mediumturquoise", [72, 209, 204, 1],
|
||||||
|
"mediumTurquoise", [72, 209, 204, 1],
|
||||||
|
"medium\\turquoise", [72, 209, 204, 1],
|
||||||
|
"medium\\74 urquoise", [72, 209, 204, 1],
|
||||||
|
"mediumurquoise", null,
|
||||||
|
"mediumvioletred", [199, 21, 133, 1],
|
||||||
|
"mediumvIoletred", [199, 21, 133, 1],
|
||||||
|
"mediumv\\ioletred", [199, 21, 133, 1],
|
||||||
|
"mediumv\\69 oletred", [199, 21, 133, 1],
|
||||||
|
"mediumvoletred", null,
|
||||||
|
"midnightblue", [25, 25, 112, 1],
|
||||||
|
"midniGhtblue", [25, 25, 112, 1],
|
||||||
|
"midni\\ghtblue", [25, 25, 112, 1],
|
||||||
|
"midni\\67 htblue", [25, 25, 112, 1],
|
||||||
|
"midnihtblue", null,
|
||||||
|
"mintcream", [245, 255, 250, 1],
|
||||||
|
"mintcrEam", [245, 255, 250, 1],
|
||||||
|
"mintcr\\65 am", [245, 255, 250, 1],
|
||||||
|
"mintcram", null,
|
||||||
|
"mistyrose", [255, 228, 225, 1],
|
||||||
|
"mistyroSe", [255, 228, 225, 1],
|
||||||
|
"mistyro\\se", [255, 228, 225, 1],
|
||||||
|
"mistyro\\73 e", [255, 228, 225, 1],
|
||||||
|
"mistyroe", null,
|
||||||
|
"moccasin", [255, 228, 181, 1],
|
||||||
|
"moccAsin", [255, 228, 181, 1],
|
||||||
|
"mocc\\61 sin", [255, 228, 181, 1],
|
||||||
|
"moccsin", null,
|
||||||
|
"navajowhite", [255, 222, 173, 1],
|
||||||
|
"navajowHite", [255, 222, 173, 1],
|
||||||
|
"navajow\\hite", [255, 222, 173, 1],
|
||||||
|
"navajow\\68 ite", [255, 222, 173, 1],
|
||||||
|
"navajowite", null,
|
||||||
|
"navy", [0, 0, 128, 1],
|
||||||
|
"naVy", [0, 0, 128, 1],
|
||||||
|
"na\\vy", [0, 0, 128, 1],
|
||||||
|
"na\\76 y", [0, 0, 128, 1],
|
||||||
|
"nay", null,
|
||||||
|
"oldlace", [253, 245, 230, 1],
|
||||||
|
"Oldlace", [253, 245, 230, 1],
|
||||||
|
"\\oldlace", [253, 245, 230, 1],
|
||||||
|
"\\6F ldlace", [253, 245, 230, 1],
|
||||||
|
"ldlace", null,
|
||||||
|
"olive", [128, 128, 0, 1],
|
||||||
|
"Olive", [128, 128, 0, 1],
|
||||||
|
"\\olive", [128, 128, 0, 1],
|
||||||
|
"\\6F live", [128, 128, 0, 1],
|
||||||
|
"live", null,
|
||||||
|
"olivedrab", [107, 142, 35, 1],
|
||||||
|
"olivEdrab", [107, 142, 35, 1],
|
||||||
|
"oliv\\65 drab", [107, 142, 35, 1],
|
||||||
|
"olivdrab", null,
|
||||||
|
"orange", [255, 165, 0, 1],
|
||||||
|
"orAnge", [255, 165, 0, 1],
|
||||||
|
"or\\61 nge", [255, 165, 0, 1],
|
||||||
|
"ornge", null,
|
||||||
|
"orangered", [255, 69, 0, 1],
|
||||||
|
"orangeRed", [255, 69, 0, 1],
|
||||||
|
"orange\\red", [255, 69, 0, 1],
|
||||||
|
"orange\\72 ed", [255, 69, 0, 1],
|
||||||
|
"orangeed", null,
|
||||||
|
"orchid", [218, 112, 214, 1],
|
||||||
|
"orchId", [218, 112, 214, 1],
|
||||||
|
"orch\\id", [218, 112, 214, 1],
|
||||||
|
"orch\\69 d", [218, 112, 214, 1],
|
||||||
|
"orchd", null,
|
||||||
|
"palegoldenrod", [238, 232, 170, 1],
|
||||||
|
"palegoldEnrod", [238, 232, 170, 1],
|
||||||
|
"palegold\\65 nrod", [238, 232, 170, 1],
|
||||||
|
"palegoldnrod", null,
|
||||||
|
"palegreen", [152, 251, 152, 1],
|
||||||
|
"Palegreen", [152, 251, 152, 1],
|
||||||
|
"\\palegreen", [152, 251, 152, 1],
|
||||||
|
"\\70 alegreen", [152, 251, 152, 1],
|
||||||
|
"alegreen", null,
|
||||||
|
"paleturquoise", [175, 238, 238, 1],
|
||||||
|
"paleturquoIse", [175, 238, 238, 1],
|
||||||
|
"paleturquo\\ise", [175, 238, 238, 1],
|
||||||
|
"paleturquo\\69 se", [175, 238, 238, 1],
|
||||||
|
"paleturquose", null,
|
||||||
|
"palevioletred", [219, 112, 147, 1],
|
||||||
|
"palevioletrEd", [219, 112, 147, 1],
|
||||||
|
"palevioletr\\65 d", [219, 112, 147, 1],
|
||||||
|
"palevioletrd", null,
|
||||||
|
"papayawhip", [255, 239, 213, 1],
|
||||||
|
"papayawhiP", [255, 239, 213, 1],
|
||||||
|
"papayawhi\\p", [255, 239, 213, 1],
|
||||||
|
"papayawhi\\70 ", [255, 239, 213, 1],
|
||||||
|
"papayawhi", null,
|
||||||
|
"peachpuff", [255, 218, 185, 1],
|
||||||
|
"peacHpuff", [255, 218, 185, 1],
|
||||||
|
"peac\\hpuff", [255, 218, 185, 1],
|
||||||
|
"peac\\68 puff", [255, 218, 185, 1],
|
||||||
|
"peacpuff", null,
|
||||||
|
"peru", [205, 133, 63, 1],
|
||||||
|
"perU", [205, 133, 63, 1],
|
||||||
|
"per\\u", [205, 133, 63, 1],
|
||||||
|
"per\\75 ", [205, 133, 63, 1],
|
||||||
|
"per", null,
|
||||||
|
"pink", [255, 192, 203, 1],
|
||||||
|
"Pink", [255, 192, 203, 1],
|
||||||
|
"\\pink", [255, 192, 203, 1],
|
||||||
|
"\\70 ink", [255, 192, 203, 1],
|
||||||
|
"ink", null,
|
||||||
|
"pinK", null,
|
||||||
|
"plum", [221, 160, 221, 1],
|
||||||
|
"pLum", [221, 160, 221, 1],
|
||||||
|
"p\\lum", [221, 160, 221, 1],
|
||||||
|
"p\\6C um", [221, 160, 221, 1],
|
||||||
|
"pum", null,
|
||||||
|
"powderblue", [176, 224, 230, 1],
|
||||||
|
"powdErblue", [176, 224, 230, 1],
|
||||||
|
"powd\\65 rblue", [176, 224, 230, 1],
|
||||||
|
"powdrblue", null,
|
||||||
|
"purple", [128, 0, 128, 1],
|
||||||
|
"purPle", [128, 0, 128, 1],
|
||||||
|
"pur\\ple", [128, 0, 128, 1],
|
||||||
|
"pur\\70 le", [128, 0, 128, 1],
|
||||||
|
"purle", null,
|
||||||
|
"red", [255, 0, 0, 1],
|
||||||
|
"rEd", [255, 0, 0, 1],
|
||||||
|
"r\\65 d", [255, 0, 0, 1],
|
||||||
|
"rd", null,
|
||||||
|
"rosybrown", [188, 143, 143, 1],
|
||||||
|
"roSybrown", [188, 143, 143, 1],
|
||||||
|
"ro\\sybrown", [188, 143, 143, 1],
|
||||||
|
"ro\\73 ybrown", [188, 143, 143, 1],
|
||||||
|
"roybrown", null,
|
||||||
|
"royalblue", [65, 105, 225, 1],
|
||||||
|
"royAlblue", [65, 105, 225, 1],
|
||||||
|
"roy\\61 lblue", [65, 105, 225, 1],
|
||||||
|
"roylblue", null,
|
||||||
|
"saddlebrown", [139, 69, 19, 1],
|
||||||
|
"saddlebRown", [139, 69, 19, 1],
|
||||||
|
"saddleb\\rown", [139, 69, 19, 1],
|
||||||
|
"saddleb\\72 own", [139, 69, 19, 1],
|
||||||
|
"saddlebown", null,
|
||||||
|
"salmon", [250, 128, 114, 1],
|
||||||
|
"saLmon", [250, 128, 114, 1],
|
||||||
|
"sa\\lmon", [250, 128, 114, 1],
|
||||||
|
"sa\\6C mon", [250, 128, 114, 1],
|
||||||
|
"samon", null,
|
||||||
|
"sandybrown", [244, 164, 96, 1],
|
||||||
|
"sAndybrown", [244, 164, 96, 1],
|
||||||
|
"s\\61 ndybrown", [244, 164, 96, 1],
|
||||||
|
"sndybrown", null,
|
||||||
|
"seagreen", [46, 139, 87, 1],
|
||||||
|
"seagreEn", [46, 139, 87, 1],
|
||||||
|
"seagre\\65 n", [46, 139, 87, 1],
|
||||||
|
"seagren", null,
|
||||||
|
"seashell", [255, 245, 238, 1],
|
||||||
|
"seashelL", [255, 245, 238, 1],
|
||||||
|
"seashel\\l", [255, 245, 238, 1],
|
||||||
|
"seashel\\6C ", [255, 245, 238, 1],
|
||||||
|
"seashel", null,
|
||||||
|
"sienna", [160, 82, 45, 1],
|
||||||
|
"Sienna", [160, 82, 45, 1],
|
||||||
|
"\\sienna", [160, 82, 45, 1],
|
||||||
|
"\\73 ienna", [160, 82, 45, 1],
|
||||||
|
"ienna", null,
|
||||||
|
"silver", [192, 192, 192, 1],
|
||||||
|
"sIlver", [192, 192, 192, 1],
|
||||||
|
"s\\ilver", [192, 192, 192, 1],
|
||||||
|
"s\\69 lver", [192, 192, 192, 1],
|
||||||
|
"slver", null,
|
||||||
|
"skyblue", [135, 206, 235, 1],
|
||||||
|
"skybluE", [135, 206, 235, 1],
|
||||||
|
"skyblu\\65 ", [135, 206, 235, 1],
|
||||||
|
"skyblu", null,
|
||||||
|
"sKyblue", null,
|
||||||
|
"slateblue", [106, 90, 205, 1],
|
||||||
|
"slaTeblue", [106, 90, 205, 1],
|
||||||
|
"sla\\teblue", [106, 90, 205, 1],
|
||||||
|
"sla\\74 eblue", [106, 90, 205, 1],
|
||||||
|
"slaeblue", null,
|
||||||
|
"slategray", [112, 128, 144, 1],
|
||||||
|
"slatEgray", [112, 128, 144, 1],
|
||||||
|
"slat\\65 gray", [112, 128, 144, 1],
|
||||||
|
"slatgray", null,
|
||||||
|
"slategrey", [112, 128, 144, 1],
|
||||||
|
"slateGrey", [112, 128, 144, 1],
|
||||||
|
"slate\\grey", [112, 128, 144, 1],
|
||||||
|
"slate\\67 rey", [112, 128, 144, 1],
|
||||||
|
"slaterey", null,
|
||||||
|
"snow", [255, 250, 250, 1],
|
||||||
|
"snOw", [255, 250, 250, 1],
|
||||||
|
"sn\\ow", [255, 250, 250, 1],
|
||||||
|
"sn\\6F w", [255, 250, 250, 1],
|
||||||
|
"snw", null,
|
||||||
|
"springgreen", [0, 255, 127, 1],
|
||||||
|
"springgrEen", [0, 255, 127, 1],
|
||||||
|
"springgr\\65 en", [0, 255, 127, 1],
|
||||||
|
"springgren", null,
|
||||||
|
"steelblue", [70, 130, 180, 1],
|
||||||
|
"steelbluE", [70, 130, 180, 1],
|
||||||
|
"steelblu\\65 ", [70, 130, 180, 1],
|
||||||
|
"steelblu", null,
|
||||||
|
"tan", [210, 180, 140, 1],
|
||||||
|
"Tan", [210, 180, 140, 1],
|
||||||
|
"\\tan", [210, 180, 140, 1],
|
||||||
|
"\\74 an", [210, 180, 140, 1],
|
||||||
|
"an", null,
|
||||||
|
"teal", [0, 128, 128, 1],
|
||||||
|
"teAl", [0, 128, 128, 1],
|
||||||
|
"te\\61 l", [0, 128, 128, 1],
|
||||||
|
"tel", null,
|
||||||
|
"thistle", [216, 191, 216, 1],
|
||||||
|
"tHistle", [216, 191, 216, 1],
|
||||||
|
"t\\histle", [216, 191, 216, 1],
|
||||||
|
"t\\68 istle", [216, 191, 216, 1],
|
||||||
|
"tistle", null,
|
||||||
|
"tomato", [255, 99, 71, 1],
|
||||||
|
"Tomato", [255, 99, 71, 1],
|
||||||
|
"\\tomato", [255, 99, 71, 1],
|
||||||
|
"\\74 omato", [255, 99, 71, 1],
|
||||||
|
"omato", null,
|
||||||
|
"turquoise", [64, 224, 208, 1],
|
||||||
|
"turqUoise", [64, 224, 208, 1],
|
||||||
|
"turq\\uoise", [64, 224, 208, 1],
|
||||||
|
"turq\\75 oise", [64, 224, 208, 1],
|
||||||
|
"turqoise", null,
|
||||||
|
"violet", [238, 130, 238, 1],
|
||||||
|
"viOlet", [238, 130, 238, 1],
|
||||||
|
"vi\\olet", [238, 130, 238, 1],
|
||||||
|
"vi\\6F let", [238, 130, 238, 1],
|
||||||
|
"vilet", null,
|
||||||
|
"wheat", [245, 222, 179, 1],
|
||||||
|
"wheaT", [245, 222, 179, 1],
|
||||||
|
"whea\\t", [245, 222, 179, 1],
|
||||||
|
"whea\\74 ", [245, 222, 179, 1],
|
||||||
|
"whea", null,
|
||||||
|
"white", [255, 255, 255, 1],
|
||||||
|
"White", [255, 255, 255, 1],
|
||||||
|
"\\white", [255, 255, 255, 1],
|
||||||
|
"\\77 hite", [255, 255, 255, 1],
|
||||||
|
"hite", null,
|
||||||
|
"whitesmoke", [245, 245, 245, 1],
|
||||||
|
"wHitesmoke", [245, 245, 245, 1],
|
||||||
|
"w\\hitesmoke", [245, 245, 245, 1],
|
||||||
|
"w\\68 itesmoke", [245, 245, 245, 1],
|
||||||
|
"witesmoke", null,
|
||||||
|
"whitesmoKe", null,
|
||||||
|
"yellow", [255, 255, 0, 1],
|
||||||
|
"Yellow", [255, 255, 0, 1],
|
||||||
|
"\\yellow", [255, 255, 0, 1],
|
||||||
|
"\\79 ellow", [255, 255, 0, 1],
|
||||||
|
"ellow", null,
|
||||||
|
"yellowgreen", [154, 205, 50, 1],
|
||||||
|
"yellowgreEn", [154, 205, 50, 1],
|
||||||
|
"yellowgre\\65 n", [154, 205, 50, 1],
|
||||||
|
"yellowgren", null
|
||||||
|
]
|
|
@ -0,0 +1,426 @@
|
||||||
|
[
|
||||||
|
|
||||||
|
"", [],
|
||||||
|
|
||||||
|
"/*/*///** /* **/*//* ", [
|
||||||
|
"/", "*", "/"
|
||||||
|
],
|
||||||
|
|
||||||
|
"red", [
|
||||||
|
["ident", "red"]
|
||||||
|
],
|
||||||
|
|
||||||
|
" \t\t\r\n\nRed ", [
|
||||||
|
" ", ["ident", "Red"], " "
|
||||||
|
],
|
||||||
|
|
||||||
|
"red/* CDC */-->", [
|
||||||
|
["ident", "red"], "-->"
|
||||||
|
],
|
||||||
|
|
||||||
|
"red-->/* Not CDC */", [
|
||||||
|
["ident", "red--"], ">"
|
||||||
|
],
|
||||||
|
|
||||||
|
"\\- red0 -red --red -\\-red\\ blue 0red -0red \u0000red _Red .red rêd r\\êd \u007F\u0080\u0081", [
|
||||||
|
["ident", "-"], " ",
|
||||||
|
["ident", "red0"], " ",
|
||||||
|
["ident", "-red"], " ",
|
||||||
|
"-", ["ident", "-red"], " ",
|
||||||
|
["ident", "--red blue"], " ",
|
||||||
|
["dimension", "0", 0, "integer", "red"], " ",
|
||||||
|
["dimension", "-0", 0, "integer", "red"], " ",
|
||||||
|
["ident", "\uFFFDred"], " ",
|
||||||
|
["ident", "_Red"], " ",
|
||||||
|
".", ["ident", "red"], " ",
|
||||||
|
["ident", "rêd"], " ",
|
||||||
|
["ident", "rêd"], " ",
|
||||||
|
"\u007F", ["ident", "\u0080\u0081"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"\\30red \\00030 red \\30\r\nred \\0000000red \\1100000red \\red \\r ed \\.red \\ red \\\nred \\376\\37 6\\000376\\0000376\\", [
|
||||||
|
["ident", "0red"], " ",
|
||||||
|
["ident", "0red"], " ",
|
||||||
|
["ident", "0red"], " ",
|
||||||
|
["ident", "\uFFFD0red"], " ",
|
||||||
|
["ident", "\uFFFD0red"], " ",
|
||||||
|
["ident", "red"], " ",
|
||||||
|
["ident", "r"], " ", ["ident", "ed"], " ",
|
||||||
|
["ident", ".red"], " ",
|
||||||
|
["ident", " red"], " ",
|
||||||
|
"\\", " ", ["ident", "red"], " ",
|
||||||
|
["ident", "Ͷ76Ͷ76\uFFFD"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"rgba0() -rgba() --rgba() -\\-rgba() 0rgba() -0rgba() _rgba() .rgba() rgbâ() \\30rgba() rgba () @rgba() #rgba()", [
|
||||||
|
["function", "rgba0"], " ",
|
||||||
|
["function", "-rgba"], " ",
|
||||||
|
"-", ["function", "-rgba"], " ",
|
||||||
|
["function", "--rgba"], " ",
|
||||||
|
["dimension", "0", 0, "integer", "rgba"], ["()"], " ",
|
||||||
|
["dimension", "-0", 0, "integer", "rgba"], ["()"], " ",
|
||||||
|
["function", "_rgba"], " ",
|
||||||
|
".", ["function", "rgba"], " ",
|
||||||
|
["function", "rgbâ"], " ",
|
||||||
|
["function", "0rgba"], " ",
|
||||||
|
["ident", "rgba"], " ", ["()"], " ",
|
||||||
|
["at-keyword", "rgba"], ["()"], " ",
|
||||||
|
["hash", "rgba", "id"], ["()"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"@media0 @-Media @--media @-\\-media @0media @-0media @_media @.media @medİa @\\30 media\\", [
|
||||||
|
["at-keyword", "media0"], " ",
|
||||||
|
["at-keyword", "-Media"], " ",
|
||||||
|
"@", "-", ["ident", "-media"], " ",
|
||||||
|
["at-keyword", "--media"], " ",
|
||||||
|
"@", ["dimension", "0", 0, "integer", "media"], " ",
|
||||||
|
"@", ["dimension", "-0", 0, "integer", "media"], " ",
|
||||||
|
["at-keyword", "_media"], " ",
|
||||||
|
"@", ".", ["ident", "media"], " ",
|
||||||
|
["at-keyword", "medİa"], " ",
|
||||||
|
["at-keyword", "0media\uFFFD"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"#red0 #-Red #--red #-\\-red #0red #-0red #_Red #.red #rêd #êrd #\\.red\\", [
|
||||||
|
["hash", "red0", "id"], " ",
|
||||||
|
["hash", "-Red", "id"], " ",
|
||||||
|
["hash", "--red", "unrestricted"], " ",
|
||||||
|
["hash", "--red", "id"], " ",
|
||||||
|
["hash", "0red", "unrestricted"], " ",
|
||||||
|
["hash", "-0red", "unrestricted"], " ",
|
||||||
|
["hash", "_Red", "id"], " ",
|
||||||
|
"#", ".", ["ident", "red"], " ",
|
||||||
|
["hash", "rêd", "id"], " ",
|
||||||
|
["hash", "êrd", "id"], " ",
|
||||||
|
["hash", ".red\uFFFD", "id"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"p[example=\"\\\nfoo(int x) {\\\n this.x = x;\\\n}\\\n\"]", [
|
||||||
|
["ident", "p"], ["[]",
|
||||||
|
["ident", "example"], "=", ["string", "foo(int x) { this.x = x;}"]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
|
||||||
|
"'' 'Lorem \"îpsum\"' 'a\\\nb' 'a\nb 'eof", [
|
||||||
|
["string", ""], " ",
|
||||||
|
["string", "Lorem \"îpsum\""], " ",
|
||||||
|
["string", "ab"], " ",
|
||||||
|
["error", "bad-string"], " ", ["ident", "b"], " ",
|
||||||
|
["string", "eof"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"\"\" \"Lorem 'îpsum'\" \"a\\\nb\" \"a\nb \"eof", [
|
||||||
|
["string", ""], " ",
|
||||||
|
["string", "Lorem 'îpsum'"], " ",
|
||||||
|
["string", "ab"], " ",
|
||||||
|
["error", "bad-string"], " ", ["ident", "b"], " ",
|
||||||
|
["string", "eof"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"\"Lo\\rem \\130 ps\\u m\" '\\376\\37 6\\000376\\0000376\\", [
|
||||||
|
["string", "Lorem İpsu m"], " ",
|
||||||
|
["string", "Ͷ76Ͷ76"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"url( '') url('Lorem \"îpsum\"'\n) url('a\\\nb' ) url('a\nb' \\){ ) url('eof", [
|
||||||
|
["url", ""], " ",
|
||||||
|
["url", "Lorem \"îpsum\""], " ",
|
||||||
|
["url", "ab"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["url", "eof"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"url(", [
|
||||||
|
["url", ""]
|
||||||
|
],
|
||||||
|
|
||||||
|
"url( \t", [
|
||||||
|
["url", ""]
|
||||||
|
],
|
||||||
|
|
||||||
|
"url(\"\") url(\"Lorem 'îpsum'\"\n) url(\"a\\\nb\" ) url(\"a\nb\" \\){ ) url(\"eof", [
|
||||||
|
["url", ""], " ",
|
||||||
|
["url", "Lorem 'îpsum'"], " ",
|
||||||
|
["url", "ab"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["url", "eof"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"url(\"Lo\\rem \\130 ps\\u m\") url('\\376\\37 6\\000376\\0000376\\", [
|
||||||
|
["url", "Lorem İpsu m"], " ",
|
||||||
|
["url", "Ͷ76Ͷ76"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"URL(foo) Url(foo) ûrl(foo) url (foo) url\\ (foo) url(\t 'foo' ", [
|
||||||
|
["url", "foo"], " ",
|
||||||
|
["url", "foo"], " ",
|
||||||
|
["function", "ûrl", ["ident", "foo"]], " ",
|
||||||
|
["ident", "url"], " ", ["()", ["ident", "foo"]], " ",
|
||||||
|
["function", "url ", ["ident", "foo"]], " ",
|
||||||
|
["url", "foo"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"url('a' b) url('c' d)", [["error", "bad-url"], " ", ["error", "bad-url"]],
|
||||||
|
|
||||||
|
"url('a\nb') url('c\n", [["error", "bad-url"], " ", ["error", "bad-url"]],
|
||||||
|
|
||||||
|
"url() url( \t) url(\n Foô\\030\n!\n) url(\na\nb\n) url(a\\ b) url(a(b) url(a\\(b) url(a'b) url(a\\'b) url(a\"b) url(a\\\"b) url(a\nb) url(a\\\nb) url(a\\a b) url(a\\", [
|
||||||
|
["url", ""], " ",
|
||||||
|
["url", ""], " ",
|
||||||
|
["url", "Foô0!"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["url", "a b"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["url", "a(b"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["url", "a'b"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["url", "a\"b"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["url", "a\nb"], " ",
|
||||||
|
["url", "a\uFFFD"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"url(\u0000!#$%&*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0080\u0081\u009e\u009f\u00a0\u00a1\u00a2", [
|
||||||
|
["url", "\uFFFD!#$%&*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0080\u0081\u009e\u009f\u00a0¡¢"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"url(\u0001) url(\u0002) url(\u0003) url(\u0004) url(\u0005) url(\u0006) url(\u0007) url(\u0008) url(\u000b) url(\u000e) url(\u000f) url(\u0010) url(\u0011) url(\u0012) url(\u0013) url(\u0014) url(\u0015) url(\u0016) url(\u0017) url(\u0018) url(\u0019) url(\u001a) url(\u001b) url(\u001c) url(\u001d) url(\u001e) url(\u001f) url(\u007f)", [
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"], " ",
|
||||||
|
["error", "bad-url"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"12 +34 -45 .67 +.89 -.01 2.3 +45.0 -0.67", [
|
||||||
|
["number", "12", 12, "integer"], " ",
|
||||||
|
["number", "+34", 34, "integer"], " ",
|
||||||
|
["number", "-45", -45, "integer"], " ",
|
||||||
|
["number", ".67", 0.67, "number"], " ",
|
||||||
|
["number", "+.89", 0.89, "number"], " ",
|
||||||
|
["number", "-.01", -0.01, "number"], " ",
|
||||||
|
["number", "2.3", 2.3, "number"], " ",
|
||||||
|
["number", "+45.0", 45, "number"], " ",
|
||||||
|
["number", "-0.67", -0.67, "number"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"12e2 +34e+1 -45E-0 .68e+3 +.79e-1 -.01E2 2.3E+1 +45.0e6 -0.67e0", [
|
||||||
|
["number", "12e2", 1200, "number"], " ",
|
||||||
|
["number", "+34e+1", 340, "number"], " ",
|
||||||
|
["number", "-45E-0", -45, "number"], " ",
|
||||||
|
["number", ".68e+3", 680, "number"], " ",
|
||||||
|
["number", "+.79e-1", 0.079, "number"], " ",
|
||||||
|
["number", "-.01E2", -1, "number"], " ",
|
||||||
|
["number", "2.3E+1", 23, "number"], " ",
|
||||||
|
["number", "+45.0e6", 45000000, "number"], " ",
|
||||||
|
["number", "-0.67e0", -0.67, "number"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"3. /* Decimal point must have following digits */", [
|
||||||
|
["number", "3", 3, "integer"], ".", " "
|
||||||
|
],
|
||||||
|
|
||||||
|
"3\\65-2 /* Scientific notation E can not be escaped */", [
|
||||||
|
["dimension", "3", 3, "integer", "e-2"], " "
|
||||||
|
],
|
||||||
|
|
||||||
|
"3e-2.1 /* Integer exponents only */", [
|
||||||
|
["number", "3e-2", 0.03, "number"],
|
||||||
|
["number", ".1", 0.1, "number"], " "
|
||||||
|
],
|
||||||
|
|
||||||
|
"12% +34% -45% .67% +.89% -.01% 2.3% +45.0% -0.67%", [
|
||||||
|
["percentage", "12", 12, "integer"], " ",
|
||||||
|
["percentage", "+34", 34, "integer"], " ",
|
||||||
|
["percentage", "-45", -45, "integer"], " ",
|
||||||
|
["percentage", ".67", 0.67, "number"], " ",
|
||||||
|
["percentage", "+.89", 0.89, "number"], " ",
|
||||||
|
["percentage", "-.01", -0.01, "number"], " ",
|
||||||
|
["percentage", "2.3", 2.3, "number"], " ",
|
||||||
|
["percentage", "+45.0", 45, "number"], " ",
|
||||||
|
["percentage", "-0.67", -0.67, "number"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"12e2% +34e+1% -45E-0% .68e+3% +.79e-1% -.01E2% 2.3E+1% +45.0e6% -0.67e0%", [
|
||||||
|
["percentage", "12e2", 1200, "number"], " ",
|
||||||
|
["percentage", "+34e+1", 340, "number"], " ",
|
||||||
|
["percentage", "-45E-0", -45, "number"], " ",
|
||||||
|
["percentage", ".68e+3", 680, "number"], " ",
|
||||||
|
["percentage", "+.79e-1", 0.079, "number"], " ",
|
||||||
|
["percentage", "-.01E2", -1, "number"], " ",
|
||||||
|
["percentage", "2.3E+1", 23, "number"], " ",
|
||||||
|
["percentage", "+45.0e6", 45000000, "number"], " ",
|
||||||
|
["percentage", "-0.67e0", -0.67, "number"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"12\\% /* Percent sign can not be escaped */", [
|
||||||
|
["dimension", "12", 12, "integer", "%"], " "
|
||||||
|
],
|
||||||
|
|
||||||
|
"12px +34px -45px .67px +.89px -.01px 2.3px +45.0px -0.67px", [
|
||||||
|
["dimension", "12", 12, "integer", "px"], " ",
|
||||||
|
["dimension", "+34", 34, "integer", "px"], " ",
|
||||||
|
["dimension", "-45", -45, "integer", "px"], " ",
|
||||||
|
["dimension", ".67", 0.67, "number", "px"], " ",
|
||||||
|
["dimension", "+.89", 0.89, "number", "px"], " ",
|
||||||
|
["dimension", "-.01", -0.01, "number", "px"], " ",
|
||||||
|
["dimension", "2.3", 2.3, "number", "px"], " ",
|
||||||
|
["dimension", "+45.0", 45, "number", "px"], " ",
|
||||||
|
["dimension", "-0.67", -0.67, "number", "px"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"12e2px +34e+1px -45E-0px .68e+3px +.79e-1px -.01E2px 2.3E+1px +45.0e6px -0.67e0px", [
|
||||||
|
["dimension", "12e2", 1200, "number", "px"], " ",
|
||||||
|
["dimension", "+34e+1", 340, "number", "px"], " ",
|
||||||
|
["dimension", "-45E-0", -45, "number", "px"], " ",
|
||||||
|
["dimension", ".68e+3", 680, "number", "px"], " ",
|
||||||
|
["dimension", "+.79e-1", 0.079, "number", "px"], " ",
|
||||||
|
["dimension", "-.01E2", -1, "number", "px"], " ",
|
||||||
|
["dimension", "2.3E+1", 23, "number", "px"], " ",
|
||||||
|
["dimension", "+45.0e6", 45000000, "number", "px"], " ",
|
||||||
|
["dimension", "-0.67e0", -0.67, "number", "px"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"12red0 12.0-red 12--red 12-\\-red 120red 12-0red 12\u0000red 12_Red 12.red 12rêd", [
|
||||||
|
["dimension", "12", 12.0, "integer", "red0"], " ",
|
||||||
|
["dimension", "12.0", 12.0, "number", "-red"], " ",
|
||||||
|
["number", "12", 12.0, "integer"], "-", ["ident", "-red"], " ",
|
||||||
|
["dimension", "12", 12.0, "integer", "--red"], " ",
|
||||||
|
["dimension", "120", 120.0, "integer", "red"], " ",
|
||||||
|
["number", "12", 12.0, "integer"], ["dimension", "-0", 0, "integer", "red"], " ",
|
||||||
|
["dimension", "12", 12.0, "integer", "\uFFFDred"], " ",
|
||||||
|
["dimension", "12", 12.0, "integer", "_Red"], " ",
|
||||||
|
["number", "12", 12.0, "integer"], ".", ["ident", "red"], " ",
|
||||||
|
["dimension", "12", 12.0, "integer", "rêd"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"u+1 U+10 U+100 U+1000 U+10000 U+100000 U+1000000", [
|
||||||
|
["unicode-range", 1, 1], " ",
|
||||||
|
["unicode-range", 16, 16], " ",
|
||||||
|
["unicode-range", 256, 256], " ",
|
||||||
|
["unicode-range", 4096, 4096], " ",
|
||||||
|
["unicode-range", 65536, 65536], " ",
|
||||||
|
["unicode-range", 1048576, 1048576], " ",
|
||||||
|
["unicode-range", 1048576, 1048576], ["number", "0", 0, "integer"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"u+? u+1? U+10? U+100? U+1000? U+10000? U+100000?", [
|
||||||
|
["unicode-range", 0, 15], " ",
|
||||||
|
["unicode-range", 16, 31], " ",
|
||||||
|
["unicode-range", 256, 271], " ",
|
||||||
|
["unicode-range", 4096, 4111], " ",
|
||||||
|
["unicode-range", 65536, 65551], " ",
|
||||||
|
["unicode-range", 1048576, 1048591], " ",
|
||||||
|
["unicode-range", 1048576, 1048576], "?"
|
||||||
|
],
|
||||||
|
|
||||||
|
"u+?? U+1?? U+10?? U+100?? U+1000?? U+10000??", [
|
||||||
|
["unicode-range", 0, 255], " ",
|
||||||
|
["unicode-range", 256, 511], " ",
|
||||||
|
["unicode-range", 4096, 4351], " ",
|
||||||
|
["unicode-range", 65536, 65791], " ",
|
||||||
|
["unicode-range", 1048576, 1048831], " ",
|
||||||
|
["unicode-range", 1048576, 1048591], "?"
|
||||||
|
],
|
||||||
|
|
||||||
|
"u+??? U+1??? U+10??? U+100??? U+1000???", [
|
||||||
|
["unicode-range", 0, 4095], " ",
|
||||||
|
["unicode-range", 4096, 8191], " ",
|
||||||
|
["unicode-range", 65536, 69631], " ",
|
||||||
|
["unicode-range", 1048576, 1052671], " ",
|
||||||
|
["unicode-range", 1048576, 1048831], "?"
|
||||||
|
],
|
||||||
|
|
||||||
|
"u+???? U+1???? U+10???? U+100????", [
|
||||||
|
["unicode-range", 0, 65535], " ",
|
||||||
|
["unicode-range", 65536, 131071], " ",
|
||||||
|
["unicode-range", 1048576, 1114111], " ",
|
||||||
|
["unicode-range", 1048576, 1052671], "?"
|
||||||
|
],
|
||||||
|
|
||||||
|
"u+????? U+1????? U+10?????", [
|
||||||
|
["unicode-range", 0, 1048575], " ",
|
||||||
|
["unicode-range", 1048576, 2097151], " ",
|
||||||
|
["unicode-range", 1048576, 1114111], "?"
|
||||||
|
],
|
||||||
|
|
||||||
|
"u+?????? U+1??????", [
|
||||||
|
["unicode-range", 0, 16777215], " ",
|
||||||
|
["unicode-range", 1048576, 2097151], "?"
|
||||||
|
],
|
||||||
|
|
||||||
|
"u+1-2 U+100000-2 U+1000000-2 U+10-200000", [
|
||||||
|
["unicode-range", 1, 2], " ",
|
||||||
|
["unicode-range", 1048576, 2], " ",
|
||||||
|
["unicode-range", 1048576, 1048576], ["number", "0", 0, "integer"],
|
||||||
|
["number", "-2", -2, "integer"], " ",
|
||||||
|
["unicode-range", 16, 2097152]
|
||||||
|
],
|
||||||
|
|
||||||
|
"ù+12 Ü+12 u +12 U+ 12 U+12 - 20 U+1?2 U+1?-50", [
|
||||||
|
["ident", "ù"], ["number", "+12", 12, "integer"], " ",
|
||||||
|
["ident", "Ü"], ["number", "+12", 12, "integer"], " ",
|
||||||
|
["ident", "u"], " ", ["number", "+12", 12, "integer"], " ",
|
||||||
|
["ident", "U"], "+", " ", ["number", "12", 12, "integer"], " ",
|
||||||
|
["unicode-range", 18, 18], " ", "-", " ", ["number", "20", 20, "integer"], " ",
|
||||||
|
["unicode-range", 16, 31], ["number", "2", 2, "integer"], " ",
|
||||||
|
["unicode-range", 16, 31], ["number", "-50", -50, "integer"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"~=|=^=$=*=||<!------> |/**/| ~/**/=", [
|
||||||
|
"~=", "|=", "^=", "$=", "*=", "||", "<!--", "-", "-", "-->",
|
||||||
|
" ", "|", "|", " ", "~", "="
|
||||||
|
],
|
||||||
|
|
||||||
|
"a:not([href^=http\\:], [href ^=\t'https\\:'\n]) { color: rgba(0%, 100%, 50%); }", [
|
||||||
|
["ident", "a"], ":", ["function", "not",
|
||||||
|
["[]",
|
||||||
|
["ident", "href"], "^=", ["ident", "http:"]
|
||||||
|
], ",", " ", ["[]",
|
||||||
|
["ident", "href"], " ", "^=", " ", ["string", "https:"], " "
|
||||||
|
]
|
||||||
|
], " ", ["{}",
|
||||||
|
" ", ["ident", "color"], ":", " ", ["function", "rgba",
|
||||||
|
["percentage", "0", 0, "integer"], ",", " ",
|
||||||
|
["percentage", "100", 100, "integer"], ",", " ",
|
||||||
|
["percentage", "50", 50, "integer"]
|
||||||
|
], ";", " "
|
||||||
|
]
|
||||||
|
],
|
||||||
|
|
||||||
|
"@media print { (foo]{bar) }baz", [
|
||||||
|
["at-keyword", "media"], " ", ["ident", "print"], " ", ["{}",
|
||||||
|
" ", ["()",
|
||||||
|
["ident", "foo"], ["error", "]"], ["{}",
|
||||||
|
["ident", "bar"], ["error", ")"], " "
|
||||||
|
], ["ident", "baz"]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
]
|
|
@ -0,0 +1,44 @@
|
||||||
|
[
|
||||||
|
|
||||||
|
"", [],
|
||||||
|
";; /**/ ; ;", [],
|
||||||
|
"a:b; c:d 42!important;\n", [
|
||||||
|
["declaration", "a", [["ident", "b"]], false],
|
||||||
|
["declaration", "c", [["ident", "d"], " ", ["number", "42", 42, "integer"]], true]
|
||||||
|
],
|
||||||
|
|
||||||
|
"z;a:b", [
|
||||||
|
["error", "invalid"],
|
||||||
|
["declaration", "a", [["ident", "b"]], false]
|
||||||
|
],
|
||||||
|
|
||||||
|
"z:x!;a:b", [
|
||||||
|
["declaration", "z", [["ident", "x"], "!"], false],
|
||||||
|
["declaration", "a", [["ident", "b"]], false]
|
||||||
|
],
|
||||||
|
|
||||||
|
"a:b; c+:d", [
|
||||||
|
["declaration", "a", [["ident", "b"]], false],
|
||||||
|
["error", "invalid"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"@import 'foo.css'; a:b; @import 'bar.css'", [
|
||||||
|
["at-rule", "import", [" ", ["string", "foo.css"]], null],
|
||||||
|
["declaration", "a", [["ident", "b"]], false],
|
||||||
|
["at-rule", "import", [" ", ["string", "bar.css"]], null]
|
||||||
|
],
|
||||||
|
|
||||||
|
"@media screen { div{;}} a:b;; @media print{div{", [
|
||||||
|
["at-rule", "media", [" ", ["ident", "screen"], " "], [" ", ["ident", "div"], ["{}", ";"]]],
|
||||||
|
["declaration", "a", [["ident", "b"]], false],
|
||||||
|
["at-rule", "media", [" ", ["ident", "print"]], [["ident", "div"], ["{}"]]]
|
||||||
|
],
|
||||||
|
|
||||||
|
"@ media screen { div{;}} a:b;; @media print{div{", [
|
||||||
|
["error", "invalid"],
|
||||||
|
["at-rule", "media", [" ", ["ident", "print"]], [["ident", "div"], ["{}"]]]
|
||||||
|
],
|
||||||
|
|
||||||
|
"", []
|
||||||
|
|
||||||
|
]
|
|
@ -0,0 +1,23 @@
|
||||||
|
import colorsys # It turns out Python already does HSL -> RGB!
|
||||||
|
|
||||||
|
|
||||||
|
def trim(s):
|
||||||
|
return s if not s.endswith('.0') else s[:-2]
|
||||||
|
|
||||||
|
|
||||||
|
print('[')
|
||||||
|
print(',\n'.join(
|
||||||
|
'"hsl%s(%s, %s%%, %s%%%s)", [%s, %s, %s, %s]' % (
|
||||||
|
('a' if a is not None else '', h,
|
||||||
|
trim(str(s / 10.)), trim(str(l / 10.)),
|
||||||
|
', %s' % a if a is not None else '') +
|
||||||
|
tuple(trim(str(round(v, 10)))
|
||||||
|
for v in colorsys.hls_to_rgb(h / 360., l / 1000., s / 1000.)) +
|
||||||
|
(a if a is not None else 1,)
|
||||||
|
)
|
||||||
|
for a in [None, 1, .2, 0]
|
||||||
|
for l in range(0, 1001, 125)
|
||||||
|
for s in range(0, 1001, 125)
|
||||||
|
for h in range(0, 360, 30)
|
||||||
|
))
|
||||||
|
print(']')
|
|
@ -0,0 +1,192 @@
|
||||||
|
all_keywords = [
|
||||||
|
('transparent', (0, 0, 0, 0)),
|
||||||
|
|
||||||
|
('black', (0, 0, 0, 1)),
|
||||||
|
('silver', (192, 192, 192, 1)),
|
||||||
|
('gray', (128, 128, 128, 1)),
|
||||||
|
('white', (255, 255, 255, 1)),
|
||||||
|
('maroon', (128, 0, 0, 1)),
|
||||||
|
('red', (255, 0, 0, 1)),
|
||||||
|
('purple', (128, 0, 128, 1)),
|
||||||
|
('fuchsia', (255, 0, 255, 1)),
|
||||||
|
('green', (0, 128, 0, 1)),
|
||||||
|
('lime', (0, 255, 0, 1)),
|
||||||
|
('olive', (128, 128, 0, 1)),
|
||||||
|
('yellow', (255, 255, 0, 1)),
|
||||||
|
('navy', (0, 0, 128, 1)),
|
||||||
|
('blue', (0, 0, 255, 1)),
|
||||||
|
('teal', (0, 128, 128, 1)),
|
||||||
|
('aqua', (0, 255, 255, 1)),
|
||||||
|
|
||||||
|
('aliceblue', (240, 248, 255, 1)),
|
||||||
|
('antiquewhite', (250, 235, 215, 1)),
|
||||||
|
('aqua', (0, 255, 255, 1)),
|
||||||
|
('aquamarine', (127, 255, 212, 1)),
|
||||||
|
('azure', (240, 255, 255, 1)),
|
||||||
|
('beige', (245, 245, 220, 1)),
|
||||||
|
('bisque', (255, 228, 196, 1)),
|
||||||
|
('black', (0, 0, 0, 1)),
|
||||||
|
('blanchedalmond', (255, 235, 205, 1)),
|
||||||
|
('blue', (0, 0, 255, 1)),
|
||||||
|
('blueviolet', (138, 43, 226, 1)),
|
||||||
|
('brown', (165, 42, 42, 1)),
|
||||||
|
('burlywood', (222, 184, 135, 1)),
|
||||||
|
('cadetblue', (95, 158, 160, 1)),
|
||||||
|
('chartreuse', (127, 255, 0, 1)),
|
||||||
|
('chocolate', (210, 105, 30, 1)),
|
||||||
|
('coral', (255, 127, 80, 1)),
|
||||||
|
('cornflowerblue', (100, 149, 237, 1)),
|
||||||
|
('cornsilk', (255, 248, 220, 1)),
|
||||||
|
('crimson', (220, 20, 60, 1)),
|
||||||
|
('cyan', (0, 255, 255, 1)),
|
||||||
|
('darkblue', (0, 0, 139, 1)),
|
||||||
|
('darkcyan', (0, 139, 139, 1)),
|
||||||
|
('darkgoldenrod', (184, 134, 11, 1)),
|
||||||
|
('darkgray', (169, 169, 169, 1)),
|
||||||
|
('darkgreen', (0, 100, 0, 1)),
|
||||||
|
('darkgrey', (169, 169, 169, 1)),
|
||||||
|
('darkkhaki', (189, 183, 107, 1)),
|
||||||
|
('darkmagenta', (139, 0, 139, 1)),
|
||||||
|
('darkolivegreen', (85, 107, 47, 1)),
|
||||||
|
('darkorange', (255, 140, 0, 1)),
|
||||||
|
('darkorchid', (153, 50, 204, 1)),
|
||||||
|
('darkred', (139, 0, 0, 1)),
|
||||||
|
('darksalmon', (233, 150, 122, 1)),
|
||||||
|
('darkseagreen', (143, 188, 143, 1)),
|
||||||
|
('darkslateblue', (72, 61, 139, 1)),
|
||||||
|
('darkslategray', (47, 79, 79, 1)),
|
||||||
|
('darkslategrey', (47, 79, 79, 1)),
|
||||||
|
('darkturquoise', (0, 206, 209, 1)),
|
||||||
|
('darkviolet', (148, 0, 211, 1)),
|
||||||
|
('deeppink', (255, 20, 147, 1)),
|
||||||
|
('deepskyblue', (0, 191, 255, 1)),
|
||||||
|
('dimgray', (105, 105, 105, 1)),
|
||||||
|
('dimgrey', (105, 105, 105, 1)),
|
||||||
|
('dodgerblue', (30, 144, 255, 1)),
|
||||||
|
('firebrick', (178, 34, 34, 1)),
|
||||||
|
('floralwhite', (255, 250, 240, 1)),
|
||||||
|
('forestgreen', (34, 139, 34, 1)),
|
||||||
|
('fuchsia', (255, 0, 255, 1)),
|
||||||
|
('gainsboro', (220, 220, 220, 1)),
|
||||||
|
('ghostwhite', (248, 248, 255, 1)),
|
||||||
|
('gold', (255, 215, 0, 1)),
|
||||||
|
('goldenrod', (218, 165, 32, 1)),
|
||||||
|
('gray', (128, 128, 128, 1)),
|
||||||
|
('green', (0, 128, 0, 1)),
|
||||||
|
('greenyellow', (173, 255, 47, 1)),
|
||||||
|
('grey', (128, 128, 128, 1)),
|
||||||
|
('honeydew', (240, 255, 240, 1)),
|
||||||
|
('hotpink', (255, 105, 180, 1)),
|
||||||
|
('indianred', (205, 92, 92, 1)),
|
||||||
|
('indigo', (75, 0, 130, 1)),
|
||||||
|
('ivory', (255, 255, 240, 1)),
|
||||||
|
('khaki', (240, 230, 140, 1)),
|
||||||
|
('lavender', (230, 230, 250, 1)),
|
||||||
|
('lavenderblush', (255, 240, 245, 1)),
|
||||||
|
('lawngreen', (124, 252, 0, 1)),
|
||||||
|
('lemonchiffon', (255, 250, 205, 1)),
|
||||||
|
('lightblue', (173, 216, 230, 1)),
|
||||||
|
('lightcoral', (240, 128, 128, 1)),
|
||||||
|
('lightcyan', (224, 255, 255, 1)),
|
||||||
|
('lightgoldenrodyellow', (250, 250, 210, 1)),
|
||||||
|
('lightgray', (211, 211, 211, 1)),
|
||||||
|
('lightgreen', (144, 238, 144, 1)),
|
||||||
|
('lightgrey', (211, 211, 211, 1)),
|
||||||
|
('lightpink', (255, 182, 193, 1)),
|
||||||
|
('lightsalmon', (255, 160, 122, 1)),
|
||||||
|
('lightseagreen', (32, 178, 170, 1)),
|
||||||
|
('lightskyblue', (135, 206, 250, 1)),
|
||||||
|
('lightslategray', (119, 136, 153, 1)),
|
||||||
|
('lightslategrey', (119, 136, 153, 1)),
|
||||||
|
('lightsteelblue', (176, 196, 222, 1)),
|
||||||
|
('lightyellow', (255, 255, 224, 1)),
|
||||||
|
('lime', (0, 255, 0, 1)),
|
||||||
|
('limegreen', (50, 205, 50, 1)),
|
||||||
|
('linen', (250, 240, 230, 1)),
|
||||||
|
('magenta', (255, 0, 255, 1)),
|
||||||
|
('maroon', (128, 0, 0, 1)),
|
||||||
|
('mediumaquamarine', (102, 205, 170, 1)),
|
||||||
|
('mediumblue', (0, 0, 205, 1)),
|
||||||
|
('mediumorchid', (186, 85, 211, 1)),
|
||||||
|
('mediumpurple', (147, 112, 219, 1)),
|
||||||
|
('mediumseagreen', (60, 179, 113, 1)),
|
||||||
|
('mediumslateblue', (123, 104, 238, 1)),
|
||||||
|
('mediumspringgreen', (0, 250, 154, 1)),
|
||||||
|
('mediumturquoise', (72, 209, 204, 1)),
|
||||||
|
('mediumvioletred', (199, 21, 133, 1)),
|
||||||
|
('midnightblue', (25, 25, 112, 1)),
|
||||||
|
('mintcream', (245, 255, 250, 1)),
|
||||||
|
('mistyrose', (255, 228, 225, 1)),
|
||||||
|
('moccasin', (255, 228, 181, 1)),
|
||||||
|
('navajowhite', (255, 222, 173, 1)),
|
||||||
|
('navy', (0, 0, 128, 1)),
|
||||||
|
('oldlace', (253, 245, 230, 1)),
|
||||||
|
('olive', (128, 128, 0, 1)),
|
||||||
|
('olivedrab', (107, 142, 35, 1)),
|
||||||
|
('orange', (255, 165, 0, 1)),
|
||||||
|
('orangered', (255, 69, 0, 1)),
|
||||||
|
('orchid', (218, 112, 214, 1)),
|
||||||
|
('palegoldenrod', (238, 232, 170, 1)),
|
||||||
|
('palegreen', (152, 251, 152, 1)),
|
||||||
|
('paleturquoise', (175, 238, 238, 1)),
|
||||||
|
('palevioletred', (219, 112, 147, 1)),
|
||||||
|
('papayawhip', (255, 239, 213, 1)),
|
||||||
|
('peachpuff', (255, 218, 185, 1)),
|
||||||
|
('peru', (205, 133, 63, 1)),
|
||||||
|
('pink', (255, 192, 203, 1)),
|
||||||
|
('plum', (221, 160, 221, 1)),
|
||||||
|
('powderblue', (176, 224, 230, 1)),
|
||||||
|
('purple', (128, 0, 128, 1)),
|
||||||
|
('red', (255, 0, 0, 1)),
|
||||||
|
('rosybrown', (188, 143, 143, 1)),
|
||||||
|
('royalblue', (65, 105, 225, 1)),
|
||||||
|
('saddlebrown', (139, 69, 19, 1)),
|
||||||
|
('salmon', (250, 128, 114, 1)),
|
||||||
|
('sandybrown', (244, 164, 96, 1)),
|
||||||
|
('seagreen', (46, 139, 87, 1)),
|
||||||
|
('seashell', (255, 245, 238, 1)),
|
||||||
|
('sienna', (160, 82, 45, 1)),
|
||||||
|
('silver', (192, 192, 192, 1)),
|
||||||
|
('skyblue', (135, 206, 235, 1)),
|
||||||
|
('slateblue', (106, 90, 205, 1)),
|
||||||
|
('slategray', (112, 128, 144, 1)),
|
||||||
|
('slategrey', (112, 128, 144, 1)),
|
||||||
|
('snow', (255, 250, 250, 1)),
|
||||||
|
('springgreen', (0, 255, 127, 1)),
|
||||||
|
('steelblue', (70, 130, 180, 1)),
|
||||||
|
('tan', (210, 180, 140, 1)),
|
||||||
|
('teal', (0, 128, 128, 1)),
|
||||||
|
('thistle', (216, 191, 216, 1)),
|
||||||
|
('tomato', (255, 99, 71, 1)),
|
||||||
|
('turquoise', (64, 224, 208, 1)),
|
||||||
|
('violet', (238, 130, 238, 1)),
|
||||||
|
('wheat', (245, 222, 179, 1)),
|
||||||
|
('white', (255, 255, 255, 1)),
|
||||||
|
('whitesmoke', (245, 245, 245, 1)),
|
||||||
|
('yellow', (255, 255, 0, 1)),
|
||||||
|
('yellowgreen', (154, 205, 50, 1)),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def replace(s, i, r):
|
||||||
|
i %= len(s)
|
||||||
|
return s[:i] + r(s[i]) + s[i + 1:]
|
||||||
|
|
||||||
|
|
||||||
|
print('[')
|
||||||
|
print(',\n'.join(
|
||||||
|
'"%s", %s' % (css, list(rgba) if valid else 'null')
|
||||||
|
for i, (keyword, rgba) in enumerate(all_keywords)
|
||||||
|
for css, valid, run in [
|
||||||
|
(keyword, True, True),
|
||||||
|
(replace(keyword, i, str.upper), True, True),
|
||||||
|
(replace(keyword, i, lambda c: r'\\' + c), True,
|
||||||
|
keyword[i % len(keyword)] not in 'abcdef'),
|
||||||
|
(replace(keyword, i, lambda c: r'\\%X ' % ord(c)), True, True),
|
||||||
|
(replace(keyword, i, lambda c: ''), False, True),
|
||||||
|
# Kelving sign: u'K'.lower() == u'k', but should not match in CSS
|
||||||
|
(keyword.replace('k', u'K'), False, 'k' in keyword)
|
||||||
|
]
|
||||||
|
if run
|
||||||
|
))
|
||||||
|
print(']')
|
|
@ -0,0 +1,27 @@
|
||||||
|
[
|
||||||
|
|
||||||
|
"", ["error", "empty"],
|
||||||
|
" ", ["error", "empty"],
|
||||||
|
"/**/", ["error", "empty"],
|
||||||
|
" /**/\t/* a */\n\n", ["error", "empty"],
|
||||||
|
|
||||||
|
".", ".",
|
||||||
|
"a", ["ident", "a"],
|
||||||
|
"/**/ 4px", ["dimension", "4", 4, "integer", "px"],
|
||||||
|
"rgba(100%, 0%, 50%, .5)", ["function", "rgba",
|
||||||
|
["percentage", "100", 100, "integer"], ",", " ",
|
||||||
|
["percentage", "0", 0, "integer"], ",", " ",
|
||||||
|
["percentage", "50", 50, "integer"], ",", " ",
|
||||||
|
["number", ".5", 0.5, "number"]
|
||||||
|
],
|
||||||
|
|
||||||
|
" /**/ { foo: bar; @baz [)", ["{}",
|
||||||
|
" ", ["ident", "foo"], ":", " ", ["ident", "bar"], ";", " ",
|
||||||
|
["at-keyword", "baz"], " ", ["[]",
|
||||||
|
["error", ")"]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
|
||||||
|
".foo", ["error", "extra-input"]
|
||||||
|
|
||||||
|
]
|
|
@ -0,0 +1,46 @@
|
||||||
|
[
|
||||||
|
|
||||||
|
"", ["error", "empty"],
|
||||||
|
" /**/\n", ["error", "empty"],
|
||||||
|
" ;", ["error", "invalid"],
|
||||||
|
"foo", ["error", "invalid"],
|
||||||
|
"@foo:", ["error", "invalid"],
|
||||||
|
"#foo:", ["error", "invalid"],
|
||||||
|
".foo:", ["error", "invalid"],
|
||||||
|
"foo*:", ["error", "invalid"],
|
||||||
|
"foo.. 9000", ["error", "invalid"],
|
||||||
|
"foo:", ["declaration", "foo", [], false],
|
||||||
|
"foo :", ["declaration", "foo", [], false],
|
||||||
|
"\n/**/ foo: ", ["declaration", "foo", [" "], false],
|
||||||
|
"foo:;", ["declaration", "foo", [";"], false],
|
||||||
|
" /**/ foo /**/ :", ["declaration", "foo", [], false],
|
||||||
|
"foo:;bar:;", ["declaration", "foo", [";", ["ident", "bar"], ":", ";"], false],
|
||||||
|
|
||||||
|
"foo: 9000 !Important", ["declaration", "foo", [
|
||||||
|
" ", ["number", "9000", 9000, "integer"], " "
|
||||||
|
], true],
|
||||||
|
"foo: 9000 ! /**/\t IMPORTant /**/\f", ["declaration", "foo", [
|
||||||
|
" ", ["number", "9000", 9000, "integer"], " "
|
||||||
|
], true],
|
||||||
|
|
||||||
|
"foo: 9000 /* Dotted capital I */!İmportant", ["declaration", "foo", [
|
||||||
|
" ", ["number", "9000", 9000, "integer"], " ", "!", ["ident", "İmportant"]
|
||||||
|
], false],
|
||||||
|
"foo: 9000 !important!", ["declaration", "foo", [
|
||||||
|
" ", ["number", "9000", 9000, "integer"], " ", "!", ["ident", "important"], "!"
|
||||||
|
], false],
|
||||||
|
|
||||||
|
"foo: 9000 important", ["declaration", "foo", [
|
||||||
|
" ", ["number", "9000", 9000, "integer"], " ", ["ident", "important"]
|
||||||
|
], false],
|
||||||
|
"foo:important", ["declaration", "foo", [
|
||||||
|
["ident", "important"]
|
||||||
|
], false],
|
||||||
|
|
||||||
|
"foo: 9000 @bar{ !important", ["declaration", "foo", [
|
||||||
|
" ", ["number", "9000", 9000, "integer"], " ", ["at-keyword", "bar"], ["{}",
|
||||||
|
" ", "!", ["ident", "important"]
|
||||||
|
]
|
||||||
|
], false]
|
||||||
|
|
||||||
|
]
|
|
@ -0,0 +1,36 @@
|
||||||
|
[
|
||||||
|
|
||||||
|
"", ["error", "empty"],
|
||||||
|
"foo", ["error", "invalid"],
|
||||||
|
"foo 4", ["error", "invalid"],
|
||||||
|
|
||||||
|
"@foo", ["at-rule", "foo", [], null],
|
||||||
|
|
||||||
|
"@foo bar; \t/* comment */", ["at-rule", "foo", [" ", ["ident", "bar"]], null],
|
||||||
|
" /**/ @foo bar{[(4", ["at-rule", "foo",
|
||||||
|
[" ", ["ident", "bar"]],
|
||||||
|
[["[]", ["()", ["number", "4", 4, "integer"]]]]
|
||||||
|
],
|
||||||
|
|
||||||
|
"@foo { bar", ["at-rule", "foo", [" "], [" ", ["ident", "bar"]]],
|
||||||
|
"@foo [ bar", ["at-rule", "foo", [" ", ["[]", " ", ["ident", "bar"]]], null],
|
||||||
|
|
||||||
|
" /**/ div > p { color: #aaa; } /**/ ", ["qualified rule",
|
||||||
|
[["ident", "div"], " ", ">", " ", ["ident", "p"], " "],
|
||||||
|
[" ", ["ident", "color"], ":", " ", ["hash", "aaa", "id"], ";", " "]
|
||||||
|
],
|
||||||
|
|
||||||
|
" /**/ { color: #aaa ", ["qualified rule",
|
||||||
|
[],
|
||||||
|
[" ", ["ident", "color"], ":", " ", ["hash", "aaa", "id"], " "]
|
||||||
|
],
|
||||||
|
|
||||||
|
" /* CDO/CDC are not special */ <!-- --> {", ["qualified rule",
|
||||||
|
["<!--", " ", "-->", " "], []
|
||||||
|
],
|
||||||
|
|
||||||
|
"div { color: #aaa; } p{}", ["error", "extra-input"],
|
||||||
|
"div {} -->", ["error", "extra-input"],
|
||||||
|
"{}a", ["error", "extra-input"]
|
||||||
|
|
||||||
|
]
|
|
@ -0,0 +1,48 @@
|
||||||
|
[
|
||||||
|
|
||||||
|
"", [],
|
||||||
|
"foo", [["error", "invalid"]],
|
||||||
|
"foo 4", [["error", "invalid"]],
|
||||||
|
|
||||||
|
"@foo", [["at-rule", "foo", [], null]],
|
||||||
|
|
||||||
|
"@foo bar; \t/* comment */", [["at-rule", "foo", [" ", ["ident", "bar"]], null]],
|
||||||
|
|
||||||
|
" /**/ @foo bar{[(4", [["at-rule", "foo",
|
||||||
|
[" ", ["ident", "bar"]],
|
||||||
|
[["[]", ["()", ["number", "4", 4, "integer"]]]]
|
||||||
|
]],
|
||||||
|
|
||||||
|
"@foo { bar", [["at-rule", "foo", [" "], [" ", ["ident", "bar"]]]],
|
||||||
|
"@foo [ bar", [["at-rule", "foo", [" ", ["[]", " ", ["ident", "bar"]]], null]],
|
||||||
|
|
||||||
|
" /**/ div > p { color: #aaa; } /**/ ", [["qualified rule",
|
||||||
|
[["ident", "div"], " ", ">", " ", ["ident", "p"], " "],
|
||||||
|
[" ", ["ident", "color"], ":", " ", ["hash", "aaa", "id"], ";", " "]
|
||||||
|
]],
|
||||||
|
|
||||||
|
" /**/ { color: #aaa ", [["qualified rule",
|
||||||
|
[],
|
||||||
|
[" ", ["ident", "color"], ":", " ", ["hash", "aaa", "id"], " "]
|
||||||
|
]],
|
||||||
|
|
||||||
|
" /* CDO/CDC are not special */ <!-- --> {", [["qualified rule",
|
||||||
|
["<!--", " ", "-->", " "], []
|
||||||
|
]],
|
||||||
|
|
||||||
|
"div { color: #aaa; } p{}", [
|
||||||
|
["qualified rule", [["ident", "div"], " "],
|
||||||
|
[" ", ["ident", "color"], ":", " ", ["hash", "aaa", "id"], ";", " "]
|
||||||
|
],
|
||||||
|
["qualified rule", [["ident", "p"]], []]
|
||||||
|
],
|
||||||
|
|
||||||
|
"div {} -->", [
|
||||||
|
["qualified rule", [["ident", "div"], " "], []],
|
||||||
|
["error", "invalid"]
|
||||||
|
],
|
||||||
|
|
||||||
|
"{}a", [["qualified rule", [], []], ["error", "invalid"]],
|
||||||
|
"{}@a", [["qualified rule", [], []], ["at-rule", "a", [], null]]
|
||||||
|
|
||||||
|
]
|
|
@ -0,0 +1,44 @@
|
||||||
|
[
|
||||||
|
|
||||||
|
"", [],
|
||||||
|
"foo", [["error", "invalid"]],
|
||||||
|
"foo 4", [["error", "invalid"]],
|
||||||
|
|
||||||
|
"@foo", [["at-rule", "foo", [], null]],
|
||||||
|
|
||||||
|
"@foo bar; \t/* comment */", [["at-rule", "foo", [" ", ["ident", "bar"]], null]],
|
||||||
|
|
||||||
|
" /**/ @foo bar{[(4", [["at-rule", "foo",
|
||||||
|
[" ", ["ident", "bar"]],
|
||||||
|
[["[]", ["()", ["number", "4", 4, "integer"]]]]
|
||||||
|
]],
|
||||||
|
|
||||||
|
"@foo { bar", [["at-rule", "foo", [" "], [" ", ["ident", "bar"]]]],
|
||||||
|
"@foo [ bar", [["at-rule", "foo", [" ", ["[]", " ", ["ident", "bar"]]], null]],
|
||||||
|
|
||||||
|
" /**/ div > p { color: #aaa; } /**/ ", [["qualified rule",
|
||||||
|
[["ident", "div"], " ", ">", " ", ["ident", "p"], " "],
|
||||||
|
[" ", ["ident", "color"], ":", " ", ["hash", "aaa", "id"], ";", " "]
|
||||||
|
]],
|
||||||
|
|
||||||
|
" /**/ { color: #aaa ", [["qualified rule",
|
||||||
|
[],
|
||||||
|
[" ", ["ident", "color"], ":", " ", ["hash", "aaa", "id"], " "]
|
||||||
|
]],
|
||||||
|
|
||||||
|
" /* CDO/CDC are ignored between rules */ <!-- --> {", [["qualified rule", [], []]],
|
||||||
|
" <!-- --> a<!---->{", [["qualified rule", [["ident", "a"], "<!--", "-->"], []]],
|
||||||
|
|
||||||
|
"div { color: #aaa; } p{}", [
|
||||||
|
["qualified rule", [["ident", "div"], " "],
|
||||||
|
[" ", ["ident", "color"], ":", " ", ["hash", "aaa", "id"], ";", " "]
|
||||||
|
],
|
||||||
|
["qualified rule", [["ident", "p"]], []]
|
||||||
|
],
|
||||||
|
|
||||||
|
"div {} -->", [["qualified rule", [["ident", "div"], " "], []]],
|
||||||
|
|
||||||
|
"{}a", [["qualified rule", [], []], ["error", "invalid"]],
|
||||||
|
"{}@a", [["qualified rule", [], []], ["at-rule", "a", [], null]]
|
||||||
|
|
||||||
|
]
|
|
@ -0,0 +1,146 @@
|
||||||
|
[
|
||||||
|
|
||||||
|
{"css_bytes": ""},
|
||||||
|
[[], "utf-8"],
|
||||||
|
|
||||||
|
{"css_bytes": "@\u00C3\u00A9",
|
||||||
|
"protocol_encoding": null, "environment_encoding": null},
|
||||||
|
[[["at-rule", "é", [], null]], "utf-8"],
|
||||||
|
|
||||||
|
{"css_bytes": "@\u00C3\u00A9"},
|
||||||
|
[[["at-rule", "é", [], null]], "utf-8"],
|
||||||
|
|
||||||
|
{"css_bytes": "@\u0000\u00E9\u0000",
|
||||||
|
"comment": "Untagged UTF-16, parsed as UTF-8"},
|
||||||
|
[[["at-rule", "<22><><EFBFBD>", [], null]], "utf-8"],
|
||||||
|
|
||||||
|
{"css_bytes": "\u00FF\u00FE@\u0000\u00E9\u0000",
|
||||||
|
"comment": "UTF-16 with a BOM"},
|
||||||
|
[[["at-rule", "é", [], null]], "utf-16le"],
|
||||||
|
|
||||||
|
{"css_bytes": "\u00FE\u00FF\u0000@\u0000\u00E9"},
|
||||||
|
[[["at-rule", "é", [], null]], "utf-16be"],
|
||||||
|
|
||||||
|
{"css_bytes": "@\u00E9"},
|
||||||
|
[[["at-rule", "<22>", [], null]], "utf-8"],
|
||||||
|
|
||||||
|
|
||||||
|
{"css_bytes": "@\u00E9", "protocol_encoding": "ISO-8859-2"},
|
||||||
|
[[["at-rule", "é", [], null]], "iso-8859-2"],
|
||||||
|
|
||||||
|
{"css_bytes": "@\u00E9", "protocol_encoding": "ISO-8859-5"},
|
||||||
|
[[["at-rule", "щ", [], null]], "iso-8859-5"],
|
||||||
|
|
||||||
|
{"css_bytes": "@\u00C3\u00A9", "protocol_encoding": "ISO-8859-2"},
|
||||||
|
[[["at-rule", "ĂŠ", [], null]], "iso-8859-2"],
|
||||||
|
|
||||||
|
{"css_bytes": "\u00EF\u00BB\u00BF @\u00C3\u00A9",
|
||||||
|
"protocol_encoding": "ISO-8859-2",
|
||||||
|
"comment": "BOM takes precedence over protocol"},
|
||||||
|
[[["at-rule", "é", [], null]], "utf-8"],
|
||||||
|
|
||||||
|
|
||||||
|
{"css_bytes": "@charset \"ISO-8859-5\"; @\u00E9"},
|
||||||
|
[[["at-rule", "charset", [" ", ["string", "ISO-8859-5"]], null],
|
||||||
|
["at-rule", "щ", [], null]],
|
||||||
|
"iso-8859-5"],
|
||||||
|
|
||||||
|
{"css_bytes": "@Charset \"ISO-8859-5\"; @\u00E9",
|
||||||
|
"comment": "@charset has to match an exact byte pattern"},
|
||||||
|
[[["at-rule", "Charset", [" ", ["string", "ISO-8859-5"]], null],
|
||||||
|
["at-rule", "<22>", [], null]],
|
||||||
|
"utf-8"],
|
||||||
|
|
||||||
|
{"css_bytes": "@charset \"ISO-8859-5\"; @\u00E9",
|
||||||
|
"comment": "@charset has to match an exact byte pattern"},
|
||||||
|
[[["at-rule", "charset", [" ", ["string", "ISO-8859-5"]], null],
|
||||||
|
["at-rule", "<22>", [], null]],
|
||||||
|
"utf-8"],
|
||||||
|
|
||||||
|
{"css_bytes": "@charset 'ISO-8859-5'; @\u00E9",
|
||||||
|
"comment": "@charset has to match an exact byte pattern"},
|
||||||
|
[[["at-rule", "charset", [" ", ["string", "ISO-8859-5"]], null],
|
||||||
|
["at-rule", "<22>", [], null]],
|
||||||
|
"utf-8"],
|
||||||
|
|
||||||
|
{"css_bytes": "@charset \"ISO-8859-5\" ; @\u00E9",
|
||||||
|
"comment": "@charset has to match an exact byte pattern"},
|
||||||
|
[[["at-rule", "charset", [" ", ["string", "ISO-8859-5"], " "], null],
|
||||||
|
["at-rule", "<22>", [], null]],
|
||||||
|
"utf-8"],
|
||||||
|
|
||||||
|
|
||||||
|
{"css_bytes": "@\u0000c\u0000h\u0000a\u0000r\u0000s\u0000e\u0000t\u0000 \u0000\"\u0000U\u0000T\u0000F\u0000-\u00001\u00006\u0000L\u0000E\u0000\"\u0000;\u0000@\u0000\u00e9\u0000",
|
||||||
|
"comment": "@charset has to be ASCII-compatible itself"},
|
||||||
|
[[["at-rule", "<22>c<EFBFBD>h<EFBFBD>a<EFBFBD>r<EFBFBD>s<EFBFBD>e<EFBFBD>t<EFBFBD>",
|
||||||
|
[" ", ["ident", "<22>"], ["string", "<22>U<EFBFBD>T<EFBFBD>F<EFBFBD>-<2D>1<EFBFBD>6<EFBFBD>L<EFBFBD>E<EFBFBD>"], ["ident", "<22>"]], null],
|
||||||
|
["error", "invalid"]],
|
||||||
|
"utf-8"],
|
||||||
|
|
||||||
|
{"css_bytes": "@charset \"UTF-16LE\"; @\u00C3\u00A9",
|
||||||
|
"comment": "@charset can only specify ASCII-compatible encodings"},
|
||||||
|
[[["at-rule", "charset", [" ", ["string", "UTF-16LE"]], null],
|
||||||
|
["at-rule", "é", [], null]],
|
||||||
|
"utf-8"],
|
||||||
|
|
||||||
|
|
||||||
|
{"css_bytes": "\u00EF\u00BB\u00BF @charset \"ISO-8859-5\"; @\u00E9",
|
||||||
|
"comment": "BOM takes precedence over @charset"},
|
||||||
|
[[["at-rule", "charset", [" ", ["string", "ISO-8859-5"]], null],
|
||||||
|
["at-rule", "<22>", [], null]],
|
||||||
|
"utf-8"],
|
||||||
|
|
||||||
|
{"css_bytes": "\u00EF\u00BB\u00BF @charset \"ISO-8859-5\"; @\u00C3\u00A9",
|
||||||
|
"comment": "BOM takes precedence over @charset"},
|
||||||
|
[[["at-rule", "charset", [" ", ["string", "ISO-8859-5"]], null],
|
||||||
|
["at-rule", "é", [], null]],
|
||||||
|
"utf-8"],
|
||||||
|
|
||||||
|
{"css_bytes": "@charset \"ISO-8859-5\"; @\u00E9",
|
||||||
|
"protocol_encoding": " Iso-8859-2",
|
||||||
|
"comment": "Protocol takes precedence over @charset"},
|
||||||
|
[[["at-rule", "charset", [" ", ["string", "ISO-8859-5"]], null],
|
||||||
|
["at-rule", "é", [], null]],
|
||||||
|
"iso-8859-2"],
|
||||||
|
|
||||||
|
{"css_bytes": "@charset \"ISO-8859-5\"; @\u00E9",
|
||||||
|
"protocol_encoding": "kamoulox",
|
||||||
|
"comment": "Unknow protocol encoding falls back to @charset"},
|
||||||
|
[[["at-rule", "charset", [" ", ["string", "ISO-8859-5"]], null],
|
||||||
|
["at-rule", "щ", [], null]],
|
||||||
|
"iso-8859-5"],
|
||||||
|
|
||||||
|
|
||||||
|
{"css_bytes": "@\u00E9", "environment_encoding": "ISO-8859-2"},
|
||||||
|
[[["at-rule", "é", [], null]], "iso-8859-2"],
|
||||||
|
|
||||||
|
{"css_bytes": "@\u00E9", "environment_encoding": "ISO-8859-5"},
|
||||||
|
[[["at-rule", "щ", [], null]], "iso-8859-5"],
|
||||||
|
|
||||||
|
{"css_bytes": "@charset \"ISO-8859-5\"; @\u00E9",
|
||||||
|
"environment_encoding": "ISO-8859-2",
|
||||||
|
"comment": "@character takes precedence over environment"},
|
||||||
|
[[["at-rule", "charset", [" ", ["string", "ISO-8859-5"]], null],
|
||||||
|
["at-rule", "щ", [], null]],
|
||||||
|
"iso-8859-5"],
|
||||||
|
|
||||||
|
{"css_bytes": "@charset \"kamoulox\"; @\u00E9",
|
||||||
|
"environment_encoding": "ISO-8859-2",
|
||||||
|
"comment": "@character with unknown encoding falls back to environment encoding"},
|
||||||
|
[[["at-rule", "charset", [" ", ["string", "kamoulox"]], null],
|
||||||
|
["at-rule", "é", [], null]],
|
||||||
|
"iso-8859-2"],
|
||||||
|
|
||||||
|
{"css_bytes": "@\u00E9",
|
||||||
|
"protocol_encoding": "ISO-8859-2",
|
||||||
|
"environment_encoding": "ISO-8859-5",
|
||||||
|
"comment": "protocol takes precedence over environment"},
|
||||||
|
[[["at-rule", "é", [], null]], "iso-8859-2"],
|
||||||
|
|
||||||
|
{"css_bytes": "\u00EF\u00BB\u00BF @\u00C3\u00A9",
|
||||||
|
"environment_encoding": "ISO-8859-5",
|
||||||
|
"comment": "BOM takes precedence over environment"},
|
||||||
|
[[["at-rule", "é", [], null]], "utf-8"]
|
||||||
|
|
||||||
|
|
||||||
|
]
|
|
@ -0,0 +1,102 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
from .parser import _next_significant, _to_token_iterator
|
||||||
|
|
||||||
|
|
||||||
|
def parse_nth(input):
|
||||||
|
"""Parse `<An+B> <http://dev.w3.org/csswg/css-syntax-3/#anb>`_,
|
||||||
|
as found in `:nth-child()
|
||||||
|
<http://dev.w3.org/csswg/selectors/#nth-child-pseudo>`_
|
||||||
|
and related Selector pseudo-classes.
|
||||||
|
|
||||||
|
Although tinycss2 does not include a full Selector parser,
|
||||||
|
this bit of syntax is included as it is particularly tricky to define
|
||||||
|
on top of a CSS tokenizer.
|
||||||
|
|
||||||
|
:param input:
|
||||||
|
A :term:`string`, or an iterable yielding :term:`component values`
|
||||||
|
(eg. the :attr:`~tinycss2.ast.FunctionBlock.arguments`
|
||||||
|
of a functional pseudo-class.)
|
||||||
|
:returns:
|
||||||
|
A ``(a, b)`` tuple of integers, or :obj:`None` if the input is invalid.
|
||||||
|
|
||||||
|
"""
|
||||||
|
tokens = _to_token_iterator(input, skip_comments=True)
|
||||||
|
token = _next_significant(tokens)
|
||||||
|
if token is None:
|
||||||
|
return
|
||||||
|
token_type = token.type
|
||||||
|
if token_type == 'number' and token.is_integer:
|
||||||
|
return parse_end(tokens, 0, token.int_value)
|
||||||
|
elif token_type == 'dimension' and token.is_integer:
|
||||||
|
unit = token.lower_unit
|
||||||
|
if unit == 'n':
|
||||||
|
return parse_b(tokens, token.int_value)
|
||||||
|
elif unit == 'n-':
|
||||||
|
return parse_signless_b(tokens, token.int_value, -1)
|
||||||
|
else:
|
||||||
|
match = N_DASH_DIGITS_RE.match(unit)
|
||||||
|
if match:
|
||||||
|
return parse_end(tokens, token.int_value, int(match.group(1)))
|
||||||
|
elif token_type == 'ident':
|
||||||
|
ident = token.lower_value
|
||||||
|
if ident == 'even':
|
||||||
|
return parse_end(tokens, 2, 0)
|
||||||
|
elif ident == 'odd':
|
||||||
|
return parse_end(tokens, 2, 1)
|
||||||
|
elif ident == 'n':
|
||||||
|
return parse_b(tokens, 1)
|
||||||
|
elif ident == '-n':
|
||||||
|
return parse_b(tokens, -1)
|
||||||
|
elif ident == 'n-':
|
||||||
|
return parse_signless_b(tokens, 1, -1)
|
||||||
|
elif ident == '-n-':
|
||||||
|
return parse_signless_b(tokens, -1, -1)
|
||||||
|
elif ident[0] == '-':
|
||||||
|
match = N_DASH_DIGITS_RE.match(ident[1:])
|
||||||
|
if match:
|
||||||
|
return parse_end(tokens, -1, int(match.group(1)))
|
||||||
|
else:
|
||||||
|
match = N_DASH_DIGITS_RE.match(ident)
|
||||||
|
if match:
|
||||||
|
return parse_end(tokens, 1, int(match.group(1)))
|
||||||
|
elif token == '+':
|
||||||
|
token = next(tokens) # Whitespace after an initial '+' is invalid.
|
||||||
|
if token.type == 'ident':
|
||||||
|
ident = token.lower_value
|
||||||
|
if ident == 'n':
|
||||||
|
return parse_b(tokens, 1)
|
||||||
|
elif ident == 'n-':
|
||||||
|
return parse_signless_b(tokens, 1, -1)
|
||||||
|
else:
|
||||||
|
match = N_DASH_DIGITS_RE.match(ident)
|
||||||
|
if match:
|
||||||
|
return parse_end(tokens, 1, int(match.group(1)))
|
||||||
|
|
||||||
|
|
||||||
|
def parse_b(tokens, a):
|
||||||
|
token = _next_significant(tokens)
|
||||||
|
if token is None:
|
||||||
|
return (a, 0)
|
||||||
|
elif token == '+':
|
||||||
|
return parse_signless_b(tokens, a, 1)
|
||||||
|
elif token == '-':
|
||||||
|
return parse_signless_b(tokens, a, -1)
|
||||||
|
elif (token.type == 'number' and token.is_integer and
|
||||||
|
token.representation[0] in '-+'):
|
||||||
|
return parse_end(tokens, a, token.int_value)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_signless_b(tokens, a, b_sign):
|
||||||
|
token = _next_significant(tokens)
|
||||||
|
if (token.type == 'number' and token.is_integer and
|
||||||
|
not token.representation[0] in '-+'):
|
||||||
|
return parse_end(tokens, a, b_sign * token.int_value)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_end(tokens, a, b):
|
||||||
|
if _next_significant(tokens) is None:
|
||||||
|
return (a, b)
|
||||||
|
|
||||||
|
|
||||||
|
N_DASH_DIGITS_RE = re.compile('^n(-[0-9]+)$')
|
|
@ -0,0 +1,361 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from ._compat import basestring
|
||||||
|
from .ast import AtRule, Declaration, ParseError, QualifiedRule
|
||||||
|
from .tokenizer import parse_component_value_list
|
||||||
|
|
||||||
|
|
||||||
|
def _to_token_iterator(input, skip_comments=False):
|
||||||
|
"""
|
||||||
|
|
||||||
|
:param input: A string or an iterable of :term:`component values`.
|
||||||
|
:param skip_comments:
|
||||||
|
If the input is a string, ignore all CSS comments.
|
||||||
|
:returns: A iterator yielding :term:`component values`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Accept ASCII-only byte strings on Python 2, with implicit conversion.
|
||||||
|
if isinstance(input, basestring):
|
||||||
|
input = parse_component_value_list(input, skip_comments)
|
||||||
|
return iter(input)
|
||||||
|
|
||||||
|
|
||||||
|
def _next_significant(tokens):
|
||||||
|
"""Return the next significant (neither whitespace or comment) token.
|
||||||
|
|
||||||
|
:param tokens: An *iterator* yielding :term:`component values`.
|
||||||
|
:returns: A :term:`component value`, or :obj:`None`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
for token in tokens:
|
||||||
|
if token.type not in ('whitespace', 'comment'):
|
||||||
|
return token
|
||||||
|
|
||||||
|
|
||||||
|
def parse_one_component_value(input, skip_comments=False):
|
||||||
|
"""Parse a single :diagram:`component value`.
|
||||||
|
|
||||||
|
This is used e.g. for an attribute value
|
||||||
|
referred to by ``attr(foo length)``.
|
||||||
|
|
||||||
|
:param input:
|
||||||
|
A :term:`string`, or an iterable of :term:`component values`.
|
||||||
|
:param skip_comments:
|
||||||
|
If the input is a string, ignore all CSS comments.
|
||||||
|
:returns:
|
||||||
|
A :term:`component value` (that is neither whitespace or comment),
|
||||||
|
or a :class:`~tinycss2.ast.ParseError`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
tokens = _to_token_iterator(input, skip_comments)
|
||||||
|
first = _next_significant(tokens)
|
||||||
|
second = _next_significant(tokens)
|
||||||
|
if first is None:
|
||||||
|
return ParseError(1, 1, 'empty', 'Input is empty')
|
||||||
|
if second is not None:
|
||||||
|
return ParseError(
|
||||||
|
second.source_line, second.source_column, 'extra-input',
|
||||||
|
'Got more than one token')
|
||||||
|
else:
|
||||||
|
return first
|
||||||
|
|
||||||
|
|
||||||
|
def parse_one_declaration(input, skip_comments=False):
|
||||||
|
"""Parse a single :diagram:`declaration`.
|
||||||
|
|
||||||
|
This is used e.g. for a declaration in an `@supports
|
||||||
|
<http://dev.w3.org/csswg/css-conditional/#at-supports>`_ test.
|
||||||
|
|
||||||
|
:param input:
|
||||||
|
A :term:`string`, or an iterable of :term:`component values`.
|
||||||
|
:param skip_comments:
|
||||||
|
If the input is a string, ignore all CSS comments.
|
||||||
|
:returns:
|
||||||
|
A :class:`~tinycss2.ast.Declaration`
|
||||||
|
or :class:`~tinycss2.ast.ParseError`.
|
||||||
|
|
||||||
|
Any whitespace or comment before the ``:`` colon is dropped.
|
||||||
|
|
||||||
|
"""
|
||||||
|
tokens = _to_token_iterator(input, skip_comments)
|
||||||
|
first_token = _next_significant(tokens)
|
||||||
|
if first_token is None:
|
||||||
|
return ParseError(1, 1, 'empty', 'Input is empty')
|
||||||
|
return _parse_declaration(first_token, tokens)
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_declaration(first_token, tokens):
|
||||||
|
"""Parse a declaration.
|
||||||
|
|
||||||
|
Consume :obj:`tokens` until the end of the declaration or the first error.
|
||||||
|
|
||||||
|
:param first_token: The first :term:`component value` of the rule.
|
||||||
|
:param tokens: An *iterator* yielding :term:`component values`.
|
||||||
|
:returns:
|
||||||
|
A :class:`~tinycss2.ast.Declaration`
|
||||||
|
or :class:`~tinycss2.ast.ParseError`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = first_token
|
||||||
|
if name.type != 'ident':
|
||||||
|
return ParseError(name.source_line, name.source_column, 'invalid',
|
||||||
|
'Expected <ident> for declaration name, got %s.'
|
||||||
|
% name.type)
|
||||||
|
|
||||||
|
colon = _next_significant(tokens)
|
||||||
|
if colon is None:
|
||||||
|
return ParseError(name.source_line, name.source_column, 'invalid',
|
||||||
|
"Expected ':' after declaration name, got EOF")
|
||||||
|
elif colon != ':':
|
||||||
|
return ParseError(colon.source_line, colon.source_column, 'invalid',
|
||||||
|
"Expected ':' after declaration name, got %s."
|
||||||
|
% colon.type)
|
||||||
|
|
||||||
|
value = []
|
||||||
|
state = 'value'
|
||||||
|
for i, token in enumerate(tokens):
|
||||||
|
if state == 'value' and token == '!':
|
||||||
|
state = 'bang'
|
||||||
|
bang_position = i
|
||||||
|
elif state == 'bang' and token.type == 'ident' \
|
||||||
|
and token.lower_value == 'important':
|
||||||
|
state = 'important'
|
||||||
|
elif token.type not in ('whitespace', 'comment'):
|
||||||
|
state = 'value'
|
||||||
|
value.append(token)
|
||||||
|
|
||||||
|
if state == 'important':
|
||||||
|
del value[bang_position:]
|
||||||
|
|
||||||
|
return Declaration(name.source_line, name.source_column, name.value,
|
||||||
|
name.lower_value, value, state == 'important')
|
||||||
|
|
||||||
|
|
||||||
|
def _consume_declaration_in_list(first_token, tokens):
|
||||||
|
"""Like :func:`_parse_declaration`, but stop at the first ``;``."""
|
||||||
|
other_declaration_tokens = []
|
||||||
|
for token in tokens:
|
||||||
|
if token == ';':
|
||||||
|
break
|
||||||
|
other_declaration_tokens.append(token)
|
||||||
|
return _parse_declaration(first_token, iter(other_declaration_tokens))
|
||||||
|
|
||||||
|
|
||||||
|
def parse_declaration_list(input, skip_comments=False, skip_whitespace=False):
|
||||||
|
"""Parse a :diagram:`declaration list` (which may also contain at-rules).
|
||||||
|
|
||||||
|
This is used e.g. for the :attr:`~tinycss2.ast.QualifiedRule.content`
|
||||||
|
of a style rule or ``@page`` rule,
|
||||||
|
or for the ``style`` attribute of an HTML element.
|
||||||
|
|
||||||
|
In contexts that don’t expect any at-rule,
|
||||||
|
all :class:`~tinycss2.ast.AtRule` objects
|
||||||
|
should simply be rejected as invalid.
|
||||||
|
|
||||||
|
:param input: A string or an iterable of :term:`component values`.
|
||||||
|
:param skip_comments:
|
||||||
|
Ignore CSS comments at the top-level of the list.
|
||||||
|
If the input is a string, ignore all comments.
|
||||||
|
:param skip_whitespace:
|
||||||
|
Ignore whitespace at the top-level of the list.
|
||||||
|
Whitespace is still preserved
|
||||||
|
in the :attr:`~tinycss2.ast.Declaration.value` of declarations
|
||||||
|
and the :attr:`~tinycss2.ast.AtRule.prelude`
|
||||||
|
and :attr:`~tinycss2.ast.AtRule.content` of at-rules.
|
||||||
|
:returns:
|
||||||
|
A list of
|
||||||
|
:class:`~tinycss2.ast.Declaration`,
|
||||||
|
:class:`~tinycss2.ast.AtRule`,
|
||||||
|
:class:`~tinycss2.ast.Comment` (if ``skip_comments`` is false),
|
||||||
|
:class:`~tinycss2.ast.WhitespaceToken`
|
||||||
|
(if ``skip_whitespace`` is false),
|
||||||
|
and :class:`~tinycss2.ast.ParseError` objects
|
||||||
|
|
||||||
|
"""
|
||||||
|
tokens = _to_token_iterator(input, skip_comments)
|
||||||
|
result = []
|
||||||
|
for token in tokens:
|
||||||
|
if token.type == 'whitespace':
|
||||||
|
if not skip_whitespace:
|
||||||
|
result.append(token)
|
||||||
|
elif token.type == 'comment':
|
||||||
|
if not skip_comments:
|
||||||
|
result.append(token)
|
||||||
|
elif token.type == 'at-keyword':
|
||||||
|
result.append(_consume_at_rule(token, tokens))
|
||||||
|
elif token != ';':
|
||||||
|
result.append(_consume_declaration_in_list(token, tokens))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def parse_one_rule(input, skip_comments=False):
|
||||||
|
"""Parse a single :diagram:`qualified rule` or :diagram:`at-rule`.
|
||||||
|
|
||||||
|
This would be used e.g. by `insertRule()
|
||||||
|
<http://dev.w3.org/csswg/cssom/#dom-cssstylesheet-insertrule>`_
|
||||||
|
in an implementation of CSSOM.
|
||||||
|
|
||||||
|
:param input: A string or an iterable of :term:`component values`.
|
||||||
|
:param skip_comments:
|
||||||
|
If the input is a string, ignore all CSS comments.
|
||||||
|
:returns:
|
||||||
|
A :class:`~tinycss2.ast.QualifiedRule`,
|
||||||
|
:class:`~tinycss2.ast.AtRule`,
|
||||||
|
or :class:`~tinycss2.ast.ParseError` objects.
|
||||||
|
|
||||||
|
Any whitespace or comment before or after the rule is dropped.
|
||||||
|
|
||||||
|
"""
|
||||||
|
tokens = _to_token_iterator(input, skip_comments)
|
||||||
|
first = _next_significant(tokens)
|
||||||
|
if first is None:
|
||||||
|
return ParseError(1, 1, 'empty', 'Input is empty')
|
||||||
|
|
||||||
|
rule = _consume_rule(first, tokens)
|
||||||
|
next = _next_significant(tokens)
|
||||||
|
if next is not None:
|
||||||
|
return ParseError(
|
||||||
|
next.source_line, next.source_column, 'extra-input',
|
||||||
|
'Expected a single rule, got %s after the first rule.' % next.type)
|
||||||
|
return rule
|
||||||
|
|
||||||
|
|
||||||
|
def parse_rule_list(input, skip_comments=False, skip_whitespace=False):
|
||||||
|
"""Parse a non-top-level :diagram:`rule list`.
|
||||||
|
|
||||||
|
This is used for parsing the :attr:`~tinycss2.ast.AtRule.content`
|
||||||
|
of nested rules like ``@media``.
|
||||||
|
This differs from :func:`parse_stylesheet` in that
|
||||||
|
top-level ``<!--`` and ``-->`` tokens are not ignored.
|
||||||
|
|
||||||
|
:param input: A string or an iterable of :term:`component values`.
|
||||||
|
:param skip_comments:
|
||||||
|
Ignore CSS comments at the top-level of the list.
|
||||||
|
If the input is a string, ignore all comments.
|
||||||
|
:param skip_whitespace:
|
||||||
|
Ignore whitespace at the top-level of the list.
|
||||||
|
Whitespace is still preserved
|
||||||
|
in the :attr:`~tinycss2.ast.QualifiedRule.prelude`
|
||||||
|
and the :attr:`~tinycss2.ast.QualifiedRule.content` of rules.
|
||||||
|
:returns:
|
||||||
|
A list of
|
||||||
|
:class:`~tinycss2.ast.QualifiedRule`,
|
||||||
|
:class:`~tinycss2.ast.AtRule`,
|
||||||
|
:class:`~tinycss2.ast.Comment` (if ``skip_comments`` is false),
|
||||||
|
:class:`~tinycss2.ast.WhitespaceToken`
|
||||||
|
(if ``skip_whitespace`` is false),
|
||||||
|
and :class:`~tinycss2.ast.ParseError` objects.
|
||||||
|
|
||||||
|
"""
|
||||||
|
tokens = _to_token_iterator(input, skip_comments)
|
||||||
|
result = []
|
||||||
|
for token in tokens:
|
||||||
|
if token.type == 'whitespace':
|
||||||
|
if not skip_whitespace:
|
||||||
|
result.append(token)
|
||||||
|
elif token.type == 'comment':
|
||||||
|
if not skip_comments:
|
||||||
|
result.append(token)
|
||||||
|
else:
|
||||||
|
result.append(_consume_rule(token, tokens))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def parse_stylesheet(input, skip_comments=False, skip_whitespace=False):
|
||||||
|
"""Parse :diagram:`stylesheet` from text.
|
||||||
|
|
||||||
|
This is used e.g. for a ``<style>`` HTML element.
|
||||||
|
|
||||||
|
This differs from :func:`parse_rule_list` in that
|
||||||
|
top-level ``<!--`` and ``-->`` tokens are ignored.
|
||||||
|
This is a legacy quirk for the ``<style>`` HTML element.
|
||||||
|
|
||||||
|
:param input: A string or an iterable of :term:`component values`.
|
||||||
|
:param skip_comments:
|
||||||
|
Ignore CSS comments at the top-level of the stylesheet.
|
||||||
|
If the input is a string, ignore all comments.
|
||||||
|
:param skip_whitespace:
|
||||||
|
Ignore whitespace at the top-level of the stylesheet.
|
||||||
|
Whitespace is still preserved
|
||||||
|
in the :attr:`~tinycss2.ast.QualifiedRule.prelude`
|
||||||
|
and the :attr:`~tinycss2.ast.QualifiedRule.content` of rules.
|
||||||
|
:returns:
|
||||||
|
A list of
|
||||||
|
:class:`~tinycss2.ast.QualifiedRule`,
|
||||||
|
:class:`~tinycss2.ast.AtRule`,
|
||||||
|
:class:`~tinycss2.ast.Comment` (if ``skip_comments`` is false),
|
||||||
|
:class:`~tinycss2.ast.WhitespaceToken`
|
||||||
|
(if ``skip_whitespace`` is false),
|
||||||
|
and :class:`~tinycss2.ast.ParseError` objects.
|
||||||
|
|
||||||
|
"""
|
||||||
|
tokens = _to_token_iterator(input, skip_comments)
|
||||||
|
result = []
|
||||||
|
for token in tokens:
|
||||||
|
if token.type == 'whitespace':
|
||||||
|
if not skip_whitespace:
|
||||||
|
result.append(token)
|
||||||
|
elif token.type == 'comment':
|
||||||
|
if not skip_comments:
|
||||||
|
result.append(token)
|
||||||
|
elif token not in ('<!--', '-->'):
|
||||||
|
result.append(_consume_rule(token, tokens))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _consume_rule(first_token, tokens):
|
||||||
|
"""Parse a qualified rule or at-rule.
|
||||||
|
|
||||||
|
Consume just enough of :obj:`tokens` for this rule.
|
||||||
|
|
||||||
|
:param first_token: The first :term:`component value` of the rule.
|
||||||
|
:param tokens: An *iterator* yielding :term:`component values`.
|
||||||
|
:returns:
|
||||||
|
A :class:`~tinycss2.ast.QualifiedRule`,
|
||||||
|
:class:`~tinycss2.ast.AtRule`,
|
||||||
|
or :class:`~tinycss2.ast.ParseError`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if first_token.type == 'at-keyword':
|
||||||
|
return _consume_at_rule(first_token, tokens)
|
||||||
|
if first_token.type == '{} block':
|
||||||
|
prelude = []
|
||||||
|
block = first_token
|
||||||
|
else:
|
||||||
|
prelude = [first_token]
|
||||||
|
for token in tokens:
|
||||||
|
if token.type == '{} block':
|
||||||
|
block = token
|
||||||
|
break
|
||||||
|
prelude.append(token)
|
||||||
|
else:
|
||||||
|
return ParseError(
|
||||||
|
prelude[-1].source_line, prelude[-1].source_column, 'invalid',
|
||||||
|
'EOF reached before {} block for a qualified rule.')
|
||||||
|
return QualifiedRule(first_token.source_line, first_token.source_column,
|
||||||
|
prelude, block.content)
|
||||||
|
|
||||||
|
|
||||||
|
def _consume_at_rule(at_keyword, tokens):
|
||||||
|
"""Parse an at-rule.
|
||||||
|
|
||||||
|
Consume just enough of :obj:`tokens` for this rule.
|
||||||
|
|
||||||
|
:param at_keyword: The :class:`AtKeywordToken` object starting this rule.
|
||||||
|
:param tokens: An *iterator* yielding :term:`component values`.
|
||||||
|
:returns:
|
||||||
|
A :class:`~tinycss2.ast.QualifiedRule`,
|
||||||
|
or :class:`~tinycss2.ast.ParseError`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
prelude = []
|
||||||
|
content = None
|
||||||
|
for token in tokens:
|
||||||
|
if token.type == '{} block':
|
||||||
|
content = token.content
|
||||||
|
break
|
||||||
|
elif token == ';':
|
||||||
|
break
|
||||||
|
prelude.append(token)
|
||||||
|
return AtRule(at_keyword.source_line, at_keyword.source_column,
|
||||||
|
at_keyword.value, at_keyword.lower_value, prelude, content)
|
|
@ -0,0 +1,122 @@
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
|
||||||
|
def serialize(nodes):
|
||||||
|
"""Serialize nodes to CSS syntax.
|
||||||
|
|
||||||
|
This should be used for :term:`component values`
|
||||||
|
instead of just :meth:`~tinycss2.ast.Node.serialize` on each node
|
||||||
|
as it takes care of corner cases such as ``;`` between declarations,
|
||||||
|
and consecutive identifiers
|
||||||
|
that would otherwise parse back as the same token.
|
||||||
|
|
||||||
|
:param nodes: an iterable of :class:`~tinycss2.ast.Node` objects
|
||||||
|
:returns: an Unicode string
|
||||||
|
|
||||||
|
"""
|
||||||
|
chunks = []
|
||||||
|
_serialize_to(nodes, chunks.append)
|
||||||
|
return ''.join(chunks)
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_identifier(value):
|
||||||
|
"""Serialize any string as a CSS identifier
|
||||||
|
|
||||||
|
:param value: a :term:`string`
|
||||||
|
:returns:
|
||||||
|
an Unicode string
|
||||||
|
that would parse as an :class:`~tinycss2.ast.IdentToken`
|
||||||
|
whose :attr:`~tinycss2.ast.IdentToken.value` attribute
|
||||||
|
equals the passed :obj:`value` argument.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if value == '-':
|
||||||
|
return r'\-'
|
||||||
|
|
||||||
|
if value[0] == '-':
|
||||||
|
result = '-'
|
||||||
|
value = value[1:]
|
||||||
|
else:
|
||||||
|
result = ''
|
||||||
|
c = value[0]
|
||||||
|
result += (
|
||||||
|
c if c in ('abcdefghijklmnopqrstuvwxyz_'
|
||||||
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZ') or ord(c) > 0x7F else
|
||||||
|
r'\A ' if c == '\n' else
|
||||||
|
r'\D ' if c == '\r' else
|
||||||
|
r'\C ' if c == '\f' else
|
||||||
|
'\\%X ' % ord(c) if c in '0123456789' else
|
||||||
|
'\\' + c
|
||||||
|
)
|
||||||
|
result += serialize_name(value[1:])
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_name(value):
|
||||||
|
return ''.join(
|
||||||
|
c if c in ('abcdefghijklmnopqrstuvwxyz-_0123456789'
|
||||||
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZ') or ord(c) > 0x7F else
|
||||||
|
r'\A ' if c == '\n' else
|
||||||
|
r'\D ' if c == '\r' else
|
||||||
|
r'\C ' if c == '\f' else
|
||||||
|
'\\' + c
|
||||||
|
for c in value
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_string_value(value):
|
||||||
|
return ''.join(
|
||||||
|
r'\"' if c == '"' else
|
||||||
|
r'\\' if c == '\\' else
|
||||||
|
r'\A ' if c == '\n' else
|
||||||
|
r'\D ' if c == '\r' else
|
||||||
|
r'\C ' if c == '\f' else
|
||||||
|
c
|
||||||
|
for c in value
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# http://dev.w3.org/csswg/css-syntax/#serialization-tables
|
||||||
|
def _serialize_to(nodes, write):
|
||||||
|
"""Serialize an iterable of nodes to CSS syntax,
|
||||||
|
writing chunks as Unicode string
|
||||||
|
by calling the provided :obj:`write` callback.
|
||||||
|
|
||||||
|
"""
|
||||||
|
bad_pairs = BAD_PAIRS
|
||||||
|
previous_type = None
|
||||||
|
for node in nodes:
|
||||||
|
serialization_type = (node.type if node.type != 'literal'
|
||||||
|
else node.value)
|
||||||
|
if (previous_type, serialization_type) in bad_pairs:
|
||||||
|
write('/**/')
|
||||||
|
elif previous_type == '\\' and not (
|
||||||
|
serialization_type == 'whitespace' and
|
||||||
|
node.value.startswith('\n')):
|
||||||
|
write('\n')
|
||||||
|
node._serialize_to(write)
|
||||||
|
if serialization_type == 'declaration':
|
||||||
|
write(';')
|
||||||
|
previous_type = serialization_type
|
||||||
|
|
||||||
|
|
||||||
|
BAD_PAIRS = set(
|
||||||
|
[(a, b)
|
||||||
|
for a in ('ident', 'at-keyword', 'hash', 'dimension', '#', '-',
|
||||||
|
'number')
|
||||||
|
for b in ('ident', 'function', 'url', 'number', 'percentage',
|
||||||
|
'dimension', 'unicode-range')] +
|
||||||
|
[(a, b)
|
||||||
|
for a in ('ident', 'at-keyword', 'hash', 'dimension')
|
||||||
|
for b in ('-', '-->')] +
|
||||||
|
[(a, b)
|
||||||
|
for a in ('#', '-', 'number', '@')
|
||||||
|
for b in ('ident', 'function', 'url')] +
|
||||||
|
[(a, b)
|
||||||
|
for a in ('unicode-range', '.', '+')
|
||||||
|
for b in ('number', 'percentage', 'dimension')] +
|
||||||
|
[('@', b) for b in ('ident', 'function', 'url', 'unicode-range', '-')] +
|
||||||
|
[('unicode-range', b) for b in ('ident', 'function', '?')] +
|
||||||
|
[(a, '=') for a in '$*^~|'] +
|
||||||
|
[('ident', '() block'), ('|', '|'), ('/', '*')]
|
||||||
|
)
|
|
@ -0,0 +1,230 @@
|
||||||
|
# coding: utf8
|
||||||
|
|
||||||
|
import functools
|
||||||
|
import json
|
||||||
|
import os.path
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from webencodings import Encoding, lookup
|
||||||
|
|
||||||
|
from . import (parse_component_value_list, parse_declaration_list,
|
||||||
|
parse_one_component_value, parse_one_declaration,
|
||||||
|
parse_one_rule, parse_rule_list, parse_stylesheet,
|
||||||
|
parse_stylesheet_bytes, serialize)
|
||||||
|
from .ast import (AtKeywordToken, AtRule, Comment, CurlyBracketsBlock,
|
||||||
|
Declaration, DimensionToken, FunctionBlock, HashToken,
|
||||||
|
IdentToken, LiteralToken, NumberToken, ParenthesesBlock,
|
||||||
|
ParseError, PercentageToken, QualifiedRule,
|
||||||
|
SquareBracketsBlock, StringToken, UnicodeRangeToken,
|
||||||
|
URLToken, WhitespaceToken)
|
||||||
|
from .color3 import RGBA, parse_color
|
||||||
|
from .nth import parse_nth
|
||||||
|
|
||||||
|
|
||||||
|
def generic(func):
|
||||||
|
implementations = func()
|
||||||
|
|
||||||
|
@functools.wraps(func)
|
||||||
|
def run(value):
|
||||||
|
repr(value) # Test that this does not raise.
|
||||||
|
return implementations[type(value)](value)
|
||||||
|
return run
|
||||||
|
|
||||||
|
|
||||||
|
@generic
|
||||||
|
def to_json():
|
||||||
|
def numeric(t):
|
||||||
|
return [
|
||||||
|
t.representation, t.value,
|
||||||
|
'integer' if t.int_value is not None else 'number']
|
||||||
|
return {
|
||||||
|
type(None): lambda _: None,
|
||||||
|
str: lambda s: s,
|
||||||
|
int: lambda s: s,
|
||||||
|
list: lambda l: [to_json(el) for el in l],
|
||||||
|
tuple: lambda l: [to_json(el) for el in l],
|
||||||
|
Encoding: lambda e: e.name,
|
||||||
|
ParseError: lambda e: ['error', e.kind],
|
||||||
|
|
||||||
|
Comment: lambda t: '/* … */',
|
||||||
|
WhitespaceToken: lambda t: ' ',
|
||||||
|
LiteralToken: lambda t: t.value,
|
||||||
|
IdentToken: lambda t: ['ident', t.value],
|
||||||
|
AtKeywordToken: lambda t: ['at-keyword', t.value],
|
||||||
|
HashToken: lambda t: ['hash', t.value,
|
||||||
|
'id' if t.is_identifier else 'unrestricted'],
|
||||||
|
StringToken: lambda t: ['string', t.value],
|
||||||
|
URLToken: lambda t: ['url', t.value],
|
||||||
|
NumberToken: lambda t: ['number'] + numeric(t),
|
||||||
|
PercentageToken: lambda t: ['percentage'] + numeric(t),
|
||||||
|
DimensionToken: lambda t: ['dimension'] + numeric(t) + [t.unit],
|
||||||
|
UnicodeRangeToken: lambda t: ['unicode-range', t.start, t.end],
|
||||||
|
|
||||||
|
CurlyBracketsBlock: lambda t: ['{}'] + to_json(t.content),
|
||||||
|
SquareBracketsBlock: lambda t: ['[]'] + to_json(t.content),
|
||||||
|
ParenthesesBlock: lambda t: ['()'] + to_json(t.content),
|
||||||
|
FunctionBlock: lambda t: ['function', t.name] + to_json(t.arguments),
|
||||||
|
|
||||||
|
Declaration: lambda d: ['declaration', d.name,
|
||||||
|
to_json(d.value), d.important],
|
||||||
|
AtRule: lambda r: ['at-rule', r.at_keyword, to_json(r.prelude),
|
||||||
|
to_json(r.content)],
|
||||||
|
QualifiedRule: lambda r: ['qualified rule', to_json(r.prelude),
|
||||||
|
to_json(r.content)],
|
||||||
|
|
||||||
|
RGBA: lambda v: [round(c, 10) for c in v],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def load_json(filename):
|
||||||
|
json_data = json.load(open(os.path.join(
|
||||||
|
os.path.dirname(__file__), 'css-parsing-tests', filename)))
|
||||||
|
return list(zip(json_data[::2], json_data[1::2]))
|
||||||
|
|
||||||
|
|
||||||
|
def json_test(filename=None):
|
||||||
|
def decorator(function):
|
||||||
|
filename_ = filename or function.__name__.split('_', 1)[-1] + '.json'
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(('css', 'expected'), load_json(filename_))
|
||||||
|
def test(css, expected):
|
||||||
|
value = to_json(function(css))
|
||||||
|
if value != expected: # pragma: no cover
|
||||||
|
pprint.pprint(value)
|
||||||
|
assert value == expected
|
||||||
|
return test
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
SKIP = dict(skip_comments=True, skip_whitespace=True)
|
||||||
|
|
||||||
|
|
||||||
|
@json_test()
|
||||||
|
def test_component_value_list(input):
|
||||||
|
return parse_component_value_list(input, skip_comments=True)
|
||||||
|
|
||||||
|
|
||||||
|
@json_test()
|
||||||
|
def test_one_component_value(input):
|
||||||
|
return parse_one_component_value(input, skip_comments=True)
|
||||||
|
|
||||||
|
|
||||||
|
@json_test()
|
||||||
|
def test_declaration_list(input):
|
||||||
|
return parse_declaration_list(input, **SKIP)
|
||||||
|
|
||||||
|
|
||||||
|
@json_test()
|
||||||
|
def test_one_declaration(input):
|
||||||
|
return parse_one_declaration(input, skip_comments=True)
|
||||||
|
|
||||||
|
|
||||||
|
@json_test()
|
||||||
|
def test_stylesheet(input):
|
||||||
|
return parse_stylesheet(input, **SKIP)
|
||||||
|
|
||||||
|
|
||||||
|
@json_test()
|
||||||
|
def test_rule_list(input):
|
||||||
|
return parse_rule_list(input, **SKIP)
|
||||||
|
|
||||||
|
|
||||||
|
@json_test()
|
||||||
|
def test_one_rule(input):
|
||||||
|
return parse_one_rule(input, skip_comments=True)
|
||||||
|
|
||||||
|
|
||||||
|
@json_test()
|
||||||
|
def test_color3(input):
|
||||||
|
return parse_color(input)
|
||||||
|
|
||||||
|
|
||||||
|
@json_test(filename='An+B.json')
|
||||||
|
def test_nth(input):
|
||||||
|
return parse_nth(input)
|
||||||
|
|
||||||
|
|
||||||
|
# Do not use @pytest.mark.parametrize because it is slow with that many values.
|
||||||
|
def test_color3_hsl():
|
||||||
|
for css, expected in load_json('color3_hsl.json'):
|
||||||
|
assert to_json(parse_color(css)) == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_color3_keywords():
|
||||||
|
for css, expected in load_json('color3_keywords.json'):
|
||||||
|
result = parse_color(css)
|
||||||
|
if result is not None:
|
||||||
|
r, g, b, a = result
|
||||||
|
result = [r * 255, g * 255, b * 255, a]
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
|
||||||
|
@json_test()
|
||||||
|
def test_stylesheet_bytes(kwargs):
|
||||||
|
kwargs['css_bytes'] = kwargs['css_bytes'].encode('latin1')
|
||||||
|
kwargs.pop('comment', None)
|
||||||
|
if kwargs.get('environment_encoding'):
|
||||||
|
kwargs['environment_encoding'] = lookup(kwargs['environment_encoding'])
|
||||||
|
kwargs.update(SKIP)
|
||||||
|
return parse_stylesheet_bytes(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@json_test(filename='component_value_list.json')
|
||||||
|
def test_serialization(css):
|
||||||
|
parsed = parse_component_value_list(css, skip_comments=True)
|
||||||
|
return parse_component_value_list(serialize(parsed), skip_comments=True)
|
||||||
|
|
||||||
|
|
||||||
|
def test_skip():
|
||||||
|
source = '''
|
||||||
|
/* foo */
|
||||||
|
@media print {
|
||||||
|
#foo {
|
||||||
|
width: /* bar*/4px;
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
no_ws = parse_stylesheet(source, skip_whitespace=True)
|
||||||
|
no_comment = parse_stylesheet(source, skip_comments=True)
|
||||||
|
default = parse_component_value_list(source)
|
||||||
|
assert serialize(no_ws) != source
|
||||||
|
assert serialize(no_comment) != source
|
||||||
|
assert serialize(default) == source
|
||||||
|
|
||||||
|
|
||||||
|
def test_comment_eof():
|
||||||
|
source = '/* foo '
|
||||||
|
parsed = parse_component_value_list(source)
|
||||||
|
assert serialize(parsed) == '/* foo */'
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_declaration_value_color():
|
||||||
|
source = 'color:#369'
|
||||||
|
declaration = parse_one_declaration(source)
|
||||||
|
(value_token,) = declaration.value
|
||||||
|
assert parse_color(value_token) == (.2, .4, .6, 1)
|
||||||
|
assert declaration.serialize() == source
|
||||||
|
|
||||||
|
|
||||||
|
def test_serialize_rules():
|
||||||
|
source = '@import "a.css"; foo#bar.baz { color: red } /**/ @media print{}'
|
||||||
|
rules = parse_rule_list(source)
|
||||||
|
assert serialize(rules) == source
|
||||||
|
|
||||||
|
|
||||||
|
def test_serialize_declarations():
|
||||||
|
source = 'color: #123; /**/ @top-left {} width:7px !important;'
|
||||||
|
rules = parse_declaration_list(source)
|
||||||
|
assert serialize(rules) == source
|
||||||
|
|
||||||
|
|
||||||
|
def test_backslash_delim():
|
||||||
|
source = '\\\nfoo'
|
||||||
|
tokens = parse_component_value_list(source)
|
||||||
|
assert [t.type for t in tokens] == ['literal', 'whitespace', 'ident']
|
||||||
|
assert tokens[0].value == '\\'
|
||||||
|
del tokens[1]
|
||||||
|
assert [t.type for t in tokens] == ['literal', 'ident']
|
||||||
|
assert serialize(tokens) == source
|
|
@ -0,0 +1,402 @@
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from webencodings import ascii_lower
|
||||||
|
|
||||||
|
from ._compat import unichr
|
||||||
|
from .ast import (AtKeywordToken, Comment, CurlyBracketsBlock, DimensionToken,
|
||||||
|
FunctionBlock, HashToken, IdentToken, LiteralToken,
|
||||||
|
NumberToken, ParenthesesBlock, ParseError, PercentageToken,
|
||||||
|
SquareBracketsBlock, StringToken, UnicodeRangeToken,
|
||||||
|
URLToken, WhitespaceToken)
|
||||||
|
|
||||||
|
_NUMBER_RE = re.compile(r'[-+]?([0-9]*\.)?[0-9]+([eE][+-]?[0-9]+)?')
|
||||||
|
_HEX_ESCAPE_RE = re.compile(r'([0-9A-Fa-f]{1,6})[ \n\t]?')
|
||||||
|
|
||||||
|
|
||||||
|
def parse_component_value_list(css, skip_comments=False):
|
||||||
|
"""Parse a list of component values.
|
||||||
|
|
||||||
|
:param css: A :term:`string`.
|
||||||
|
:param skip_comments:
|
||||||
|
Ignore CSS comments.
|
||||||
|
The return values (and recursively its blocks and functions)
|
||||||
|
will not contain any :class:`~tinycss2.ast.Comment` object.
|
||||||
|
:returns: A list of :term:`component values`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
css = (css.replace('\0', '\uFFFD')
|
||||||
|
# This turns out to be faster than a regexp:
|
||||||
|
.replace('\r\n', '\n').replace('\r', '\n').replace('\f', '\n'))
|
||||||
|
length = len(css)
|
||||||
|
token_start_pos = pos = 0 # Character index in the css source.
|
||||||
|
line = 1 # First line is line 1.
|
||||||
|
last_newline = -1
|
||||||
|
root = tokens = []
|
||||||
|
end_char = None # Pop the stack when encountering this character.
|
||||||
|
stack = [] # Stack of nested blocks: (tokens, end_char) tuples.
|
||||||
|
|
||||||
|
while pos < length:
|
||||||
|
newline = css.rfind('\n', token_start_pos, pos)
|
||||||
|
if newline != -1:
|
||||||
|
line += 1 + css.count('\n', token_start_pos, newline)
|
||||||
|
last_newline = newline
|
||||||
|
# First character in a line is in column 1.
|
||||||
|
column = pos - last_newline
|
||||||
|
token_start_pos = pos
|
||||||
|
c = css[pos]
|
||||||
|
|
||||||
|
if c in ' \n\t':
|
||||||
|
pos += 1
|
||||||
|
while css.startswith((' ', '\n', '\t'), pos):
|
||||||
|
pos += 1
|
||||||
|
value = css[token_start_pos:pos]
|
||||||
|
tokens.append(WhitespaceToken(line, column, value))
|
||||||
|
continue
|
||||||
|
elif (c in 'Uu' and pos + 2 < length and css[pos + 1] == '+' and
|
||||||
|
css[pos + 2] in '0123456789abcdefABCDEF?'):
|
||||||
|
start, end, pos = _consume_unicode_range(css, pos + 2)
|
||||||
|
tokens.append(UnicodeRangeToken(line, column, start, end))
|
||||||
|
continue
|
||||||
|
elif css.startswith('-->', pos): # Check before identifiers
|
||||||
|
tokens.append(LiteralToken(line, column, '-->'))
|
||||||
|
pos += 3
|
||||||
|
continue
|
||||||
|
elif _is_ident_start(css, pos):
|
||||||
|
value, pos = _consume_ident(css, pos)
|
||||||
|
if not css.startswith('(', pos): # Not a function
|
||||||
|
tokens.append(IdentToken(line, column, value))
|
||||||
|
continue
|
||||||
|
pos += 1 # Skip the '('
|
||||||
|
if ascii_lower(value) == 'url':
|
||||||
|
value, pos = _consume_url(css, pos)
|
||||||
|
tokens.append(
|
||||||
|
URLToken(line, column, value) if value is not None
|
||||||
|
else ParseError(line, column, 'bad-url', 'bad URL token'))
|
||||||
|
continue
|
||||||
|
arguments = []
|
||||||
|
tokens.append(FunctionBlock(line, column, value, arguments))
|
||||||
|
stack.append((tokens, end_char))
|
||||||
|
end_char = ')'
|
||||||
|
tokens = arguments
|
||||||
|
continue
|
||||||
|
|
||||||
|
match = _NUMBER_RE.match(css, pos)
|
||||||
|
if match:
|
||||||
|
pos = match.end()
|
||||||
|
repr_ = css[token_start_pos:pos]
|
||||||
|
value = float(repr_)
|
||||||
|
int_value = int(repr_) if not any(match.groups()) else None
|
||||||
|
if pos < length and _is_ident_start(css, pos):
|
||||||
|
unit, pos = _consume_ident(css, pos)
|
||||||
|
tokens.append(DimensionToken(
|
||||||
|
line, column, value, int_value, repr_, unit))
|
||||||
|
elif css.startswith('%', pos):
|
||||||
|
pos += 1
|
||||||
|
tokens.append(PercentageToken(
|
||||||
|
line, column, value, int_value, repr_))
|
||||||
|
else:
|
||||||
|
tokens.append(NumberToken(
|
||||||
|
line, column, value, int_value, repr_))
|
||||||
|
elif c == '@':
|
||||||
|
pos += 1
|
||||||
|
if pos < length and _is_ident_start(css, pos):
|
||||||
|
value, pos = _consume_ident(css, pos)
|
||||||
|
tokens.append(AtKeywordToken(line, column, value))
|
||||||
|
else:
|
||||||
|
tokens.append(LiteralToken(line, column, '@'))
|
||||||
|
elif c == '#':
|
||||||
|
pos += 1
|
||||||
|
if pos < length and (
|
||||||
|
css[pos] in '0123456789abcdefghijklmnopqrstuvwxyz'
|
||||||
|
'-_ABCDEFGHIJKLMNOPQRSTUVWXYZ' or
|
||||||
|
ord(css[pos]) > 0x7F or # Non-ASCII
|
||||||
|
# Valid escape:
|
||||||
|
(css[pos] == '\\' and not css.startswith('\\\n', pos))):
|
||||||
|
is_identifier = _is_ident_start(css, pos)
|
||||||
|
value, pos = _consume_ident(css, pos)
|
||||||
|
tokens.append(HashToken(line, column, value, is_identifier))
|
||||||
|
else:
|
||||||
|
tokens.append(LiteralToken(line, column, '#'))
|
||||||
|
elif c == '{':
|
||||||
|
content = []
|
||||||
|
tokens.append(CurlyBracketsBlock(line, column, content))
|
||||||
|
stack.append((tokens, end_char))
|
||||||
|
end_char = '}'
|
||||||
|
tokens = content
|
||||||
|
pos += 1
|
||||||
|
elif c == '[':
|
||||||
|
content = []
|
||||||
|
tokens.append(SquareBracketsBlock(line, column, content))
|
||||||
|
stack.append((tokens, end_char))
|
||||||
|
end_char = ']'
|
||||||
|
tokens = content
|
||||||
|
pos += 1
|
||||||
|
elif c == '(':
|
||||||
|
content = []
|
||||||
|
tokens.append(ParenthesesBlock(line, column, content))
|
||||||
|
stack.append((tokens, end_char))
|
||||||
|
end_char = ')'
|
||||||
|
tokens = content
|
||||||
|
pos += 1
|
||||||
|
elif c == end_char: # Matching }, ] or )
|
||||||
|
# The top-level end_char is None (never equal to a character),
|
||||||
|
# so we never get here if the stack is empty.
|
||||||
|
tokens, end_char = stack.pop()
|
||||||
|
pos += 1
|
||||||
|
elif c in '}])':
|
||||||
|
tokens.append(ParseError(line, column, c, 'Unmatched ' + c))
|
||||||
|
pos += 1
|
||||||
|
elif c in ('"', "'"):
|
||||||
|
value, pos = _consume_quoted_string(css, pos)
|
||||||
|
tokens.append(
|
||||||
|
StringToken(line, column, value) if value is not None
|
||||||
|
else ParseError(line, column, 'bad-string',
|
||||||
|
'bad string token'))
|
||||||
|
elif css.startswith('/*', pos): # Comment
|
||||||
|
pos = css.find('*/', pos + 2)
|
||||||
|
if pos == -1:
|
||||||
|
if not skip_comments:
|
||||||
|
tokens.append(
|
||||||
|
Comment(line, column, css[token_start_pos + 2:]))
|
||||||
|
break
|
||||||
|
if not skip_comments:
|
||||||
|
tokens.append(
|
||||||
|
Comment(line, column, css[token_start_pos + 2:pos]))
|
||||||
|
pos += 2
|
||||||
|
elif css.startswith('<!--', pos):
|
||||||
|
tokens.append(LiteralToken(line, column, '<!--'))
|
||||||
|
pos += 4
|
||||||
|
elif css.startswith('||', pos):
|
||||||
|
tokens.append(LiteralToken(line, column, '||'))
|
||||||
|
pos += 2
|
||||||
|
elif c in '~|^$*':
|
||||||
|
pos += 1
|
||||||
|
if css.startswith('=', pos):
|
||||||
|
pos += 1
|
||||||
|
tokens.append(LiteralToken(line, column, c + '='))
|
||||||
|
else:
|
||||||
|
tokens.append(LiteralToken(line, column, c))
|
||||||
|
else:
|
||||||
|
tokens.append(LiteralToken(line, column, c))
|
||||||
|
pos += 1
|
||||||
|
return root
|
||||||
|
|
||||||
|
|
||||||
|
def _is_name_start(css, pos):
|
||||||
|
"""Return true if the given character is a name-start code point."""
|
||||||
|
# https://www.w3.org/TR/css-syntax-3/#name-start-code-point
|
||||||
|
c = css[pos]
|
||||||
|
return (
|
||||||
|
c in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_' or
|
||||||
|
ord(c) > 0x7F)
|
||||||
|
|
||||||
|
|
||||||
|
def _is_ident_start(css, pos):
|
||||||
|
"""Return True if the given position is the start of a CSS identifier."""
|
||||||
|
# https://www.w3.org/TR/css-syntax-3/#would-start-an-identifier
|
||||||
|
if _is_name_start(css, pos):
|
||||||
|
return True
|
||||||
|
elif css[pos] == '-':
|
||||||
|
pos += 1
|
||||||
|
return (
|
||||||
|
# Name-start code point:
|
||||||
|
(pos < len(css) and _is_name_start(css, pos)) or
|
||||||
|
# Valid escape:
|
||||||
|
(css.startswith('\\', pos) and not css.startswith('\\\n', pos)))
|
||||||
|
elif css[pos] == '\\':
|
||||||
|
return not css.startswith('\\\n', pos)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _consume_ident(css, pos):
|
||||||
|
"""Return (unescaped_value, new_pos).
|
||||||
|
|
||||||
|
Assumes pos starts at a valid identifier. See :func:`_is_ident_start`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
# http://dev.w3.org/csswg/css-syntax/#consume-a-name
|
||||||
|
chunks = []
|
||||||
|
length = len(css)
|
||||||
|
start_pos = pos
|
||||||
|
while pos < length:
|
||||||
|
c = css[pos]
|
||||||
|
if c in ('abcdefghijklmnopqrstuvwxyz-_0123456789'
|
||||||
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZ') or ord(c) > 0x7F:
|
||||||
|
pos += 1
|
||||||
|
elif c == '\\' and not css.startswith('\\\n', pos):
|
||||||
|
# Valid escape
|
||||||
|
chunks.append(css[start_pos:pos])
|
||||||
|
c, pos = _consume_escape(css, pos + 1)
|
||||||
|
chunks.append(c)
|
||||||
|
start_pos = pos
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
chunks.append(css[start_pos:pos])
|
||||||
|
return ''.join(chunks), pos
|
||||||
|
|
||||||
|
|
||||||
|
def _consume_quoted_string(css, pos):
|
||||||
|
"""Return (unescaped_value, new_pos)."""
|
||||||
|
# http://dev.w3.org/csswg/css-syntax/#consume-a-string-token
|
||||||
|
quote = css[pos]
|
||||||
|
assert quote in ('"', "'")
|
||||||
|
pos += 1
|
||||||
|
chunks = []
|
||||||
|
length = len(css)
|
||||||
|
start_pos = pos
|
||||||
|
while pos < length:
|
||||||
|
c = css[pos]
|
||||||
|
if c == quote:
|
||||||
|
chunks.append(css[start_pos:pos])
|
||||||
|
pos += 1
|
||||||
|
break
|
||||||
|
elif c == '\\':
|
||||||
|
chunks.append(css[start_pos:pos])
|
||||||
|
pos += 1
|
||||||
|
if pos < length:
|
||||||
|
if css[pos] == '\n': # Ignore escaped newlines
|
||||||
|
pos += 1
|
||||||
|
else:
|
||||||
|
c, pos = _consume_escape(css, pos)
|
||||||
|
chunks.append(c)
|
||||||
|
# else: Escaped EOF, do nothing
|
||||||
|
start_pos = pos
|
||||||
|
elif c == '\n': # Unescaped newline
|
||||||
|
return None, pos # bad-string
|
||||||
|
else:
|
||||||
|
pos += 1
|
||||||
|
else:
|
||||||
|
chunks.append(css[start_pos:pos])
|
||||||
|
return ''.join(chunks), pos
|
||||||
|
|
||||||
|
|
||||||
|
def _consume_escape(css, pos):
|
||||||
|
r"""Return (unescaped_char, new_pos).
|
||||||
|
|
||||||
|
Assumes a valid escape: pos is just after '\' and not followed by '\n'.
|
||||||
|
|
||||||
|
"""
|
||||||
|
# http://dev.w3.org/csswg/css-syntax/#consume-an-escaped-character
|
||||||
|
hex_match = _HEX_ESCAPE_RE.match(css, pos)
|
||||||
|
if hex_match:
|
||||||
|
codepoint = int(hex_match.group(1), 16)
|
||||||
|
return (
|
||||||
|
unichr(codepoint) if 0 < codepoint <= sys.maxunicode else '\uFFFD',
|
||||||
|
hex_match.end())
|
||||||
|
elif pos < len(css):
|
||||||
|
return css[pos], pos + 1
|
||||||
|
else:
|
||||||
|
return '\uFFFD', pos
|
||||||
|
|
||||||
|
|
||||||
|
def _consume_url(css, pos):
|
||||||
|
"""Return (unescaped_url, new_pos)
|
||||||
|
|
||||||
|
The given pos is assumed to be just after the '(' of 'url('.
|
||||||
|
|
||||||
|
"""
|
||||||
|
length = len(css)
|
||||||
|
# http://dev.w3.org/csswg/css-syntax/#consume-a-url-token
|
||||||
|
# Skip whitespace
|
||||||
|
while css.startswith((' ', '\n', '\t'), pos):
|
||||||
|
pos += 1
|
||||||
|
if pos >= length: # EOF
|
||||||
|
return '', pos
|
||||||
|
c = css[pos]
|
||||||
|
if c in ('"', "'"):
|
||||||
|
value, pos = _consume_quoted_string(css, pos)
|
||||||
|
elif c == ')':
|
||||||
|
return '', pos + 1
|
||||||
|
else:
|
||||||
|
chunks = []
|
||||||
|
start_pos = pos
|
||||||
|
while 1:
|
||||||
|
if pos >= length: # EOF
|
||||||
|
chunks.append(css[start_pos:pos])
|
||||||
|
return ''.join(chunks), pos
|
||||||
|
c = css[pos]
|
||||||
|
if c == ')':
|
||||||
|
chunks.append(css[start_pos:pos])
|
||||||
|
pos += 1
|
||||||
|
return ''.join(chunks), pos
|
||||||
|
elif c in ' \n\t':
|
||||||
|
chunks.append(css[start_pos:pos])
|
||||||
|
value = ''.join(chunks)
|
||||||
|
pos += 1
|
||||||
|
break
|
||||||
|
elif c == '\\' and not css.startswith('\\\n', pos):
|
||||||
|
# Valid escape
|
||||||
|
chunks.append(css[start_pos:pos])
|
||||||
|
c, pos = _consume_escape(css, pos + 1)
|
||||||
|
chunks.append(c)
|
||||||
|
start_pos = pos
|
||||||
|
elif (c in
|
||||||
|
'"\'('
|
||||||
|
# http://dev.w3.org/csswg/css-syntax/#non-printable-character
|
||||||
|
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0e'
|
||||||
|
'\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19'
|
||||||
|
'\x1a\x1b\x1c\x1d\x1e\x1f\x7f'):
|
||||||
|
value = None # Parse error
|
||||||
|
pos += 1
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
pos += 1
|
||||||
|
|
||||||
|
if value is not None:
|
||||||
|
while css.startswith((' ', '\n', '\t'), pos):
|
||||||
|
pos += 1
|
||||||
|
if pos < length:
|
||||||
|
if css[pos] == ')':
|
||||||
|
return value, pos + 1
|
||||||
|
else:
|
||||||
|
return value, pos
|
||||||
|
|
||||||
|
# http://dev.w3.org/csswg/css-syntax/#consume-the-remnants-of-a-bad-url0
|
||||||
|
while pos < length:
|
||||||
|
if css.startswith('\\)', pos):
|
||||||
|
pos += 2
|
||||||
|
elif css[pos] == ')':
|
||||||
|
pos += 1
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
pos += 1
|
||||||
|
return None, pos # bad-url
|
||||||
|
|
||||||
|
|
||||||
|
def _consume_unicode_range(css, pos):
|
||||||
|
"""Return (range, new_pos)
|
||||||
|
|
||||||
|
The given pos is assume to be just after the '+' of 'U+' or 'u+'.
|
||||||
|
|
||||||
|
"""
|
||||||
|
# http://dev.w3.org/csswg/css-syntax/#consume-a-unicode-range-token
|
||||||
|
length = len(css)
|
||||||
|
start_pos = pos
|
||||||
|
max_pos = min(pos + 6, length)
|
||||||
|
while pos < max_pos and css[pos] in '0123456789abcdefABCDEF':
|
||||||
|
pos += 1
|
||||||
|
start = css[start_pos:pos]
|
||||||
|
|
||||||
|
start_pos = pos
|
||||||
|
# Same max_pos as before: total of hex digits and question marks <= 6
|
||||||
|
while pos < max_pos and css[pos] == '?':
|
||||||
|
pos += 1
|
||||||
|
question_marks = pos - start_pos
|
||||||
|
|
||||||
|
if question_marks:
|
||||||
|
end = start + 'F' * question_marks
|
||||||
|
start = start + '0' * question_marks
|
||||||
|
elif (pos + 1 < length and css[pos] == '-' and
|
||||||
|
css[pos + 1] in '0123456789abcdefABCDEF'):
|
||||||
|
pos += 1
|
||||||
|
start_pos = pos
|
||||||
|
max_pos = min(pos + 6, length)
|
||||||
|
while pos < max_pos and css[pos] in '0123456789abcdefABCDEF':
|
||||||
|
pos += 1
|
||||||
|
end = css[start_pos:pos]
|
||||||
|
else:
|
||||||
|
end = start
|
||||||
|
return int(start, 16), int(end, 16), pos
|
Loading…
Reference in New Issue