diff --git a/CHANGES b/CHANGES index a799c249a..cecb622f9 100644 --- a/CHANGES +++ b/CHANGES @@ -48,6 +48,7 @@ Features added * #7466: autosummary: headings in generated documents are not translated * #7490: autosummary: Add ``:caption:`` option to autosummary directive to set a caption to the toctree +* #7469: autosummary: Support module attributes * #248, #6040: autosummary: Add ``:recursive:`` option to autosummary directive to generate stub files recursively * #4030: autosummary: Add :confval:`autosummary_context` to add template @@ -65,6 +66,7 @@ Features added * #7541: html theme: Add a "clearer" at the end of the "body" * #7542: html theme: Make admonition/topic/sidebar scrollable * #7543: html theme: Add top and bottom margins to tables +* #7695: html theme: Add viewport meta tag for basic theme * C and C++: allow semicolon in the end of declarations. * C++, parse parameterized noexcept specifiers. * #7294: C++, parse expressions with user-defined literals. @@ -73,6 +75,8 @@ Features added :rst:dir:`py:exception:` and :rst:dir:`py:method:` directives * #7596: py domain: Change a type annotation for variables to a hyperlink * #7582: napoleon: a type for attribute are represented like type annotation +* #7683: Add ``allowed_exceptions`` parameter to ``Sphinx.emit()`` to allow + handlers to raise specified exceptions Bugs fixed ---------- @@ -90,16 +94,32 @@ Bugs fixed * #7362: autodoc: does not render correct signatures for built-in functions * #7654: autodoc: ``Optional[Union[foo, bar]]`` is presented as ``Union[foo, bar, None]`` +* #7629: autodoc: autofunction emits an unfriendly warning if an invalid object + specified +* #7650: autodoc: undecorated signature is shown for decorated functions +* #7676: autodoc: typo in the default value of autodoc_member_order +* #7676: autodoc: wrong value for :member-order: option is ignored silently +* #7676: autodoc: member-order="bysource" does not work for C module * #7668: autodoc: wrong retann value is passed to a handler of autodoc-proccess-signature * #7551: autosummary: a nested class is indexed as non-nested class +* #7661: autosummary: autosummary directive emits warnings twices if failed to + import the target module +* #7685: autosummary: The template variable "members" contains imported members + even if :confval:`autossummary_imported_members` is False * #7535: sphinx-autogen: crashes when custom template uses inheritance * #7536: sphinx-autogen: crashes when template uses i18n feature +* #7653: sphinx-quickstart: Fix multiple directory creation for nested relpath * #2785: html: Bad alignment of equation links * #7581: napoleon: bad parsing of inline code in attribute docstrings * #7628: imgconverter: runs imagemagick once unnecessary for builders not supporting images * #7610: incorrectly renders consecutive backslashes for docutils-0.16 +* #7646: handle errors on event handlers +* C++, fix rendering and xrefs in nested names explicitly starting + in global scope, e.g., ``::A::B``. +* C, fix rendering and xrefs in nested names explicitly starting + in global scope, e.g., ``.A.B``. Testing -------- @@ -124,6 +144,7 @@ Bugs fixed * #7567: autodoc: parametrized types are shown twice for generic types * #7637: autodoc: system defined TypeVars are shown in Python 3.9 +* #7696: html: Updated jQuery version from 3.4.1 to 3.5.1 for security reasons * #7611: md5 fails when OpenSSL FIPS is enabled * #7626: release package does not contain ``CODE_OF_CONDUCT`` diff --git a/doc/extdev/appapi.rst b/doc/extdev/appapi.rst index 961558600..d5b1a8a98 100644 --- a/doc/extdev/appapi.rst +++ b/doc/extdev/appapi.rst @@ -230,11 +230,15 @@ connect handlers to the events. Example: .. event:: missing-reference (app, env, node, contnode) - Emitted when a cross-reference to a Python module or object cannot be - resolved. If the event handler can resolve the reference, it should return a + Emitted when a cross-reference to an object cannot be resolved. + If the event handler can resolve the reference, it should return a new docutils node to be inserted in the document tree in place of the node *node*. Usually this node is a :class:`reference` node containing *contnode* as a child. + If the handler can not resolve the cross-reference, + it can either return ``None`` to let other handlers try, + or raise :class:`NoUri` to prevent other handlers in trying and suppress + a warning about this cross-reference being unresolved. :param env: The build environment (``app.builder.env``). :param node: The :class:`pending_xref` node to be resolved. Its attributes diff --git a/doc/usage/extensions/autosummary.rst b/doc/usage/extensions/autosummary.rst index f3a5aea0e..38d18361e 100644 --- a/doc/usage/extensions/autosummary.rst +++ b/doc/usage/extensions/autosummary.rst @@ -285,8 +285,12 @@ The following variables available in the templates: .. data:: attributes - List containing names of "public" attributes in the class. Only available - for classes. + List containing names of "public" attributes in the class/module. Only + available for classes and modules. + + .. versionchanged:: 3.1 + + Attributes of modules are supported. .. data:: modules diff --git a/doc/usage/restructuredtext/basics.rst b/doc/usage/restructuredtext/basics.rst index dffaf297c..8f596ed9a 100644 --- a/doc/usage/restructuredtext/basics.rst +++ b/doc/usage/restructuredtext/basics.rst @@ -159,7 +159,7 @@ Doctest blocks Doctest blocks (:duref:`ref `) are interactive Python sessions cut-and-pasted into docstrings. They do not require the :ref:`literal blocks ` syntax. The doctest block must end -with a blank line and should *not* end with with an unused prompt:: +with a blank line and should *not* end with an unused prompt:: >>> 1 + 1 2 diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index 847a6d715..5e191e989 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -112,6 +112,13 @@ class desc_signature(nodes.Part, nodes.Inline, nodes.TextElement): In that case all child nodes must be ``desc_signature_line`` nodes. """ + @property + def child_text_separator(self): + if self.get('is_multiline'): + return ' ' + else: + return super().child_text_separator + class desc_signature_line(nodes.Part, nodes.Inline, nodes.FixedTextElement): """Node for a line in a multi-line object signatures. @@ -150,6 +157,9 @@ class desc_parameterlist(nodes.Part, nodes.Inline, nodes.FixedTextElement): """Node for a general parameter list.""" child_text_separator = ', ' + def astext(self): + return '({})'.format(super().astext()) + class desc_parameter(nodes.Part, nodes.Inline, nodes.FixedTextElement): """Node for a single parameter.""" diff --git a/sphinx/application.py b/sphinx/application.py index 8f06bf9cf..b02fb4d60 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -436,22 +436,32 @@ class Sphinx: logger.debug('[app] disconnecting event: [id=%s]', listener_id) self.events.disconnect(listener_id) - def emit(self, event: str, *args: Any) -> List: + def emit(self, event: str, *args: Any, + allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> List: """Emit *event* and pass *arguments* to the callback functions. Return the return values of all callbacks as a list. Do not emit core Sphinx events in extensions! - """ - return self.events.emit(event, *args) - def emit_firstresult(self, event: str, *args: Any) -> Any: + .. versionchanged:: 3.1 + + Added *allowed_exceptions* to specify path-through exceptions + """ + return self.events.emit(event, *args, allowed_exceptions=allowed_exceptions) + + def emit_firstresult(self, event: str, *args: Any, + allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> Any: """Emit *event* and pass *arguments* to the callback functions. Return the result of the first callback that doesn't return ``None``. .. versionadded:: 0.5 + .. versionchanged:: 3.1 + + Added *allowed_exceptions* to specify path-through exceptions """ - return self.events.emit_firstresult(event, *args) + return self.events.emit_firstresult(event, *args, + allowed_exceptions=allowed_exceptions) # registering addon parts diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index 0c9020bd5..cad3c65e5 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -357,6 +357,7 @@ def generate(d: Dict, overwrite: bool = True, silent: bool = False, templatedir: d.setdefault('extensions', []) d['copyright'] = time.strftime('%Y') + ', ' + d['author'] + d["path"] = os.path.abspath(d['path']) ensuredir(d['path']) srcdir = path.join(d['path'], 'source') if d['sep'] else d['path'] diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index 6e0dc2a54..164a87254 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -186,11 +186,17 @@ class ASTNestedName(ASTBase): # If lastIsName, then wrap all of the prefix in a desc_addname, # else append directly to signode. # TODO: also for C? - # NOTE: Breathe relies on the prefix being in the desc_addname node, + # NOTE: Breathe previously relied on the prefix being in the desc_addname node, # so it can remove it in inner declarations. dest = signode if mode == 'lastIsName': dest = addnodes.desc_addname() + if self.rooted: + prefix += '.' + if mode == 'lastIsName' and len(names) == 0: + signode += nodes.Text('.') + else: + dest += nodes.Text('.') for i in range(len(names)): ident = names[i] if not first: diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 4dc8809ec..b801f4030 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -752,11 +752,17 @@ class ASTNestedName(ASTBase): names = self.names[:-1] if mode == 'lastIsName' else self.names # If lastIsName, then wrap all of the prefix in a desc_addname, # else append directly to signode. - # NOTE: Breathe relies on the prefix being in the desc_addname node, + # NOTE: Breathe previously relied on the prefix being in the desc_addname node, # so it can remove it in inner declarations. dest = signode if mode == 'lastIsName': dest = addnodes.desc_addname() + if self.rooted: + prefix += '::' + if mode == 'lastIsName' and len(names) == 0: + signode += nodes.Text('::') + else: + dest += nodes.Text('::') for i in range(len(names)): nne = names[i] template = self.templates[i] @@ -3722,8 +3728,8 @@ class LookupKey: class Symbol: debug_indent = 0 debug_indent_string = " " - debug_lookup = False - debug_show_tree = False + debug_lookup = False # overridden by the corresponding config value + debug_show_tree = False # overridden by the corresponding config value @staticmethod def debug_print(*args: Any) -> None: @@ -7383,9 +7389,18 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value("cpp_paren_attributes", [], 'env') app.add_post_transform(AliasTransform) + # debug stuff + app.add_config_value("cpp_debug_lookup", False, '') + app.add_config_value("cpp_debug_show_tree", False, '') + + def setDebugFlags(app): + Symbol.debug_lookup = app.config.cpp_debug_lookup + Symbol.debug_show_tree = app.config.cpp_debug_show_tree + app.connect("builder-inited", setDebugFlags) + return { 'version': 'builtin', - 'env_version': 2, + 'env_version': 3, 'parallel_read_safe': True, 'parallel_write_safe': True, } diff --git a/sphinx/errors.py b/sphinx/errors.py index a9d027cb8..d9a83712c 100644 --- a/sphinx/errors.py +++ b/sphinx/errors.py @@ -116,7 +116,8 @@ class PycodeError(Exception): class NoUri(Exception): - """Raised by builder.get_relative_uri() if there is no URI available.""" + """Raised by builder.get_relative_uri() or from missing-reference handlers + if there is no URI available.""" pass diff --git a/sphinx/events.py b/sphinx/events.py index ff49f290c..0911dfaaa 100644 --- a/sphinx/events.py +++ b/sphinx/events.py @@ -13,15 +13,16 @@ import warnings from collections import defaultdict from operator import attrgetter -from typing import Any, Callable, Dict, List, NamedTuple +from typing import Any, Callable, Dict, List, NamedTuple, Tuple from sphinx.deprecation import RemovedInSphinx40Warning -from sphinx.errors import ExtensionError +from sphinx.errors import ExtensionError, SphinxError from sphinx.locale import __ from sphinx.util import logging if False: # For type annotation + from typing import Type # for python3.5.1 from sphinx.application import Sphinx @@ -88,7 +89,8 @@ class EventManager: if listener.id == listener_id: listeners.remove(listener) - def emit(self, name: str, *args: Any) -> List: + def emit(self, name: str, *args: Any, + allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> List: """Emit a Sphinx event.""" try: logger.debug('[app] emitting event: %r%s', name, repr(args)[:100]) @@ -100,19 +102,29 @@ class EventManager: results = [] listeners = sorted(self.listeners[name], key=attrgetter("priority")) for listener in listeners: - if self.app is None: - # for compatibility; RemovedInSphinx40Warning - results.append(listener.handler(*args)) - else: - results.append(listener.handler(self.app, *args)) + try: + if self.app is None: + # for compatibility; RemovedInSphinx40Warning + results.append(listener.handler(*args)) + else: + results.append(listener.handler(self.app, *args)) + except allowed_exceptions: + # pass through the errors specified as *allowed_exceptions* + raise + except SphinxError: + raise + except Exception as exc: + raise ExtensionError(__("Handler %r for event %r threw an exception") % + (listener.handler, name)) from exc return results - def emit_firstresult(self, name: str, *args: Any) -> Any: + def emit_firstresult(self, name: str, *args: Any, + allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> Any: """Emit a Sphinx event and returns first result. This returns the result of the first handler that doesn't return ``None``. """ - for result in self.emit(name, *args): + for result in self.emit(name, *args, allowed_exceptions=allowed_exceptions): if result is not None: return result return None diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index f81a53d02..f9c775f7d 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -15,14 +15,15 @@ import re import warnings from inspect import Parameter from types import ModuleType -from typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Union -from unittest.mock import patch +from typing import ( + Any, Callable, Dict, Iterator, List, Optional, Sequence, Set, Tuple, Type, Union +) from docutils.statemachine import StringList import sphinx from sphinx.application import Sphinx -from sphinx.config import ENUM +from sphinx.config import Config, ENUM from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning from sphinx.environment import BuildEnvironment from sphinx.ext.autodoc.importer import import_object, get_module_members, get_object_members @@ -93,6 +94,16 @@ def inherited_members_option(arg: Any) -> Union[object, Set[str]]: return arg +def member_order_option(arg: Any) -> Optional[str]: + """Used to convert the :members: option to auto directives.""" + if arg is None: + return None + elif arg in ('alphabetical', 'bysource', 'groupwise'): + return arg + else: + raise ValueError(__('invalid value for member-order option: %s') % arg) + + SUPPRESS = object() @@ -427,8 +438,15 @@ class Documenter: directive = getattr(self, 'directivetype', self.objtype) name = self.format_name() sourcename = self.get_sourcename() - self.add_line('.. %s:%s:: %s%s' % (domain, directive, name, sig), - sourcename) + + # one signature per line, indented by column + prefix = '.. %s:%s:: ' % (domain, directive) + for i, sig_line in enumerate(sig.split("\n")): + self.add_line('%s%s%s' % (prefix, name, sig_line), + sourcename) + if i == 0: + prefix = " " * len(prefix) + if self.options.noindex: self.add_line(' :noindex:', sourcename) if self.objpath: @@ -521,12 +539,12 @@ class Documenter: else: logger.warning(__('missing attribute %s in object %s') % (name, self.fullname), type='autodoc') - return False, sorted(selected) + return False, selected elif self.options.inherited_members: - return False, sorted((m.name, m.value) for m in members.values()) + return False, [(m.name, m.value) for m in members.values()] else: - return False, sorted((m.name, m.value) for m in members.values() - if m.directly_defined) + return False, [(m.name, m.value) for m in members.values() + if m.directly_defined] def filter_members(self, members: List[Tuple[str, Any]], want_all: bool ) -> List[Tuple[str, Any, bool]]: @@ -699,17 +717,26 @@ class Documenter: member_order = self.options.member_order or \ self.env.config.autodoc_member_order if member_order == 'groupwise': - # sort by group; relies on stable sort to keep items in the - # same group sorted alphabetically - memberdocumenters.sort(key=lambda e: e[0].member_order) - elif member_order == 'bysource' and self.analyzer: - # sort by source order, by virtue of the module analyzer - tagorder = self.analyzer.tagorder + # sort by group; alphabetically within groups + memberdocumenters.sort(key=lambda e: (e[0].member_order, e[0].name)) + elif member_order == 'bysource': + if self.analyzer: + # sort by source order, by virtue of the module analyzer + tagorder = self.analyzer.tagorder - def keyfunc(entry: Tuple[Documenter, bool]) -> int: - fullname = entry[0].name.split('::')[1] - return tagorder.get(fullname, len(tagorder)) - memberdocumenters.sort(key=keyfunc) + def keyfunc(entry: Tuple[Documenter, bool]) -> int: + fullname = entry[0].name.split('::')[1] + return tagorder.get(fullname, len(tagorder)) + memberdocumenters.sort(key=keyfunc) + else: + # Assume that member discovery order matches source order. + # This is a reasonable assumption in Python 3.6 and up, where + # module.__dict__ is insertion-ordered. + pass + elif member_order == 'alphabetical': + memberdocumenters.sort(key=lambda e: e[0].name) + else: + raise ValueError("Illegal member order {}".format(member_order)) for documenter, isattr in memberdocumenters: documenter.generate( @@ -817,7 +844,7 @@ class ModuleDocumenter(Documenter): 'noindex': bool_option, 'inherited-members': inherited_members_option, 'show-inheritance': bool_option, 'synopsis': identity, 'platform': identity, 'deprecated': bool_option, - 'member-order': identity, 'exclude-members': members_set_option, + 'member-order': member_order_option, 'exclude-members': members_set_option, 'private-members': bool_option, 'special-members': members_option, 'imported-members': bool_option, 'ignore-module-all': bool_option } # type: Dict[str, Callable] @@ -948,7 +975,7 @@ class ClassLevelDocumenter(Documenter): try: modname, qualname = split_full_qualified_name(mod_cls) - parents = qualname.split(".") + parents = qualname.split(".") if qualname else [] except ImportError: parents = mod_cls.split(".") @@ -1057,12 +1084,18 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ if self.env.config.autodoc_typehints in ('none', 'description'): kwargs.setdefault('show_annotation', False) - unwrapped = inspect.unwrap(self.object) try: - self.env.app.emit('autodoc-before-process-signature', unwrapped, False) - sig = inspect.signature(unwrapped) + self.env.app.emit('autodoc-before-process-signature', self.object, False) + if inspect.is_singledispatch_function(self.object): + sig = inspect.signature(self.object, follow_wrapped=True) + else: + sig = inspect.signature(self.object) args = stringify_signature(sig, **kwargs) - except TypeError: + except TypeError as exc: + logger.warning(__("Failed to get a function signature for %s: %s"), + self.fullname, exc) + return None + except ValueError: args = '' if self.env.config.strip_signature_backslash: @@ -1075,41 +1108,28 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ def add_directive_header(self, sig: str) -> None: sourcename = self.get_sourcename() - if inspect.is_singledispatch_function(self.object): - self.add_singledispatch_directive_header(sig) - else: - super().add_directive_header(sig) + super().add_directive_header(sig) if inspect.iscoroutinefunction(self.object): self.add_line(' :async:', sourcename) - def add_singledispatch_directive_header(self, sig: str) -> None: - sourcename = self.get_sourcename() + def format_signature(self, **kwargs: Any) -> str: + sig = super().format_signature(**kwargs) + sigs = [sig] - # intercept generated directive headers - # TODO: It is very hacky to use mock to intercept header generation - with patch.object(self, 'add_line') as add_line: - super().add_directive_header(sig) + if inspect.is_singledispatch_function(self.object): + # append signature of singledispatch'ed functions + for typ, func in self.object.registry.items(): + if typ is object: + pass # default implementation. skipped. + else: + self.annotate_to_first_argument(func, typ) - # output first line of header - self.add_line(*add_line.call_args_list[0][0]) + documenter = FunctionDocumenter(self.directive, '') + documenter.object = func + sigs.append(documenter.format_signature()) - # inserts signature of singledispatch'ed functions - for typ, func in self.object.registry.items(): - if typ is object: - pass # default implementation. skipped. - else: - self.annotate_to_first_argument(func, typ) - - documenter = FunctionDocumenter(self.directive, '') - documenter.object = func - self.add_line(' %s%s' % (self.format_name(), - documenter.format_signature()), - sourcename) - - # output remains of directive header - for call in add_line.call_args_list[1:]: - self.add_line(*call[0]) + return "\n".join(sigs) def annotate_to_first_argument(self, func: Callable, typ: Type) -> None: """Annotate type hint to the first argument of function if needed.""" @@ -1157,7 +1177,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: option_spec = { 'members': members_option, 'undoc-members': bool_option, 'noindex': bool_option, 'inherited-members': inherited_members_option, - 'show-inheritance': bool_option, 'member-order': identity, + 'show-inheritance': bool_option, 'member-order': member_order_option, 'exclude-members': members_set_option, 'private-members': bool_option, 'special-members': members_option, } # type: Dict[str, Callable] @@ -1453,7 +1473,6 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: if self.env.config.autodoc_typehints in ('none', 'description'): kwargs.setdefault('show_annotation', False) - unwrapped = inspect.unwrap(self.object) try: if self.object == object.__init__ and self.parent != object: # Classes not having own __init__() method are shown as no arguments. @@ -1462,13 +1481,23 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: # But it makes users confused. args = '()' else: - if inspect.isstaticmethod(unwrapped, cls=self.parent, name=self.object_name): - self.env.app.emit('autodoc-before-process-signature', unwrapped, False) - sig = inspect.signature(unwrapped, bound_method=False) + if inspect.isstaticmethod(self.object, cls=self.parent, name=self.object_name): + self.env.app.emit('autodoc-before-process-signature', self.object, False) + sig = inspect.signature(self.object, bound_method=False) else: - self.env.app.emit('autodoc-before-process-signature', unwrapped, True) - sig = inspect.signature(unwrapped, bound_method=True) + self.env.app.emit('autodoc-before-process-signature', self.object, True) + + meth = self.parent.__dict__.get(self.objpath[-1], None) + if meth and inspect.is_singledispatch_method(meth): + sig = inspect.signature(self.object, bound_method=True, + follow_wrapped=True) + else: + sig = inspect.signature(self.object, bound_method=True) args = stringify_signature(sig, **kwargs) + except TypeError as exc: + logger.warning(__("Failed to get a method signature for %s: %s"), + self.fullname, exc) + return None except ValueError: args = '' @@ -1478,11 +1507,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: return args def add_directive_header(self, sig: str) -> None: - meth = self.parent.__dict__.get(self.objpath[-1]) - if inspect.is_singledispatch_method(meth): - self.add_singledispatch_directive_header(sig) - else: - super().add_directive_header(sig) + super().add_directive_header(sig) sourcename = self.get_sourcename() obj = self.parent.__dict__.get(self.object_name, self.object) @@ -1500,34 +1525,26 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: def document_members(self, all_members: bool = False) -> None: pass - def add_singledispatch_directive_header(self, sig: str) -> None: - sourcename = self.get_sourcename() + def format_signature(self, **kwargs: Any) -> str: + sig = super().format_signature(**kwargs) + sigs = [sig] - # intercept generated directive headers - # TODO: It is very hacky to use mock to intercept header generation - with patch.object(self, 'add_line') as add_line: - super().add_directive_header(sig) - - # output first line of header - self.add_line(*add_line.call_args_list[0][0]) - - # inserts signature of singledispatch'ed functions meth = self.parent.__dict__.get(self.objpath[-1]) - for typ, func in meth.dispatcher.registry.items(): - if typ is object: - pass # default implementation. skipped. - else: - self.annotate_to_first_argument(func, typ) + if inspect.is_singledispatch_method(meth): + # append signature of singledispatch'ed functions + for typ, func in meth.dispatcher.registry.items(): + if typ is object: + pass # default implementation. skipped. + else: + self.annotate_to_first_argument(func, typ) - documenter = MethodDocumenter(self.directive, '') - documenter.object = func - self.add_line(' %s%s' % (self.format_name(), - documenter.format_signature()), - sourcename) + documenter = MethodDocumenter(self.directive, '') + documenter.parent = self.parent + documenter.object = func + documenter.objpath = [None] + sigs.append(documenter.format_signature()) - # output remains of directive header - for call in add_line.call_args_list[1:]: - self.add_line(*call[0]) + return "\n".join(sigs) def annotate_to_first_argument(self, func: Callable, typ: Type) -> None: """Annotate type hint to the first argument of function if needed.""" @@ -1764,6 +1781,14 @@ def autodoc_attrgetter(app: Sphinx, obj: Any, name: str, *defargs: Any) -> Any: return safe_getattr(obj, name, *defargs) +def migrate_autodoc_member_order(app: Sphinx, config: Config) -> None: + if config.autodoc_member_order == 'alphabetic': + # RemovedInSphinx50Warning + logger.warning(__('autodoc_member_order now accepts "alphabetical" ' + 'instead of "alphabetic". Please update your setting.')) + config.autodoc_member_order = 'alphabetical' # type: ignore + + def setup(app: Sphinx) -> Dict[str, Any]: app.add_autodocumenter(ModuleDocumenter) app.add_autodocumenter(ClassDocumenter) @@ -1779,7 +1804,8 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_autodocumenter(SlotsAttributeDocumenter) app.add_config_value('autoclass_content', 'class', True, ENUM('both', 'class', 'init')) - app.add_config_value('autodoc_member_order', 'alphabetic', True) + app.add_config_value('autodoc_member_order', 'alphabetical', True, + ENUM('alphabetic', 'alphabetical', 'bysource', 'groupwise')) app.add_config_value('autodoc_default_options', {}, True) app.add_config_value('autodoc_docstring_signature', True, True) app.add_config_value('autodoc_mock_imports', [], True) @@ -1792,6 +1818,8 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_event('autodoc-process-signature') app.add_event('autodoc-skip-member') + app.connect('config-inited', migrate_autodoc_member_order, priority=800) + app.setup_extension('sphinx.ext.autodoc.type_comment') app.setup_extension('sphinx.ext.autodoc.typehints') diff --git a/sphinx/ext/autosectionlabel.py b/sphinx/ext/autosectionlabel.py index 9890cdf7d..4bb401791 100644 --- a/sphinx/ext/autosectionlabel.py +++ b/sphinx/ext/autosectionlabel.py @@ -15,6 +15,7 @@ from docutils import nodes from docutils.nodes import Node from sphinx.application import Sphinx +from sphinx.domains.std import StandardDomain from sphinx.locale import __ from sphinx.util import logging from sphinx.util.nodes import clean_astext @@ -33,8 +34,7 @@ def get_node_depth(node: Node) -> int: def register_sections_as_label(app: Sphinx, document: Node) -> None: - labels = app.env.domaindata['std']['labels'] - anonlabels = app.env.domaindata['std']['anonlabels'] + domain = cast(StandardDomain, app.env.get_domain('std')) for node in document.traverse(nodes.section): if (app.config.autosectionlabel_maxdepth and get_node_depth(node) >= app.config.autosectionlabel_maxdepth): @@ -49,13 +49,13 @@ def register_sections_as_label(app: Sphinx, document: Node) -> None: name = nodes.fully_normalize_name(ref_name) sectname = clean_astext(title) - if name in labels: + if name in domain.labels: logger.warning(__('duplicate label %s, other instance in %s'), - name, app.env.doc2path(labels[name][0]), + name, app.env.doc2path(domain.labels[name][0]), location=node, type='autosectionlabel', subtype=docname) - anonlabels[name] = docname, labelid - labels[name] = docname, labelid, sectname + domain.anonlabels[name] = docname, labelid + domain.labels[name] = docname, labelid, sectname def setup(app: Sphinx) -> Dict[str, Any]: diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index ed49c56df..0cdd88feb 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -302,8 +302,7 @@ class Autosummary(SphinxDirective): with mock(self.config.autosummary_mock_imports): real_name, obj, parent, modname = import_by_name(name, prefixes=prefixes) except ImportError: - logger.warning(__('failed to import %s'), name) - items.append((name, '', '', name)) + logger.warning(__('autosummary: failed to import %s'), name) continue self.bridge.result = StringList() # initialize for each documenter diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 071d75348..473ac3db6 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -18,6 +18,7 @@ """ import argparse +import inspect import locale import os import pkgutil @@ -42,6 +43,7 @@ from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warnin from sphinx.ext.autodoc import Documenter from sphinx.ext.autosummary import import_by_name, get_documenter from sphinx.locale import __ +from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.registry import SphinxComponentRegistry from sphinx.util import logging from sphinx.util import rst @@ -175,6 +177,56 @@ class AutosummaryRenderer: # -- Generating output --------------------------------------------------------- +class ModuleScanner: + def __init__(self, app: Any, obj: Any) -> None: + self.app = app + self.object = obj + + def get_object_type(self, name: str, value: Any) -> str: + return get_documenter(self.app, value, self.object).objtype + + def is_skipped(self, name: str, value: Any, objtype: str) -> bool: + try: + return self.app.emit_firstresult('autodoc-skip-member', objtype, + name, value, False, {}) + except Exception as exc: + logger.warning(__('autosummary: failed to determine %r to be documented, ' + 'the following exception was raised:\n%s'), + name, exc, type='autosummary') + return False + + def scan(self, imported_members: bool) -> List[str]: + members = [] + for name in dir(self.object): + try: + value = safe_getattr(self.object, name) + except AttributeError: + value = None + + objtype = self.get_object_type(name, value) + if self.is_skipped(name, value, objtype): + continue + + try: + if inspect.ismodule(value): + imported = True + elif safe_getattr(value, '__module__') != self.object.__name__: + imported = True + else: + imported = False + except AttributeError: + imported = False + + if imported_members: + # list all members up + members.append(name) + elif imported is False: + # list not-imported members up + members.append(name) + + return members + + def generate_autosummary_content(name: str, obj: Any, parent: Any, template: AutosummaryRenderer, template_name: str, imported_members: bool, app: Any, @@ -218,6 +270,21 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, public.append(name) return public, items + def get_module_attrs(members: Any) -> Tuple[List[str], List[str]]: + """Find module attributes with docstrings.""" + attrs, public = [], [] + try: + analyzer = ModuleAnalyzer.for_module(name) + attr_docs = analyzer.find_attr_docs() + for namespace, attr_name in attr_docs: + if namespace == '' and attr_name in members: + attrs.append(attr_name) + if not attr_name.startswith('_'): + public.append(attr_name) + except PycodeError: + pass # give up if ModuleAnalyzer fails to parse code + return public, attrs + def get_modules(obj: Any) -> Tuple[List[str], List[str]]: items = [] # type: List[str] for _, modname, ispkg in pkgutil.iter_modules(obj.__path__): @@ -230,13 +297,16 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, ns.update(context) if doc.objtype == 'module': - ns['members'] = dir(obj) + scanner = ModuleScanner(app, obj) + ns['members'] = scanner.scan(imported_members) ns['functions'], ns['all_functions'] = \ get_members(obj, {'function'}, imported=imported_members) ns['classes'], ns['all_classes'] = \ get_members(obj, {'class'}, imported=imported_members) ns['exceptions'], ns['all_exceptions'] = \ get_members(obj, {'exception'}, imported=imported_members) + ns['attributes'], ns['all_attributes'] = \ + get_module_attrs(ns['members']) ispackage = hasattr(obj, '__path__') if ispackage and recursive: ns['modules'], ns['all_modules'] = get_modules(obj) diff --git a/sphinx/ext/autosummary/templates/autosummary/module.rst b/sphinx/ext/autosummary/templates/autosummary/module.rst index 5b70d5c40..3a93e872a 100644 --- a/sphinx/ext/autosummary/templates/autosummary/module.rst +++ b/sphinx/ext/autosummary/templates/autosummary/module.rst @@ -2,6 +2,17 @@ .. automodule:: {{ fullname }} + {% block attributes %} + {% if attributes %} + .. rubric:: Module Attributes + + .. autosummary:: + {% for item in attributes %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + {% block functions %} {% if functions %} .. rubric:: {{ _('Functions') }} diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index dc24a1993..a2eeb7891 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -131,8 +131,10 @@ def env_merge_info(app: Sphinx, env: BuildEnvironment, docnames: Iterable[str], def missing_reference(app: Sphinx, env: BuildEnvironment, node: Element, contnode: Node ) -> Node: - # resolve our "viewcode" reference nodes -- they need special treatment - if node['reftype'] == 'viewcode': + if app.builder.format != 'html': + return None + elif node['reftype'] == 'viewcode': + # resolve our "viewcode" reference nodes -- they need special treatment return make_refnode(app.builder, node['refdoc'], node['reftarget'], node['refid'], contnode) diff --git a/sphinx/templates/quickstart/make.bat_t b/sphinx/templates/quickstart/make.bat_t index 774585566..830cf656e 100644 --- a/sphinx/templates/quickstart/make.bat_t +++ b/sphinx/templates/quickstart/make.bat_t @@ -27,9 +27,9 @@ if "%1" == "help" ( echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and an HTML help project - echo. qthelp to make HTML files and a qthelp project + echo. qthelp to make HTML files and a Qt help project echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub + echo. epub to make an EPUB echo. latex to make LaTeX files (you can set PAPER=a4 or PAPER=letter) echo. latexpdf to make LaTeX files and then PDFs out of them echo. text to make text files @@ -69,7 +69,7 @@ if errorlevel 9009 ( echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ + echo.https://sphinx-doc.org/ exit /b 1 ) diff --git a/sphinx/themes/basic/layout.html b/sphinx/themes/basic/layout.html index 685e548fb..50feffd71 100644 --- a/sphinx/themes/basic/layout.html +++ b/sphinx/themes/basic/layout.html @@ -120,6 +120,7 @@ {%- else %} {%- endif %} + {{- metatags }} {%- block htmltitle %} {{ title|striptags|e }}{{ titlesuffix }} diff --git a/sphinx/themes/basic/static/jquery-3.4.1.js b/sphinx/themes/basic/static/jquery-3.5.1.js similarity index 91% rename from sphinx/themes/basic/static/jquery-3.4.1.js rename to sphinx/themes/basic/static/jquery-3.5.1.js index 773ad95c5..50937333b 100644 --- a/sphinx/themes/basic/static/jquery-3.4.1.js +++ b/sphinx/themes/basic/static/jquery-3.5.1.js @@ -1,5 +1,5 @@ /*! - * jQuery JavaScript Library v3.4.1 + * jQuery JavaScript Library v3.5.1 * https://jquery.com/ * * Includes Sizzle.js @@ -9,7 +9,7 @@ * Released under the MIT license * https://jquery.org/license * - * Date: 2019-05-01T21:04Z + * Date: 2020-05-04T22:49Z */ ( function( global, factory ) { @@ -47,13 +47,16 @@ var arr = []; -var document = window.document; - var getProto = Object.getPrototypeOf; var slice = arr.slice; -var concat = arr.concat; +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + var push = arr.push; @@ -86,6 +89,8 @@ var isWindow = function isWindow( obj ) { }; +var document = window.document; + var preservedScriptAttributes = { @@ -142,7 +147,7 @@ function toType( obj ) { var - version = "3.4.1", + version = "3.5.1", // Define a local copy of jQuery jQuery = function( selector, context ) { @@ -150,11 +155,7 @@ var // The jQuery object is actually just the init constructor 'enhanced' // Need init if jQuery is called (just allow error to be thrown if not included) return new jQuery.fn.init( selector, context ); - }, - - // Support: Android <=4.0 only - // Make sure we trim BOM and NBSP - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; + }; jQuery.fn = jQuery.prototype = { @@ -220,6 +221,18 @@ jQuery.fn = jQuery.prototype = { return this.eq( -1 ); }, + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + eq: function( i ) { var len = this.length, j = +i + ( i < 0 ? len : 0 ); @@ -353,9 +366,10 @@ jQuery.extend( { return true; }, - // Evaluates a script in a global context - globalEval: function( code, options ) { - DOMEval( code, { nonce: options && options.nonce } ); + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); }, each: function( obj, callback ) { @@ -379,13 +393,6 @@ jQuery.extend( { return obj; }, - // Support: Android <=4.0 only - trim: function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - // results is for internal usage only makeArray: function( arr, results ) { var ret = results || []; @@ -472,7 +479,7 @@ jQuery.extend( { } // Flatten any nested arrays - return concat.apply( [], ret ); + return flat( ret ); }, // A global GUID counter for objects @@ -489,7 +496,7 @@ if ( typeof Symbol === "function" ) { // Populate the class2type map jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( i, name ) { +function( _i, name ) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); } ); @@ -511,17 +518,16 @@ function isArrayLike( obj ) { } var Sizzle = /*! - * Sizzle CSS Selector Engine v2.3.4 + * Sizzle CSS Selector Engine v2.3.5 * https://sizzlejs.com/ * * Copyright JS Foundation and other contributors * Released under the MIT license * https://js.foundation/ * - * Date: 2019-04-08 + * Date: 2020-03-14 */ -(function( window ) { - +( function( window ) { var i, support, Expr, @@ -561,59 +567,70 @@ var i, }, // Instance methods - hasOwn = ({}).hasOwnProperty, + hasOwn = ( {} ).hasOwnProperty, arr = [], pop = arr.pop, - push_native = arr.push, + pushNative = arr.push, push = arr.push, slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native // https://jsperf.com/thor-indexof-vs-for/5 indexOf = function( list, elem ) { var i = 0, len = list.length; for ( ; i < len; i++ ) { - if ( list[i] === elem ) { + if ( list[ i ] === elem ) { return i; } } return -1; }, - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", // Regular expressions // http://www.w3.org/TR/css3-selectors/#whitespace whitespace = "[\\x20\\t\\r\\n\\f]", - // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) "*([*^$|!~]?=)" + whitespace + - // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + - "*\\]", + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: // 1. quoted (capture 3; capture 4 or capture 5) "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) ".*" + ")\\)|)", // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), rdescend = new RegExp( whitespace + "|>" ), rpseudo = new RegExp( pseudos ), @@ -625,14 +642,16 @@ var i, "TAG": new RegExp( "^(" + identifier + "|[*])" ), "ATTR": new RegExp( "^" + attributes ), "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) }, rhtml = /HTML$/i, @@ -648,18 +667,21 @@ var i, // CSS escapes // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), - funescape = function( _, escaped, escapedWhitespace ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - // Support: Firefox<24 - // Workaround erroneous numeric interpretation of +"0x" - return high !== high || escapedWhitespace ? - escaped : + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair high < 0 ? - // BMP codepoint String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); }, @@ -675,7 +697,8 @@ var i, } // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; } // Other potentially-special ASCII characters get backslash-escaped @@ -700,18 +723,20 @@ var i, // Optimize for push.apply( _, NodeList ) try { push.apply( - (arr = slice.call( preferredDoc.childNodes )), + ( arr = slice.call( preferredDoc.childNodes ) ), preferredDoc.childNodes ); + // Support: Android<4.0 // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions arr[ preferredDoc.childNodes.length ].nodeType; } catch ( e ) { push = { apply: arr.length ? // Leverage slice if possible function( target, els ) { - push_native.apply( target, slice.call(els) ); + pushNative.apply( target, slice.call( els ) ); } : // Support: IE<9 @@ -719,8 +744,9 @@ try { function( target, els ) { var j = target.length, i = 0; + // Can't trust NodeList.length - while ( (target[j++] = els[i++]) ) {} + while ( ( target[ j++ ] = els[ i++ ] ) ) {} target.length = j - 1; } }; @@ -744,24 +770,21 @@ function Sizzle( selector, context, results, seed ) { // Try to shortcut find operations (as opposed to filters) in HTML documents if ( !seed ) { - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } + setDocument( context ); context = context || document; if ( documentIsHTML ) { // If the selector is sufficiently simple, try using a "get*By*" DOM method // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { // ID selector - if ( (m = match[1]) ) { + if ( ( m = match[ 1 ] ) ) { // Document context if ( nodeType === 9 ) { - if ( (elem = context.getElementById( m )) ) { + if ( ( elem = context.getElementById( m ) ) ) { // Support: IE, Opera, Webkit // TODO: identify versions @@ -780,7 +803,7 @@ function Sizzle( selector, context, results, seed ) { // Support: IE, Opera, Webkit // TODO: identify versions // getElementById can match elements by name instead of ID - if ( newContext && (elem = newContext.getElementById( m )) && + if ( newContext && ( elem = newContext.getElementById( m ) ) && contains( context, elem ) && elem.id === m ) { @@ -790,12 +813,12 @@ function Sizzle( selector, context, results, seed ) { } // Type selector - } else if ( match[2] ) { + } else if ( match[ 2 ] ) { push.apply( results, context.getElementsByTagName( selector ) ); return results; // Class selector - } else if ( (m = match[3]) && support.getElementsByClassName && + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && context.getElementsByClassName ) { push.apply( results, context.getElementsByClassName( m ) ); @@ -806,11 +829,11 @@ function Sizzle( selector, context, results, seed ) { // Take advantage of querySelectorAll if ( support.qsa && !nonnativeSelectorCache[ selector + " " ] && - (!rbuggyQSA || !rbuggyQSA.test( selector )) && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && // Support: IE 8 only // Exclude object elements - (nodeType !== 1 || context.nodeName.toLowerCase() !== "object") ) { + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { newSelector = selector; newContext = context; @@ -819,27 +842,36 @@ function Sizzle( selector, context, results, seed ) { // descendant combinators, which is not what we want. // In such cases, we work around the behavior by prefixing every selector in the // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. // Thanks to Andrew Dupont for this technique. - if ( nodeType === 1 && rdescend.test( selector ) ) { + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { - // Capture the context ID, setting it first if necessary - if ( (nid = context.getAttribute( "id" )) ) { - nid = nid.replace( rcssescape, fcssescape ); - } else { - context.setAttribute( "id", (nid = expando) ); + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } } // Prefix every selector in the list groups = tokenize( selector ); i = groups.length; while ( i-- ) { - groups[i] = "#" + nid + " " + toSelector( groups[i] ); + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); } newSelector = groups.join( "," ); - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; } try { @@ -872,12 +904,14 @@ function createCache() { var keys = []; function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries delete cache[ keys.shift() ]; } - return (cache[ key + " " ] = value); + return ( cache[ key + " " ] = value ); } return cache; } @@ -896,17 +930,19 @@ function markFunction( fn ) { * @param {Function} fn Passed the created element and returns a boolean result */ function assert( fn ) { - var el = document.createElement("fieldset"); + var el = document.createElement( "fieldset" ); try { return !!fn( el ); - } catch (e) { + } catch ( e ) { return false; } finally { + // Remove from its parent by default if ( el.parentNode ) { el.parentNode.removeChild( el ); } + // release memory in IE el = null; } @@ -918,11 +954,11 @@ function assert( fn ) { * @param {Function} handler The method that will be applied */ function addHandle( attrs, handler ) { - var arr = attrs.split("|"), + var arr = attrs.split( "|" ), i = arr.length; while ( i-- ) { - Expr.attrHandle[ arr[i] ] = handler; + Expr.attrHandle[ arr[ i ] ] = handler; } } @@ -944,7 +980,7 @@ function siblingCheck( a, b ) { // Check if b follows a if ( cur ) { - while ( (cur = cur.nextSibling) ) { + while ( ( cur = cur.nextSibling ) ) { if ( cur === b ) { return -1; } @@ -972,7 +1008,7 @@ function createInputPseudo( type ) { function createButtonPseudo( type ) { return function( elem ) { var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; + return ( name === "input" || name === "button" ) && elem.type === type; }; } @@ -1015,7 +1051,7 @@ function createDisabledPseudo( disabled ) { // Where there is no isDisabled, check manually /* jshint -W018 */ elem.isDisabled !== !disabled && - inDisabledFieldset( elem ) === disabled; + inDisabledFieldset( elem ) === disabled; } return elem.disabled === disabled; @@ -1037,21 +1073,21 @@ function createDisabledPseudo( disabled ) { * @param {Function} fn */ function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { + return markFunction( function( argument ) { argument = +argument; - return markFunction(function( seed, matches ) { + return markFunction( function( seed, matches ) { var j, matchIndexes = fn( [], seed.length, argument ), i = matchIndexes.length; // Match elements found at the specified indexes while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); } } - }); - }); + } ); + } ); } /** @@ -1073,7 +1109,7 @@ support = Sizzle.support = {}; */ isXML = Sizzle.isXML = function( elem ) { var namespace = elem.namespaceURI, - docElem = (elem.ownerDocument || elem).documentElement; + docElem = ( elem.ownerDocument || elem ).documentElement; // Support: IE <=8 // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes @@ -1091,7 +1127,11 @@ setDocument = Sizzle.setDocument = function( node ) { doc = node ? node.ownerDocument || node : preferredDoc; // Return early if doc is invalid or already selected - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { return document; } @@ -1100,10 +1140,14 @@ setDocument = Sizzle.setDocument = function( node ) { docElem = document.documentElement; documentIsHTML = !isXML( document ); - // Support: IE 9-11, Edge + // Support: IE 9 - 11+, Edge 12 - 18+ // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - if ( preferredDoc !== document && - (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { // Support: IE 11, Edge if ( subWindow.addEventListener ) { @@ -1115,25 +1159,36 @@ setDocument = Sizzle.setDocument = function( node ) { } } + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + /* Attributes ---------------------------------------------------------------------- */ // Support: IE<8 // Verify that getAttribute really returns attributes and not properties // (excepting IE8 booleans) - support.attributes = assert(function( el ) { + support.attributes = assert( function( el ) { el.className = "i"; - return !el.getAttribute("className"); - }); + return !el.getAttribute( "className" ); + } ); /* getElement(s)By* ---------------------------------------------------------------------- */ // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert(function( el ) { - el.appendChild( document.createComment("") ); - return !el.getElementsByTagName("*").length; - }); + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); // Support: IE<9 support.getElementsByClassName = rnative.test( document.getElementsByClassName ); @@ -1142,38 +1197,38 @@ setDocument = Sizzle.setDocument = function( node ) { // Check if getElementById returns elements by name // The broken getElementById methods don't pick up programmatically-set names, // so use a roundabout getElementsByName test - support.getById = assert(function( el ) { + support.getById = assert( function( el ) { docElem.appendChild( el ).id = expando; return !document.getElementsByName || !document.getElementsByName( expando ).length; - }); + } ); // ID filter and find if ( support.getById ) { - Expr.filter["ID"] = function( id ) { + Expr.filter[ "ID" ] = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { - return elem.getAttribute("id") === attrId; + return elem.getAttribute( "id" ) === attrId; }; }; - Expr.find["ID"] = function( id, context ) { + Expr.find[ "ID" ] = function( id, context ) { if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { var elem = context.getElementById( id ); return elem ? [ elem ] : []; } }; } else { - Expr.filter["ID"] = function( id ) { + Expr.filter[ "ID" ] = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode("id"); + elem.getAttributeNode( "id" ); return node && node.value === attrId; }; }; // Support: IE 6 - 7 only // getElementById is not reliable as a find shortcut - Expr.find["ID"] = function( id, context ) { + Expr.find[ "ID" ] = function( id, context ) { if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { var node, i, elems, elem = context.getElementById( id ); @@ -1181,7 +1236,7 @@ setDocument = Sizzle.setDocument = function( node ) { if ( elem ) { // Verify the id attribute - node = elem.getAttributeNode("id"); + node = elem.getAttributeNode( "id" ); if ( node && node.value === id ) { return [ elem ]; } @@ -1189,8 +1244,8 @@ setDocument = Sizzle.setDocument = function( node ) { // Fall back on getElementsByName elems = context.getElementsByName( id ); i = 0; - while ( (elem = elems[i++]) ) { - node = elem.getAttributeNode("id"); + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); if ( node && node.value === id ) { return [ elem ]; } @@ -1203,7 +1258,7 @@ setDocument = Sizzle.setDocument = function( node ) { } // Tag - Expr.find["TAG"] = support.getElementsByTagName ? + Expr.find[ "TAG" ] = support.getElementsByTagName ? function( tag, context ) { if ( typeof context.getElementsByTagName !== "undefined" ) { return context.getElementsByTagName( tag ); @@ -1218,12 +1273,13 @@ setDocument = Sizzle.setDocument = function( node ) { var elem, tmp = [], i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too results = context.getElementsByTagName( tag ); // Filter out possible comments if ( tag === "*" ) { - while ( (elem = results[i++]) ) { + while ( ( elem = results[ i++ ] ) ) { if ( elem.nodeType === 1 ) { tmp.push( elem ); } @@ -1235,7 +1291,7 @@ setDocument = Sizzle.setDocument = function( node ) { }; // Class - Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { return context.getElementsByClassName( className ); } @@ -1256,10 +1312,14 @@ setDocument = Sizzle.setDocument = function( node ) { // See https://bugs.jquery.com/ticket/13378 rbuggyQSA = []; - if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + // Build QSA regex // Regex strategy adopted from Diego Perini - assert(function( el ) { + assert( function( el ) { + + var input; + // Select is set to empty string on purpose // This is to test IE's treatment of not explicitly // setting a boolean content attribute, @@ -1273,78 +1333,98 @@ setDocument = Sizzle.setDocument = function( node ) { // Nothing should be selected when empty strings follow ^= or $= or *= // The test attribute must be unknown in Opera but "safe" for WinRT // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( el.querySelectorAll("[msallowcapture^='']").length ) { + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); } // Support: IE8 // Boolean attributes and "value" are not treated correctly - if ( !el.querySelectorAll("[selected]").length ) { + if ( !el.querySelectorAll( "[selected]" ).length ) { rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); } // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push("~="); + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); } // Webkit/Opera - :checked should return selected option elements // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked // IE8 throws error here and will not see later tests - if ( !el.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); } // Support: Safari 8+, iOS 8+ // https://bugs.webkit.org/show_bug.cgi?id=136851 // In-page `selector#id sibling-combinator selector` fails if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push(".#.+[+~]"); + rbuggyQSA.push( ".#.+[+~]" ); } - }); - assert(function( el ) { + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { el.innerHTML = "" + ""; // Support: Windows 8 Native Apps // The type and name attributes are restricted during .innerHTML assignment - var input = document.createElement("input"); + var input = document.createElement( "input" ); input.setAttribute( "type", "hidden" ); el.appendChild( input ).setAttribute( "name", "D" ); // Support: IE8 // Enforce case-sensitivity of name attribute - if ( el.querySelectorAll("[name=d]").length ) { + if ( el.querySelectorAll( "[name=d]" ).length ) { rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); } // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) // IE8 throws error here and will not see later tests - if ( el.querySelectorAll(":enabled").length !== 2 ) { + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { rbuggyQSA.push( ":enabled", ":disabled" ); } // Support: IE9-11+ // IE's :disabled selector does not pick up the children of disabled fieldsets docElem.appendChild( el ).disabled = true; - if ( el.querySelectorAll(":disabled").length !== 2 ) { + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { rbuggyQSA.push( ":enabled", ":disabled" ); } + // Support: Opera 10 - 11 only // Opera 10-11 does not throw on post-comma invalid pseudos - el.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); } - if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || docElem.webkitMatchesSelector || docElem.mozMatchesSelector || docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { - assert(function( el ) { // Check to see if it's possible to do matchesSelector // on a disconnected node (IE 9) support.disconnectedMatch = matches.call( el, "*" ); @@ -1353,11 +1433,11 @@ setDocument = Sizzle.setDocument = function( node ) { // Gecko does not error, returns false instead matches.call( el, "[s!='']:x" ); rbuggyMatches.push( "!=", pseudos ); - }); + } ); } - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); /* Contains ---------------------------------------------------------------------- */ @@ -1374,11 +1454,11 @@ setDocument = Sizzle.setDocument = function( node ) { adown.contains ? adown.contains( bup ) : a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); + ) ); } : function( a, b ) { if ( b ) { - while ( (b = b.parentNode) ) { + while ( ( b = b.parentNode ) ) { if ( b === a ) { return true; } @@ -1407,7 +1487,11 @@ setDocument = Sizzle.setDocument = function( node ) { } // Calculate position if both inputs belong to the same document - compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? a.compareDocumentPosition( b ) : // Otherwise we know they are disconnected @@ -1415,13 +1499,24 @@ setDocument = Sizzle.setDocument = function( node ) { // Disconnected nodes if ( compare & 1 || - (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { // Choose the first element that is related to our preferred document - if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { return -1; } - if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { return 1; } @@ -1434,6 +1529,7 @@ setDocument = Sizzle.setDocument = function( node ) { return compare & 4 ? -1 : 1; } : function( a, b ) { + // Exit early if the nodes are identical if ( a === b ) { hasDuplicate = true; @@ -1449,8 +1545,14 @@ setDocument = Sizzle.setDocument = function( node ) { // Parentless nodes are either documents or disconnected if ( !aup || !bup ) { - return a === document ? -1 : - b === document ? 1 : + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ aup ? -1 : bup ? 1 : sortInput ? @@ -1464,26 +1566,32 @@ setDocument = Sizzle.setDocument = function( node ) { // Otherwise we need full lists of their ancestors for comparison cur = a; - while ( (cur = cur.parentNode) ) { + while ( ( cur = cur.parentNode ) ) { ap.unshift( cur ); } cur = b; - while ( (cur = cur.parentNode) ) { + while ( ( cur = cur.parentNode ) ) { bp.unshift( cur ); } // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { + while ( ap[ i ] === bp[ i ] ) { i++; } return i ? + // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : + siblingCheck( ap[ i ], bp[ i ] ) : // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ 0; }; @@ -1495,10 +1603,7 @@ Sizzle.matches = function( expr, elements ) { }; Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } + setDocument( elem ); if ( support.matchesSelector && documentIsHTML && !nonnativeSelectorCache[ expr + " " ] && @@ -1510,12 +1615,13 @@ Sizzle.matchesSelector = function( elem, expr ) { // IE 9's matchesSelector returns false on disconnected nodes if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { return ret; } - } catch (e) { + } catch ( e ) { nonnativeSelectorCache( expr, true ); } } @@ -1524,20 +1630,31 @@ Sizzle.matchesSelector = function( elem, expr ) { }; Sizzle.contains = function( context, elem ) { + // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { setDocument( context ); } return contains( context, elem ); }; Sizzle.attr = function( elem, name ) { + // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { setDocument( elem ); } var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? fn( elem, name, !documentIsHTML ) : @@ -1547,13 +1664,13 @@ Sizzle.attr = function( elem, name ) { val : support.attributes || !documentIsHTML ? elem.getAttribute( name ) : - (val = elem.getAttributeNode(name)) && val.specified ? + ( val = elem.getAttributeNode( name ) ) && val.specified ? val.value : null; }; Sizzle.escape = function( sel ) { - return (sel + "").replace( rcssescape, fcssescape ); + return ( sel + "" ).replace( rcssescape, fcssescape ); }; Sizzle.error = function( msg ) { @@ -1576,7 +1693,7 @@ Sizzle.uniqueSort = function( results ) { results.sort( sortOrder ); if ( hasDuplicate ) { - while ( (elem = results[i++]) ) { + while ( ( elem = results[ i++ ] ) ) { if ( elem === results[ i ] ) { j = duplicates.push( i ); } @@ -1604,17 +1721,21 @@ getText = Sizzle.getText = function( elem ) { nodeType = elem.nodeType; if ( !nodeType ) { + // If no nodeType, this is expected to be an array - while ( (node = elem[i++]) ) { + while ( ( node = elem[ i++ ] ) ) { + // Do not traverse comment nodes ret += getText( node ); } } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements // innerText usage removed for consistency of new lines (jQuery #11153) if ( typeof elem.textContent === "string" ) { return elem.textContent; } else { + // Traverse its children for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { ret += getText( elem ); @@ -1623,6 +1744,7 @@ getText = Sizzle.getText = function( elem ) { } else if ( nodeType === 3 || nodeType === 4 ) { return elem.nodeValue; } + // Do not include comment or processing instruction nodes return ret; @@ -1650,19 +1772,21 @@ Expr = Sizzle.selectors = { preFilter: { "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; } return match.slice( 0, 4 ); }, "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] 1 type (only|nth|...) 2 what (child|of-type) @@ -1673,22 +1797,25 @@ Expr = Sizzle.selectors = { 7 sign of y-component 8 y of y-component */ - match[1] = match[1].toLowerCase(); + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { - if ( match[1].slice( 0, 3 ) === "nth" ) { // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); } // numeric x and y parameters for Expr.filter.CHILD // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); } return match; @@ -1696,26 +1823,28 @@ Expr = Sizzle.selectors = { "PSEUDO": function( match ) { var excess, - unquoted = !match[6] && match[2]; + unquoted = !match[ 6 ] && match[ 2 ]; - if ( matchExpr["CHILD"].test( match[0] ) ) { + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { return null; } // Accept quoted arguments as-is - if ( match[3] ) { - match[2] = match[4] || match[5] || ""; + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; // Strip excess characters from unquoted arguments } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && + ( excess = tokenize( unquoted, true ) ) && + // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); } // Return only captures needed by the pseudo filter method (type and argument) @@ -1728,7 +1857,9 @@ Expr = Sizzle.selectors = { "TAG": function( nodeNameSelector ) { var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); return nodeNameSelector === "*" ? - function() { return true; } : + function() { + return true; + } : function( elem ) { return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; }; @@ -1738,10 +1869,16 @@ Expr = Sizzle.selectors = { var pattern = classCache[ className + " " ]; return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); - }); + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); }, "ATTR": function( name, operator, check ) { @@ -1757,6 +1894,8 @@ Expr = Sizzle.selectors = { result += ""; + /* eslint-disable max-len */ + return operator === "=" ? result === check : operator === "!=" ? result !== check : operator === "^=" ? check && result.indexOf( check ) === 0 : @@ -1765,10 +1904,12 @@ Expr = Sizzle.selectors = { operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : false; + /* eslint-enable max-len */ + }; }, - "CHILD": function( type, what, argument, first, last ) { + "CHILD": function( type, what, _argument, first, last ) { var simple = type.slice( 0, 3 ) !== "nth", forward = type.slice( -4 ) !== "last", ofType = what === "of-type"; @@ -1780,7 +1921,7 @@ Expr = Sizzle.selectors = { return !!elem.parentNode; } : - function( elem, context, xml ) { + function( elem, _context, xml ) { var cache, uniqueCache, outerCache, node, nodeIndex, start, dir = simple !== forward ? "nextSibling" : "previousSibling", parent = elem.parentNode, @@ -1794,7 +1935,7 @@ Expr = Sizzle.selectors = { if ( simple ) { while ( dir ) { node = elem; - while ( (node = node[ dir ]) ) { + while ( ( node = node[ dir ] ) ) { if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { @@ -1802,6 +1943,7 @@ Expr = Sizzle.selectors = { return false; } } + // Reverse direction for :only-* (if we haven't yet done so) start = dir = type === "only" && !start && "nextSibling"; } @@ -1817,22 +1959,22 @@ Expr = Sizzle.selectors = { // ...in a gzip-friendly way node = parent; - outerCache = node[ expando ] || (node[ expando ] = {}); + outerCache = node[ expando ] || ( node[ expando ] = {} ); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); + ( outerCache[ node.uniqueID ] = {} ); cache = uniqueCache[ type ] || []; nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; diff = nodeIndex && cache[ 2 ]; node = nodeIndex && parent.childNodes[ nodeIndex ]; - while ( (node = ++nodeIndex && node && node[ dir ] || + while ( ( node = ++nodeIndex && node && node[ dir ] || // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { + ( diff = nodeIndex = 0 ) || start.pop() ) ) { // When found, cache indexes on `parent` and break if ( node.nodeType === 1 && ++diff && node === elem ) { @@ -1842,16 +1984,18 @@ Expr = Sizzle.selectors = { } } else { + // Use previously-cached element index if available if ( useCache ) { + // ...in a gzip-friendly way node = elem; - outerCache = node[ expando ] || (node[ expando ] = {}); + outerCache = node[ expando ] || ( node[ expando ] = {} ); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); + ( outerCache[ node.uniqueID ] = {} ); cache = uniqueCache[ type ] || []; nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; @@ -1861,9 +2005,10 @@ Expr = Sizzle.selectors = { // xml :nth-child(...) // or :nth-last-child(...) or :nth(-last)?-of-type(...) if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start - while ( (node = ++nodeIndex && node && node[ dir ] || - (diff = nodeIndex = 0) || start.pop()) ) { + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { if ( ( ofType ? node.nodeName.toLowerCase() === name : @@ -1872,12 +2017,13 @@ Expr = Sizzle.selectors = { // Cache the index of each encountered element if ( useCache ) { - outerCache = node[ expando ] || (node[ expando ] = {}); + outerCache = node[ expando ] || + ( node[ expando ] = {} ); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); + ( outerCache[ node.uniqueID ] = {} ); uniqueCache[ type ] = [ dirruns, diff ]; } @@ -1898,6 +2044,7 @@ Expr = Sizzle.selectors = { }, "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive // http://www.w3.org/TR/selectors/#pseudo-classes // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters @@ -1917,15 +2064,15 @@ Expr = Sizzle.selectors = { if ( fn.length > 1 ) { args = [ pseudo, pseudo, "", argument ]; return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { + markFunction( function( seed, matches ) { var idx, matched = fn( seed, argument ), i = matched.length; while ( i-- ) { - idx = indexOf( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); } - }) : + } ) : function( elem ) { return fn( elem, 0, args ); }; @@ -1936,8 +2083,10 @@ Expr = Sizzle.selectors = { }, pseudos: { + // Potentially complex pseudos - "not": markFunction(function( selector ) { + "not": markFunction( function( selector ) { + // Trim the selector passed to compile // to avoid treating leading and trailing // spaces as combinators @@ -1946,39 +2095,40 @@ Expr = Sizzle.selectors = { matcher = compile( selector.replace( rtrim, "$1" ) ); return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { + markFunction( function( seed, matches, _context, xml ) { var elem, unmatched = matcher( seed, null, xml, [] ), i = seed.length; // Match elements unmatched by `matcher` while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); } } - }) : - function( elem, context, xml ) { - input[0] = elem; + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; matcher( input, null, xml, results ); + // Don't keep the element (issue #299) - input[0] = null; + input[ 0 ] = null; return !results.pop(); }; - }), + } ), - "has": markFunction(function( selector ) { + "has": markFunction( function( selector ) { return function( elem ) { return Sizzle( selector, elem ).length > 0; }; - }), + } ), - "contains": markFunction(function( text ) { + "contains": markFunction( function( text ) { text = text.replace( runescape, funescape ); return function( elem ) { return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; }; - }), + } ), // "Whether an element is represented by a :lang() selector // is based solely on the element's language value @@ -1988,25 +2138,26 @@ Expr = Sizzle.selectors = { // The identifier C does not have to be a valid language name." // http://www.w3.org/TR/selectors/#lang-pseudo "lang": markFunction( function( lang ) { + // lang value must be a valid identifier - if ( !ridentifier.test(lang || "") ) { + if ( !ridentifier.test( lang || "" ) ) { Sizzle.error( "unsupported lang: " + lang ); } lang = lang.replace( runescape, funescape ).toLowerCase(); return function( elem ) { var elemLang; do { - if ( (elemLang = documentIsHTML ? + if ( ( elemLang = documentIsHTML ? elem.lang : - elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { elemLang = elemLang.toLowerCase(); return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); return false; }; - }), + } ), // Miscellaneous "target": function( elem ) { @@ -2019,7 +2170,9 @@ Expr = Sizzle.selectors = { }, "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); }, // Boolean properties @@ -2027,16 +2180,20 @@ Expr = Sizzle.selectors = { "disabled": createDisabledPseudo( true ), "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); }, "selected": function( elem ) { + // Accessing this property makes selected-by-default // options in Safari work properly if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions elem.parentNode.selectedIndex; } @@ -2045,6 +2202,7 @@ Expr = Sizzle.selectors = { // Contents "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), // but not by others (comment: 8; processing instruction: 7; etc.) @@ -2058,7 +2216,7 @@ Expr = Sizzle.selectors = { }, "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); + return !Expr.pseudos[ "empty" ]( elem ); }, // Element/input types @@ -2082,39 +2240,40 @@ Expr = Sizzle.selectors = { // Support: IE<8 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); }, // Position-in-collection - "first": createPositionalPseudo(function() { + "first": createPositionalPseudo( function() { return [ 0 ]; - }), + } ), - "last": createPositionalPseudo(function( matchIndexes, length ) { + "last": createPositionalPseudo( function( _matchIndexes, length ) { return [ length - 1 ]; - }), + } ), - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { return [ argument < 0 ? argument + length : argument ]; - }), + } ), - "even": createPositionalPseudo(function( matchIndexes, length ) { + "even": createPositionalPseudo( function( matchIndexes, length ) { var i = 0; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); } return matchIndexes; - }), + } ), - "odd": createPositionalPseudo(function( matchIndexes, length ) { + "odd": createPositionalPseudo( function( matchIndexes, length ) { var i = 1; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); } return matchIndexes; - }), + } ), - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { var i = argument < 0 ? argument + length : argument > length ? @@ -2124,19 +2283,19 @@ Expr = Sizzle.selectors = { matchIndexes.push( i ); } return matchIndexes; - }), + } ), - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { var i = argument < 0 ? argument + length : argument; for ( ; ++i < length; ) { matchIndexes.push( i ); } return matchIndexes; - }) + } ) } }; -Expr.pseudos["nth"] = Expr.pseudos["eq"]; +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; // Add button/input type pseudos for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { @@ -2167,37 +2326,39 @@ tokenize = Sizzle.tokenize = function( selector, parseOnly ) { while ( soFar ) { // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { if ( match ) { + // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; + soFar = soFar.slice( match[ 0 ].length ) || soFar; } - groups.push( (tokens = []) ); + groups.push( ( tokens = [] ) ); } matched = false; // Combinators - if ( (match = rcombinators.exec( soFar )) ) { + if ( ( match = rcombinators.exec( soFar ) ) ) { matched = match.shift(); - tokens.push({ + tokens.push( { value: matched, + // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - }); + type: match[ 0 ].replace( rtrim, " " ) + } ); soFar = soFar.slice( matched.length ); } // Filters for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { matched = match.shift(); - tokens.push({ + tokens.push( { value: matched, type: type, matches: match - }); + } ); soFar = soFar.slice( matched.length ); } } @@ -2214,6 +2375,7 @@ tokenize = Sizzle.tokenize = function( selector, parseOnly ) { soFar.length : soFar ? Sizzle.error( selector ) : + // Cache the tokens tokenCache( selector, groups ).slice( 0 ); }; @@ -2223,7 +2385,7 @@ function toSelector( tokens ) { len = tokens.length, selector = ""; for ( ; i < len; i++ ) { - selector += tokens[i].value; + selector += tokens[ i ].value; } return selector; } @@ -2236,9 +2398,10 @@ function addCombinator( matcher, combinator, base ) { doneName = done++; return combinator.first ? + // Check against closest ancestor/preceding element function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { + while ( ( elem = elem[ dir ] ) ) { if ( elem.nodeType === 1 || checkNonElements ) { return matcher( elem, context, xml ); } @@ -2253,7 +2416,7 @@ function addCombinator( matcher, combinator, base ) { // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching if ( xml ) { - while ( (elem = elem[ dir ]) ) { + while ( ( elem = elem[ dir ] ) ) { if ( elem.nodeType === 1 || checkNonElements ) { if ( matcher( elem, context, xml ) ) { return true; @@ -2261,27 +2424,29 @@ function addCombinator( matcher, combinator, base ) { } } } else { - while ( (elem = elem[ dir ]) ) { + while ( ( elem = elem[ dir ] ) ) { if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); if ( skip && skip === elem.nodeName.toLowerCase() ) { elem = elem[ dir ] || elem; - } else if ( (oldCache = uniqueCache[ key ]) && + } else if ( ( oldCache = uniqueCache[ key ] ) && oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { // Assign to newCache so results back-propagate to previous elements - return (newCache[ 2 ] = oldCache[ 2 ]); + return ( newCache[ 2 ] = oldCache[ 2 ] ); } else { + // Reuse newcache so results back-propagate to previous elements uniqueCache[ key ] = newCache; // A match means we're done; a fail means we have to keep checking - if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { return true; } } @@ -2297,20 +2462,20 @@ function elementMatcher( matchers ) { function( elem, context, xml ) { var i = matchers.length; while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { + if ( !matchers[ i ]( elem, context, xml ) ) { return false; } } return true; } : - matchers[0]; + matchers[ 0 ]; } function multipleContexts( selector, contexts, results ) { var i = 0, len = contexts.length; for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); + Sizzle( selector, contexts[ i ], results ); } return results; } @@ -2323,7 +2488,7 @@ function condense( unmatched, map, filter, context, xml ) { mapped = map != null; for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { + if ( ( elem = unmatched[ i ] ) ) { if ( !filter || filter( elem, context, xml ) ) { newUnmatched.push( elem ); if ( mapped ) { @@ -2343,14 +2508,18 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS if ( postFinder && !postFinder[ expando ] ) { postFinder = setMatcher( postFinder, postSelector ); } - return markFunction(function( seed, results, context, xml ) { + return markFunction( function( seed, results, context, xml ) { var temp, i, elem, preMap = [], postMap = [], preexisting = results.length, // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), // Prefilter to get matcher input, preserving a map for seed-results synchronization matcherIn = preFilter && ( seed || !selector ) ? @@ -2358,6 +2527,7 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS elems, matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, postFinder || ( seed ? preFilter : preexisting || postFilter ) ? @@ -2381,8 +2551,8 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS // Un-match failing elements by moving them back to matcherIn i = temp.length; while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); } } } @@ -2390,25 +2560,27 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS if ( seed ) { if ( postFinder || preFilter ) { if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts temp = []; i = matcherOut.length; while ( i-- ) { - if ( (elem = matcherOut[i]) ) { + if ( ( elem = matcherOut[ i ] ) ) { + // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); + temp.push( ( matcherIn[ i ] = elem ) ); } } - postFinder( null, (matcherOut = []), temp, xml ); + postFinder( null, ( matcherOut = [] ), temp, xml ); } // Move matched elements from seed to results to keep them synchronized i = matcherOut.length; while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { - seed[temp] = !(results[temp] = elem); + seed[ temp ] = !( results[ temp ] = elem ); } } } @@ -2426,14 +2598,14 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS push.apply( results, matcherOut ); } } - }); + } ); } function matcherFromTokens( tokens ) { var checkContext, matcher, j, len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], i = leadingRelative ? 1 : 0, // The foundational matcher ensures that elements are reachable from top-level context(s) @@ -2445,38 +2617,43 @@ function matcherFromTokens( tokens ) { }, implicitRelative, true ), matchers = [ function( elem, context, xml ) { var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? + ( checkContext = context ).nodeType ? matchContext( elem, context, xml ) : matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) checkContext = null; return ret; } ]; for ( ; i < len; i++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); // Return special upon seeing a positional matcher if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling j = ++i; for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { + if ( Expr.relative[ tokens[ j ].type ] ) { break; } } return setMatcher( i > 1 && elementMatcher( matchers ), i > 1 && toSelector( - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) ).replace( rtrim, "$1" ), matcher, i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), j < len && toSelector( tokens ) ); } @@ -2497,28 +2674,40 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { unmatched = seed && [], setMatched = [], contextBackup = outermostContext, + // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), len = elems.length; if ( outermost ) { - outermostContext = context === document || context || outermost; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; } // Add elements passing elementMatchers directly to results // Support: IE<9, Safari // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id - for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { if ( byElement && elem ) { j = 0; - if ( !context && elem.ownerDocument !== document ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { setDocument( elem ); xml = !documentIsHTML; } - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context || document, xml) ) { + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { results.push( elem ); break; } @@ -2530,8 +2719,9 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { // Track unmatched elements for set filters if ( bySet ) { + // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { + if ( ( elem = !matcher && elem ) ) { matchedCount--; } @@ -2555,16 +2745,17 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { // numerically zero. if ( bySet && i !== matchedCount ) { j = 0; - while ( (matcher = setMatchers[j++]) ) { + while ( ( matcher = setMatchers[ j++ ] ) ) { matcher( unmatched, setMatched, context, xml ); } if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting if ( matchedCount > 0 ) { while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); } } } @@ -2605,13 +2796,14 @@ compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { cached = compilerCache[ selector + " " ]; if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element if ( !match ) { match = tokenize( selector ); } i = match.length; while ( i-- ) { - cached = matcherFromTokens( match[i] ); + cached = matcherFromTokens( match[ i ] ); if ( cached[ expando ] ) { setMatchers.push( cached ); } else { @@ -2620,7 +2812,10 @@ compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { } // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); // Save selector and tokenization cached.selector = selector; @@ -2640,7 +2835,7 @@ compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { select = Sizzle.select = function( selector, context, results, seed ) { var i, tokens, token, type, find, compiled = typeof selector === "function" && selector, - match = !seed && tokenize( (selector = compiled.selector || selector) ); + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); results = results || []; @@ -2649,11 +2844,12 @@ select = Sizzle.select = function( selector, context, results, seed ) { if ( match.length === 1 ) { // Reduce context if the leading compound selector is an ID - tokens = match[0] = match[0].slice( 0 ); - if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && - context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { - context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; if ( !context ) { return results; @@ -2666,20 +2862,22 @@ select = Sizzle.select = function( selector, context, results, seed ) { } // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; while ( i-- ) { - token = tokens[i]; + token = tokens[ i ]; // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { + if ( Expr.relative[ ( type = token.type ) ] ) { break; } - if ( (find = Expr.find[ type ]) ) { + if ( ( find = Expr.find[ type ] ) ) { + // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context - )) ) { + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { // If seed is empty or no tokens remain, we can return early tokens.splice( i, 1 ); @@ -2710,7 +2908,7 @@ select = Sizzle.select = function( selector, context, results, seed ) { // One-time assignments // Sort stability -support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; // Support: Chrome 14-35+ // Always assume duplicates if they aren't passed to the comparison function @@ -2721,58 +2919,59 @@ setDocument(); // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) // Detached nodes confoundingly follow *each other* -support.sortDetached = assert(function( el ) { +support.sortDetached = assert( function( el ) { + // Should return 1, but returns 4 (following) - return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; -}); + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); // Support: IE<8 // Prevent attribute/property "interpolation" // https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert(function( el ) { +if ( !assert( function( el ) { el.innerHTML = ""; - return el.firstChild.getAttribute("href") === "#" ; -}) ) { + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { addHandle( "type|href|height|width", function( elem, name, isXML ) { if ( !isXML ) { return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); } - }); + } ); } // Support: IE<9 // Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert(function( el ) { +if ( !support.attributes || !assert( function( el ) { el.innerHTML = ""; el.firstChild.setAttribute( "value", "" ); return el.firstChild.getAttribute( "value" ) === ""; -}) ) { - addHandle( "value", function( elem, name, isXML ) { +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { return elem.defaultValue; } - }); + } ); } // Support: IE<9 // Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert(function( el ) { - return el.getAttribute("disabled") == null; -}) ) { +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { addHandle( booleans, function( elem, name, isXML ) { var val; if ( !isXML ) { return elem[ name ] === true ? name.toLowerCase() : - (val = elem.getAttributeNode( name )) && val.specified ? + ( val = elem.getAttributeNode( name ) ) && val.specified ? val.value : - null; + null; } - }); + } ); } return Sizzle; -})( window ); +} )( window ); @@ -3141,7 +3340,7 @@ jQuery.each( { parents: function( elem ) { return dir( elem, "parentNode" ); }, - parentsUntil: function( elem, i, until ) { + parentsUntil: function( elem, _i, until ) { return dir( elem, "parentNode", until ); }, next: function( elem ) { @@ -3156,10 +3355,10 @@ jQuery.each( { prevAll: function( elem ) { return dir( elem, "previousSibling" ); }, - nextUntil: function( elem, i, until ) { + nextUntil: function( elem, _i, until ) { return dir( elem, "nextSibling", until ); }, - prevUntil: function( elem, i, until ) { + prevUntil: function( elem, _i, until ) { return dir( elem, "previousSibling", until ); }, siblings: function( elem ) { @@ -3169,7 +3368,13 @@ jQuery.each( { return siblings( elem.firstChild ); }, contents: function( elem ) { - if ( typeof elem.contentDocument !== "undefined" ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + return elem.contentDocument; } @@ -3512,7 +3717,7 @@ jQuery.extend( { var fns = arguments; return jQuery.Deferred( function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { + jQuery.each( tuples, function( _i, tuple ) { // Map tuples (progress, done, fail) to arguments (done, fail, progress) var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; @@ -3965,7 +4170,7 @@ var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { // ...except when executing function values } else { bulk = fn; - fn = function( elem, key, value ) { + fn = function( elem, _key, value ) { return bulk.call( jQuery( elem ), value ); }; } @@ -4000,7 +4205,7 @@ var rmsPrefix = /^-ms-/, rdashAlpha = /-([a-z])/g; // Used by camelCase as callback to replace() -function fcamelCase( all, letter ) { +function fcamelCase( _all, letter ) { return letter.toUpperCase(); } @@ -4528,27 +4733,6 @@ var isHiddenWithinTree = function( elem, el ) { jQuery.css( elem, "display" ) === "none"; }; -var swap = function( elem, options, callback, args ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.apply( elem, args || [] ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; -}; - - function adjustCSS( elem, prop, valueParts, tween ) { @@ -4719,11 +4903,40 @@ var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); -// We have to close these tags to support XHTML (#13200) -var wrapMap = { +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; // Support: IE <=9 only - option: [ 1, "" ], + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { // XHTML parsers do not magically insert elements in the // same way that tag soup parsers do. So we cannot shorten @@ -4736,12 +4949,14 @@ var wrapMap = { _default: [ 0, "", "" ] }; -// Support: IE <=9 only -wrapMap.optgroup = wrapMap.option; - wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td; +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + function getAll( context, tag ) { @@ -4874,32 +5089,6 @@ function buildFragment( elems, context, scripts, selection, ignored ) { } -( function() { - var fragment = document.createDocumentFragment(), - div = fragment.appendChild( document.createElement( "div" ) ), - input = document.createElement( "input" ); - - // Support: Android 4.0 - 4.3 only - // Check state lost if the name is set (#11217) - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (#14901) - input.setAttribute( "type", "radio" ); - input.setAttribute( "checked", "checked" ); - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - - // Support: Android <=4.1 only - // Older WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE <=11 only - // Make sure textarea (and checkbox) defaultValue is properly cloned - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; -} )(); - - var rkeyEvent = /^key/, rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, @@ -5008,8 +5197,8 @@ jQuery.event = { special, handlers, type, namespaces, origType, elemData = dataPriv.get( elem ); - // Don't attach events to noData or text/comment nodes (but allow plain objects) - if ( !elemData ) { + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { return; } @@ -5033,7 +5222,7 @@ jQuery.event = { // Init the element's event structure and main handler, if this is the first if ( !( events = elemData.events ) ) { - events = elemData.events = {}; + events = elemData.events = Object.create( null ); } if ( !( eventHandle = elemData.handle ) ) { eventHandle = elemData.handle = function( e ) { @@ -5191,12 +5380,15 @@ jQuery.event = { dispatch: function( nativeEvent ) { - // Make a writable jQuery.Event from the native event object - var event = jQuery.event.fix( nativeEvent ); - var i, j, ret, matched, handleObj, handlerQueue, args = new Array( arguments.length ), - handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], special = jQuery.event.special[ event.type ] || {}; // Use the fix-ed jQuery.Event rather than the (read-only) native event @@ -5771,13 +5963,6 @@ jQuery.fn.extend( { var - /* eslint-disable max-len */ - - // See https://github.com/eslint/eslint/issues/3229 - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, - - /* eslint-enable */ - // Support: IE <=10 - 11, Edge 12 - 13 only // In IE/Edge using regex groups here causes severe slowdowns. // See https://connect.microsoft.com/IE/feedback/details/1736512/ @@ -5814,7 +5999,7 @@ function restoreScript( elem ) { } function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + var i, l, type, pdataOld, udataOld, udataCur, events; if ( dest.nodeType !== 1 ) { return; @@ -5822,13 +6007,11 @@ function cloneCopyEvent( src, dest ) { // 1. Copy private data: events, handlers, etc. if ( dataPriv.hasData( src ) ) { - pdataOld = dataPriv.access( src ); - pdataCur = dataPriv.set( dest, pdataOld ); + pdataOld = dataPriv.get( src ); events = pdataOld.events; if ( events ) { - delete pdataCur.handle; - pdataCur.events = {}; + dataPriv.remove( dest, "handle events" ); for ( type in events ) { for ( i = 0, l = events[ type ].length; i < l; i++ ) { @@ -5864,7 +6047,7 @@ function fixInput( src, dest ) { function domManip( collection, args, callback, ignored ) { // Flatten any nested arrays - args = concat.apply( [], args ); + args = flat( args ); var fragment, first, scripts, hasScripts, node, doc, i = 0, @@ -5939,7 +6122,7 @@ function domManip( collection, args, callback, ignored ) { if ( jQuery._evalUrl && !node.noModule ) { jQuery._evalUrl( node.src, { nonce: node.nonce || node.getAttribute( "nonce" ) - } ); + }, doc ); } } else { DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); @@ -5976,7 +6159,7 @@ function remove( elem, selector, keepData ) { jQuery.extend( { htmlPrefilter: function( html ) { - return html.replace( rxhtmlTag, "<$1>" ); + return html; }, clone: function( elem, dataAndEvents, deepDataAndEvents ) { @@ -6238,6 +6421,27 @@ var getStyles = function( elem ) { return view.getComputedStyle( elem ); }; +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); @@ -6295,7 +6499,7 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); } var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, - reliableMarginLeftVal, + reliableTrDimensionsVal, reliableMarginLeftVal, container = document.createElement( "div" ), div = document.createElement( "div" ); @@ -6330,6 +6534,35 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); scrollboxSize: function() { computeStyleTests(); return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px"; + tr.style.height = "1px"; + trChild.style.height = "9px"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; } } ); } )(); @@ -6454,7 +6687,7 @@ var fontWeight: "400" }; -function setPositiveNumber( elem, value, subtract ) { +function setPositiveNumber( _elem, value, subtract ) { // Any relative (+/-) values have already been // normalized at this point @@ -6559,17 +6792,26 @@ function getWidthOrHeight( elem, dimension, extra ) { } - // Fall back to offsetWidth/offsetHeight when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - // Support: Android <=4.1 - 4.3 only - // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) - // Support: IE 9-11 only - // Also use offsetWidth/offsetHeight for when box sizing is unreliable - // We use getClientRects() to check for hidden/disconnected. - // In those cases, the computed value can be trusted to be border-box + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected elem.getClientRects().length ) { isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; @@ -6764,7 +7006,7 @@ jQuery.extend( { } } ); -jQuery.each( [ "height", "width" ], function( i, dimension ) { +jQuery.each( [ "height", "width" ], function( _i, dimension ) { jQuery.cssHooks[ dimension ] = { get: function( elem, computed, extra ) { if ( computed ) { @@ -7537,7 +7779,7 @@ jQuery.fn.extend( { clearQueue = type; type = undefined; } - if ( clearQueue && type !== false ) { + if ( clearQueue ) { this.queue( type || "fx", [] ); } @@ -7620,7 +7862,7 @@ jQuery.fn.extend( { } } ); -jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { var cssFn = jQuery.fn[ name ]; jQuery.fn[ name ] = function( speed, easing, callback ) { return speed == null || typeof speed === "boolean" ? @@ -7841,7 +8083,7 @@ boolHook = { } }; -jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { var getter = attrHandle[ name ] || jQuery.find.attr; attrHandle[ name ] = function( elem, name, isXML ) { @@ -8465,7 +8707,9 @@ jQuery.extend( jQuery.event, { special.bindType || type; // jQuery handler - handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + handle = ( + dataPriv.get( cur, "events" ) || Object.create( null ) + )[ event.type ] && dataPriv.get( cur, "handle" ); if ( handle ) { handle.apply( cur, data ); @@ -8576,7 +8820,10 @@ if ( !support.focusin ) { jQuery.event.special[ fix ] = { setup: function() { - var doc = this.ownerDocument || this, + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, attaches = dataPriv.access( doc, fix ); if ( !attaches ) { @@ -8585,7 +8832,7 @@ if ( !support.focusin ) { dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); }, teardown: function() { - var doc = this.ownerDocument || this, + var doc = this.ownerDocument || this.document || this, attaches = dataPriv.access( doc, fix ) - 1; if ( !attaches ) { @@ -8601,7 +8848,7 @@ if ( !support.focusin ) { } var location = window.location; -var nonce = Date.now(); +var nonce = { guid: Date.now() }; var rquery = ( /\?/ ); @@ -8733,7 +8980,7 @@ jQuery.fn.extend( { rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && ( this.checked || !rcheckableType.test( type ) ); } ) - .map( function( i, elem ) { + .map( function( _i, elem ) { var val = jQuery( this ).val(); if ( val == null ) { @@ -9346,7 +9593,8 @@ jQuery.extend( { // Add or update anti-cache param if needed if ( s.cache === false ) { cacheURL = cacheURL.replace( rantiCache, "$1" ); - uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; } // Put hash and anti-cache on the URL that will be requested (gh-1732) @@ -9479,6 +9727,11 @@ jQuery.extend( { response = ajaxHandleResponses( s, jqXHR, responses ); } + // Use a noop converter for missing script + if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + s.converters[ "text script" ] = function() {}; + } + // Convert no matter what (that way responseXXX fields are always set) response = ajaxConvert( s, response, jqXHR, isSuccess ); @@ -9569,7 +9822,7 @@ jQuery.extend( { } } ); -jQuery.each( [ "get", "post" ], function( i, method ) { +jQuery.each( [ "get", "post" ], function( _i, method ) { jQuery[ method ] = function( url, data, callback, type ) { // Shift arguments if data argument was omitted @@ -9590,8 +9843,17 @@ jQuery.each( [ "get", "post" ], function( i, method ) { }; } ); +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); -jQuery._evalUrl = function( url, options ) { + +jQuery._evalUrl = function( url, options, doc ) { return jQuery.ajax( { url: url, @@ -9609,7 +9871,7 @@ jQuery._evalUrl = function( url, options ) { "text script": function() {} }, dataFilter: function( response ) { - jQuery.globalEval( response, options ); + jQuery.globalEval( response, options, doc ); } } ); }; @@ -9931,7 +10193,7 @@ var oldCallbacks = [], jQuery.ajaxSetup( { jsonp: "callback", jsonpCallback: function() { - var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); + var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce.guid++ ) ); this[ callback ] = true; return callback; } @@ -10148,23 +10410,6 @@ jQuery.fn.load = function( url, params, callback ) { -// Attach a bunch of functions for handling common AJAX events -jQuery.each( [ - "ajaxStart", - "ajaxStop", - "ajaxComplete", - "ajaxError", - "ajaxSuccess", - "ajaxSend" -], function( i, type ) { - jQuery.fn[ type ] = function( fn ) { - return this.on( type, fn ); - }; -} ); - - - - jQuery.expr.pseudos.animated = function( elem ) { return jQuery.grep( jQuery.timers, function( fn ) { return elem === fn.elem; @@ -10221,6 +10466,12 @@ jQuery.offset = { options.using.call( elem, props ); } else { + if ( typeof props.top === "number" ) { + props.top += "px"; + } + if ( typeof props.left === "number" ) { + props.left += "px"; + } curElem.css( props ); } } @@ -10371,7 +10622,7 @@ jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( // Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347 // getComputedStyle returns percent when specified for top/left/bottom/right; // rather than make the css module depend on the offset module, just check for it here -jQuery.each( [ "top", "left" ], function( i, prop ) { +jQuery.each( [ "top", "left" ], function( _i, prop ) { jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition, function( elem, computed ) { if ( computed ) { @@ -10434,25 +10685,19 @@ jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { } ); -jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup contextmenu" ).split( " " ), - function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); +jQuery.each( [ + "ajaxStart", + "ajaxStop", + "ajaxComplete", + "ajaxError", + "ajaxSuccess", + "ajaxSend" +], function( _i, type ) { + jQuery.fn[ type ] = function( fn ) { + return this.on( type, fn ); }; } ); -jQuery.fn.extend( { - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -} ); - @@ -10474,9 +10719,33 @@ jQuery.fn.extend( { return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); } } ); +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( _i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; + } ); + + + + +// Support: Android <=4.0 only +// Make sure we trim BOM and NBSP +var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; + // Bind a function to a context, optionally partially applying any // arguments. // jQuery.proxy is deprecated to promote standards (specifically Function#bind) @@ -10539,6 +10808,11 @@ jQuery.isNumeric = function( obj ) { !isNaN( obj - parseFloat( obj ) ); }; +jQuery.trim = function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); +}; @@ -10587,7 +10861,7 @@ jQuery.noConflict = function( deep ) { // Expose jQuery and $ identifiers, even in AMD // (#7102#comment:10, https://github.com/jquery/jquery/pull/557) // and CommonJS for browser emulators (#13566) -if ( !noGlobal ) { +if ( typeof noGlobal === "undefined" ) { window.jQuery = window.$ = jQuery; } diff --git a/sphinx/themes/basic/static/jquery.js b/sphinx/themes/basic/static/jquery.js index a1c07fd80..b0614034a 100644 --- a/sphinx/themes/basic/static/jquery.js +++ b/sphinx/themes/basic/static/jquery.js @@ -1,2 +1,2 @@ -/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function qe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function He(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 bool: return getattr(builtins, name, None) is cls -def signature(subject: Callable, bound_method: bool = False) -> inspect.Signature: +def signature(subject: Callable, bound_method: bool = False, follow_wrapped: bool = False + ) -> inspect.Signature: """Return a Signature object for the given *subject*. :param bound_method: Specify *subject* is a bound method or not + :param follow_wrapped: Same as ``inspect.signature()``. + Defaults to ``False`` (get a signature of *subject*). """ try: - signature = inspect.signature(subject) + try: + signature = inspect.signature(subject, follow_wrapped=follow_wrapped) + except ValueError: + # follow built-in wrappers up (ex. functools.lru_cache) + signature = inspect.signature(subject) parameters = list(signature.parameters.values()) return_annotation = signature.return_annotation except IndexError: diff --git a/tests/roots/test-ext-autodoc/target/decorator.py b/tests/roots/test-ext-autodoc/target/decorator.py index 4ccfedf28..61398b324 100644 --- a/tests/roots/test-ext-autodoc/target/decorator.py +++ b/tests/roots/test-ext-autodoc/target/decorator.py @@ -1,5 +1,9 @@ +from functools import wraps + + def deco1(func): """docstring for deco1""" + @wraps(func) def wrapper(): return func() @@ -14,3 +18,14 @@ def deco2(condition, message): return wrapper return decorator + + +@deco1 +def foo(name=None, age=None): + pass + + +class Bar: + @deco1 + def meth(self, name=None, age=None): + pass diff --git a/tests/roots/test-ext-autosummary/autosummary_dummy_module.py b/tests/roots/test-ext-autosummary/autosummary_dummy_module.py index ffd381f51..85981a0f8 100644 --- a/tests/roots/test-ext-autosummary/autosummary_dummy_module.py +++ b/tests/roots/test-ext-autosummary/autosummary_dummy_module.py @@ -1,4 +1,4 @@ -from os import * # NOQA +from os import path # NOQA from typing import Union @@ -17,5 +17,25 @@ class Foo: pass -def bar(x: Union[int, str], y: int = 1): +class _Baz: pass + + +def bar(x: Union[int, str], y: int = 1) -> None: + pass + + +def _quux(): + pass + + +class Exc(Exception): + pass + + +class _Exc(Exception): + pass + + +#: a module-level attribute +qux = 2 diff --git a/tests/roots/test-ext-autosummary/index.rst b/tests/roots/test-ext-autosummary/index.rst index bc3f80234..9f657bb73 100644 --- a/tests/roots/test-ext-autosummary/index.rst +++ b/tests/roots/test-ext-autosummary/index.rst @@ -11,4 +11,5 @@ autosummary_dummy_module.Foo autosummary_dummy_module.Foo.Bar autosummary_dummy_module.bar + autosummary_dummy_module.qux autosummary_importfail diff --git a/tests/test_domain_c.py b/tests/test_domain_c.py index 237519fcc..795e8ed37 100644 --- a/tests/test_domain_c.py +++ b/tests/test_domain_c.py @@ -27,15 +27,29 @@ def parse(name, string): return ast -def _check(name, input, idDict, output): +def _check(name, input, idDict, output, key, asTextOutput): + if key is None: + key = name + key += ' ' + if name in ('function', 'member'): + inputActual = input + outputAst = output + outputAsText = output + else: + inputActual = input.format(key='') + outputAst = output.format(key='') + outputAsText = output.format(key=key) + if asTextOutput is not None: + outputAsText = asTextOutput + # first a simple check of the AST - ast = parse(name, input) + ast = parse(name, inputActual) res = str(ast) - if res != output: + if res != outputAst: print("") print("Input: ", input) print("Result: ", res) - print("Expected: ", output) + print("Expected: ", outputAst) raise DefinitionError("") rootSymbol = Symbol(None, None, None, None) symbol = rootSymbol.add_declaration(ast, docname="TestDoc") @@ -43,6 +57,13 @@ def _check(name, input, idDict, output): signode = addnodes.desc_signature(input, '') parentNode += signode ast.describe_signature(signode, 'lastIsName', symbol, options={}) + resAsText = parentNode.astext() + if resAsText != outputAsText: + print("") + print("Input: ", input) + print("astext(): ", resAsText) + print("Expected: ", outputAsText) + raise DefinitionError("") idExpected = [None] for i in range(1, _max_id + 1): @@ -75,14 +96,15 @@ def _check(name, input, idDict, output): raise DefinitionError("") -def check(name, input, idDict, output=None): +def check(name, input, idDict, output=None, key=None, asTextOutput=None): if output is None: output = input # First, check without semicolon - _check(name, input, idDict, output) + _check(name, input, idDict, output, key, asTextOutput) if name != 'macro': # Second, check with semicolon - _check(name, input + ' ;', idDict, output + ';') + _check(name, input + ' ;', idDict, output + ';', key, + asTextOutput + ';' if asTextOutput is not None else None) def test_expressions(): @@ -234,24 +256,24 @@ def test_expressions(): def test_type_definitions(): - check('type', "T", {1: "T"}) + check('type', "{key}T", {1: "T"}) - check('type', "bool *b", {1: 'b'}) - check('type', "bool *const b", {1: 'b'}) - check('type', "bool *const *b", {1: 'b'}) - check('type', "bool *volatile *b", {1: 'b'}) - check('type', "bool *restrict *b", {1: 'b'}) - check('type', "bool *volatile const b", {1: 'b'}) - check('type', "bool *volatile const b", {1: 'b'}) - check('type', "bool *volatile const *b", {1: 'b'}) - check('type', "bool b[]", {1: 'b'}) - check('type', "long long int foo", {1: 'foo'}) + check('type', "{key}bool *b", {1: 'b'}, key='typedef') + check('type', "{key}bool *const b", {1: 'b'}, key='typedef') + check('type', "{key}bool *const *b", {1: 'b'}, key='typedef') + check('type', "{key}bool *volatile *b", {1: 'b'}, key='typedef') + check('type', "{key}bool *restrict *b", {1: 'b'}, key='typedef') + check('type', "{key}bool *volatile const b", {1: 'b'}, key='typedef') + check('type', "{key}bool *volatile const b", {1: 'b'}, key='typedef') + check('type', "{key}bool *volatile const *b", {1: 'b'}, key='typedef') + check('type', "{key}bool b[]", {1: 'b'}, key='typedef') + check('type', "{key}long long int foo", {1: 'foo'}, key='typedef') # test decl specs on right - check('type', "bool const b", {1: 'b'}) + check('type', "{key}bool const b", {1: 'b'}, key='typedef') # from breathe#267 (named function parameters for function pointers - check('type', 'void (*gpio_callback_t)(struct device *port, uint32_t pin)', - {1: 'gpio_callback_t'}) + check('type', '{key}void (*gpio_callback_t)(struct device *port, uint32_t pin)', + {1: 'gpio_callback_t'}, key='typedef') def test_macro_definitions(): @@ -378,28 +400,34 @@ def test_function_definitions(): output='void f(int arr[static volatile const 42])') -def test_union_definitions(): - check('struct', 'A', {1: 'A'}) +class test_nested_name(): + check('struct', '{key}.A', {1: "A"}) + check('struct', '{key}.A.B', {1: "A.B"}) + check('function', 'void f(.A a)', {1: "f"}) + check('function', 'void f(.A.B a)', {1: "f"}) def test_union_definitions(): - check('union', 'A', {1: 'A'}) + check('struct', '{key}A', {1: 'A'}) + + +def test_union_definitions(): + check('union', '{key}A', {1: 'A'}) def test_enum_definitions(): - check('enum', 'A', {1: 'A'}) + check('enum', '{key}A', {1: 'A'}) - check('enumerator', 'A', {1: 'A'}) - check('enumerator', 'A = 42', {1: 'A'}) + check('enumerator', '{key}A', {1: 'A'}) + check('enumerator', '{key}A = 42', {1: 'A'}) def test_anon_definitions(): - return # TODO - check('class', '@a', {3: "Ut1_a"}) - check('union', '@a', {3: "Ut1_a"}) - check('enum', '@a', {3: "Ut1_a"}) - check('class', '@1', {3: "Ut1_1"}) - check('class', '@a::A', {3: "NUt1_a1AE"}) + check('struct', '@a', {1: "@a"}, asTextOutput='struct [anonymous]') + check('union', '@a', {1: "@a"}, asTextOutput='union [anonymous]') + check('enum', '@a', {1: "@a"}, asTextOutput='enum [anonymous]') + check('struct', '@1', {1: "@1"}, asTextOutput='struct [anonymous]') + check('struct', '@a.A', {1: "@a.A"}, asTextOutput='struct [anonymous].A') def test_initializers(): diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index bfb6934cf..38c89d282 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -33,15 +33,29 @@ def parse(name, string): return ast -def _check(name, input, idDict, output): +def _check(name, input, idDict, output, key, asTextOutput): + if key is None: + key = name + key += ' ' + if name in ('function', 'member'): + inputActual = input + outputAst = output + outputAsText = output + else: + inputActual = input.format(key='') + outputAst = output.format(key='') + outputAsText = output.format(key=key) + if asTextOutput is not None: + outputAsText = asTextOutput + # first a simple check of the AST - ast = parse(name, input) + ast = parse(name, inputActual) res = str(ast) - if res != output: + if res != outputAst: print("") print("Input: ", input) print("Result: ", res) - print("Expected: ", output) + print("Expected: ", outputAst) raise DefinitionError("") rootSymbol = Symbol(None, None, None, None, None, None) symbol = rootSymbol.add_declaration(ast, docname="TestDoc") @@ -49,6 +63,13 @@ def _check(name, input, idDict, output): signode = addnodes.desc_signature(input, '') parentNode += signode ast.describe_signature(signode, 'lastIsName', symbol, options={}) + resAsText = parentNode.astext() + if resAsText != outputAsText: + print("") + print("Input: ", input) + print("astext(): ", resAsText) + print("Expected: ", outputAsText) + raise DefinitionError("") idExpected = [None] for i in range(1, _max_id + 1): @@ -81,13 +102,14 @@ def _check(name, input, idDict, output): raise DefinitionError("") -def check(name, input, idDict, output=None): +def check(name, input, idDict, output=None, key=None, asTextOutput=None): if output is None: output = input # First, check without semicolon - _check(name, input, idDict, output) + _check(name, input, idDict, output, key, asTextOutput) # Second, check with semicolon - _check(name, input + ' ;', idDict, output + ';') + _check(name, input + ' ;', idDict, output + ';', key, + asTextOutput + ';' if asTextOutput is not None else None) def test_fundamental_types(): @@ -113,10 +135,11 @@ def test_fundamental_types(): def test_expressions(): def exprCheck(expr, id, id4=None): ids = 'IE1CIA%s_1aE' - idDict = {2: ids % expr, 3: ids % id} + # call .format() on the expr to unescape double curly braces + idDict = {2: ids % expr.format(), 3: ids % id} if id4 is not None: idDict[4] = ids % id4 - check('class', 'template<> C' % expr, idDict) + check('class', 'template<> {key}C' % expr, idDict) class Config: cpp_id_attributes = ["id_attr"] @@ -229,8 +252,8 @@ def test_expressions(): exprCheck('new int()', 'nw_ipiE') exprCheck('new int(5, 42)', 'nw_ipiL5EL42EE') exprCheck('::new int', 'nw_iE') - exprCheck('new int{}', 'nw_iilE') - exprCheck('new int{5, 42}', 'nw_iilL5EL42EE') + exprCheck('new int{{}}', 'nw_iilE') + exprCheck('new int{{5, 42}}', 'nw_iilL5EL42EE') # delete-expression exprCheck('delete p', 'dl1p') exprCheck('delete [] p', 'da1p') @@ -291,7 +314,7 @@ def test_expressions(): exprCheck('a xor_eq 5', 'eO1aL5E') exprCheck('a |= 5', 'oR1aL5E') exprCheck('a or_eq 5', 'oR1aL5E') - exprCheck('a = {1, 2, 3}', 'aS1ailL1EL2EL3EE') + exprCheck('a = {{1, 2, 3}}', 'aS1ailL1EL2EL3EE') # comma operator exprCheck('a, 5', 'cm1aL5E') @@ -301,8 +324,8 @@ def test_expressions(): check('function', 'template<> void f(A &v)', {2: "IE1fR1AI1BX2EE", 3: "IE1fR1AI1BXL2EEE", 4: "IE1fvR1AI1BXL2EEE"}) exprCheck('A<1>::value', 'N1AIXL1EEE5valueE') - check('class', "template A", {2: "I_iE1A"}) - check('enumerator', 'A = std::numeric_limits::max()', {2: "1A"}) + check('class', "template {key}A", {2: "I_iE1A"}) + check('enumerator', '{key}A = std::numeric_limits::max()', {2: "1A"}) exprCheck('operator()()', 'clclE') exprCheck('operator()()', 'clclIiEE') @@ -312,58 +335,59 @@ def test_expressions(): def test_type_definitions(): - check("type", "public bool b", {1: "b", 2: "1b"}, "bool b") - check("type", "bool A::b", {1: "A::b", 2: "N1A1bE"}) - check("type", "bool *b", {1: "b", 2: "1b"}) - check("type", "bool *const b", {1: "b", 2: "1b"}) - check("type", "bool *volatile const b", {1: "b", 2: "1b"}) - check("type", "bool *volatile const b", {1: "b", 2: "1b"}) - check("type", "bool *volatile const *b", {1: "b", 2: "1b"}) - check("type", "bool &b", {1: "b", 2: "1b"}) - check("type", "bool b[]", {1: "b", 2: "1b"}) - check("type", "std::pair coord", {1: "coord", 2: "5coord"}) - check("type", "long long int foo", {1: "foo", 2: "3foo"}) - check("type", 'std::vector> module::blah', - {1: "module::blah", 2: "N6module4blahE"}) - check("type", "std::function F", {1: "F", 2: "1F"}) - check("type", "std::function F", {1: "F", 2: "1F"}) - check("type", "std::function F", {1: "F", 2: "1F"}) - check("type", "std::function F", {1: "F", 2: "1F"}) - check("type", "MyContainer::const_iterator", + check("type", "public bool b", {1: "b", 2: "1b"}, "{key}bool b", key='typedef') + check("type", "{key}bool A::b", {1: "A::b", 2: "N1A1bE"}, key='typedef') + check("type", "{key}bool *b", {1: "b", 2: "1b"}, key='typedef') + check("type", "{key}bool *const b", {1: "b", 2: "1b"}, key='typedef') + check("type", "{key}bool *volatile const b", {1: "b", 2: "1b"}, key='typedef') + check("type", "{key}bool *volatile const b", {1: "b", 2: "1b"}, key='typedef') + check("type", "{key}bool *volatile const *b", {1: "b", 2: "1b"}, key='typedef') + check("type", "{key}bool &b", {1: "b", 2: "1b"}, key='typedef') + check("type", "{key}bool b[]", {1: "b", 2: "1b"}, key='typedef') + check("type", "{key}std::pair coord", {1: "coord", 2: "5coord"}, key='typedef') + check("type", "{key}long long int foo", {1: "foo", 2: "3foo"}, key='typedef') + check("type", '{key}std::vector> module::blah', + {1: "module::blah", 2: "N6module4blahE"}, key='typedef') + check("type", "{key}std::function F", {1: "F", 2: "1F"}, key='typedef') + check("type", "{key}std::function F", {1: "F", 2: "1F"}, key='typedef') + check("type", "{key}std::function F", {1: "F", 2: "1F"}, key='typedef') + check("type", "{key}std::function F", {1: "F", 2: "1F"}, key='typedef') + check("type", "{key}MyContainer::const_iterator", {1: "MyContainer::const_iterator", 2: "N11MyContainer14const_iteratorE"}) check("type", "public MyContainer::const_iterator", {1: "MyContainer::const_iterator", 2: "N11MyContainer14const_iteratorE"}, - output="MyContainer::const_iterator") + output="{key}MyContainer::const_iterator") # test decl specs on right - check("type", "bool const b", {1: "b", 2: "1b"}) + check("type", "{key}bool const b", {1: "b", 2: "1b"}, key='typedef') # test name in global scope - check("type", "bool ::B::b", {1: "B::b", 2: "N1B1bE"}) + check("type", "{key}bool ::B::b", {1: "B::b", 2: "N1B1bE"}, key='typedef') - check('type', 'A = B', {2: '1A'}) - check('type', 'A = decltype(b)', {2: '1A'}) + check('type', '{key}A = B', {2: '1A'}, key='using') + check('type', '{key}A = decltype(b)', {2: '1A'}, key='using') # from breathe#267 (named function parameters for function pointers - check('type', 'void (*gpio_callback_t)(struct device *port, uint32_t pin)', - {1: 'gpio_callback_t', 2: '15gpio_callback_t'}) - check('type', 'void (*f)(std::function g)', {1: 'f', 2: '1f'}) + check('type', '{key}void (*gpio_callback_t)(struct device *port, uint32_t pin)', + {1: 'gpio_callback_t', 2: '15gpio_callback_t'}, key='typedef') + check('type', '{key}void (*f)(std::function g)', {1: 'f', 2: '1f'}, + key='typedef') - check('type', 'T = A::template B::template C', {2: '1T'}) + check('type', '{key}T = A::template B::template C', {2: '1T'}, key='using') - check('type', 'T = Q', {2: '1T'}) - check('type', 'T = Q>', {2: '1T'}) - check('type', 'T = Q', {2: '1T'}) + check('type', '{key}T = Q', {2: '1T'}, key='using') + check('type', '{key}T = Q>', {2: '1T'}, key='using') + check('type', '{key}T = Q', {2: '1T'}, key='using') def test_concept_definitions(): - check('concept', 'template A::B::Concept', + check('concept', 'template {key}A::B::Concept', {2: 'I0EN1A1B7ConceptE'}) - check('concept', 'template Foo', + check('concept', 'template {key}Foo', {2: 'I00DpE3Foo'}) with pytest.raises(DefinitionError): - parse('concept', 'Foo') + parse('concept', '{key}Foo') with pytest.raises(DefinitionError): - parse('concept', 'template template Foo') + parse('concept', 'template template {key}Foo') def test_member_definitions(): @@ -639,95 +663,102 @@ def test_operators(): check('function', 'void operator[]()', {1: "subscript-operator", 2: "ixv"}) +class test_nested_name(): + check('class', '{key}::A', {1: "A", 2: "1A"}) + check('class', '{key}::A::B', {1: "A::B", 2: "N1A1BE"}) + check('function', 'void f(::A a)', {1: "f__A", 2: "1f1A"}) + check('function', 'void f(::A::B a)', {1: "f__A::B", 2: "1fN1A1BE"}) + + def test_class_definitions(): - check('class', 'public A', {1: "A", 2: "1A"}, output='A') - check('class', 'private A', {1: "A", 2: "1A"}) - check('class', 'A final', {1: 'A', 2: '1A'}) + check('class', 'public A', {1: "A", 2: "1A"}, output='{key}A') + check('class', 'private {key}A', {1: "A", 2: "1A"}) + check('class', '{key}A final', {1: 'A', 2: '1A'}) # test bases - check('class', 'A', {1: "A", 2: "1A"}) - check('class', 'A::B::C', {1: "A::B::C", 2: "N1A1B1CE"}) - check('class', 'A : B', {1: "A", 2: "1A"}) - check('class', 'A : private B', {1: "A", 2: "1A"}) - check('class', 'A : public B', {1: "A", 2: "1A"}) - check('class', 'A : B, C', {1: "A", 2: "1A"}) - check('class', 'A : B, protected C, D', {1: "A", 2: "1A"}) - check('class', 'A : virtual private B', {1: 'A', 2: '1A'}, output='A : private virtual B') - check('class', 'A : private virtual B', {1: 'A', 2: '1A'}) - check('class', 'A : B, virtual C', {1: 'A', 2: '1A'}) - check('class', 'A : public virtual B', {1: 'A', 2: '1A'}) - check('class', 'A : B, C...', {1: 'A', 2: '1A'}) - check('class', 'A : B..., C', {1: 'A', 2: '1A'}) + check('class', '{key}A', {1: "A", 2: "1A"}) + check('class', '{key}A::B::C', {1: "A::B::C", 2: "N1A1B1CE"}) + check('class', '{key}A : B', {1: "A", 2: "1A"}) + check('class', '{key}A : private B', {1: "A", 2: "1A"}) + check('class', '{key}A : public B', {1: "A", 2: "1A"}) + check('class', '{key}A : B, C', {1: "A", 2: "1A"}) + check('class', '{key}A : B, protected C, D', {1: "A", 2: "1A"}) + check('class', 'A : virtual private B', {1: 'A', 2: '1A'}, output='{key}A : private virtual B') + check('class', '{key}A : private virtual B', {1: 'A', 2: '1A'}) + check('class', '{key}A : B, virtual C', {1: 'A', 2: '1A'}) + check('class', '{key}A : public virtual B', {1: 'A', 2: '1A'}) + check('class', '{key}A : B, C...', {1: 'A', 2: '1A'}) + check('class', '{key}A : B..., C', {1: 'A', 2: '1A'}) # from #4094 - check('class', 'template> has_var', {2: 'I00E7has_var'}) - check('class', 'template has_var>', + check('class', 'template> {key}has_var', {2: 'I00E7has_var'}) + check('class', 'template {key}has_var>', {2: 'I0E7has_varI1TNSt6void_tIDTadN1T3varEEEEE'}) - check('class', 'template T', + check('class', 'template {key}T', {2: 'IDpE1TIJPFi2TsEEE'}) - check('class', 'template T<(Is)...>', + check('class', 'template {key}T<(Is)...>', {2: 'I_DpiE1TIJX(Is)EEE', 3: 'I_DpiE1TIJX2IsEEE'}) def test_union_definitions(): - check('union', 'A', {2: "1A"}) + check('union', '{key}A', {2: "1A"}) def test_enum_definitions(): - check('enum', 'A', {2: "1A"}) - check('enum', 'A : std::underlying_type::type', {2: "1A"}) - check('enum', 'A : unsigned int', {2: "1A"}) - check('enum', 'public A', {2: "1A"}, output='A') - check('enum', 'private A', {2: "1A"}) + check('enum', '{key}A', {2: "1A"}) + check('enum', '{key}A : std::underlying_type::type', {2: "1A"}) + check('enum', '{key}A : unsigned int', {2: "1A"}) + check('enum', 'public A', {2: "1A"}, output='{key}A') + check('enum', 'private {key}A', {2: "1A"}) - check('enumerator', 'A', {2: "1A"}) - check('enumerator', 'A = std::numeric_limits::max()', {2: "1A"}) + check('enumerator', '{key}A', {2: "1A"}) + check('enumerator', '{key}A = std::numeric_limits::max()', {2: "1A"}) def test_anon_definitions(): - check('class', '@a', {3: "Ut1_a"}) - check('union', '@a', {3: "Ut1_a"}) - check('enum', '@a', {3: "Ut1_a"}) - check('class', '@1', {3: "Ut1_1"}) - check('class', '@a::A', {3: "NUt1_a1AE"}) + check('class', '@a', {3: "Ut1_a"}, asTextOutput='class [anonymous]') + check('union', '@a', {3: "Ut1_a"}, asTextOutput='union [anonymous]') + check('enum', '@a', {3: "Ut1_a"}, asTextOutput='enum [anonymous]') + check('class', '@1', {3: "Ut1_1"}, asTextOutput='class [anonymous]') + check('class', '@a::A', {3: "NUt1_a1AE"}, asTextOutput='class [anonymous]::A') def test_templates(): - check('class', "A", {2: "IE1AI1TE"}, output="template<> A") + check('class', "A", {2: "IE1AI1TE"}, output="template<> {key}A") # first just check which objects support templating - check('class', "template<> A", {2: "IE1A"}) + check('class', "template<> {key}A", {2: "IE1A"}) check('function', "template<> void A()", {2: "IE1Av", 4: "IE1Avv"}) check('member', "template<> A a", {2: "IE1a"}) - check('type', "template<> a = A", {2: "IE1a"}) + check('type', "template<> {key}a = A", {2: "IE1a"}, key='using') with pytest.raises(DefinitionError): parse('enum', "template<> A") with pytest.raises(DefinitionError): parse('enumerator', "template<> A") # then all the real tests - check('class', "template A", {2: "I00E1A"}) - check('type', "template<> a", {2: "IE1a"}) + check('class', "template {key}A", {2: "I00E1A"}) + check('type', "template<> {key}a", {2: "IE1a"}, key='using') - check('class', "template A", {2: "I0E1A"}) - check('class', "template A", {2: "I0E1A"}) - check('class', "template A", {2: "IDpE1A"}) - check('class', "template A", {2: "IDpE1A"}) - check('class', "template A", {2: "I0E1A"}) - check('class', "template A", {2: "I0E1A"}) + check('class', "template {key}A", {2: "I0E1A"}) + check('class', "template {key}A", {2: "I0E1A"}) + check('class', "template {key}A", {2: "IDpE1A"}) + check('class', "template {key}A", {2: "IDpE1A"}) + check('class', "template {key}A", {2: "I0E1A"}) + check('class', "template {key}A", {2: "I0E1A"}) - check('class', "template typename T> A", {2: "II0E0E1A"}) - check('class', "template typename> A", {2: "II0E0E1A"}) - check('class', "template typename ...T> A", {2: "II0EDpE1A"}) - check('class', "template typename...> A", {2: "II0EDpE1A"}) + check('class', "template typename T> {key}A", {2: "II0E0E1A"}) + check('class', "template typename> {key}A", {2: "II0E0E1A"}) + check('class', "template typename ...T> {key}A", {2: "II0EDpE1A"}) + check('class', "template typename...> {key}A", {2: "II0EDpE1A"}) - check('class', "template A", {2: "I_iE1A"}) - check('class', "template A", {2: "I_iE1A"}) - check('class', "template A", {2: "I_DpiE1A"}) - check('class', "template A", {2: "I_iE1A"}) - check('class', "template A", {2: "I_iE1A"}) + check('class', "template {key}A", {2: "I_iE1A"}) + check('class', "template {key}A", {2: "I_iE1A"}) + check('class', "template {key}A", {2: "I_DpiE1A"}) + check('class', "template {key}A", {2: "I_iE1A"}) + check('class', "template {key}A", {2: "I_iE1A"}) - check('class', "template<> A>", {2: "IE1AIN2NS1BIEEE"}) + check('class', "template<> {key}A>", {2: "IE1AIN2NS1BIEEE"}) # from #2058 check('function', @@ -747,21 +778,21 @@ def test_templates(): parse('enum', 'abc::ns::foo{id_0, id_1, id_2} A') with pytest.raises(DefinitionError): parse('enumerator', 'abc::ns::foo{id_0, id_1, id_2} A') - check('class', 'abc::ns::foo{id_0, id_1, id_2} xyz::bar', + check('class', 'abc::ns::foo{{id_0, id_1, id_2}} {key}xyz::bar', {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'}) - check('class', 'abc::ns::foo{id_0, id_1, ...id_2} xyz::bar', + check('class', 'abc::ns::foo{{id_0, id_1, ...id_2}} {key}xyz::bar', {2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'}) - check('class', 'abc::ns::foo{id_0, id_1, id_2} xyz::bar', + check('class', 'abc::ns::foo{{id_0, id_1, id_2}} {key}xyz::bar', {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barI4id_04id_14id_2EE'}) - check('class', 'abc::ns::foo{id_0, id_1, ...id_2} xyz::bar', + check('class', 'abc::ns::foo{{id_0, id_1, ...id_2}} {key}xyz::bar', {2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barI4id_04id_1Dp4id_2EE'}) - check('class', 'template<> Concept{U} A::B', {2: 'IEI0EX7ConceptI1UEEN1AIiE1BE'}) + check('class', 'template<> Concept{{U}} {key}A::B', {2: 'IEI0EX7ConceptI1UEEN1AIiE1BE'}) - check('type', 'abc::ns::foo{id_0, id_1, id_2} xyz::bar = ghi::qux', - {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'}) - check('type', 'abc::ns::foo{id_0, id_1, ...id_2} xyz::bar = ghi::qux', - {2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'}) + check('type', 'abc::ns::foo{{id_0, id_1, id_2}} {key}xyz::bar = ghi::qux', + {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'}, key='using') + check('type', 'abc::ns::foo{{id_0, id_1, ...id_2}} {key}xyz::bar = ghi::qux', + {2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'}, key='using') check('function', 'abc::ns::foo{id_0, id_1, id_2} void xyz::bar()', {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barEv', 4: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barEvv'}) @@ -772,8 +803,8 @@ def test_templates(): {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'}) check('member', 'abc::ns::foo{id_0, id_1, ...id_2} ghi::qux xyz::bar', {2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'}) - check('concept', 'Iterator{T, U} Another', {2: 'I00EX8IteratorI1T1UEE7Another'}) - check('concept', 'template Numerics = (... && Numeric)', + check('concept', 'Iterator{{T, U}} {key}Another', {2: 'I00EX8IteratorI1T1UEE7Another'}) + check('concept', 'template {key}Numerics = (... && Numeric)', {2: 'IDpE8Numerics'}) # explicit specializations of members @@ -785,7 +816,7 @@ def test_templates(): output='template<> template<> int A::B::b') # same as above # defaulted constrained type parameters - check('type', 'template A', {2: 'I_1CE1A'}) + check('type', 'template {key}A', {2: 'I_1CE1A'}, key='using') def test_template_args(): @@ -797,9 +828,10 @@ def test_template_args(): 3: "I0E5allowP1FN4funcI1F1BXne1GL1EEE4typeE", 4: "I0E5allowvP1FN4funcI1F1BXne1GL1EEE4typeE"}) # from #3542 - check('type', "template " + check('type', "template {key}" "enable_if_not_array_t = std::enable_if_t::value, int>", - {2: "I0E21enable_if_not_array_t"}) + {2: "I0E21enable_if_not_array_t"}, + key='using') def test_initializers(): diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index 08b3da21e..98b295b99 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -40,22 +40,22 @@ def parse(sig): def test_function_signatures(): rv = parse('func(a=1) -> int object') - assert rv == 'a=1' + assert rv == '(a=1)' rv = parse('func(a=1, [b=None])') - assert rv == 'a=1, [b=None]' + assert rv == '(a=1, [b=None])' rv = parse('func(a=1[, b=None])') - assert rv == 'a=1, [b=None]' + assert rv == '(a=1, [b=None])' rv = parse("compile(source : string, filename, symbol='file')") - assert rv == "source : string, filename, symbol='file'" + assert rv == "(source : string, filename, symbol='file')" rv = parse('func(a=[], [b=None])') - assert rv == 'a=[], [b=None]' + assert rv == '(a=[], [b=None])' rv = parse('func(a=[][, b=None])') - assert rv == 'a=[], [b=None]' + assert rv == '(a=[], [b=None])' @pytest.mark.sphinx('dummy', testroot='domain-py') @@ -453,8 +453,8 @@ def test_pyobject_prefix(app): desc, addnodes.index, desc)])])) - assert doctree[1][1][1].astext().strip() == 'say' # prefix is stripped - assert doctree[1][1][3].astext().strip() == 'FooBar.say' # not stripped + assert doctree[1][1][1].astext().strip() == 'say()' # prefix is stripped + assert doctree[1][1][3].astext().strip() == 'FooBar.say()' # not stripped def test_pydata(app): diff --git a/tests/test_events.py b/tests/test_events.py index 4881588a4..4fbe03a17 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -8,6 +8,9 @@ :license: BSD, see LICENSE for details. """ +import pytest + +from sphinx.errors import ExtensionError from sphinx.events import EventManager @@ -22,3 +25,19 @@ def test_event_priority(): events.emit('builder-inited') assert result == [3, 1, 2, 5, 4] + + +def test_event_allowed_exceptions(): + def raise_error(app): + raise RuntimeError + + events = EventManager(object()) # pass an dummy object as an app + events.connect('builder-inited', raise_error, priority=500) + + # all errors are conveted to ExtensionError + with pytest.raises(ExtensionError): + events.emit('builder-inited') + + # Allow RuntimeError (pass-through) + with pytest.raises(RuntimeError): + events.emit('builder-inited', allowed_exceptions=(RuntimeError,)) diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py index 58a93dd22..50d641dc9 100644 --- a/tests/test_ext_autodoc.py +++ b/tests/test_ext_autodoc.py @@ -59,7 +59,7 @@ def make_directive_bridge(env): platform = '', deprecated = False, members = [], - member_order = 'alphabetic', + member_order = 'alphabetical', exclude_members = set(), ignore_module_all = False, ) @@ -142,6 +142,7 @@ def test_format_signature(app): inst = app.registry.documenters[objtype](directive, name) inst.fullname = name inst.doc_as_attr = False # for class objtype + inst.parent = object # dummy inst.object = obj inst.objpath = [name] inst.args = args @@ -271,6 +272,7 @@ def test_get_doc(app): def getdocl(objtype, obj): inst = app.registry.documenters[objtype](directive, 'tmp') + inst.parent = object # dummy inst.object = obj inst.objpath = [obj.__name__] inst.doc_as_attr = False @@ -1263,6 +1265,17 @@ def test_autofunction_for_methoddescriptor(app): ] +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autofunction_for_decorated(app): + actual = do_autodoc(app, 'function', 'target.decorator.foo') + assert list(actual) == [ + '', + '.. py:function:: foo()', + ' :module: target.decorator', + '', + ] + + @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_automethod_for_builtin(app): actual = do_autodoc(app, 'method', 'builtins.int.__add__') @@ -1276,6 +1289,17 @@ def test_automethod_for_builtin(app): ] +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_automethod_for_decorated(app): + actual = do_autodoc(app, 'method', 'target.decorator.Bar.meth') + assert list(actual) == [ + '', + '.. py:method:: Bar.meth()', + ' :module: target.decorator', + '', + ] + + @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_abstractmethods(app): options = {"members": None, @@ -1435,7 +1459,7 @@ def test_coroutine(app): actual = do_autodoc(app, 'function', 'target.coroutine.sync_func') assert list(actual) == [ '', - '.. py:function:: sync_func()', + '.. py:function:: sync_func(*args, **kwargs)', ' :module: target.coroutine', '', ] @@ -1655,8 +1679,8 @@ def test_singledispatch(app): '', '', '.. py:function:: func(arg, kwarg=None)', - ' func(arg: int, kwarg=None)', - ' func(arg: str, kwarg=None)', + ' func(arg: int, kwarg=None)', + ' func(arg: str, kwarg=None)', ' :module: target.singledispatch', '', ' A function for general use.', @@ -1671,8 +1695,8 @@ def test_singledispatch_autofunction(app): assert list(actual) == [ '', '.. py:function:: func(arg, kwarg=None)', - ' func(arg: int, kwarg=None)', - ' func(arg: str, kwarg=None)', + ' func(arg: int, kwarg=None)', + ' func(arg: str, kwarg=None)', ' :module: target.singledispatch', '', ' A function for general use.', @@ -1698,8 +1722,8 @@ def test_singledispatchmethod(app): '', '', ' .. py:method:: Foo.meth(arg, kwarg=None)', - ' Foo.meth(arg: int, kwarg=None)', - ' Foo.meth(arg: str, kwarg=None)', + ' Foo.meth(arg: int, kwarg=None)', + ' Foo.meth(arg: str, kwarg=None)', ' :module: target.singledispatchmethod', '', ' A method for general use.', @@ -1716,8 +1740,8 @@ def test_singledispatchmethod_automethod(app): assert list(actual) == [ '', '.. py:method:: Foo.meth(arg, kwarg=None)', - ' Foo.meth(arg: int, kwarg=None)', - ' Foo.meth(arg: str, kwarg=None)', + ' Foo.meth(arg: int, kwarg=None)', + ' Foo.meth(arg: str, kwarg=None)', ' :module: target.singledispatchmethod', '', ' A method for general use.', @@ -1795,7 +1819,7 @@ def test_autodoc(app, status, warning): content = app.env.get_doctree('index') assert isinstance(content[3], addnodes.desc) - assert content[3][0].astext() == 'autodoc_dummy_module.test' + assert content[3][0].astext() == 'autodoc_dummy_module.test()' assert content[3][1].astext() == 'Dummy function using dummy.*' # issue sphinx-doc/sphinx#2437 diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py index 365a5a53c..281ba141e 100644 --- a/tests/test_ext_autosummary.py +++ b/tests/test_ext_autosummary.py @@ -19,7 +19,10 @@ from sphinx import addnodes from sphinx.ext.autosummary import ( autosummary_table, autosummary_toc, mangle_signature, import_by_name, extract_summary ) -from sphinx.ext.autosummary.generate import AutosummaryEntry, generate_autosummary_docs, main as autogen_main +from sphinx.ext.autosummary.generate import ( + AutosummaryEntry, generate_autosummary_content, generate_autosummary_docs, + main as autogen_main +) from sphinx.testing.util import assert_node, etree_parse from sphinx.util.docutils import new_document from sphinx.util.osutil import cd @@ -189,6 +192,83 @@ def test_escaping(app, status, warning): assert str_content(title) == 'underscore_module_' +@pytest.mark.sphinx(testroot='ext-autosummary') +def test_autosummary_generate_content_for_module(app): + import autosummary_dummy_module + template = Mock() + + generate_autosummary_content('autosummary_dummy_module', autosummary_dummy_module, None, + template, None, False, app, False, {}) + assert template.render.call_args[0][0] == 'module' + + context = template.render.call_args[0][1] + assert context['members'] == ['Exc', 'Foo', '_Baz', '_Exc', '__builtins__', + '__cached__', '__doc__', '__file__', '__name__', + '__package__', '_quux', 'bar', 'qux'] + assert context['functions'] == ['bar'] + assert context['all_functions'] == ['_quux', 'bar'] + assert context['classes'] == ['Foo'] + assert context['all_classes'] == ['Foo', '_Baz'] + assert context['exceptions'] == ['Exc'] + assert context['all_exceptions'] == ['Exc', '_Exc'] + assert context['attributes'] == ['qux'] + assert context['all_attributes'] == ['qux'] + assert context['fullname'] == 'autosummary_dummy_module' + assert context['module'] == 'autosummary_dummy_module' + assert context['objname'] == '' + assert context['name'] == '' + assert context['objtype'] == 'module' + + +@pytest.mark.sphinx(testroot='ext-autosummary') +def test_autosummary_generate_content_for_module_skipped(app): + import autosummary_dummy_module + template = Mock() + + def skip_member(app, what, name, obj, skip, options): + if name in ('Foo', 'bar', 'Exc'): + return True + + app.connect('autodoc-skip-member', skip_member) + generate_autosummary_content('autosummary_dummy_module', autosummary_dummy_module, None, + template, None, False, app, False, {}) + context = template.render.call_args[0][1] + assert context['members'] == ['_Baz', '_Exc', '__builtins__', '__cached__', '__doc__', + '__file__', '__name__', '__package__', '_quux', 'qux'] + assert context['functions'] == [] + assert context['classes'] == [] + assert context['exceptions'] == [] + + +@pytest.mark.sphinx(testroot='ext-autosummary') +def test_autosummary_generate_content_for_module_imported_members(app): + import autosummary_dummy_module + template = Mock() + + generate_autosummary_content('autosummary_dummy_module', autosummary_dummy_module, None, + template, None, True, app, False, {}) + assert template.render.call_args[0][0] == 'module' + + context = template.render.call_args[0][1] + assert context['members'] == ['Exc', 'Foo', 'Union', '_Baz', '_Exc', '__builtins__', + '__cached__', '__doc__', '__file__', '__loader__', + '__name__', '__package__', '__spec__', '_quux', + 'bar', 'path', 'qux'] + assert context['functions'] == ['bar'] + assert context['all_functions'] == ['_quux', 'bar'] + assert context['classes'] == ['Foo'] + assert context['all_classes'] == ['Foo', '_Baz'] + assert context['exceptions'] == ['Exc'] + assert context['all_exceptions'] == ['Exc', '_Exc'] + assert context['attributes'] == ['qux'] + assert context['all_attributes'] == ['qux'] + assert context['fullname'] == 'autosummary_dummy_module' + assert context['module'] == 'autosummary_dummy_module' + assert context['objname'] == '' + assert context['name'] == '' + assert context['objtype'] == 'module' + + @pytest.mark.sphinx('dummy', testroot='ext-autosummary') def test_autosummary_generate(app, status, warning): app.builder.build_all() @@ -209,11 +289,12 @@ def test_autosummary_generate(app, status, warning): nodes.row)])]) assert_node(doctree[4][0], addnodes.toctree, caption="An autosummary") + assert len(doctree[3][0][0][2]) == 5 assert doctree[3][0][0][2][0].astext() == 'autosummary_dummy_module\n\n' assert doctree[3][0][0][2][1].astext() == 'autosummary_dummy_module.Foo()\n\n' assert doctree[3][0][0][2][2].astext() == 'autosummary_dummy_module.Foo.Bar\n\n' assert doctree[3][0][0][2][3].astext() == 'autosummary_dummy_module.bar(x[, y])\n\n' - assert doctree[3][0][0][2][4].astext() == 'autosummary_importfail\n\n' + assert doctree[3][0][0][2][4].astext() == 'autosummary_dummy_module.qux\n\na module-level attribute' module = (app.srcdir / 'generated' / 'autosummary_dummy_module.rst').read_text() assert (' .. autosummary::\n' @@ -238,6 +319,11 @@ def test_autosummary_generate(app, status, warning): '\n' '.. autoclass:: Foo.Bar\n' in FooBar) + qux = (app.srcdir / 'generated' / 'autosummary_dummy_module.qux.rst').read_text() + assert ('.. currentmodule:: autosummary_dummy_module\n' + '\n' + '.. autodata:: qux' in qux) + @pytest.mark.sphinx('dummy', testroot='ext-autosummary', confoverrides={'autosummary_generate_overwrite': False}) @@ -397,7 +483,7 @@ def test_autosummary_template(app): confoverrides={'autosummary_generate': []}) def test_empty_autosummary_generate(app, status, warning): app.build() - assert ("WARNING: autosummary: stub file not found 'autosummary_importfail'" + assert ("WARNING: autosummary: failed to import autosummary_importfail" in warning.getvalue()) diff --git a/tests/test_theming.py b/tests/test_theming.py index affaf5408..93671eab8 100644 --- a/tests/test_theming.py +++ b/tests/test_theming.py @@ -74,7 +74,7 @@ def test_js_source(app, status, warning): app.builder.build(['contents']) - v = '3.4.1' + v = '3.5.1' msg = 'jquery.js version does not match to {v}'.format(v=v) jquery_min = (app.outdir / '_static' / 'jquery.js').read_text() assert 'jQuery v{v}'.format(v=v) in jquery_min, msg diff --git a/tests/test_util_inspect.py b/tests/test_util_inspect.py index dd71d367c..4da61df47 100644 --- a/tests/test_util_inspect.py +++ b/tests/test_util_inspect.py @@ -97,7 +97,7 @@ def test_signature_methods(): # wrapped bound method sig = inspect.signature(wrapped_bound_method) - assert stringify_signature(sig) == '(arg1, **kwargs)' + assert stringify_signature(sig) == '(*args, **kwargs)' def test_signature_partialmethod():