Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
201 commits
Select commit Hold shift + click to select a range
d2a57ab
ENH: Add actions base class
j-t-1 Dec 6, 2025
388b902
Fix error
j-t-1 Dec 6, 2025
695a2c9
Increase code coverage
j-t-1 Dec 6, 2025
ef335cc
Fix error
j-t-1 Dec 6, 2025
efbb46e
Add to test
j-t-1 Dec 6, 2025
82c9e5d
Debug test
j-t-1 Dec 7, 2025
5ea4e6c
Debug
j-t-1 Dec 7, 2025
7f4077a
Modify actions
j-t-1 Jan 1, 2026
dc27124
Revert
j-t-1 Jan 1, 2026
52cee63
Fix test
j-t-1 Jan 1, 2026
03db2c6
Fix test
j-t-1 Jan 1, 2026
a44f4af
Fix coverage
j-t-1 Jan 1, 2026
4593f1c
Fix test_page_add_action
j-t-1 Jan 1, 2026
486b215
More fixes
j-t-1 Jan 2, 2026
77cceb0
Improve tests
j-t-1 Jan 2, 2026
84b5215
Fixes
j-t-1 Jan 2, 2026
a3fe3c3
Replace single quotes with double quotes
j-t-1 Jan 2, 2026
61975f0
Update actions
j-t-1 Jan 28, 2026
6e0b128
Fix tests
j-t-1 Feb 17, 2026
4c5b1fe
Add assert
j-t-1 Feb 17, 2026
e74df20
Replace single quotes with double quotes
j-t-1 Feb 17, 2026
2def725
Add test
j-t-1 Feb 17, 2026
be4a454
Fix docstring
j-t-1 Feb 18, 2026
3215f49
Add coverage
j-t-1 Feb 18, 2026
6b2220c
Fix error
j-t-1 Feb 18, 2026
c3a0612
Fix error
j-t-1 Feb 18, 2026
fd9a071
Fix error
j-t-1 Feb 18, 2026
40f00cc
Fix error
j-t-1 Feb 18, 2026
b271cd0
Add actions.rst
j-t-1 Feb 18, 2026
055a0d1
Add to toctree
j-t-1 Feb 18, 2026
9512011
Fix coverage
j-t-1 Feb 18, 2026
ae04f7d
Fix coverage
j-t-1 Feb 18, 2026
b51c376
Fix test error
j-t-1 Feb 24, 2026
5e5a1d9
Merge branch 'main' into actions
j-t-1 Feb 24, 2026
5b77d55
Merge branch 'main' into actions
j-t-1 Feb 24, 2026
91149f5
Fix coverage
j-t-1 Feb 25, 2026
dbaa92f
Fix coverage
j-t-1 Feb 26, 2026
bbe9979
Change error type and fix mypy error
j-t-1 Mar 5, 2026
2dc05b5
Fix error
j-t-1 Mar 5, 2026
0894957
Merge branch 'main' into actions
j-t-1 Mar 5, 2026
990f7a1
Add infinite loop mitigation
j-t-1 Mar 6, 2026
50d1632
import RESOURCE_ROOT
j-t-1 Mar 9, 2026
eafc441
Remove unused import
j-t-1 Mar 9, 2026
cfb068a
Add ArrayObject to cycle detection
j-t-1 Mar 11, 2026
d76f5d0
Change cycle detection
j-t-1 Mar 11, 2026
eaca2be
ENH: Add actions base class
j-t-1 Apr 28, 2026
449b2a6
ENH: Add actions base class
j-t-1 Apr 29, 2026
e039151
ENH: Add actions base class
j-t-1 Dec 6, 2025
4657e44
Fix error
j-t-1 Dec 6, 2025
0c4f51a
Increase code coverage
j-t-1 Dec 6, 2025
b5a7126
Fix error
j-t-1 Dec 6, 2025
b7d8dcc
Add to test
j-t-1 Dec 6, 2025
68687e4
Debug test
j-t-1 Dec 7, 2025
68c8859
Debug
j-t-1 Dec 7, 2025
7495ace
Modify actions
j-t-1 Jan 1, 2026
8c44c37
Revert
j-t-1 Jan 1, 2026
2a1e285
Fix test
j-t-1 Jan 1, 2026
ecdd69c
Fix test
j-t-1 Jan 1, 2026
4560c46
Fix coverage
j-t-1 Jan 1, 2026
397eda5
Fix test_page_add_action
j-t-1 Jan 1, 2026
5050c99
More fixes
j-t-1 Jan 2, 2026
dac0a1d
Improve tests
j-t-1 Jan 2, 2026
884b534
Fixes
j-t-1 Jan 2, 2026
328dc0a
Replace single quotes with double quotes
j-t-1 Jan 2, 2026
d774d44
Update actions
j-t-1 Jan 28, 2026
a350a48
Fix tests
j-t-1 Feb 17, 2026
ad86aa2
Add assert
j-t-1 Feb 17, 2026
c3e08dd
Replace single quotes with double quotes
j-t-1 Feb 17, 2026
b37338e
Add test
j-t-1 Feb 17, 2026
a381dfc
Fix docstring
j-t-1 Feb 18, 2026
8b05fec
Add coverage
j-t-1 Feb 18, 2026
0ca5987
Fix error
j-t-1 Feb 18, 2026
4a4b6d9
Fix error
j-t-1 Feb 18, 2026
dd57257
Fix error
j-t-1 Feb 18, 2026
dbd97ff
Fix error
j-t-1 Feb 18, 2026
0248f1d
Add actions.rst
j-t-1 Feb 18, 2026
b558acf
Add to toctree
j-t-1 Feb 18, 2026
b9ad57d
Fix coverage
j-t-1 Feb 18, 2026
b8f040d
Fix coverage
j-t-1 Feb 18, 2026
1ad0939
Fix test error
j-t-1 Feb 24, 2026
8530c35
Fix coverage
j-t-1 Feb 25, 2026
0e88167
Fix coverage
j-t-1 Feb 26, 2026
6d6ec5b
Change error type and fix mypy error
j-t-1 Mar 5, 2026
81a9daa
Fix error
j-t-1 Mar 5, 2026
cda8f63
Add infinite loop mitigation
j-t-1 Mar 6, 2026
ee42260
import RESOURCE_ROOT
j-t-1 Mar 9, 2026
3f51390
Remove unused import
j-t-1 Mar 9, 2026
14bca27
Add ArrayObject to cycle detection
j-t-1 Mar 11, 2026
b955577
Change cycle detection
j-t-1 Mar 11, 2026
29f2234
ENH: Add actions base class
j-t-1 Apr 28, 2026
a79df96
ENH: Add actions base class
j-t-1 Apr 29, 2026
e0951b8
ENH: Add actions base class
j-t-1 Apr 29, 2026
4f0d20f
ENH: Add actions base class
j-t-1 Apr 29, 2026
afacb0e
ENH: Add actions base class
j-t-1 Apr 29, 2026
6179167
ENH: Add actions base class
j-t-1 Apr 29, 2026
1770fd2
ENH: Add actions base class
j-t-1 Apr 29, 2026
252f9c8
ENH: Add actions base class
j-t-1 Apr 30, 2026
5d68369
ENH: Add actions base class
j-t-1 Apr 30, 2026
5df6084
ENH: Add actions base class
j-t-1 Apr 30, 2026
54491f2
ENH: Add actions base class
j-t-1 Apr 30, 2026
7decde9
ENH: Add actions base class
j-t-1 Apr 30, 2026
7c35f98
ENH: Add actions base class
j-t-1 Apr 30, 2026
114e29b
ENH: Add actions base class
j-t-1 Apr 30, 2026
c72d531
ENH: Add actions base class
j-t-1 Apr 30, 2026
f9b7028
Merge branch 'main' into actions
j-t-1 May 4, 2026
3bbb842
ENH: Update test_actions.py
j-t-1 May 4, 2026
6541b91
ENT: Update test_actions.py
j-t-1 May 4, 2026
d70790a
ENH: Update test_actions.py
j-t-1 May 4, 2026
090a8bd
ENH: Update test_actions.py
j-t-1 May 4, 2026
d8ea299
ENH: Improve tests
j-t-1 May 4, 2026
236107a
ENH: Update test_actions.py
j-t-1 May 4, 2026
ddb87dd
ENH: Update
j-t-1 May 5, 2026
d8da741
ENH: Add actions base class
j-t-1 May 5, 2026
a658c71
ENH: Add actions base class
j-t-1 May 5, 2026
0a64847
ENH: Add actions base class
j-t-1 May 5, 2026
5f1c587
ENH: Add actions base class
j-t-1 May 5, 2026
df84a93
ENH: Add actions base class
j-t-1 May 6, 2026
c8b595b
ENH: Add actions base class
j-t-1 May 6, 2026
1b6eebe
Update pypdf/actions/_actions.py
j-t-1 May 6, 2026
838af1e
Update tests/test_actions.py
j-t-1 May 6, 2026
2ef3ea2
ENH: Update
j-t-1 May 6, 2026
0b06a27
ENH: Update
j-t-1 May 6, 2026
7518d55
ENH: Update
j-t-1 May 6, 2026
f666a7b
ENH: Update
j-t-1 May 6, 2026
1a79bc3
ENH: Update
j-t-1 May 6, 2026
7b5c9b5
ENH: Update
j-t-1 May 6, 2026
152c3ea
ENH: Add actions
j-t-1 May 7, 2026
824d4e2
ENH: Add action base class
j-t-1 May 7, 2026
ea38b9c
ENH: Add action base class
j-t-1 May 7, 2026
8855b57
ENH: Add action base class
j-t-1 May 7, 2026
f1b9127
ENH: Add action base class
j-t-1 May 7, 2026
2bd082e
ENH: Add action base class
j-t-1 May 7, 2026
012ea3e
ENH: Add action base class
j-t-1 May 7, 2026
6a13653
ENH: Add actions base class
j-t-1 May 8, 2026
670a7cc
ENH: Add actions base
j-t-1 May 8, 2026
fc1d687
ENH: Add actions base class
j-t-1 May 8, 2026
3fdcc0d
ENH: Add actions base class
j-t-1 May 8, 2026
d185997
ENH: Add actions base class
j-t-1 May 8, 2026
868e6c5
ENH: Fix errros
j-t-1 May 8, 2026
29b7f8e
ENH: Add actions base class
j-t-1 May 12, 2026
75bf15c
Merge branch 'main' into actions
j-t-1 May 12, 2026
e938ade
ENH: Add actions base class
j-t-1 May 12, 2026
368d964
ENH: Add actions base class
j-t-1 May 12, 2026
4389848
ENH: Add actions base class
j-t-1 May 12, 2026
1fd79dd
ENH: Add actions base class
j-t-1 May 12, 2026
c720eab
ENH: Add actions base class
j-t-1 May 12, 2026
2c4bc57
ENH: Add actions base class
j-t-1 May 12, 2026
5f6ee96
ENH: Add actions base class
j-t-1 May 12, 2026
0bc854b
ENH: Add actions base class
j-t-1 May 12, 2026
6fdfd70
ENH: Add actions base class
j-t-1 May 12, 2026
c946f03
ENH: Add actions base class
j-t-1 May 12, 2026
73cc4ad
ENH: Add actions base class
j-t-1 May 12, 2026
7253b20
ENH: Add actions base class
j-t-1 May 13, 2026
65d4fc2
ENH: Add actions base class
j-t-1 May 13, 2026
d4be0bf
ENH: Add actions base class
j-t-1 May 13, 2026
165e0ca
ENH: Add actions base class
j-t-1 May 13, 2026
01a1618
ENH: Add actions base class
j-t-1 May 13, 2026
6f87edd
ENH: Add actions base class
j-t-1 May 13, 2026
20f27fc
ENH: Add actions base class
j-t-1 May 13, 2026
332ea19
ENH: Add actions base class
j-t-1 May 13, 2026
048d672
ENH: Add actions base class
j-t-1 May 13, 2026
161e438
ENH: Fix
j-t-1 May 14, 2026
5f5feab
ENH: Fix
j-t-1 May 14, 2026
05cb20c
ENH: Add actions base class
j-t-1 May 14, 2026
ff17a3f
ENH: Fix
j-t-1 May 14, 2026
669cfd8
ENH: Fix
j-t-1 May 14, 2026
3979839
ENH: Add actions base class
j-t-1 May 14, 2026
ba619a4
ENH: Add actions base class
j-t-1 May 19, 2026
e486125
ENH: Add actions base class
j-t-1 May 19, 2026
5330235
ENH: Fix
j-t-1 May 19, 2026
5f03dfd
ENH: Add actions base class
j-t-1 May 19, 2026
3e7e714
ENH: Add actions base class
j-t-1 May 19, 2026
c8cae88
ENH: Add actions base class
j-t-1 May 19, 2026
a0756d2
Merge branch 'main' into actions
stefan6419846 May 20, 2026
efcd908
ENH: Fix
j-t-1 May 20, 2026
689e6c9
ENH: Fix
j-t-1 May 20, 2026
82d8bb6
Apply suggestions from code review
j-t-1 May 20, 2026
9d02048
ENH: Fix
j-t-1 May 20, 2026
86a7c40
Update pypdf/actions/_actions.py
j-t-1 May 20, 2026
c3a4fab
ENH: Add actions base class
j-t-1 May 20, 2026
2a5bd04
ENH: Add actions base class
j-t-1 May 20, 2026
c9c13f2
ENH: Add actions base class
j-t-1 May 21, 2026
552a64f
ENH: Add actions base class
j-t-1 May 21, 2026
d95ba3e
ENH: Add actions base class
j-t-1 May 21, 2026
4fee484
ENH: Add actions base class
j-t-1 May 21, 2026
a6bdf24
Update pypdf/actions/_actions.py
j-t-1 May 21, 2026
1165401
Update tests/test_actions.py
j-t-1 May 21, 2026
ebf964d
Update pypdf/actions/_actions.py
j-t-1 May 21, 2026
3422ecf
Apply suggestions from code review
j-t-1 May 21, 2026
30bda9e
ENH: Add actions base class
j-t-1 May 21, 2026
937ff1f
Merge branch 'actions' of https://github.com/j-t-1/pypdf into actions
j-t-1 May 21, 2026
28485d2
ENH: Add actions base class
j-t-1 May 21, 2026
7c531ad
ENH: Fix error
j-t-1 May 21, 2026
7075025
ENH: Fix
j-t-1 May 21, 2026
01b7c8b
ENH: Fix
j-t-1 May 21, 2026
2474478
ENH: Fix
j-t-1 May 21, 2026
8097221
ENH: Fix
j-t-1 May 21, 2026
f414ed3
ENH: Fix
j-t-1 May 21, 2026
2d39b9e
ENH: Fix
j-t-1 May 21, 2026
392ead8
ENH: Fix
j-t-1 May 21, 2026
dde8004
Merge branch 'main' into actions
j-t-1 May 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ You can contribute to `pypdf on GitHub <https://github.com/py-pdf/pypdf>`_.
modules/RectangleObject
modules/Transformation
modules/XmpInformation
modules/actions
modules/annotations
modules/constants
modules/errors
Expand Down
7 changes: 7 additions & 0 deletions docs/modules/actions.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Actions
-------

