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