├── warning-example.png ├── docs ├── cilium-example.png ├── .doctrees │ ├── index.doctree │ └── environment.pickle ├── marshmallow-example.png ├── requirements.txt ├── get-involved.rst ├── releasing.rst ├── who-is-using-it.rst ├── installation.rst ├── configuration.rst ├── index.rst └── conf.py ├── versionwarning ├── __init__.py ├── extension.py ├── signals.py └── _static │ └── js │ ├── versionwarning.src.js │ └── versionwarning.js ├── MANIFEST.in ├── package.json ├── .readthedocs.yml ├── .gitignore ├── webpack.config.js ├── setup.py ├── LICENSE ├── README.rst └── CHANGELOG.rst /warning-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/humitos/sphinx-version-warning/HEAD/warning-example.png -------------------------------------------------------------------------------- /docs/cilium-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/humitos/sphinx-version-warning/HEAD/docs/cilium-example.png -------------------------------------------------------------------------------- /versionwarning/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | name = 'versionwarning' 3 | version = '1.1.2.dev0' 4 | -------------------------------------------------------------------------------- /docs/.doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/humitos/sphinx-version-warning/HEAD/docs/.doctrees/index.doctree -------------------------------------------------------------------------------- /docs/marshmallow-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/humitos/sphinx-version-warning/HEAD/docs/marshmallow-example.png -------------------------------------------------------------------------------- /docs/.doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/humitos/sphinx-version-warning/HEAD/docs/.doctrees/environment.pickle -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst 2 | include LICENSE 3 | include CHANGELOG.rst 4 | include versionwarning/_static/js/versionwarning.js 5 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx==1.8.5 2 | sphinx-prompt==1.1.0 3 | sphinx-tabs==1.1.11 4 | sphinx-rtd-theme==0.4.3 5 | sphinxemoji==0.1.3 6 | sphinx-autoapi==1.1.0 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sphinx-version-warning", 3 | "version": "1.1.2", 4 | "dependencies": { 5 | "semver": "^5.6.0", 6 | "webpack": "^4.24.0", 7 | "webpack-cli": "^3.1.2" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | image: latest 5 | 6 | python: 7 | version: 3 8 | install: 9 | - method: pip 10 | path: . 11 | - requirements: docs/requirements.txt 12 | 13 | sphinx: 14 | configuration: docs/conf.py 15 | 16 | formats: [] 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /example/_build 2 | /docs/_build 3 | /versionwarning/__pycache__ 4 | /build 5 | /dist 6 | /example/.doctrees 7 | /sphinx_version_warning.egg-info 8 | /versionwarning/_static/data/data.json 9 | /node_modules 10 | /package-lock.json 11 | *.pyc 12 | /versionwarning/_static/data 13 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | mode: 'production', 5 | entry: './versionwarning/_static/js/versionwarning.src.js', 6 | output: { 7 | path: path.resolve(__dirname, 'versionwarning/_static/js/'), 8 | filename: 'versionwarning.js' 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /docs/get-involved.rst: -------------------------------------------------------------------------------- 1 | Get Involved 2 | ============ 3 | 4 | We appreciate a lot your interest on getting involved in this small project! 5 | 6 | Please, if you want to collaborate with us, 7 | you can check out `the list of issues we have on GitHub`_ and comment there if you need further guidance or just send a Pull Request |:heart:|. 8 | 9 | .. _the list of issues we have on GitHub: https://github.com/humitos/sphinx-version-warning/issues 10 | -------------------------------------------------------------------------------- /docs/releasing.rst: -------------------------------------------------------------------------------- 1 | Releasing a new version 2 | ======================= 3 | 4 | These are the steps needed to release a new version: 5 | 6 | #. Increment the version in ``versionwarning/__init__.py`` 7 | #. Increment the version in ``package.json`` 8 | #. Update the ``CHANGELOG.rst`` 9 | #. Update ``npm``:: 10 | 11 | $ npm update 12 | 13 | #. Compile assets:: 14 | 15 | $ npm install 16 | $ ./node_modules/.bin/webpack 17 | 18 | #. Commit the changes: ``git commit -m "Release $NEW_VERSION"`` 19 | #. Tag the release in git: ``git tag $NEW_VERSION`` 20 | #. Push the tag to GitHub: ``git push --tags origin`` 21 | #. Upload the package to PyPI:: 22 | 23 | $ rm -rf dist/ 24 | $ python setup.py sdist bdist_wheel 25 | $ twine upload dist/* 26 | -------------------------------------------------------------------------------- /docs/who-is-using-it.rst: -------------------------------------------------------------------------------- 1 | Who Is Using It? 2 | ================ 3 | 4 | These are some projects using this extension 5 | that you can take a look at to understand how they are configured and what's the behavior. 6 | 7 | 8 | marshmallow 9 | ----------- 10 | 11 | * https://github.com/marshmallow-code/marshmallow 12 | * `Example URL `__ 13 | * `Configuration file `__ 14 | 15 | .. image:: marshmallow-example.png 16 | 17 | 18 | Cilium 19 | ------ 20 | 21 | * https://github.com/cilium/cilium 22 | * `Example URL `__ 23 | * `Configuration file `__ 24 | 25 | .. image:: cilium-example.png 26 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import setuptools 4 | import versionwarning 5 | 6 | with open('README.rst', 'r') as fh: 7 | long_description = fh.read() 8 | 9 | setuptools.setup( 10 | name='sphinx-version-warning', 11 | version=versionwarning.version, 12 | author='Manuel Kaufmann', 13 | author_email='humitos@gmail.com', 14 | description='Sphinx extension to add a warning banner', 15 | url='https://github.com/humitos/sphinx-version-warning', 16 | packages=setuptools.find_packages(), 17 | long_description=long_description, 18 | long_description_content_type='text/x-rst', 19 | include_package_data=True, 20 | zip_safe=False, 21 | classifiers=( 22 | 'Programming Language :: Python :: 3', 23 | 'License :: OSI Approved :: MIT License', 24 | 'Operating System :: OS Independent', 25 | ), 26 | install_requires=[ 27 | 'sphinx', 28 | ], 29 | ) 30 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | Install the package 5 | 6 | .. tabs:: 7 | 8 | .. tab:: from PyPI 9 | 10 | .. prompt:: bash 11 | 12 | pip install sphinx-version-warning 13 | 14 | .. tab:: from GitHub 15 | 16 | .. prompt:: bash 17 | 18 | pip install git+https://github.com/humitos/sphinx-version-warning@master 19 | 20 | 21 | Once you have the package installed, 22 | you have to configure it on your Sphinx documentation. 23 | To do this, add this extension to your Sphinx's extensions in the ``conf.py`` file. 24 | 25 | .. code-block:: python 26 | 27 | # conf.py 28 | extensions = [ 29 | # ... other extensions here 30 | 'versionwarning.extension', 31 | ] 32 | 33 | 34 | After installing the package and adding the extension in the ``conf.py`` file, 35 | if you build the documentation of an old version on Read the Docs, 36 | you will see a nice banner pointing to your latest release. 37 | 38 | In case you want to show a customized banner in a specific version, 39 | see :doc:`configuration` setting. 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Manuel Kaufmann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | |PyPI version| |Docs badge| |License| 2 | 3 | sphinx-version-warning 4 | ====================== 5 | 6 | ``sphinx-version-warning`` is a Sphinx extension that allows you to show a Warning banner at the top of your documentation. 7 | By default, the banner is shown based on the version that is displayed compared (using SemVer_) with the latest version on the server. 8 | 9 | 10 | Installation 11 | ------------ 12 | 13 | :: 14 | 15 | pip install sphinx-version-warning 16 | 17 | 18 | Configuration 19 | ------------- 20 | 21 | Add this extension in your ``conf.py`` file as: 22 | 23 | .. code-block:: python 24 | 25 | extensions = [ 26 | # ... other extensions here 27 | 28 | 'versionwarning.extension', 29 | ] 30 | 31 | 32 | Documentation 33 | ------------- 34 | 35 | Check out the full documentation at https://sphinx-version-warning.readthedocs.io/ 36 | 37 | .. _SemVer: https://semver.org/ 38 | 39 | 40 | .. |PyPI version| image:: https://img.shields.io/pypi/v/sphinx-version-warning.svg 41 | :target: https://pypi.org/project/sphinx-version-warning 42 | :alt: Current PyPI version 43 | .. |Docs badge| image:: https://readthedocs.org/projects/sphinx-version-warning/badge/?version=latest 44 | :target: https://sphinx-version-warning.readthedocs.io/en/latest/?badge=latest 45 | :alt: Documentation status 46 | .. |License| image:: https://img.shields.io/github/license/humitos/sphinx-version-warning.svg 47 | :target: LICENSE 48 | :alt: Repository license 49 | -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | 1.1.2 2 | ----- 3 | 4 | :Date: 2018-11-03 5 | 6 | * Load JSON file in all the pages properly (https://github.com/humitos/sphinx-version-warning/pull/20) 7 | 8 | 1.1.1 9 | ----- 10 | 11 | :Date: 2018-10-31 12 | 13 | * Fix calling to ``coerce`` by ``semver.coerce`` 14 | 15 | 1.1.0 16 | ----- 17 | 18 | :Date: 2018-10-31 19 | 20 | * Support semver prefixed with ``v``, like ``v2.0.5`` (https://github.com/humitos/sphinx-version-warning/pull/16) 21 | 22 | 1.0.2 23 | ----- 24 | 25 | :Date: 2018-10-22 26 | 27 | * Fix a mistake when releasing 28 | 29 | 1.0.1 30 | ----- 31 | 32 | :Date: 2018-10-22 33 | 34 | * Fix compatibility between Sphinx 1.7 and Sphinx 1.8 35 | 36 | 37 | 1.0.0 38 | ----- 39 | 40 | :Date: 2018-10-21 41 | 42 | * Remove ability to add the warning banner statically 43 | 44 | * Make the banner more customizable (all the configs are included in the ``json`` file generated and available from Javascript) 45 | 46 | * Rename ``versionwarning_default_admonition_type`` by ``versionwarning_admonition_type`` 47 | 48 | * Rename ``versionwarning_body_default_selector`` by ``versionwarning_body_selector`` 49 | 50 | * Remove ``versionwarning_body_extra_selector`` 51 | 52 | * Refactor the code to avoid potential circular imports 53 | 54 | * Filter Read the Docs versions by ``active=True`` when retrieving versions 55 | 56 | 57 | 0.2.0 58 | ----- 59 | 60 | :Date: 2018-07-30 61 | 62 | * Use ``READTHEDOCS_PROJECT`` and ``READTHEDOCS_VERSION`` environment variables 63 | 64 | * Remove ``versionwarning_enabled`` config since it wasn't used and it's not necessary 65 | 66 | * Parse ``versionwarning_messages`` as reStructuredText (https://github.com/humitos/sphinx-version-warning/pull/7) 67 | 68 | 0.1.0 69 | ----- 70 | 71 | :Date: 2018-07-29 72 | 73 | * Make banner more configurable (https://github.com/humitos/sphinx-version-warning/pull/6). 74 | New configs (api_url, banner_html, banner_id_div, body_default_selector, body_extra_selector) were added. 75 | 76 | * Compatibility with Sphinx 1.7.x added 77 | 78 | 0.0.1 79 | ----- 80 | 81 | :Date: 2018-07-27 82 | 83 | * Initial release 84 | -------------------------------------------------------------------------------- /versionwarning/extension.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os 3 | import sphinx 4 | from versionwarning import version 5 | from .signals import generate_versionwarning_data_json 6 | 7 | 8 | def setup(app): 9 | default_message = 'You are not reading the most up to date version of this documentation. {newest} is the newest version.' 10 | 11 | banner_html = ''' 12 |
13 |