.. automodule:: pypdf.actions
:members:
:undoc-members:
:show-inheritance:
42 changes: 42 additions & 0 deletions pypdf/_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
logger_warning,
matrix_multiply,
)
from .actions import Action, PageTrigger
from .constants import (
_INLINE_IMAGE_KEY_MAPPING,
_INLINE_IMAGE_VALUE_MAPPING,
Expand Down Expand Up @@ -2168,6 +2169,47 @@ def annotations(self, value: Optional[ArrayObject]) -> None:
else:
self[NameObject("/Annots")] = value

def add_action(self, trigger: PageTrigger, action: Action) -> None:
"""
Add an action which will launch on the given trigger event of this page.

Args:
trigger: The action trigger to use.
action: A :py:class:`~pypdf.actions.Action` object.

Example:
>>> from pypdf import PdfWriter
>>> from pypdf.actions import JavaScript, PageTrigger
>>> writer = PdfWriter()
>>> page = writer.add_blank_page(595, 842)
>>> # Display the page number when the page is opened
>>> page.add_action(PageTrigger("open"), JavaScript("app.alert('This is page ' + this.pageNum);"))
>>> # Display the page number when the page is closed
>>> page.add_action(PageTrigger("close"), JavaScript("app.alert('This is page ' + this.pageNum);"))
"""
return Action._create_new(self, trigger, action)

def delete_action(self, trigger: PageTrigger) -> None:
"""
Delete an action associated with an open or close trigger event of this page.

Args:
trigger: A :py:class:`~pypdf.actions.PageTrigger` object.

Example:
>>> from pypdf import PdfWriter
>>> from pypdf.actions import JavaScript, PageTrigger
>>> writer = PdfWriter()
>>> page = writer.add_blank_page(595, 842)
>>> page.add_action(PageTrigger("open"), JavaScript("app.alert('This is page ' + this.pageNum);"))
>>> page.add_action(PageTrigger("close"), JavaScript("app.alert('This is page ' + this.pageNum);"))
>>> # Delete all actions triggered by a page open
>>> page.delete_action(PageTrigger("open"))
>>> # Delete all actions triggered by a page close
>>> page.delete_action(PageTrigger("close"))
"""
return Action._delete(self, trigger)


class _VirtualList(Sequence[PageObject]):
def __init__(
Expand Down
17 changes: 17 additions & 0 deletions pypdf/actions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""
PDF includes a wide variety of standard action types, whose characteristics and
behaviour are defined by an action dictionary. These are defined in this
submodule.

Trigger events are the other component of actions, and are specific to their
associated object.
"""


from ._actions import Action, JavaScript, PageTrigger

__all__ = [
"Action",
"JavaScript",
"PageTrigger",
]
179 changes: 179 additions & 0 deletions pypdf/actions/_actions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
"""Action types"""
import sys
from abc import ABC
from enum import Enum, unique
from typing import (
TYPE_CHECKING,
cast,
)

from .._utils import logger_warning
from ..errors import ParseError
from ..generic import (
ArrayObject,
DictionaryObject,
NameObject,
NullObject,
TextStringObject,
is_null_or_none,
)

if sys.version_info >= (3, 11):
from enum import StrEnum
else:
class StrEnum(str, Enum):
def __str__(self) -> str:
return str(self.value)

if TYPE_CHECKING:
from .._page import PageObject


@unique
class PageTrigger(StrEnum):
Comment thread
j-t-1 marked this conversation as resolved.
"""Trigger event entries in a page object's additional-actions dictionary."""
OPEN = "open"
"""A :py:class:`~pypdf.actions.PageTrigger` object triggering an action when the page is opened."""
CLOSE = "close"
"""A :py:class:`~pypdf.actions.PageTrigger` object triggering an action when the page is closed."""


class Action(DictionaryObject, ABC):
"""An action dictionary defines the characteristics and behaviour of an action."""
def __init__(self) -> None:
super().__init__()
self[NameObject("/Type")] = NameObject("/Action")
# The next action or sequence of actions that shall be performed after the action
# represented by this dictionary. The value is either a single action dictionary
# or an array of action dictionaries that shall be performed in order.
self[NameObject("/Next")] = NullObject() # Optional

@classmethod
def _create_new(cls, page: "PageObject", trigger: PageTrigger, action: "Action") -> None:
"""
Create a new action and add it to the page.

Args:
page: The page to add the action.
trigger: A :py:class:`~pypdf.actions.PageTrigger` object.
action: A :py:class:`~pypdf.actions.Action` object.
"""
trigger_name = NameObject("/O") if PageTrigger(trigger).value == PageTrigger.OPEN else NameObject("/C")

if "/AA" not in page:
# Additional actions key not present
page[NameObject("/AA")] = DictionaryObject(
{trigger_name: action}
)
return

if isinstance(page["/AA"], NullObject):
page[NameObject("/AA")] = DictionaryObject()

if not isinstance(page["/AA"].get_object(), DictionaryObject):
if page.pdf is not None and getattr(page.pdf, "strict", False):
current_type = type(page["/AA"])
raise ParseError(
f"The AA entry of the page should be a DictionaryObject. "
f"It currently is a {current_type}."
)
logger_warning(
"The AA entry of the page should be a DictionaryObject. It currently is a %(type)s.",
source=__name__,
type=type(page["/AA"])
)
return

additional_actions = cast(DictionaryObject, page["/AA"])

if is_null_or_none(additional_actions.get(trigger_name)):
additional_actions.update({trigger_name: action})
return

# The action dictionary's Next entry allows sequences of actions to be
# chained together. For example, the effect of clicking a link
# annotation with the mouse can be to play a sound, jump to a new
# page, and start up a movie. Note that the Next entry is not
# restricted to a single action but can contain an array of actions,
# each of which in turn can have a Next entry of its own.
# §12.6.2 Action dictionaries ISO 32000-2:2020
head = current = additional_actions.get(trigger_name)
if not isinstance(head, DictionaryObject):
raise ParseError(
f"The type in a page object's additional-actions key must be a DictionaryObject: "
f"received type {type(head)}"
)
current = cast(DictionaryObject, current)

visited = set()
while True:
next_ = current.get("/Next", None)

if is_null_or_none(next_):
break

if not isinstance(next_, (ArrayObject, DictionaryObject)):
raise TypeError(
f"An action dictionary’s Next entry must be an Action dictionary "
f"or an array of Action dictionaries: received type {type(next_)}"
)

id_ = id(next_)
if id_ in visited:
logger_warning("Detected cycle in the action tree for %(current)s", source=__name__, current=current)
break
visited.add(id_)

if isinstance(next_, ArrayObject):
current = next_[-1]
else:
current = next_

if not is_null_or_none(next_ := current.get("/Next")) and id(next_) in visited:
logger_warning("Detected cycle in the action tree for %(current)s", source=__name__, current=current)

current[NameObject("/Next")] = action
additional_actions.update({trigger_name: head})

@classmethod
def _delete(cls, page: "PageObject", trigger: PageTrigger) -> None:
"""
Delete an object on the page.

Args:
page: The page to add the action.
trigger: A :py:class:`~pypdf.actions.PageTrigger` object.
"""
if "/AA" not in page:
return

trigger_name = NameObject("/O") if PageTrigger(trigger).value == PageTrigger.OPEN else NameObject("/C")

additional_actions = cast(DictionaryObject, page["/AA"])

if trigger_name not in additional_actions:
return

del additional_actions[trigger_name]

if not additional_actions:
del page["/AA"]


class JavaScript(Action):
Comment thread
stefan6419846 marked this conversation as resolved.
"""
Upon invocation of an ECMAScript action, a PDF processor shall execute a
script that is written in the ECMAScript programming language. ECMAScript
extensions described in ISO/DIS 21757-1 shall also be allowed.
"""

def __init__(self, js: str) -> None:
Comment thread
j-t-1 marked this conversation as resolved.
Comment thread
j-t-1 marked this conversation as resolved.
"""
Initialize JavaScript with a string.

Args:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not appear in the docs: https://pypdf--3552.org.readthedocs.build/en/3552/modules/actions.html Please check other cases and correct accordingly.

js: A text string containing the ECMAScript script to be executed.
"""
super().__init__()
self[NameObject("/S")] = NameObject("/JavaScript")
self[NameObject("/JS")] = TextStringObject(js)
11 changes: 7 additions & 4 deletions pypdf/constants.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
"""Various constants, enums, and flags to aid readability."""

import sys
from enum import Enum, IntFlag, auto, unique


class StrEnum(str, Enum): # Once we are on Python 3.11+: enum.StrEnum
def __str__(self) -> str:
return str(self.value)
if sys.version_info >= (3, 11):
from enum import StrEnum
else:
class StrEnum(str, Enum):
def __str__(self) -> str:
return str(self.value)


class Core:
Expand Down
4 changes: 4 additions & 0 deletions pypdf/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,7 @@
"/Projection",
"/RichMedia",
]

ActionSubtype: TypeAlias = Literal[
"/JavaScript",
]
Loading
Loading