Simplify the version bump process. ### Description

Simplify the version bump process.

- Use substitution hook in docs to update CDN URL.
  - In `dev` or `prerelease` versions, it will point to `dev` url
  - In `stable` versions, it will point it `vX.Y.Z` url
- Introduce a version bump script `tools/bump_version.py`.


~- Use `bump2version` to bump Python versions (continuing from #2460)~
~- Use `npm version` to bump JS versions~
~- Update `run_docker` script to use latest deployed pre-built docker image when `--pre-built` option is specified.~

### Checklists

- [x] Add new / update outdated documentation

import pytest


def test_runwebworker_different_package_name(
    selenium_webworker_standalone, script_type
):
    selenium = selenium_webworker_standalone
    output = selenium.run_webworker(
        """
        import pyparsing
        pyparsing.__version__
        """
    )
    assert isinstance(output, str)


def test_runwebworker_no_imports(selenium_webworker_standalone, script_type):
    selenium = selenium_webworker_standalone
    output = selenium.run_webworker(
        """
        42
        """
    )
    assert output == 42


def test_runwebworker_missing_import(selenium_webworker_standalone, script_type):
    selenium = selenium_webworker_standalone
    msg = "ModuleNotFoundError"
    with pytest.raises(selenium.JavascriptException, match=msg):
        selenium.run_webworker(
            """
            import foo
            """
        )


def test_runwebworker_exception(selenium_webworker_standalone, script_type):
    selenium = selenium_webworker_standalone
    msg = "ZeroDivisionError"
    with pytest.raises(selenium.JavascriptException, match=msg):
        selenium.run_webworker(
            """
            42 / 0
            """
        )


def test_runwebworker_exception_after_import(
    selenium_webworker_standalone, script_type
):
    selenium = selenium_webworker_standalone
    msg = "ZeroDivisionError"
    with pytest.raises(selenium.JavascriptException, match=msg):
        selenium.run_webworker(
            """
            import pyparsing
            42 / 0
            """
        )


def test_runwebworker_micropip(selenium_webworker_standalone, script_type):
    selenium = selenium_webworker_standalone
    output = selenium.run_webworker(
        """
        import micropip
        await micropip.install('snowballstemmer')
        import snowballstemmer
        stemmer = snowballstemmer.stemmer('english')
        stemmer.stemWords('go goes going gone'.split())[0]
        """
    )
    assert output == "go"

import pytest


def test_runwebworker_different_package_name(
    selenium_webworker_standalone, script_type
):
    selenium = selenium_webworker_standalone
    output = selenium.run_webworker(
        """
        import pyparsing
        pyparsing.__version__
        """
    )
    assert isinstance(output, str)


def test_runwebworker_no_imports(selenium_webworker_standalone, script_type):
    selenium = selenium_webworker_standalone
    output = selenium.run_webworker(
        """
        42
        """
    )
    assert output == 42


def test_runwebworker_missing_import(selenium_webworker_standalone, script_type):
    selenium = selenium_webworker_standalone
    msg = "ModuleNotFoundError"
    with pytest.raises(selenium.JavascriptException, match=msg):
        selenium.run_webworker(
            """
            import foo
            """
        )


def test_runwebworker_exception(selenium_webworker_standalone, script_type):
    selenium = selenium_webworker_standalone
    msg = "ZeroDivisionError"
    with pytest.raises(selenium.JavascriptException, match=msg):
        selenium.run_webworker(
            """
            42 / 0
            """
        )


def test_runwebworker_exception_after_import(
    selenium_webworker_standalone, script_type
):
    selenium = selenium_webworker_standalone
    msg = "ZeroDivisionError"
    with pytest.raises(selenium.JavascriptException, match=msg):
        selenium.run_webworker(
            """
            import pyparsing
            42 / 0
            """
        )


def test_runwebworker_micropip(selenium_webworker_standalone, script_type):
    selenium = selenium_webworker_standalone
    output = selenium.run_webworker(
        """
        import micropip
        await micropip.install('snowballstemmer')
        import snowballstemmer
        stemmer = snowballstemmer.stemmer('english')
        stemmer.stemWords('go goes going gone'.split())[0]
        """
    )
    assert output == "go"