{banner_title}

14 |

15 | {message} 16 |

17 |
''' 18 | 19 | app.add_config_value('versionwarning_message_placeholder', 'newest', 'html') 20 | app.add_config_value('versionwarning_admonition_type', 'warning', 'html') 21 | app.add_config_value('versionwarning_default_message', default_message, 'html') 22 | app.add_config_value('versionwarning_messages', {}, 'html') 23 | 24 | app.add_config_value('versionwarning_api_url', 'https://readthedocs.org/api/v2/', 'html') 25 | app.add_config_value('versionwarning_banner_html', banner_html, 'html') 26 | app.add_config_value('versionwarning_banner_id_div', 'version-warning-banner', 'html') 27 | app.add_config_value('versionwarning_banner_title', 'Warning', 'html') 28 | app.add_config_value('versionwarning_body_selector', 'div.body', 'html') 29 | app.add_config_value('versionwarning_project_slug', os.environ.get('READTHEDOCS_PROJECT', None), 'html') 30 | app.add_config_value('versionwarning_project_version', os.environ.get('READTHEDOCS_VERSION', None), 'html') 31 | 32 | if sphinx.version_info >= (1, 8): 33 | # ``config-initied`` requires Sphinx >= 1.8 34 | app.connect('config-inited', generate_versionwarning_data_json) 35 | 36 | # ``add_js_file`` requires Sphinx >= 1.8 37 | app.add_js_file('js/versionwarning.js') 38 | else: 39 | app.connect('builder-inited', generate_versionwarning_data_json) 40 | app.add_javascript('js/versionwarning.js') 41 | 42 | return { 43 | 'version': version, 44 | 'env_version': 1, 45 | 'parallel_read_safe': True, 46 | 'parallel_write_safe': True, 47 | } 48 | -------------------------------------------------------------------------------- /versionwarning/signals.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import json 4 | import os 5 | 6 | 7 | STATIC_PATH = os.path.join(os.path.dirname(__file__), '_static') 8 | JSON_DATA_FILENAME = 'versionwarning-data.json' 9 | 10 | 11 | def generate_versionwarning_data_json(app, config=None, **kwargs): 12 | """ 13 | Generate the ``versionwarning-data.json`` file. 14 | 15 | This file is included in the output and read by the AJAX request when 16 | accessing to the documentation and used to compare the live versions with 17 | the curent one. 18 | 19 | Besides, this file contains meta data about the project, the API to use and 20 | the banner itself. 21 | """ 22 | 23 | # In Sphinx >= 1.8 we use ``config-initied`` signal which comes with the 24 | # ``config`` object and in Sphinx < 1.8 we use ``builder-initied`` signal 25 | # that doesn't have the ``config`` object and we take it from the ``app`` 26 | config = config or kwargs.pop('config', None) 27 | if config is None: 28 | config = app.config 29 | 30 | if config.versionwarning_project_version in config.versionwarning_messages: 31 | custom = True 32 | message = config.versionwarning_messages.get(config.versionwarning_project_version) 33 | else: 34 | custom = False 35 | message = config.versionwarning_default_message 36 | 37 | banner_html = config.versionwarning_banner_html.format( 38 | id_div=config.versionwarning_banner_id_div, 39 | banner_title=config.versionwarning_banner_title, 40 | message=message.format( 41 | **{config.versionwarning_message_placeholder: ''}, 42 | ), 43 | admonition_type=config.versionwarning_admonition_type, 44 | ) 45 | 46 | data = json.dumps({ 47 | 'meta': { 48 | 'api_url': config.versionwarning_api_url, 49 | }, 50 | 'banner': { 51 | 'html': banner_html, 52 | 'id_div': config.versionwarning_banner_id_div, 53 | 'body_selector': config.versionwarning_body_selector, 54 | 'custom': custom, 55 | }, 56 | 'project': { 57 | 'slug': config.versionwarning_project_slug, 58 | }, 59 | 'version': { 60 | 'slug': config.versionwarning_project_version, 61 | }, 62 | }, indent=4) 63 | 64 | data_path = os.path.join(STATIC_PATH, 'data') 65 | if not os.path.exists(data_path): 66 | os.mkdir(data_path) 67 | 68 | with open(os.path.join(data_path, JSON_DATA_FILENAME), 'w') as f: 69 | f.write(data) 70 | 71 | # Add the path where ``versionwarning-data.json`` file and 72 | # ``versionwarning.js`` are saved 73 | config.html_static_path.append(STATIC_PATH) 74 | -------------------------------------------------------------------------------- /docs/configuration.rst: -------------------------------------------------------------------------------- 1 | Configuration 2 | ============= 3 | 4 | Here is the list of configurations that you can change to make the banner behaves as you want. 5 | You can customize these options in your ``conf.py`` file: 6 | 7 | .. confval:: versionwarning_admonition_type 8 | 9 | Description: Admonition node type used to render the banner. ``warning``, ``admonition``, ``tip`` or ``note``. 10 | 11 | Default: ``'warning'`` 12 | 13 | Type: string 14 | 15 | .. confval:: versionwarning_banner_title 16 | 17 | Description: Title used in the banner. 18 | 19 | Default: ``'Warning'`` 20 | 21 | Type: string 22 | 23 | .. confval:: versionwarning_default_message 24 | 25 | Description: Default message shown in the banner. 26 | 27 | Default: ``'You are not reading the most up to date version of this documentation. {newest} is the newest version.'`` 28 | 29 | Type: string 30 | 31 | .. confval:: versionwarning_messages 32 | 33 | Description: Mapping between versions and a specific messages for its banners. 34 | 35 | Default: ``{}`` 36 | 37 | Type: dict 38 | 39 | .. confval:: versionwarning_message_placeholder 40 | 41 | Description: Text to be replaced by the version number link from the message 42 | 43 | Default: ``'newest'`` 44 | 45 | Type: string 46 | 47 | .. confval:: versionwarning_project_slug 48 | 49 | Description: Slug of the project under Read the Docs. 50 | 51 | Default: ``READTHEDOCS_PROJECT`` environment variable. 52 | 53 | Type: string 54 | 55 | .. confval:: versionwarning_project_version 56 | 57 | Description: Slug of the version for the current documentation. 58 | 59 | Default: ``READTHEDOCS_VERSION`` environment variable. 60 | 61 | Type: string 62 | 63 | .. confval:: versionwarning_api_url 64 | 65 | Description: API URL to retrieve all versions for this project. 66 | 67 | Default: ``https://readthedocs.org/api/v2/`` 68 | 69 | Type: string 70 | 71 | .. confval:: versionwarning_banner_html 72 | 73 | Description: HTML code used for the banner shown 74 | 75 | Default: 76 | 77 | .. code:: html 78 | 79 |
80 |

{banner_title}

81 |

82 | {message} 83 |

84 |
85 | 86 | Type: string 87 | 88 | 89 | .. confval:: versionwarning_banner_id_div 90 | 91 | Description: HTML element ID used for the
inject as banner 92 | 93 | Default: ``version-warning-banner`` 94 | 95 | Type: string 96 | 97 | .. confval:: versionwarning_body_selector 98 | 99 | Description: jQuery selector to find the body element in the page and *prepend* the banner 100 | 101 | Default: ``div.body`` 102 | 103 | Type: string 104 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to sphinx-version-warning! 2 | ================================== 3 | 4 | ``sphinx-version-warning`` is a Sphinx extension that allows you to show a Warning banner at the top of your documentation. 5 | By default, the banner is shown based on the version that is displayed compared (using SemVer_) with the latest version on the server. 6 | 7 | 8 | Online documentation: 9 | https://sphinx-version-warning.readthedocs.io/ 10 | 11 | Source code repository (and issue tracker): 12 | https://github.com/humitos/sphinx-version-warning/ 13 | 14 | Badges: 15 | |PyPI version| |Docs badge| |License| 16 | 17 | Why do I need this extension? 18 | ----------------------------- 19 | 20 | You *probably* don't. 21 | 22 | Read the Docs `implements this feature by itself`_ adding a banner for you in old versions. 23 | 24 | Although, comparing this extension with Read the Docs' core functionality, 25 | ``sphinx-version-warning`` allows the user to highly customize the banner by changing the message, 26 | the style, the position, etc. which is not possible with Read the Docs feature. 27 | 28 | The default settings behaves in the same manner that Read the Docs' core functionality, 29 | so you will want to check out :doc:`configuration` for a better customization. 30 | 31 | .. note:: 32 | 33 | This extension was inspired by `this comment`_ on the Read the Docs issue tracker, 34 | where some discussions about what was missing from Read the Docs' feature took place. 35 | 36 | 37 | How does it work? 38 | ----------------- 39 | 40 | When visiting a page in Read the Docs that was built with this extension enabled, 41 | an AJAX request is done to the `Read the Docs Public API`_ to retrieve all the **active versions** of the project. 42 | These versions are compared against the one that the user is reading and if it's an old version, 43 | a *warning banner* appears at the top of the page. 44 | 45 | 46 | .. toctree:: 47 | :maxdepth: 1 48 | :caption: Contents 49 | 50 | installation 51 | configuration 52 | get-involved 53 | who-is-using-it 54 | releasing 55 | 56 | .. toctree:: 57 | :maxdepth: 1 58 | :caption: API Reference 59 | 60 | autoapi/versionwarning/index 61 | 62 | .. _SemVer: https://semver.org/ 63 | .. _Read the Docs Public API: https://docs.readthedocs.io/page/api/v2.html 64 | .. _implements this feature by itself: https://docs.readthedocs.io/page/versions.html#version-warning 65 | .. _this comment: https://github.com/readthedocs/readthedocs.org/issues/3481#issuecomment-378000845 66 | 67 | .. |PyPI version| image:: https://img.shields.io/pypi/v/sphinx-version-warning.svg 68 | :target: https://pypi.org/project/sphinx-version-warning 69 | :alt: Current PyPI version 70 | .. |Docs badge| image:: https://readthedocs.org/projects/sphinx-version-warning/badge/?version=latest 71 | :target: https://sphinx-version-warning.readthedocs.io/en/latest/?badge=latest 72 | :alt: Documentation status 73 | .. |License| image:: https://img.shields.io/github/license/humitos/sphinx-version-warning.svg 74 | :target: LICENSE 75 | :alt: Repository license 76 | -------------------------------------------------------------------------------- /versionwarning/_static/js/versionwarning.src.js: -------------------------------------------------------------------------------- 1 | const semver = require('semver'); 2 | 3 | function injectVersionWarningBanner(running_version, version, config) { 4 | console.debug("injectVersionWarningBanner"); 5 | var version_url = window.location.pathname.replace(running_version.slug, version.slug); 6 | var warning = $(config.banner.html); 7 | 8 | warning 9 | .find("a") 10 | .attr("href", version_url) 11 | .text(version.slug); 12 | 13 | var body = $(config.banner.body_selector); 14 | body.prepend(warning); 15 | } 16 | 17 | 18 | function injectCustomWarningBanner(config) { 19 | console.debug("injectCustomWarningBanner"); 20 | var warning = $(config.banner.html); 21 | var body = $(config.banner.body_selector); 22 | body.prepend(warning); 23 | } 24 | 25 | 26 | function getHighestVersion(versions) { 27 | console.debug("getHighestVersion"); 28 | var highest_version; 29 | 30 | $.each(versions, function (i, version) { 31 | if (!semver.valid(semver.coerce(version.slug))) { 32 | // Skip versions that are not valid 33 | } 34 | else if (!highest_version) { 35 | highest_version = version; 36 | } 37 | else if ( 38 | semver.valid(semver.coerce(version.slug)) && semver.valid(semver.coerce(highest_version.slug)) && 39 | semver.gt(semver.coerce(version.slug), semver.coerce(highest_version.slug))) { 40 | highest_version = version; 41 | } 42 | }); 43 | return highest_version; 44 | } 45 | 46 | 47 | function checkVersion(config) { 48 | console.debug("checkVersion"); 49 | var running_version = config.version; 50 | console.debug("Running version: " + running_version.slug); 51 | 52 | var get_data = { 53 | project__slug: config.project.slug, 54 | active: "true" 55 | // format: "jsonp", 56 | }; 57 | 58 | $.ajax({ 59 | url: config.meta.api_url + "version/", 60 | // Used when working locally for development 61 | // crossDomain: true, 62 | // xhrFields: { 63 | // withCredentials: true, 64 | // }, 65 | // dataType: "jsonp", 66 | data: get_data, 67 | success: function (versions) { 68 | // TODO: fetch more versions if there are more pages (next) 69 | highest_version = getHighestVersion(versions["results"]); 70 | if ( 71 | semver.valid(semver.coerce(running_version.slug)) && semver.valid(semver.coerce(highest_version.slug)) && 72 | semver.lt(semver.coerce(running_version.slug), semver.coerce(highest_version.slug))) { 73 | console.debug("Highest version: " + highest_version.slug); 74 | injectVersionWarningBanner(running_version, highest_version, config); 75 | } 76 | }, 77 | error: function () { 78 | console.error("Error loading Read the Docs active versions."); 79 | } 80 | }); 81 | } 82 | 83 | function init() { 84 | console.debug("init"); 85 | // get the base_url so we can get the versionwarning-data.json from 86 | // any page. 87 | var base_url = $('script[src*=versionwarning]').attr('src'); 88 | base_url = base_url.replace('versionwarning.js', ''); 89 | $.ajax({ 90 | url: base_url + "../../_static/data/versionwarning-data.json", 91 | success: function(config) { 92 | // Check if there is already a banner added statically 93 | var banner = document.getElementById(config.banner.id_div); 94 | if (banner) { 95 | console.debug("There is already a banner added. No checking versions.") 96 | } 97 | else if (config.banner.custom) { 98 | injectCustomWarningBanner(config); 99 | } 100 | else { 101 | checkVersion(config); 102 | } 103 | }, 104 | error: function() { 105 | console.error("Error loading versionwarning-data.json"); 106 | }, 107 | }) 108 | } 109 | 110 | 111 | $(document).ready(function () { 112 | init(); 113 | }); 114 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Configuration file for the Sphinx documentation builder. 4 | # 5 | # This file does only contain a selection of the most common options. For a 6 | # full list see the documentation: 7 | # http://www.sphinx-doc.org/en/master/config 8 | 9 | # -- Path setup -------------------------------------------------------------- 10 | 11 | # If extensions (or modules to document with autodoc) are in another directory, 12 | # add these directories to sys.path here. If the directory is relative to the 13 | # documentation root, use os.path.abspath to make it absolute, like shown here. 14 | # 15 | # import os 16 | # import sys 17 | # sys.path.insert(0, os.path.abspath('.')) 18 | 19 | 20 | # -- Project information ----------------------------------------------------- 21 | 22 | project = 'sphinx-version-warning' 23 | copyright = '2019, Manuel Kaufmann' 24 | author = 'Manuel Kaufmann' 25 | 26 | # The short X.Y version 27 | # The full version, including alpha/beta/rc tags 28 | import versionwarning 29 | version = release = versionwarning.version 30 | 31 | 32 | # -- Version Warning Banner configuration ------------------------------------ 33 | versionwarning_messages = { 34 | 'latest': 'This is a custom message only for version "latest" of this documentation.', 35 | } 36 | versionwarning_admonition_type = 'tip' 37 | versionwarning_banner_title = 'Tip' 38 | versionwarning_body_selector = 'div[itemprop="articleBody"]' 39 | 40 | # -- General configuration --------------------------------------------------- 41 | 42 | # If your documentation needs a minimal Sphinx version, state it here. 43 | # 44 | # needs_sphinx = '1.0' 45 | 46 | # Add any Sphinx extension module names here, as strings. They can be 47 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 48 | # ones. 49 | extensions = [ 50 | 'versionwarning.extension', 51 | 'autoapi.extension', 52 | 'sphinx_rtd_theme', 53 | 'sphinx_tabs.tabs', 54 | 'sphinx-prompt', 55 | 'sphinxemoji.sphinxemoji', 56 | ] 57 | 58 | autoapi_dirs = ['../versionwarning'] 59 | autoapi_add_toctree_entry = False 60 | 61 | # Add any paths that contain templates here, relative to this directory. 62 | templates_path = ['_templates'] 63 | 64 | # The suffix(es) of source filenames. 65 | # You can specify multiple suffix as a list of string: 66 | # 67 | # source_suffix = ['.rst', '.md'] 68 | source_suffix = '.rst' 69 | 70 | # The master toctree document. 71 | master_doc = 'index' 72 | 73 | # The language for content autogenerated by Sphinx. Refer to documentation 74 | # for a list of supported languages. 75 | # 76 | # This is also used if you do content translation via gettext catalogs. 77 | # Usually you set "language" from the command line for these cases. 78 | language = None 79 | 80 | # List of patterns, relative to source directory, that match files and 81 | # directories to ignore when looking for source files. 82 | # This pattern also affects html_static_path and html_extra_path. 83 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 84 | 85 | # The name of the Pygments (syntax highlighting) style to use. 86 | pygments_style = 'sphinx' 87 | 88 | 89 | # -- Options for HTML output ------------------------------------------------- 90 | 91 | # The theme to use for HTML and HTML Help pages. See the documentation for 92 | # a list of builtin themes. 93 | # 94 | html_theme = 'sphinx_rtd_theme' 95 | 96 | # Theme options are theme-specific and customize the look and feel of a theme 97 | # further. For a list of options available for each theme, see the 98 | # documentation. 99 | # 100 | # html_theme_options = {} 101 | 102 | # Add any paths that contain custom static files (such as style sheets) here, 103 | # relative to this directory. They are copied after the builtin static files, 104 | # so a file named "default.css" will overwrite the builtin "default.css". 105 | html_static_path = ['_static'] 106 | 107 | # Custom sidebar templates, must be a dictionary that maps document names 108 | # to template names. 109 | # 110 | # The default sidebars (for documents that don't match any pattern) are 111 | # defined by theme itself. Builtin themes are using these templates by 112 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', 113 | # 'searchbox.html']``. 114 | # 115 | # html_sidebars = {} 116 | 117 | 118 | # -- Options for HTMLHelp output --------------------------------------------- 119 | 120 | # Output file base name for HTML help builder. 121 | htmlhelp_basename = 'SphinxVersionWarningdoc' 122 | 123 | 124 | # -- Options for LaTeX output ------------------------------------------------ 125 | 126 | latex_elements = { 127 | # The paper size ('letterpaper' or 'a4paper'). 128 | # 129 | # 'papersize': 'letterpaper', 130 | 131 | # The font size ('10pt', '11pt' or '12pt'). 132 | # 133 | # 'pointsize': '10pt', 134 | 135 | # Additional stuff for the LaTeX preamble. 136 | # 137 | # 'preamble': '', 138 | 139 | # Latex figure (float) alignment 140 | # 141 | # 'figure_align': 'htbp', 142 | } 143 | 144 | # Grouping the document tree into LaTeX files. List of tuples 145 | # (source start file, target name, title, 146 | # author, documentclass [howto, manual, or own class]). 147 | latex_documents = [ 148 | (master_doc, 'SphinxVersionWarning.tex', 'Sphinx Version Warning Documentation', 149 | 'Manuel Kaufmann', 'manual'), 150 | ] 151 | 152 | 153 | # -- Options for manual page output ------------------------------------------ 154 | 155 | # One entry per manual page. List of tuples 156 | # (source start file, name, description, authors, manual section). 157 | man_pages = [ 158 | (master_doc, 'sphinxversionwarning', 'Sphinx Version Warning Documentation', 159 | [author], 1) 160 | ] 161 | 162 | 163 | # -- Options for Texinfo output ---------------------------------------------- 164 | 165 | # Grouping the document tree into Texinfo files. List of tuples 166 | # (source start file, target name, title, author, 167 | # dir menu entry, description, category) 168 | texinfo_documents = [ 169 | (master_doc, 'SphinxVersionWarning', 'Sphinx Version Warning Documentation', 170 | author, 'SphinxVersionWarning', 'One line description of project.', 171 | 'Miscellaneous'), 172 | ] 173 | 174 | def setup(app): 175 | app.add_object_type('confval', 'confval', 176 | 'pair: %s; configuration value') 177 | -------------------------------------------------------------------------------- /versionwarning/_static/js/versionwarning.js: -------------------------------------------------------------------------------- 1 | !function(e){var r={};function t(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=e,t.c=r,t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:n})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,r){if(1&r&&(e=t(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(t.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var o in e)t.d(n,o,function(r){return e[r]}.bind(null,o));return n},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},t.p="",t(t.s=0)}([function(e,r,t){const n=t(1);function o(e){console.debug("checkVersion");var r=e.version;console.debug("Running version: "+r.slug);var t={project__slug:e.project.slug,active:"true"};$.ajax({url:e.meta.api_url+"version/",data:t,success:function(t){highest_version=function(e){var r;return console.debug("getHighestVersion"),$.each(e,function(e,t){n.valid(n.coerce(t.slug))&&(r?n.valid(n.coerce(t.slug))&&n.valid(n.coerce(r.slug))&&n.gt(n.coerce(t.slug),n.coerce(r.slug))&&(r=t):r=t)}),r}(t.results),n.valid(n.coerce(r.slug))&&n.valid(n.coerce(highest_version.slug))&&n.lt(n.coerce(r.slug),n.coerce(highest_version.slug))&&(console.debug("Highest version: "+highest_version.slug),function(e,r,t){console.debug("injectVersionWarningBanner");var n=window.location.pathname.replace(e.slug,r.slug),o=$(t.banner.html);o.find("a").attr("href",n).text(r.slug),$(t.banner.body_selector).prepend(o)}(r,highest_version,e))},error:function(){console.error("Error loading Read the Docs active versions.")}})}function i(){console.debug("init");var e=$("script[src*=versionwarning]").attr("src");e=e.replace("versionwarning.js",""),$.ajax({url:e+"../../_static/data/versionwarning-data.json",success:function(e){document.getElementById(e.banner.id_div)?console.debug("There is already a banner added. No checking versions."):e.banner.custom?function(e){console.debug("injectCustomWarningBanner");var r=$(e.banner.html);$(e.banner.body_selector).prepend(r)}(e):o(e)},error:function(){console.error("Error loading versionwarning-data.json")}})}$(document).ready(function(){i()})},function(e,r,t){(function(t){var n;r=e.exports=W,n="object"==typeof t&&t.env&&t.env.NODE_DEBUG&&/\bsemver\b/i.test(t.env.NODE_DEBUG)?function(){var e=Array.prototype.slice.call(arguments,0);e.unshift("SEMVER"),console.log.apply(console,e)}:function(){},r.SEMVER_SPEC_VERSION="2.0.0";var o=256,i=Number.MAX_SAFE_INTEGER||9007199254740991,s=r.re=[],a=r.src=[],u=0,c=u++;a[c]="0|[1-9]\\d*";var l=u++;a[l]="[0-9]+";var p=u++;a[p]="\\d*[a-zA-Z-][a-zA-Z0-9-]*";var h=u++;a[h]="("+a[c]+")\\.("+a[c]+")\\.("+a[c]+")";var f=u++;a[f]="("+a[l]+")\\.("+a[l]+")\\.("+a[l]+")";var v=u++;a[v]="(?:"+a[c]+"|"+a[p]+")";var m=u++;a[m]="(?:"+a[l]+"|"+a[p]+")";var g=u++;a[g]="(?:-("+a[v]+"(?:\\."+a[v]+")*))";var d=u++;a[d]="(?:-?("+a[m]+"(?:\\."+a[m]+")*))";var w=u++;a[w]="[0-9A-Za-z-]+";var y=u++;a[y]="(?:\\+("+a[w]+"(?:\\."+a[w]+")*))";var b=u++,j="v?"+a[h]+a[g]+"?"+a[y]+"?";a[b]="^"+j+"$";var E="[v=\\s]*"+a[f]+a[d]+"?"+a[y]+"?",T=u++;a[T]="^"+E+"$";var $=u++;a[$]="((?:<|>)?=?)";var _=u++;a[_]=a[l]+"|x|X|\\*";var k=u++;a[k]=a[c]+"|x|X|\\*";var x=u++;a[x]="[v=\\s]*("+a[k]+")(?:\\.("+a[k]+")(?:\\.("+a[k]+")(?:"+a[g]+")?"+a[y]+"?)?)?";var P=u++;a[P]="[v=\\s]*("+a[_]+")(?:\\.("+a[_]+")(?:\\.("+a[_]+")(?:"+a[d]+")?"+a[y]+"?)?)?";var S=u++;a[S]="^"+a[$]+"\\s*"+a[x]+"$";var R=u++;a[R]="^"+a[$]+"\\s*"+a[P]+"$";var I=u++;a[I]="(?:^|[^\\d])(\\d{1,16})(?:\\.(\\d{1,16}))?(?:\\.(\\d{1,16}))?(?:$|[^\\d])";var V=u++;a[V]="(?:~>?)";var O=u++;a[O]="(\\s*)"+a[V]+"\\s+",s[O]=new RegExp(a[O],"g");var A=u++;a[A]="^"+a[V]+a[x]+"$";var M=u++;a[M]="^"+a[V]+a[P]+"$";var C=u++;a[C]="(?:\\^)";var N=u++;a[N]="(\\s*)"+a[C]+"\\s+",s[N]=new RegExp(a[N],"g");var L=u++;a[L]="^"+a[C]+a[x]+"$";var B=u++;a[B]="^"+a[C]+a[P]+"$";var D=u++;a[D]="^"+a[$]+"\\s*("+E+")$|^$";var q=u++;a[q]="^"+a[$]+"\\s*("+j+")$|^$";var X=u++;a[X]="(\\s*)"+a[$]+"\\s*("+E+"|"+a[x]+")",s[X]=new RegExp(a[X],"g");var z=u++;a[z]="^\\s*("+a[x]+")\\s+-\\s+("+a[x]+")\\s*$";var G=u++;a[G]="^\\s*("+a[P]+")\\s+-\\s+("+a[P]+")\\s*$";var Z=u++;a[Z]="(<|>)?=?\\s*\\*";for(var H=0;Ho)return null;if(!(r.loose?s[T]:s[b]).test(e))return null;try{return new W(e,r)}catch(e){return null}}function W(e,r){if(r&&"object"==typeof r||(r={loose:!!r,includePrerelease:!1}),e instanceof W){if(e.loose===r.loose)return e;e=e.version}else if("string"!=typeof e)throw new TypeError("Invalid Version: "+e);if(e.length>o)throw new TypeError("version is longer than "+o+" characters");if(!(this instanceof W))return new W(e,r);n("SemVer",e,r),this.options=r,this.loose=!!r.loose;var t=e.trim().match(r.loose?s[T]:s[b]);if(!t)throw new TypeError("Invalid Version: "+e);if(this.raw=e,this.major=+t[1],this.minor=+t[2],this.patch=+t[3],this.major>i||this.major<0)throw new TypeError("Invalid major version");if(this.minor>i||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>i||this.patch<0)throw new TypeError("Invalid patch version");t[4]?this.prerelease=t[4].split(".").map(function(e){if(/^[0-9]+$/.test(e)){var r=+e;if(r>=0&&r=0;)"number"==typeof this.prerelease[t]&&(this.prerelease[t]++,t=-2);-1===t&&this.prerelease.push(0)}r&&(this.prerelease[0]===r?isNaN(this.prerelease[1])&&(this.prerelease=[r,0]):this.prerelease=[r,0]);break;default:throw new Error("invalid increment argument: "+e)}return this.format(),this.raw=this.version,this},r.inc=function(e,r,t,n){"string"==typeof t&&(n=t,t=void 0);try{return new W(e,t).inc(r,n).version}catch(e){return null}},r.diff=function(e,r){if(ee(e,r))return null;var t=U(e),n=U(r);if(t.prerelease.length||n.prerelease.length){for(var o in t)if(("major"===o||"minor"===o||"patch"===o)&&t[o]!==n[o])return"pre"+o;return"prerelease"}for(var o in t)if(("major"===o||"minor"===o||"patch"===o)&&t[o]!==n[o])return o},r.compareIdentifiers=J;var F=/^[0-9]+$/;function J(e,r){var t=F.test(e),n=F.test(r);return t&&n&&(e=+e,r=+r),t&&!n?-1:n&&!t?1:er?1:0}function K(e,r,t){return new W(e,t).compare(new W(r,t))}function Q(e,r,t){return K(e,r,t)>0}function Y(e,r,t){return K(e,r,t)<0}function ee(e,r,t){return 0===K(e,r,t)}function re(e,r,t){return 0!==K(e,r,t)}function te(e,r,t){return K(e,r,t)>=0}function ne(e,r,t){return K(e,r,t)<=0}function oe(e,r,t,n){var o;switch(r){case"===":"object"==typeof e&&(e=e.version),"object"==typeof t&&(t=t.version),o=e===t;break;case"!==":"object"==typeof e&&(e=e.version),"object"==typeof t&&(t=t.version),o=e!==t;break;case"":case"=":case"==":o=ee(e,t,n);break;case"!=":o=re(e,t,n);break;case">":o=Q(e,t,n);break;case">=":o=te(e,t,n);break;case"<":o=Y(e,t,n);break;case"<=":o=ne(e,t,n);break;default:throw new TypeError("Invalid operator: "+r)}return o}function ie(e,r){if(r&&"object"==typeof r||(r={loose:!!r,includePrerelease:!1}),e instanceof ie){if(e.loose===!!r.loose)return e;e=e.value}if(!(this instanceof ie))return new ie(e,r);n("comparator",e,r),this.options=r,this.loose=!!r.loose,this.parse(e),this.semver===se?this.value="":this.value=this.operator+this.semver.version,n("comp",this)}r.rcompareIdentifiers=function(e,r){return J(r,e)},r.major=function(e,r){return new W(e,r).major},r.minor=function(e,r){return new W(e,r).minor},r.patch=function(e,r){return new W(e,r).patch},r.compare=K,r.compareLoose=function(e,r){return K(e,r,!0)},r.rcompare=function(e,r,t){return K(r,e,t)},r.sort=function(e,t){return e.sort(function(e,n){return r.compare(e,n,t)})},r.rsort=function(e,t){return e.sort(function(e,n){return r.rcompare(e,n,t)})},r.gt=Q,r.lt=Y,r.eq=ee,r.neq=re,r.gte=te,r.lte=ne,r.cmp=oe,r.Comparator=ie;var se={};function ae(e,r){if(r&&"object"==typeof r||(r={loose:!!r,includePrerelease:!1}),e instanceof ae)return e.loose===!!r.loose&&e.includePrerelease===!!r.includePrerelease?e:new ae(e.raw,r);if(e instanceof ie)return new ae(e.value,r);if(!(this instanceof ae))return new ae(e,r);if(this.options=r,this.loose=!!r.loose,this.includePrerelease=!!r.includePrerelease,this.raw=e,this.set=e.split(/\s*\|\|\s*/).map(function(e){return this.parseRange(e.trim())},this).filter(function(e){return e.length}),!this.set.length)throw new TypeError("Invalid SemVer Range: "+e);this.format()}function ue(e){return!e||"x"===e.toLowerCase()||"*"===e}function ce(e,r,t,n,o,i,s,a,u,c,l,p,h){return((r=ue(t)?"":ue(n)?">="+t+".0.0":ue(o)?">="+t+"."+n+".0":">="+r)+" "+(a=ue(u)?"":ue(c)?"<"+(+u+1)+".0.0":ue(l)?"<"+u+"."+(+c+1)+".0":p?"<="+u+"."+c+"."+l+"-"+p:"<="+a)).trim()}function le(e,r,t){for(var o=0;o0){var i=e[o].semver;if(i.major===r.major&&i.minor===r.minor&&i.patch===r.patch)return!0}return!1}return!0}function pe(e,r,t){try{r=new ae(r,t)}catch(e){return!1}return r.test(e)}function he(e,r,t,n){var o,i,s,a,u;switch(e=new W(e,n),r=new ae(r,n),t){case">":o=Q,i=ne,s=Y,a=">",u=">=";break;case"<":o=Y,i=te,s=Q,a="<",u="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(pe(e,r,n))return!1;for(var c=0;c=0.0.0")),l=l||e,p=p||e,o(e.semver,l.semver,n)?l=e:s(e.semver,p.semver,n)&&(p=e)}),l.operator===a||l.operator===u)return!1;if((!p.operator||p.operator===a)&&i(e,p.semver))return!1;if(p.operator===u&&s(e,p.semver))return!1}return!0}ie.prototype.parse=function(e){var r=this.options.loose?s[D]:s[q],t=e.match(r);if(!t)throw new TypeError("Invalid comparator: "+e);this.operator=t[1],"="===this.operator&&(this.operator=""),t[2]?this.semver=new W(t[2],this.options.loose):this.semver=se},ie.prototype.toString=function(){return this.value},ie.prototype.test=function(e){return n("Comparator.test",e,this.options.loose),this.semver===se||("string"==typeof e&&(e=new W(e,this.options)),oe(e,this.operator,this.semver,this.options))},ie.prototype.intersects=function(e,r){if(!(e instanceof ie))throw new TypeError("a Comparator is required");var t;if(r&&"object"==typeof r||(r={loose:!!r,includePrerelease:!1}),""===this.operator)return t=new ae(e.value,r),pe(this.value,t,r);if(""===e.operator)return t=new ae(this.value,r),pe(e.semver,t,r);var n=!(">="!==this.operator&&">"!==this.operator||">="!==e.operator&&">"!==e.operator),o=!("<="!==this.operator&&"<"!==this.operator||"<="!==e.operator&&"<"!==e.operator),i=this.semver.version===e.semver.version,s=!(">="!==this.operator&&"<="!==this.operator||">="!==e.operator&&"<="!==e.operator),a=oe(this.semver,"<",e.semver,r)&&(">="===this.operator||">"===this.operator)&&("<="===e.operator||"<"===e.operator),u=oe(this.semver,">",e.semver,r)&&("<="===this.operator||"<"===this.operator)&&(">="===e.operator||">"===e.operator);return n||o||i&&s||a||u},r.Range=ae,ae.prototype.format=function(){return this.range=this.set.map(function(e){return e.join(" ").trim()}).join("||").trim(),this.range},ae.prototype.toString=function(){return this.range},ae.prototype.parseRange=function(e){var r=this.options.loose;e=e.trim();var t=r?s[G]:s[z];e=e.replace(t,ce),n("hyphen replace",e),e=e.replace(s[X],"$1$2$3"),n("comparator trim",e,s[X]),e=(e=(e=e.replace(s[O],"$1~")).replace(s[N],"$1^")).split(/\s+/).join(" ");var o=r?s[D]:s[q],i=e.split(" ").map(function(e){return function(e,r){return n("comp",e,r),e=function(e,r){return e.trim().split(/\s+/).map(function(e){return function(e,r){n("caret",e,r),r&&"object"==typeof r||(r={loose:!!r,includePrerelease:!1});var t=r.loose?s[B]:s[L];return e.replace(t,function(r,t,o,i,s){var a;return n("caret",e,r,t,o,i,s),ue(t)?a="":ue(o)?a=">="+t+".0.0 <"+(+t+1)+".0.0":ue(i)?a="0"===t?">="+t+"."+o+".0 <"+t+"."+(+o+1)+".0":">="+t+"."+o+".0 <"+(+t+1)+".0.0":s?(n("replaceCaret pr",s),"-"!==s.charAt(0)&&(s="-"+s),a="0"===t?"0"===o?">="+t+"."+o+"."+i+s+" <"+t+"."+o+"."+(+i+1):">="+t+"."+o+"."+i+s+" <"+t+"."+(+o+1)+".0":">="+t+"."+o+"."+i+s+" <"+(+t+1)+".0.0"):(n("no pr"),a="0"===t?"0"===o?">="+t+"."+o+"."+i+" <"+t+"."+o+"."+(+i+1):">="+t+"."+o+"."+i+" <"+t+"."+(+o+1)+".0":">="+t+"."+o+"."+i+" <"+(+t+1)+".0.0"),n("caret return",a),a})}(e,r)}).join(" ")}(e,r),n("caret",e),e=function(e,r){return e.trim().split(/\s+/).map(function(e){return function(e,r){r&&"object"==typeof r||(r={loose:!!r,includePrerelease:!1});var t=r.loose?s[M]:s[A];return e.replace(t,function(r,t,o,i,s){var a;return n("tilde",e,r,t,o,i,s),ue(t)?a="":ue(o)?a=">="+t+".0.0 <"+(+t+1)+".0.0":ue(i)?a=">="+t+"."+o+".0 <"+t+"."+(+o+1)+".0":s?(n("replaceTilde pr",s),"-"!==s.charAt(0)&&(s="-"+s),a=">="+t+"."+o+"."+i+s+" <"+t+"."+(+o+1)+".0"):a=">="+t+"."+o+"."+i+" <"+t+"."+(+o+1)+".0",n("tilde return",a),a})}(e,r)}).join(" ")}(e,r),n("tildes",e),e=function(e,r){return n("replaceXRanges",e,r),e.split(/\s+/).map(function(e){return function(e,r){e=e.trim(),r&&"object"==typeof r||(r={loose:!!r,includePrerelease:!1});var t=r.loose?s[R]:s[S];return e.replace(t,function(r,t,o,i,s,a){n("xRange",e,r,t,o,i,s,a);var u=ue(o),c=u||ue(i),l=c||ue(s),p=l;return"="===t&&p&&(t=""),u?r=">"===t||"<"===t?"<0.0.0":"*":t&&p?(c&&(i=0),l&&(s=0),">"===t?(t=">=",c?(o=+o+1,i=0,s=0):l&&(i=+i+1,s=0)):"<="===t&&(t="<",c?o=+o+1:i=+i+1),r=t+o+"."+i+"."+s):c?r=">="+o+".0.0 <"+(+o+1)+".0.0":l&&(r=">="+o+"."+i+".0 <"+o+"."+(+i+1)+".0"),n("xRange return",r),r})}(e,r)}).join(" ")}(e,r),n("xrange",e),e=function(e,r){return n("replaceStars",e,r),e.trim().replace(s[Z],"")}(e,r),n("stars",e),e}(e,this.options)},this).join(" ").split(/\s+/);return this.options.loose&&(i=i.filter(function(e){return!!e.match(o)})),i=i.map(function(e){return new ie(e,this.options)},this)},ae.prototype.intersects=function(e,r){if(!(e instanceof ae))throw new TypeError("a Range is required");return this.set.some(function(t){return t.every(function(t){return e.set.some(function(e){return e.every(function(e){return t.intersects(e,r)})})})})},r.toComparators=function(e,r){return new ae(e,r).set.map(function(e){return e.map(function(e){return e.value}).join(" ").trim().split(" ")})},ae.prototype.test=function(e){if(!e)return!1;"string"==typeof e&&(e=new W(e,this.options));for(var r=0;r",t)},r.outside=he,r.prerelease=function(e,r){var t=U(e,r);return t&&t.prerelease.length?t.prerelease:null},r.intersects=function(e,r,t){return e=new ae(e,t),r=new ae(r,t),e.intersects(r)},r.coerce=function(e){if(e instanceof W)return e;if("string"!=typeof e)return null;var r=e.match(s[I]);return null==r?null:U((r[1]||"0")+"."+(r[2]||"0")+"."+(r[3]||"0"))}}).call(this,t(2))},function(e,r){var t,n,o=e.exports={};function i(){throw new Error("setTimeout has not been defined")}function s(){throw new Error("clearTimeout has not been defined")}function a(e){if(t===setTimeout)return setTimeout(e,0);if((t===i||!t)&&setTimeout)return t=setTimeout,setTimeout(e,0);try{return t(e,0)}catch(r){try{return t.call(null,e,0)}catch(r){return t.call(this,e,0)}}}!function(){try{t="function"==typeof setTimeout?setTimeout:i}catch(e){t=i}try{n="function"==typeof clearTimeout?clearTimeout:s}catch(e){n=s}}();var u,c=[],l=!1,p=-1;function h(){l&&u&&(l=!1,u.length?c=u.concat(c):p=-1,c.length&&f())}function f(){if(!l){var e=a(h);l=!0;for(var r=c.length;r;){for(u=c,c=[];++p1)for(var t=1;t