Switch to using sphinx-js fork (#4193)

This commit is contained in:
Hood Chatham 2023-09-30 16:41:02 -07:00 committed by GitHub
parent 53744b4906
commit 2bcd48c4c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 301 additions and 768 deletions

View File

@ -18,4 +18,4 @@ build:
os: ubuntu-20.04
tools:
python: "3.11"
nodejs: "14"
nodejs: "20"

View File

@ -21,7 +21,7 @@ issues and that future releases will have fewer breaking changes.
We added full support for asyncio, including a new Python event loop that
schedules tasks on the browser event loop, support for top level await in
{any}`pyodide.runPythonAsync`, and implementations of `await` for {any}`JsProxy <pyodide.ffi.JsProxy>`
and {js:class}`PyProxy`, so that it is possible to await a Python awaitable from
and `PyProxy`, so that it is possible to await a Python awaitable from
JavaScript and a JavaScript thenable from Python. This allows seamless
interoperability:
@ -99,7 +99,7 @@ We added several new conversion APIs to give more explicit control over the
foreign function interface. In particular, the goal was to make it easier for
users to avoid leaking memory.
For the basic use cases, we have {js:meth}`PyProxy.toJs` and `JsProxy.to_py`
For the basic use cases, we have `PyProxy.toJs` and `JsProxy.to_py`
which respectively convert Python objects to JavaScript objects and JavaScript
objects to Python objects. We also added also "wrong-way" conversion functions
{any}`pyodide.to_js <pyodide.ffi.to_js>` and {any}`pyodide.toPy` which are particularly helpful for
@ -110,7 +110,7 @@ The promise handler methods `JsProxy.then`, `JsProxy.catch`, and
`JsProxy.finally_` were particularly hard to use without leaking memory so
they have been updated with internal magic to automatically manage the memory.
For more advanced use cases where control over the life cycle of a {js:class}`PyProxy` is
For more advanced use cases where control over the life cycle of a `PyProxy` is
needed, there are {any}`create_proxy` and {any}`create_once_callable`.
(Added in PRs {pr}`1186`, {pr}`1244`, {pr}`1344`, {pr}`1436`)
@ -150,7 +150,7 @@ The buffer translation code in previous versions was less flexible, leaked memor
and had serious bugs including use after free ({issue}`749`) and buffer overflow errors.
We completely reworked these: buffers are now proxied like most other objects.
In simple use cases they can be converted with a copy using {js:meth}`PyProxy.toJs`
In simple use cases they can be converted with a copy using `PyProxy.toJs`
and `JsProxy.to_py`. We added new APIs `PyProxy.getBuffer`,
`JsProxy.assign`, and `JsProxy.assign_to` which give more fine-grained
control, though they are not yet as ergonomic as they could be.

View File

@ -8,7 +8,6 @@ sphinx_book_theme>=0.4.0rc1
# A dependency of the above theme, which had some breaking changes in 0.13.2
pydata_sphinx_theme < 0.13.2
sphinx-issues
sphinx-js>=3.2.1
sphinx-click
sphinx-autodoc-typehints>=1.21.7
sphinx-design>=0.3.0
@ -19,3 +18,4 @@ pydantic
micropip==0.2.2
jinja2>=3.0
ruamel.yaml
sphinx-js @ git+https://github.com/pyodide/sphinx-js-fork@3c02e364d3444c9c75ca68419d71237b61f3f5d8

View File

@ -2,6 +2,9 @@ from .jsdoc import (
PyodideAnalyzer,
get_jsdoc_content_directive,
get_jsdoc_summary_directive,
ts_post_convert,
ts_should_destructure_arg,
ts_xref_formatter,
)
from .lexers import HtmlPyodideLexer, PyodideLexer
from .mdn_xrefs import add_mdn_xrefs
@ -12,36 +15,6 @@ def wrap_analyzer(app):
app._sphinxjs_analyzer = PyodideAnalyzer(app._sphinxjs_analyzer)
def patch_templates():
"""Patch in a different jinja2 loader so we can override templates with our
own versions.
"""
from pathlib import Path
from jinja2 import ChoiceLoader, Environment, FileSystemLoader, PackageLoader
from sphinx_js.analyzer_utils import dotted_path
from sphinx_js.renderers import JsRenderer
loader = ChoiceLoader(
[
FileSystemLoader(Path(__file__).parent / "templates"),
PackageLoader("sphinx_js", "templates"),
]
)
env = Environment(loader=loader)
def patched_rst_method(self, partial_path, obj, use_short_name=False):
"""Return rendered RST about an entity with the given name and IR
object."""
dotted_name = partial_path[-1] if use_short_name else dotted_path(partial_path)
# Render to RST using Jinja:
template = env.get_template(self._template)
return template.render(**self._template_vars(dotted_name, obj))
JsRenderer.rst = patched_rst_method
def fix_pyodide_ffi_path():
"""
The `pyodide.ffi` stuff is defined in `_pyodide._core_docs`. We don't want
@ -80,7 +53,6 @@ def remove_property_prefix():
def setup(app):
patch_templates()
fix_pyodide_ffi_path()
remove_property_prefix()
app.add_lexer("pyodide", PyodideLexer)
@ -91,3 +63,7 @@ def setup(app):
app.add_directive("js-doc-content", get_jsdoc_content_directive(app))
app.add_directive("pyodide-package-list", get_packages_summary_directive(app))
app.connect("builder-inited", add_mdn_xrefs)
app.config.ts_post_convert = ts_post_convert
app.config.ts_should_destructure_arg = ts_should_destructure_arg
app.config.ts_type_xref_formatter = ts_xref_formatter
app.config.ts_type_bold = True

View File

@ -1,20 +1,17 @@
import re
from collections import OrderedDict
from typing import Any
import docutils.parsers.rst.directives as directives
from docutils import nodes
from docutils.parsers.rst import Directive
from docutils.parsers.rst import Parser as RstParser
from docutils.statemachine import StringList
from docutils.utils import new_document
from sphinx import addnodes
from sphinx.domains.javascript import JavaScriptDomain, JSCallable
from sphinx.ext.autosummary import autosummary_table, extract_summary
from sphinx.util import rst
from sphinx.util.docutils import switch_source_input
from sphinx_js.ir import Class, Function, Interface, Pathname
from sphinx_js.parsers import PathVisitor, path_and_formal_params
from sphinx_js import ir, typedoc
from sphinx_js.ir import Class, Function, Interface
from sphinx_js.renderers import (
AutoAttributeRenderer,
AutoClassRenderer,
@ -22,412 +19,118 @@ from sphinx_js.renderers import (
JsRenderer,
)
from sphinx_js.typedoc import Analyzer as TsAnalyzer
from sphinx_js.typedoc import make_path_segments
from sphinx_js.typedoc import Base, Callable, Converter, ReflectionType
_orig_convert_node = TsAnalyzer._convert_node
_orig_constructor_and_members = TsAnalyzer._constructor_and_members
_orig_top_level_properties = TsAnalyzer._top_level_properties
_orig_convert_all_nodes = TsAnalyzer._convert_all_nodes
def _constructor_and_members(self, cls):
result = _orig_constructor_and_members(self, cls)
for tag in cls.get("comment", {}).get("tags", []):
if tag["tag"] == "hideconstructor":
return (None, result[1])
return result
TsAnalyzer._constructor_and_members = _constructor_and_members
commentdict = {}
FFI_FIELDS: set[str] = set()
def _convert_all_nodes(self, root):
for node in root.get("children", []):
if node["name"] == "ffi":
FFI_FIELDS.update(x["name"] for x in node["children"])
FFI_FIELDS.remove("ffi")
break
return _orig_convert_all_nodes(self, root)
TsAnalyzer._convert_all_nodes = _convert_all_nodes
def _top_level_properties(self, node):
if "comment" not in node:
sig = {}
if "getSignature" in node:
sig = node["getSignature"][0]
elif "signatures" in node:
sig = node["signatures"][0]
node["comment"] = sig.get("comment", {})
path = str(Pathname(make_path_segments(node, self._base_dir)))
commentdict[path] = node.get("comment") or {}
result = _orig_top_level_properties(self, node)
return result
def get_tag(doclet, tag):
tags = commentdict[str(doclet.path)].get("tags", [])
for t in tags:
if t["tag"] == tag:
return True, t["text"]
return False, None
# Custom tags are a great way of conveniently passing information from the
# source code to this file. No custom tags will be seen by this code unless they
# are registered in src/js/tsdoc.json
#
# Modifier tags act like a flag, block tags have content.
def has_tag(doclet, tag):
return get_tag(doclet, tag)[0]
TsAnalyzer._top_level_properties = _top_level_properties
orig_JsRenderer_rst_ = JsRenderer.rst
def JsRenderer_rst(self, partial_path, obj, use_short_name=False):
match get_tag(obj, "deprecated"):
case (True, text):
# This is definitely not unreachable...
if not text.strip(): # type: ignore[unreachable]
obj.deprecated = True
else:
obj.deprecated = text
if has_tag(obj, "hidetype"):
obj.type = ""
return orig_JsRenderer_rst_(self, partial_path, obj, use_short_name)
for cls in [AutoAttributeRenderer, AutoFunctionRenderer, AutoClassRenderer]:
cls.rst = JsRenderer_rst
def destructure_param(param: dict[str, Any]) -> list[dict[str, Any]]:
"""We want to document a destructured argument as if it were several
separate arguments. This finds complex inline object types in the arguments
list of a function and "destructures" them into separately documented arguments.
E.g., a function
/**
* @param options
*/
function f({x , y } : {
/** The x value */
x : number,
/** The y value */
y : string
}){ ... }
should be documented like:
options.x (number) The x value
options.y (number) The y value
"""Detects whether the doclet comes from a node that has the given modifier
tag.
"""
decl = param["type"]["declaration"]
result = []
for child in decl["children"]:
child = dict(child)
if "type" not in child:
if "signatures" in child:
try:
child["comment"] = child["signatures"][0]["comment"]
except KeyError:
# TODO: handle no comment case
pass
child["type"] = {
"type": "reflection",
"declaration": dict(child),
}
else:
raise AssertionError("Didn't expect to get here...")
child["name"] = param["name"] + "." + child["name"]
result.append(child)
return result
return ("@" + tag) in doclet.modifier_tags
def fix_up_inline_object_signature(self: TsAnalyzer, node: dict[str, Any]) -> None:
"""Calls get_destructured_children on inline object types"""
kind = node.get("kindString")
if kind not in ["Call signature", "Constructor signature"]:
return
params = node.get("parameters", [])
new_params = []
for param in params:
if "@ignore" in param.get("comment", {}).get("shortText", ""):
if not param.get("flags", {}).get("isOptional"):
print("sphinx-pyodide warning: Hiding mandatory argument!")
continue
param_type = param["type"]
if (
param_type["type"] != "reflection"
or "children" not in param_type["declaration"]
):
new_params.append(param)
else:
new_params.extend(destructure_param(param))
node["parameters"] = new_params
def member_properties(self):
return dict(
is_abstract=self.flags.isAbstract,
is_optional=self.flags.isOptional,
is_static=self.flags.isStatic,
is_private=self.flags.isPrivate or self.flags.isExternal,
)
def _convert_node(self: TsAnalyzer, node: dict[str, Any]) -> Any:
"""Monkey patch for TsAnalyzer._convert_node.
Fixes two crashes and separates documentation for destructured object
arguments into a series of separate argument entries.
"""
kind = node.get("kindString")
# if a class has no documented constructor, don't crash
if kind in ["Function", "Constructor", "Method"] and not node.get("sources"):
return None, []
# This fixes a crash, not really sure what it means.
node["extendedTypes"] = [t for t in node.get("extendedTypes", []) if "id" in t]
# See docstring for destructure_param
fix_up_inline_object_signature(self, node)
converted, more_todo = _orig_convert_node(self, node)
if not converted:
return converted, more_todo
converted.is_private = node.get("flags", {}).get("isPrivate", False)
if kind in ["Call signature", "Constructor signature"]:
tags = node.get("comment", {}).get("tags", [])
converted.examples = [tag["text"] for tag in tags if tag["tag"] == "example"]
return converted, more_todo
Base.member_properties = member_properties
TsAnalyzer._convert_node = _convert_node
from os.path import relpath
def ts_should_destructure_arg(sig, param):
return param.name == "options"
def _containing_deppath(self, node):
"""Return the path pointing to the module containing the given node.
The path is absolute or relative to `root_for_relative_js_paths`.
Raises ValueError if one isn't found.
def ts_post_convert(converter, node, doclet):
doclet.exported_from = None
doclet.name = doclet.name.replace("SymbolSymbol", "Symbol")
"""
from pathlib import Path
if has_tag(doclet, "hidetype"):
doclet.type = ""
if isinstance(node, typedoc.Callable):
node.signatures[0].type = ""
filename = node["sources"][0]["fileName"].replace(".gen", "")
deppath = next(Path(self._base_dir).glob("**/" + filename), None)
if deppath:
return relpath(deppath, self._base_dir)
return ""
if isinstance(doclet, ir.Class) and has_tag(doclet, "hideconstructor"):
doclet.constructor = None
if node.name == "setStdin":
fix_set_stdin(converter, node, doclet)
if node.name == "mountNativeFS":
fix_native_fs(converter, node, doclet)
TsAnalyzer._containing_deppath = _containing_deppath
def fix_set_stdin(converter, node, doclet):
assert isinstance(node, Callable)
options = node.signatures[0].parameters[0]
assert isinstance(options.type, ReflectionType)
for param in options.type.declaration.children:
if param.name == "stdin":
break
target = converter.index[param.type.target]
for docparam in doclet.params:
if docparam.name == "stdin":
break
docparam.type = target.type.render_name(converter)
def _add_type_role(self, name):
def fix_native_fs(converter, node, doclet):
assert isinstance(node, Callable)
ty = node.signatures[0].type
target = converter.index[ty.typeArguments[0].target]
ty.typeArguments[0] = target.type
doclet.returns[0].type = ty.render_name(converter)
orig_convert_all_nodes = Converter.convert_all_nodes
def locate_ffi_fields(root):
for node in root.children:
if node.name == "js/ffi":
break
for child in node.children:
if child.name == "ffi":
break
fields = child.type.declaration.children
FFI_FIELDS.update(x.name for x in fields)
# locate the ffi fields
FFI_FIELDS: set[str] = set()
def convert_all_nodes(self, root):
locate_ffi_fields(root)
return orig_convert_all_nodes(self, root)
Converter.convert_all_nodes = convert_all_nodes
def ts_xref_formatter(self, xref):
from sphinx_pyodide.mdn_xrefs import JSDATA
name = xref.name
if name == "PyodideInterface":
return ":ref:`PyodideInterface <js-api-pyodide>`"
if name in JSDATA:
return f":js:data:`{name}`"
if name in FFI_FIELDS:
return f":js:class:`~pyodide.ffi.{name}`"
return f":js:class:`{name}`"
def object_literal_type_name(self, decl):
"""This renders the names of object literal types.
They have zero or more "children" and zero or one "indexSignatures".
For example:
{
[key: string]: string,
name : string,
id : string
}
has children "name" and "id" and an indexSignature "[key: string]: string"
"""
children = []
if "indexSignature" in decl:
index_sig = decl["indexSignature"]
assert len(index_sig["parameters"]) == 1
key = index_sig["parameters"][0]
keyname = key["name"]
keytype = self._type_name(key["type"])
valuetype = self._type_name(index_sig["type"])
children.append(rf"\ **[{keyname}:** {keytype}\ **]:** {valuetype}")
if "children" in decl:
for child in decl["children"]:
maybe_optional = ""
if child["flags"].get("isOptional"):
maybe_optional = "?"
if child["kindString"] == "Method":
child_type_name = self.function_type_name(child)
else:
child_type_name = self._type_name(child["type"])
children.append(
r"\ **" + child["name"] + maybe_optional + ":** " + child_type_name
)
return r"\ **{**\ " + r"\ **,** ".join(children) + r"\ **}**\ "
def function_type_name(self, decl):
decl_sig = None
if "signatures" in decl:
decl_sig = decl["signatures"][0]
elif decl["kindString"] == "Call signature":
decl_sig = decl
assert decl_sig
params = [
rf'\ **{ty["name"]}:** {self._type_name(ty["type"])}'
for ty in decl_sig.get("parameters", [])
]
params_str = r"\ **,** ".join(params)
ret_str = self._type_name(decl_sig["type"])
return rf"\ **(**\ {params_str}\ **) =>** {ret_str}"
def reflection_type_name(self, type):
"""Fill in the type names for type_of_type == "reflection"
This is left as a TODO in sphinx-js.
There are a couple of options: if
decl["kindString"] == "Type Literal"
then this is a literal object type. At least we assume it's a literal object
type, maybe there are other ways for that to happen.
Otherwise, we assume that it's a function type, which we want to format
like:
(a : string, b : number) => string
"""
decl = type["declaration"]
if decl["kindString"] == "Type literal" and "signatures" not in decl:
return self.object_literal_type_name(decl)
return self.function_type_name(decl)
def _type_name_root(self, type):
type_of_type = type.get("type")
if type_of_type == "reference" and type.get("id"):
node = self._index[type["id"]]
name = node["name"]
if node.get("flags", {}).get("isPrivate") and "type" in node:
return self._type_name(node["type"])
return self._add_type_role(name)
if type_of_type == "unknown":
if re.match(r"-?\d*(\.\d+)?", type["name"]): # It's a number.
# TypeDoc apparently sticks numeric constants' values into
# the type name. String constants? Nope. Function ones? Nope.
return "number"
return self._add_type_role(type["name"])
if type_of_type in ["intrinsic", "reference"]:
return self._add_type_role(type["name"])
if type_of_type == "stringLiteral":
return '"' + type["value"] + '"'
if type_of_type == "array":
return self._type_name(type["elementType"]) + r"\ **[]**"
if type_of_type == "tuple" and type.get("elements"):
types = [self._type_name(t) for t in type["elements"]]
return r"\ **[**\ " + r"\ **,** ".join(types) + r"\ **]** "
if type_of_type == "union":
return r" **|** ".join(self._type_name(t) for t in type["types"])
if type_of_type == "intersection":
return " **&** ".join(self._type_name(t) for t in type["types"])
if type_of_type == "typeOperator":
return type["operator"] + " " + self._type_name(type["target"])
# e.g. "keyof T"
if type_of_type == "typeParameter":
name = type["name"]
constraint = type.get("constraint")
if constraint is not None:
name += " extends " + self._type_name(constraint)
# e.g. K += extends + keyof T
return name
if type_of_type == "reflection":
return self.reflection_type_name(type)
if type_of_type == "named-tuple-member":
name = type["name"]
type = self._type_name(type["element"])
return rf"\ **{name}:** {type}"
if type_of_type == "predicate":
return (
f":js:data:`boolean` (typeguard for {self._type_name(type['targetType'])})"
)
if type_of_type == "literal" and type["value"] is None:
return ":js:data:`null`"
if type_of_type == "query":
return f"``typeof {type['queryType']['name']}``"
return "<TODO: other type>"
def _type_name(self, type):
"""Return a string description of a type.
:arg type: A TypeDoc-emitted type node
"""
name = self._type_name_root(type)
type_args = type.get("typeArguments")
if type_args:
arg_names = ", ".join(self._type_name(arg) for arg in type_args)
name += rf"\ **<**\ {arg_names}\ **>** "
return name
for obj in [
_add_type_role,
object_literal_type_name,
reflection_type_name,
_type_name_root,
_type_name,
function_type_name,
]:
setattr(TsAnalyzer, obj.__name__, obj)
def _param_type_formatter(param):
"""Generate types for function parameters specified in field."""
if not param.type:
return None
heads = ["type", param.name]
tail = param.type
return heads, tail
def _return_formatter(return_):
"""Derive heads and tail from ``@returns`` blocks."""
tail = ("%s -- " % return_.type) if return_.type else ""
tail += return_.description
return ["returns"], tail
import sphinx_js.renderers
for obj in [_param_type_formatter, _return_formatter]: # type:ignore[assignment]
setattr(sphinx_js.renderers, obj.__name__, obj)
class JSFuncMaybeAsync(JSCallable):
option_spec = {
**JSCallable.option_spec,
"async": directives.flag,
}
def get_display_prefix(
self,
):
if "async" in self.options:
return [
addnodes.desc_sig_keyword("async", "async"),
addnodes.desc_sig_space(),
]
return []
JavaScriptDomain.directives["function"] = JSFuncMaybeAsync
result = f":js:data:`{name}`"
elif name in FFI_FIELDS:
result = f":js:class:`~pyodide.ffi.{name}`"
else:
result = f":js:class:`{name}`"
return result
def flatten_suffix_tree(tree):
@ -478,13 +181,6 @@ class PyodideAnalyzer:
def __getattr__(self, key):
return getattr(self.inner, key)
def longname_to_path(self, name):
"""Convert the longname field produced by jsdoc to a path appropriate to use
with _sphinxjs_analyzer.get_object. Based on:
https://github.com/mozilla/sphinx-js/blob/3.1/sphinx_js/jsdoc.py#L181
"""
return PathVisitor().visit(path_and_formal_params["path"].parse(name))
def set_doclet_is_private(self, key, doclet):
if getattr(doclet, "is_private", False):
return
@ -493,6 +189,10 @@ class PyodideAnalyzer:
key = [x for x in key if "/" not in x]
filename = key[0]
toplevelname = key[1]
if doclet.name == "PyodideAPI":
doclet.is_private = True
return
if key[-1].startswith("$"):
doclet.is_private = True
return
@ -536,14 +236,10 @@ class PyodideAnalyzer:
if doclet.is_private:
continue
key = [x for x in key if "/" not in x]
filename = key[0]
toplevelname = key[1]
doclet.name = doclet.name.rpartition(".")[2]
if doclet.name.startswith("["):
# a symbol.
# \u2024 looks like a period but is not a period.
# This isn't ideal, but otherwise the coloring is weird.
doclet.name = "[Symbol\u2024" + doclet.name[1:]
if filename == "pyodide.":
items["globalThis"].append(doclet)
@ -594,21 +290,15 @@ class PyodideAnalyzer:
for key, value in items.items():
for obj in sorted(value, key=attrgetter("name")):
_, kind = get_tag(obj, "dockind")
kind = obj.block_tags.get("dockind", [None])[0]
if kind:
obj.kind = kind
obj.kind = kind[0].text
elif isinstance(obj, Class):
obj.kind = "class"
elif isinstance(obj, Function):
obj.kind = "function"
else:
obj.kind = "attribute"
obj.async_ = False
if isinstance(obj, Function):
obj.async_ = obj.returns and obj.returns[0].type.startswith(
":js:class:`Promise`"
)
self.js_docs[key][obj.kind].append(obj)
@ -635,19 +325,8 @@ def get_jsdoc_content_directive(app):
cls = AutoAttributeRenderer
renderer = cls(self, app, arguments=["dummy"], options={"members": ["*"]})
rst = renderer.rst([obj.name], obj, use_short_name=False)
if obj.async_:
rst = self.add_async_option_to_rst(rst)
return rst
def add_async_option_to_rst(self, rst: str) -> str:
rst_lines = rst.split("\n")
try:
index = next(i for i, ln in enumerate(rst_lines) if ln.startswith(".."))
except StopIteration:
index = len(rst_lines) - 1
rst_lines.insert(index + 1, " :async:")
return "\n".join(rst_lines)
def get_rst_for_group(self, objects):
return [self.get_rst(obj) for obj in objects]
@ -739,10 +418,16 @@ def get_jsdoc_summary_directive(app):
"""
sig = self.get_sig(obj)
display_name = obj.name
prefix = "**async** " if obj.async_ else ""
summary = self.extract_summary(obj.description)
prefix = "**async** " if getattr(obj, "is_async", False) else ""
qualifier = "any"
if obj.name == "ffi":
qualifier = "js:mod"
summary = self.extract_summary(
JsRenderer.render_description(None, obj.description)
)
link_name = pkgname + "." + display_name
return (prefix, display_name, sig, summary, link_name)
return (prefix, qualifier, display_name, sig, summary, link_name)
def get_summary_table(self, pkgname, group):
"""Get the data for a summary tget_summary_tableable. Return value
@ -791,9 +476,8 @@ def get_jsdoc_summary_directive(app):
row.append(nodes.entry("", node))
body.append(row)
for prefix, name, sig, summary, real_name in items:
for prefix, qualifier, name, sig, summary, real_name in items:
# The body of this loop is changed from copied code.
qualifier = "any"
sig = rst.escape(sig)
if sig:
sig = f"**{sig}**"
@ -824,7 +508,7 @@ def get_jsdoc_summary_directive(app):
name = name.removeprefix("~")
_, obj, *_ = self.import_by_name(name, prefixes=prefixes)
prefix = "**async** " if iscoroutinefunction(obj) else ""
new_items.append((prefix, *item))
new_items.append((prefix, "any", *item))
return new_items
Autosummary.get_items = get_items

View File

@ -13,11 +13,14 @@ DATA = {
"Reflect.ownKeys": "$global/",
"Array.from": "$global/",
"Atomics.wait": "$global/",
"getDirectory": "API/StorageManager/",
"showDirectoryPicker": "API/Window/",
},
"js:class": {
"Array": "$global/",
"NodeList": "API/",
"HTMLCollection": "API/",
"HTMLCanvasElement": "API/",
"Generator": "$global/",
"AsyncGenerator": "$global/",
"Date": "$global/",
@ -56,6 +59,15 @@ DATA = {
"Function.bind": "$global/",
"Function.call": "$global/",
"Array.join": "$global/",
"Array.copyWithin": "$global/",
"Array.fill": "$global/",
"Array.pop": "$global/",
"Array.push": "$global/",
"Array.reverse": "$global/",
"Array.shift": "$global/",
"Array.sort": "$global/",
"Array.splice": "$global/",
"Array.unshift": "$global/",
"Array.slice": "$global/",
"Array.lastIndexOf": "$global/",
"Array.indexOf": "$global/",

View File

@ -1,21 +0,0 @@
{% import 'common.rst' as common %}
.. js:attribute:: {{ name }}{{ '?' if is_optional else '' }}
{{ common.deprecated(deprecated)|indent(3) }}
{% if type -%}
.. rst-class:: js attribute type
type: {{ type|indent(3) }}
{%- endif %}
{% if description -%}
{{ description|indent(3) }}
{%- endif %}
{{ common.examples(examples)|indent(3) }}
{{ content|indent(3) }}
{{ common.see_also(see_also)|indent(3) }}

View File

@ -13,6 +13,7 @@ if not hasattr(inspect, "getargspec"):
from sphinx_js.suffix_tree import SuffixTree
from sphinx_js.typedoc import Analyzer as TsAnalyzer
from sphinx_js.typedoc import Project
test_directory = Path(__file__).resolve().parent
sys.path.append(str(test_directory.parent))
@ -25,18 +26,28 @@ src_dir = test_directory.parents[2] / "src"
# typedoc src/js/*.ts --tsconfig src/js/tsconfig.json --json docs/sphinx_pyodide/tests/tsdoc_dump.json
# gzip docs/sphinx_pyodide/tests/tsdoc_dump.json
# rm src/js/pyproxy.gen.ts
with gzip.open(test_directory / "tsdoc_dump.json.gz") as fh:
jsdoc_json = json.load(fh)
settings_json = json.loads((test_directory / "app_settings.json").read_text())
from sphinx_pyodide.jsdoc import (
PyodideAnalyzer,
flatten_suffix_tree,
get_jsdoc_content_directive,
get_jsdoc_summary_directive,
ts_post_convert,
ts_should_destructure_arg,
ts_xref_formatter,
)
inner_analyzer = TsAnalyzer(jsdoc_json, str(src_dir))
with gzip.open(test_directory / "tsdoc_dump.json.gz") as fh:
jsdoc_json = Project.parse_raw(fh.read())
settings_json = json.loads((test_directory / "app_settings.json").read_text())
inner_analyzer = TsAnalyzer(
jsdoc_json,
str(src_dir),
post_convert=ts_post_convert,
should_destructure_arg=ts_should_destructure_arg,
)
settings = OptionParser().get_default_values()
settings.update(settings_json, OptionParser())
@ -60,9 +71,14 @@ def test_flatten_suffix_tree():
assert d == r
class dummy_config:
ts_type_xref_formatter = ts_xref_formatter
class dummy_app:
_sphinxjs_analyzer = pyodide_analyzer
document = document
config = dummy_config
class dummy_state:
@ -83,7 +99,7 @@ def test_pyodide_analyzer():
"registerJsModule",
"runPython",
"runPythonAsync",
"setDefaultStdout",
"setDebug",
"setInterruptBuffer",
"setStderr",
"setStdin",
@ -97,6 +113,8 @@ def test_pyodide_analyzer():
"ERRNO_CODES",
"FS",
"PATH",
"canvas",
"ffi",
"version",
"globals",
"loadedPackages",
@ -171,11 +189,12 @@ def test_summary():
functions = jsdoc_summary.get_summary_table(
"pyodide", dummy_app._sphinxjs_analyzer.js_docs["pyodide"]["function"]
)
globals = {t[1]: t for t in globals}
attributes = {t[1]: t for t in attributes}
functions = {t[1]: t for t in functions}
globals = {t[2]: t for t in globals}
attributes = {t[2]: t for t in attributes}
functions = {t[2]: t for t in functions}
assert globals["loadPyodide"] == (
"**async** ",
"any",
"loadPyodide",
"(options)",
"Load the main Pyodide wasm module and initialize it.",
@ -184,13 +203,15 @@ def test_summary():
assert attributes["pyodide_py"] == (
"",
"any",
"pyodide_py",
"",
"An alias to the Python :py:mod:`pyodide` package.",
"An alias to the Python :ref:`pyodide <python-api>` package.",
"pyodide.pyodide_py",
)
assert attributes["version"] == (
"",
"any",
"version",
"",
"The Pyodide version.",
@ -198,6 +219,7 @@ def test_summary():
)
assert attributes["loadedPackages"] == (
"",
"any",
"loadedPackages",
"",
"The list of packages that Pyodide has loaded.",
@ -206,149 +228,7 @@ def test_summary():
assert functions["loadPackagesFromImports"][:-2] == (
"**async** ",
"any",
"loadPackagesFromImports",
"(code, options)",
)
def test_type_name():
tn = inner_analyzer._type_name
assert tn({"name": "void", "type": "intrinsic"}) == ":js:data:`void`"
assert tn({"value": None, "type": "literal"}) == ":js:data:`null`"
assert (
tn(
{
"name": "Promise",
"type": "reference",
"typeArguments": [{"name": "string", "type": "intrinsic"}],
}
).strip()
== r":js:class:`Promise`\ **<**\ :js:data:`string`\ **>**"
)
assert (
tn(
{
"asserts": False,
"name": "jsobj",
"targetType": {"name": "PyProxy", "type": "reference"},
"type": "predicate",
}
).strip()
== ":js:data:`boolean` (typeguard for :js:class:`PyProxy`)"
)
assert (
tn(
{
"declaration": {
"kindString": "Method",
"name": "messageCallback",
"signatures": [
{
"kindString": "Call signature",
"name": "messageCallback",
"parameters": [
{
"flags": {},
"kindString": "Parameter",
"name": "message",
"type": {"name": "string", "type": "intrinsic"},
}
],
"type": {"name": "void", "type": "intrinsic"},
}
],
},
"type": "reflection",
}
).strip()
== r"\ **(**\ \ **message:** :js:data:`string`\ **) =>** :js:data:`void`"
)
assert (
tn(
{
"name": "Iterable",
"type": "reference",
"typeArguments": [
{
"elements": [
{
"element": {"name": "string", "type": "intrinsic"},
"isOptional": False,
"name": "key",
"type": "named-tuple-member",
},
{
"element": {"name": "any", "type": "intrinsic"},
"isOptional": False,
"name": "value",
"type": "named-tuple-member",
},
],
"type": "tuple",
}
],
}
).strip()
== r":js:data:`Iterable`\ **<**\ \ **[**\ \ **key:** :js:data:`string`\ **,** \ **value:** :js:data:`any`\ **]** \ **>**"
)
assert (
tn(
{
"declaration": {
"flags": {},
"indexSignature": {
"flags": {},
"kindString": "Index signature",
"parameters": [
{
"flags": {},
"name": "key",
"type": {"name": "string", "type": "intrinsic"},
}
],
"type": {"name": "string", "type": "intrinsic"},
},
"kindString": "Type literal",
},
"type": "reflection",
}
).strip()
== r"""\ **{**\ \ **[key:** :js:data:`string`\ **]:** :js:data:`string`\ **}**\ """.strip()
)
assert (
tn(
{
"declaration": {
"children": [
{
"flags": {},
"kindString": "Property",
"name": "cache",
"type": {"name": "PyProxyCache", "type": "reference"},
},
{
"flags": {"isOptional": True},
"kindString": "Property",
"name": "destroyed_msg",
"type": {"name": "string", "type": "intrinsic"},
},
{
"flags": {},
"kindString": "Property",
"name": "ptr",
"type": {"name": "number", "type": "intrinsic"},
},
],
"flags": {},
"kindString": "Type literal",
},
"type": "reflection",
}
).strip()
== r"""\ **{**\ \ **cache:** :js:class:`PyProxyCache`\ **,** \ **destroyed_msg?:** :js:data:`string`\ **,** \ **ptr:** :js:data:`number`\ **}**\ """.strip()
)

View File

@ -43,7 +43,7 @@ import type { PyProxy } from "pyodide/ffi";
This provides APIs to set a canvas for rendering graphics.
For example, you need to set a canvas if you want to use the SDL library. See
:ref:`using-sdl` for more information.
{ref}`using-sdl` for more information.
```{eval-rst}
.. js-doc-summary:: pyodide.canvas

View File

@ -571,12 +571,12 @@ An example of a case where you would not want to use the
{js:func}`~pyodide.ffi.PyProxy.toJs` method is when the buffer is bitmapped
image data. If for instance you have a 3d buffer shaped 1920 x 1080 x 4, then
{js:func}`~pyodide.ffi.PyProxy.toJs` will be extremely slow. In this case you
could use {js:func}`~pyodide.ffi.PyProxy.getBuffer`. On the other hand, if you
could use {js:func}`~pyodide.ffi.PyBuffer.getBuffer`. On the other hand, if you
have a 3d buffer shaped 1920 x 4 x 1080, the performance of
{js:func}`~pyodide.ffi.PyProxy.toJs` will most likely be satisfactory.
Typically, the innermost dimension won't matter for performance.
The {js:func}`~pyodide.ffi.PyProxy.getBuffer` method can be used to retrieve a reference to
The {js:func}`~pyodide.ffi.PyBuffer.getBuffer` method can be used to retrieve a reference to
a JavaScript typed array that points to the data backing the Python object,
combined with other metadata about the buffer format. The metadata is suitable
for use with a JavaScript ndarray library if one is present. For instance, if

View File

@ -10,12 +10,12 @@ from ..logger import logger
def recipe(
packages: list[str] = typer.Argument(
..., help="Packages to build, or * for all packages in recipe directory"
..., help="Packages to build, or ``*`` for all packages in recipe directory"
),
recipe_dir: str = typer.Option(
None,
help="The directory containing the recipe of packages. "
"If not specified, the default is `./packages`",
"If not specified, the default is ``./packages``",
),
no_deps: bool = typer.Option(
False, help="If true, do not build dependencies of the specified packages. "
@ -28,13 +28,13 @@ def recipe(
install_dir: str = typer.Option(
None,
help="Path to install built packages and pyodide-lock.json. "
"If not specified, the default is `./dist`.",
"If not specified, the default is ``./dist``.",
),
metadata_files: bool = typer.Option(
False,
help="If true, extract the METADATA file from the built wheels "
"to a matching *.whl.metadata file. "
"If false, no *.whl.metadata file is produced.",
"to a matching ``*.whl.metadata`` file. "
"If false, no ``*.whl.metadata`` file is produced.",
),
cflags: str = typer.Option(
None, help="Extra compiling flags. Default: SIDE_MODULE_CFLAGS"

View File

@ -44,7 +44,7 @@ def new_recipe_pypi(
recipe_dir: str = typer.Option(
None,
help="The directory containing the recipe of packages."
"If not specified, the default is `<cwd>/packages`.",
"If not specified, the default is ``<cwd>/packages``.",
),
) -> None:
"""

View File

@ -280,7 +280,7 @@ Module.handle_js_error = function (e: any) {
/**
* A JavaScript error caused by a Python exception.
*
* In order to reduce the risk of large memory leaks, the :py:exc:`PythonError`
* In order to reduce the risk of large memory leaks, the :js:class:`PythonError`
* contains no reference to the Python exception that caused it. You can find
* the actual Python exception that caused this error as
* :py:data:`sys.last_value`.

View File

@ -192,7 +192,6 @@ const pyproxyAttrsSymbol = Symbol("pyproxy.attrs");
* Function so that PyProxy objects can be callable. In that case we MUST expose
* certain properties inherited from Function, but we do our best to remove as
* many as possible.
* @private
*/
function pyproxy_new(
ptr: number,
@ -344,7 +343,6 @@ let pyproxyClassMap = new Map();
* pyproxy_getflags. Multiple PyProxies with the same set of feature flags
* will share the same prototype, so the memory footprint of each individual
* PyProxy is minimal.
* @private
*/
Module.getPyProxyClass = function (flags: number) {
const FLAG_TYPE_PAIRS: [number, any][] = [
@ -556,14 +554,13 @@ export class PyProxy {
}
/**
* @private
* @hideconstructor
*/
constructor() {
throw new TypeError("PyProxy is not a constructor");
}
/** @private */
/** @hidden */
get [Symbol.toStringTag]() {
return "PyProxy";
}
@ -1033,7 +1030,6 @@ export class PyContainsMethods {
* Quote from:
* https://hacks.mozilla.org/2015/07/es6-in-depth-generators-continued/
*
* @private
*/
function* iter_helper(iterptr: number, token: {}): Generator<any> {
try {
@ -1122,7 +1118,6 @@ export class PyIterableMethods {
* Quote from:
* https://hacks.mozilla.org/2015/07/es6-in-depth-generators-continued/
*
* @private
*/
async function* aiter_helper(iterptr: number, token: {}): AsyncGenerator<any> {
try {
@ -1573,6 +1568,7 @@ function defaultCompareFunc(a: any, b: any): number {
// Missing:
// flatMap, flat,
export class PySequenceMethods {
/** @hidden */
get [Symbol.isConcatSpreadable]() {
return true;
}
@ -1645,10 +1641,11 @@ export class PySequenceMethods {
* return value is added as a single element in the new array.
* @param thisArg A value to use as ``this`` when executing ``callbackFn``.
*/
map(
callbackfn: (elt: any, index: number, array: any) => void,
map<U>(
callbackfn: (elt: any, index: number, array: any) => U,
thisArg?: any,
) {
): U[] {
// @ts-ignore
return Array.prototype.map.call(this, callbackfn, thisArg);
}
/**
@ -1842,22 +1839,23 @@ export interface PyMutableSequence extends PyMutableSequenceMethods {}
export class PyMutableSequenceMethods {
/**
* The :js:meth:`Array.reverse` method reverses a ``MutableSequence`` in
* The :js:meth:`Array.reverse` method reverses a :js:class:`PyMutableSequence` in
* place.
* @returns A reference to the same ``MutableSequence``
* @returns A reference to the same :js:class:`PyMutableSequence`
*/
reverse() {
reverse(): PyMutableSequence {
// @ts-ignore
this.$reverse();
// @ts-ignore
return this;
}
/**
* The :js:meth:`Array.sort` method sorts the elements of a
* ``MutableSequence`` in place.
* :js:class:`PyMutableSequence` in place.
* @param compareFn A function that defines the sort order.
* @returns A reference to the same ``MutableSequence``
* @returns A reference to the same :js:class:`PyMutableSequence`
*/
sort(compareFn?: (a: any, b: any) => number) {
sort(compareFn?: (a: any, b: any) => number): PyMutableSequence {
// Copy the behavior of sort described here:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#creating_displaying_and_sorting_an_array
// Yes JS sort is weird.
@ -1897,17 +1895,18 @@ export class PyMutableSequenceMethods {
cmp_to_key.destroy();
functools.destroy();
}
// @ts-ignore
return this;
}
/**
* The :js:meth:`Array.splice` method changes the contents of a
* ``MutableSequence`` by removing or replacing existing elements and/or
* :js:class:`PyMutableSequence` by removing or replacing existing elements and/or
* adding new elements in place.
* @param start Zero-based index at which to start changing the
* ``MutableSequence``.
* :js:class:`PyMutableSequence`.
* @param deleteCount An integer indicating the number of elements in the
* ``MutableSequence`` to remove from ``start``.
* @param items The elements to add to the ``MutableSequence``, beginning from
* :js:class:`PyMutableSequence` to remove from ``start``.
* @param items The elements to add to the :js:class:`PyMutableSequence`, beginning from
* ``start``.
* @returns An array containing the deleted elements.
*/
@ -1920,8 +1919,8 @@ export class PyMutableSequenceMethods {
}
/**
* The :js:meth:`Array.push` method adds the specified elements to the end of
* a ``MutableSequence``.
* @param elts The element(s) to add to the end of the ``MutableSequence``.
* a :js:class:`PyMutableSequence`.
* @param elts The element(s) to add to the end of the :js:class:`PyMutableSequence`.
* @returns The new length property of the object upon which the method was
* called.
*/
@ -1935,27 +1934,27 @@ export class PyMutableSequenceMethods {
}
/**
* The :js:meth:`Array.pop` method removes the last element from a
* ``MutableSequence``.
* @returns The removed element from the ``MutableSequence``; undefined if the
* ``MutableSequence`` is empty.
* :js:class:`PyMutableSequence`.
* @returns The removed element from the :js:class:`PyMutableSequence`; undefined if the
* :js:class:`PyMutableSequence` is empty.
*/
pop() {
return python_pop(this, false);
}
/**
* The :js:meth:`Array.shift` method removes the first element from a
* ``MutableSequence``.
* @returns The removed element from the ``MutableSequence``; undefined if the
* ``MutableSequence`` is empty.
* :js:class:`PyMutableSequence`.
* @returns The removed element from the :js:class:`PyMutableSequence`; undefined if the
* :js:class:`PyMutableSequence` is empty.
*/
shift() {
return python_pop(this, true);
}
/**
* The :js:meth:`Array.unshift` method adds the specified elements to the
* beginning of a ``MutableSequence``.
* @param elts The elements to add to the front of the ``MutableSequence``.
* @returns The new length of the ``MutableSequence``.
* beginning of a :js:class:`PyMutableSequence`.
* @param elts The elements to add to the front of the :js:class:`PyMutableSequence`.
* @returns The new length of the :js:class:`PyMutableSequence`.
*/
unshift(...elts: any[]) {
elts.forEach((elt, idx) => {
@ -1967,12 +1966,12 @@ export class PyMutableSequenceMethods {
}
/**
* The :js:meth:`Array.copyWithin` method shallow copies part of a
* ``MutableSequence`` to another location in the same ``MutableSequence``
* :js:class:`PyMutableSequence` to another location in the same :js:class:`PyMutableSequence`
* without modifying its length.
* @param target Zero-based index at which to copy the sequence to.
* @param start Zero-based index at which to start copying elements from.
* @param end Zero-based index at which to end copying elements from.
* @returns The modified ``MutableSequence``.
* @returns The modified :js:class:`PyMutableSequence`.
*/
copyWithin(target: number, start?: number, end?: number): any;
copyWithin(...args: number[]): any {
@ -2339,7 +2338,6 @@ export type PyProxyAwaitable = PyAwaitable;
/**
* The Promise / JavaScript awaitable API.
* @private
*/
export class PyAwaitableMethods {
$$: any;
@ -2444,7 +2442,7 @@ export class PyAwaitableMethods {
/**
* A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is
* :std:term:`callable` (i.e., has an :py:meth:`~operator.__call__` method).
* :std:term:`callable` (i.e., has an :py:meth:`~object.__call__` method).
*/
export class PyCallable extends PyProxy {
/** @private */
@ -2958,10 +2956,8 @@ export class PyBufferView {
*/
f_contiguous: boolean;
/** @private */
_released: boolean;
/** @private */
_view_ptr: number;
/** @private */

View File

@ -470,8 +470,8 @@ export class PyodideAPI {
* @param path The absolute path in the Emscripten file system to mount the
* native directory. If the directory does not exist, it will be created. If it
* does exist, it must be empty.
* @param fileSystemHandle A handle returned by ``navigator.storage.getDirectory()``
* or ``window.showDirectoryPicker()``.
* @param fileSystemHandle A handle returned by :js:func:`navigator.storage.getDirectory() <getDirectory>`
* or :js:func:`window.showDirectoryPicker() <showDirectoryPicker>`.
*/
static async mountNativeFS(
path: string,

145
src/js/package-lock.json generated
View File

@ -17,7 +17,7 @@
"@types/emscripten": "^1.39.5",
"@types/expect": "^24.3.0",
"@types/mocha": "^9.1.0",
"@types/node": "^17.0.25",
"@types/node": "^17.0.45",
"@types/ws": "^8.5.3",
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
@ -32,7 +32,7 @@
"prettier": "^2.2.1",
"ts-mocha": "^9.0.2",
"tsd": "^0.24.1",
"typedoc": "^0.22.15",
"typedoc": "^0.25.1",
"typescript": "^4.6.4"
}
},
@ -1262,6 +1262,12 @@
"node": ">=8"
}
},
"node_modules/ansi-sequence-parser": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz",
"integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==",
"dev": true
},
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@ -3559,9 +3565,9 @@
}
},
"node_modules/marked": {
"version": "4.2.12",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz",
"integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==",
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
"integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
"dev": true,
"bin": {
"marked": "bin/marked.js"
@ -5229,14 +5235,15 @@
}
},
"node_modules/shiki": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz",
"integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==",
"version": "0.14.4",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.4.tgz",
"integrity": "sha512-IXCRip2IQzKwxArNNq1S+On4KPML3Yyn8Zzs/xRgcgOWIr8ntIK3IKzjFPfjy/7kt9ZMjc+FItfqHRBg8b6tNQ==",
"dev": true,
"dependencies": {
"jsonc-parser": "^3.0.0",
"vscode-oniguruma": "^1.6.1",
"vscode-textmate": "5.2.0"
"ansi-sequence-parser": "^1.1.0",
"jsonc-parser": "^3.2.0",
"vscode-oniguruma": "^1.7.0",
"vscode-textmate": "^8.0.0"
}
},
"node_modules/side-channel": {
@ -5764,25 +5771,24 @@
}
},
"node_modules/typedoc": {
"version": "0.22.18",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.18.tgz",
"integrity": "sha512-NK9RlLhRUGMvc6Rw5USEYgT4DVAUFk7IF7Q6MYfpJ88KnTZP7EneEa4RcP+tX1auAcz7QT1Iy0bUSZBYYHdoyA==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.1.tgz",
"integrity": "sha512-c2ye3YUtGIadxN2O6YwPEXgrZcvhlZ6HlhWZ8jQRNzwLPn2ylhdGqdR8HbyDRyALP8J6lmSANILCkkIdNPFxqA==",
"dev": true,
"dependencies": {
"glob": "^8.0.3",
"lunr": "^2.3.9",
"marked": "^4.0.16",
"minimatch": "^5.1.0",
"shiki": "^0.10.1"
"marked": "^4.3.0",
"minimatch": "^9.0.3",
"shiki": "^0.14.1"
},
"bin": {
"typedoc": "bin/typedoc"
},
"engines": {
"node": ">= 12.10.0"
"node": ">= 16"
},
"peerDependencies": {
"typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x || 4.6.x || 4.7.x"
"typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x"
}
},
"node_modules/typedoc/node_modules/brace-expansion": {
@ -5794,35 +5800,19 @@
"balanced-match": "^1.0.0"
}
},
"node_modules/typedoc/node_modules/glob": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
"integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^5.0.1",
"once": "^1.3.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/typedoc/node_modules/minimatch": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=10"
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/typescript": {
@ -5932,9 +5922,9 @@
"dev": true
},
"node_modules/vscode-textmate": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz",
"integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==",
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz",
"integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==",
"dev": true
},
"node_modules/which": {
@ -7031,6 +7021,12 @@
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true
},
"ansi-sequence-parser": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz",
"integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==",
"dev": true
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@ -8704,9 +8700,9 @@
"dev": true
},
"marked": {
"version": "4.2.12",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz",
"integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==",
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
"integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
"dev": true
},
"media-typer": {
@ -9930,14 +9926,15 @@
"dev": true
},
"shiki": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz",
"integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==",
"version": "0.14.4",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.4.tgz",
"integrity": "sha512-IXCRip2IQzKwxArNNq1S+On4KPML3Yyn8Zzs/xRgcgOWIr8ntIK3IKzjFPfjy/7kt9ZMjc+FItfqHRBg8b6tNQ==",
"dev": true,
"requires": {
"jsonc-parser": "^3.0.0",
"vscode-oniguruma": "^1.6.1",
"vscode-textmate": "5.2.0"
"ansi-sequence-parser": "^1.1.0",
"jsonc-parser": "^3.2.0",
"vscode-oniguruma": "^1.7.0",
"vscode-textmate": "^8.0.0"
}
},
"side-channel": {
@ -10342,16 +10339,15 @@
}
},
"typedoc": {
"version": "0.22.18",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.18.tgz",
"integrity": "sha512-NK9RlLhRUGMvc6Rw5USEYgT4DVAUFk7IF7Q6MYfpJ88KnTZP7EneEa4RcP+tX1auAcz7QT1Iy0bUSZBYYHdoyA==",
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.1.tgz",
"integrity": "sha512-c2ye3YUtGIadxN2O6YwPEXgrZcvhlZ6HlhWZ8jQRNzwLPn2ylhdGqdR8HbyDRyALP8J6lmSANILCkkIdNPFxqA==",
"dev": true,
"requires": {
"glob": "^8.0.3",
"lunr": "^2.3.9",
"marked": "^4.0.16",
"minimatch": "^5.1.0",
"shiki": "^0.10.1"
"marked": "^4.3.0",
"minimatch": "^9.0.3",
"shiki": "^0.14.1"
},
"dependencies": {
"brace-expansion": {
@ -10363,23 +10359,10 @@
"balanced-match": "^1.0.0"
}
},
"glob": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
"integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^5.0.1",
"once": "^1.3.0"
}
},
"minimatch": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
"dev": true,
"requires": {
"brace-expansion": "^2.0.1"
@ -10456,9 +10439,9 @@
"dev": true
},
"vscode-textmate": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz",
"integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==",
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz",
"integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==",
"dev": true
},
"which": {

View File

@ -20,7 +20,7 @@
"@types/emscripten": "^1.39.5",
"@types/expect": "^24.3.0",
"@types/mocha": "^9.1.0",
"@types/node": "^17.0.25",
"@types/node": "^17.0.45",
"@types/ws": "^8.5.3",
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
@ -35,7 +35,7 @@
"prettier": "^2.2.1",
"ts-mocha": "^9.0.2",
"tsd": "^0.24.1",
"typedoc": "^0.22.15",
"typedoc": "^0.25.1",
"typescript": "^4.6.4"
},
"main": "pyodide.js",

23
src/js/tsdoc.json Normal file
View File

@ -0,0 +1,23 @@
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/tsdoc/v0/tsdoc.schema.json",
"extends": ["typedoc/tsdoc.json"],
"noStandardTags": false,
"tagDefinitions": [
{
"tagName": "@alias",
"syntaxKind": "modifier"
},
{
"tagName": "@hidetype",
"syntaxKind": "modifier"
},
{
"tagName": "@hideconstructor",
"syntaxKind": "modifier"
},
{
"tagName": "@dockind",
"syntaxKind": "block"
}
]
}

View File

@ -252,7 +252,7 @@ class JsProxy(metaclass=_JsProxyMetaClass):
--------
Here are a couple examples of converter functions. In addition to the
normal conversions, convert :js:class:`Date`` to :py:class:`~datetime.datetime`:
normal conversions, convert :js:class:`Date` to :py:class:`~datetime.datetime`:
.. code-block:: python