Module refinery.lib.scripts.js.model
The JavaScript syntax tree: one node type per production of the grammar, and the few predicates that answer a question about a node from the node alone.
A node states what was written and nothing about what it means. strip_parens() and names_a_property()
live here because the answer is in the shape; anything needing a scope, a binding or an effect
belongs in refinery.lib.scripts.js.analysis instead, which is why nothing here imports that package.
Nothing here holds state either, so a pass may ask any of it at any point of a rewrite.
Expand source code Browse git
"""
The JavaScript syntax tree: one node type per production of the grammar, and the few predicates that
answer a question about a node from the node alone.
A node states what was written and nothing about what it means. `strip_parens` and `names_a_property`
live here because the answer is in the shape; anything needing a scope, a binding or an effect
belongs in `refinery.lib.scripts.js.analysis` instead, which is why nothing here imports that package.
Nothing here holds state either, so a pass may ask any of it at any point of a rewrite.
"""
from __future__ import annotations
import enum
import functools
from dataclasses import dataclass, field, replace
from typing import TYPE_CHECKING
from refinery.lib.scripts import Expression, Node, Statement
from refinery.lib.scripts.js.numbers import integer_of_numeral, js_number_to_string, to_js_number
if TYPE_CHECKING:
from refinery.lib.scripts.js.strict import StrictViolation
class JsPropertyKind(enum.Enum):
INIT = 'init'
GET = 'get' # noqa
SET = 'set' # noqa
class JsMethodKind(enum.Enum):
METHOD = 'method' # noqa
GET = 'get' # noqa
SET = 'set' # noqa
CONSTRUCTOR = 'constructor' # noqa
class JsVarKind(enum.Enum):
VAR = 'var' # noqa
LET = 'let' # noqa
CONST = 'const' # noqa
@dataclass(repr=False, eq=False)
class JsErrorNode(Expression, Statement, unparsed=True):
"""
A span of source the parser could not read, kept verbatim so that what an analyst gets back
still contains what was written. It prints as `text` and so reads back as whatever that text
parses to, which is why a tree holding one states nothing about synthesizer fidelity.
It stands in either position, because the recovery that builds it does not know which was
expected. In statement position it is the statement, and is deliberately not wrapped in an
expression statement: the wrapper prints a semicolon that nobody wrote, which grows the file by
one character every time the tool reads its own output.
"""
text: str = ''
message: str = ''
@dataclass(repr=False, eq=False)
class JsIdentifier(Expression, spelling='raw'):
"""
A name. `name` is the name the source denotes and `raw` is the text it was written with, which
part ways wherever a unicode escape stands between them: `\\u0061bc` and `abc` are one binding
written two ways, and every question about names is asked of `name`.
`raw` is empty wherever the two would be the same text, so it holds something only for a name
the source wrote some other way. What it holds is trusted only for as long as it still spells
`name`, which is what leaves a pass renaming a node nothing to maintain: the synthesizer asks
whether the spelling it was handed spells the name it is printing, and writes the name itself
where it does not.
"""
name: str = ''
raw: str = ''
def has_spelling(self) -> bool:
"""
There is no name spelled by nothing. Printing one writes whatever stands around it and
closes up over the gap, so `a.` becomes `a` and a program loses a member read; the parser
builds an error node where it finds no name, and this is what says so if a transform ever
assembles one anyway.
"""
return bool(self.name)
@dataclass(repr=False, eq=False)
class JsPrivateIdentifier(Expression, spelling='raw'):
"""
A private name, written with the `#` that opens it left out of `name` and out of `raw` alike.
An escape spells one of these as it spells any other name, so `this.#\\u0061` reads the member
`#a` declares.
"""
name: str = ''
raw: str = ''
@dataclass(repr=False, eq=False)
class JsNumericLiteral(Expression, spelling='raw'):
"""
A Number literal. `value` is the double the source denotes and `raw` is how that source spelled
it; the two are independent because a spelling carries information the value does not, such as
the base of `0xFF` or the sign of `-0`. Coercion happens here rather than at the call sites so
that no construction anywhere can introduce a value JavaScript cannot hold.
"""
value: float = 0.0
raw: str = '0'
def __post_init__(self):
super().__post_init__()
self.value = to_js_number(self.value)
@dataclass(repr=False, eq=False)
class JsBigIntLiteral(Expression, spelling='raw'):
"""
A BigInt literal. `raw` is how the source spelled it, and the exact integer it denotes is read
off that spelling when it is asked for: converting a long decimal spelling is bounded by the
interpreter's limit on the digits of an integer conversion, and reading a file must not be
hostage to that limit for a value the file may never have read.
"""
raw: str = '0n'
@property
def value(self) -> int:
return integer_of_numeral(self.raw[:-1].replace('_', ''))
@dataclass(repr=False, eq=False)
class JsStringLiteral(Expression, spelling='raw'):
"""
A String literal. `value` is the text it denotes and `raw` is how the source spelled it, which
part ways wherever an escape stands between them.
`value` is `None` where the literal denotes nothing, which is a literal written with a `\\x` or
`\\u` escape that names no character. A string keeps the legacy escapes Annex B holds open for
sloppy code, so those still denote text; an escape no literal has at all denotes none, the way
the same escape leaves a `JsTemplateElement` denoting none.
`terminated` reports whether the closing quote was there. A literal the source never closed is
not a form the language has, so no text spells it: printing what was written runs the literal on
into whatever the synthesizer prints next, and printing the quote that is missing turns a file
that does not parse into a program that runs.
"""
value: str | None = ''
raw: str = "''"
terminated: bool = True
@property
def body(self) -> str:
"""
The source text between the quotes, every escape still spelled as it was written. A rule
about how a literal was written reads this rather than `value`: a directive spelled with an
escape in it denotes the text `use strict` and is not a Use Strict Directive, because what
makes a directive is the spelling and not the value.
"""
return self.raw[1:-1] if self.terminated else self.raw[1:]
@dataclass(repr=False, eq=False)
class JsRegExpLiteral(Expression, spelling='raw'):
pattern: str = ''
flags: str = ''
raw: str = '//'
terminated: bool = True
@dataclass(repr=False, eq=False)
class JsTemplateLiteral(Expression):
quasis: list[JsTemplateElement] = field(default_factory=list)
expressions: list[Expression] = field(default_factory=list)
@dataclass(repr=False, eq=False)
class JsTemplateElement(Node, spelling='raw'):
"""
One run of text in a template literal. `raw` is that run as the source wrote it and `value` the
text it denotes; neither holds the delimiters that separate the runs from the expressions,
because the literal prints those itself and a run is what stands between them.
`terminated` reports whether the delimiter that ends the run was there. Only a template can
reach the end of the file unclosed, since no line terminator ends one, and a hole the source
left open ends here as an empty run that closes nothing.
`value` is `None` where the run denotes nothing, which is a run written with an escape the
template grammar excludes. The language says the same thing by handing a tag `undefined` for
such a run, and by refusing the untagged literal outright.
"""
value: str | None = ''
raw: str = ''
tail: bool = False
terminated: bool = True
#: Whether the `}` that closes the hole in front of this run was there. Only the run behind a
#: hole the file ended inside lacks it, and such a run holds no text at all.
opened: bool = True
@dataclass(repr=False, eq=False)
class JsBooleanLiteral(Expression):
value: bool = False
@dataclass(repr=False, eq=False)
class JsNullLiteral(Expression):
@property
def value(self):
return None
@dataclass(repr=False, eq=False)
class JsThisExpression(Expression):
pass
@dataclass(repr=False, eq=False)
class JsArrayExpression(Expression):
elements: list[Expression | None] = field(default_factory=list)
#: Whether the closing bracket was there; `file_ended_inside` says what its absence means.
terminated: bool = True
@dataclass(repr=False, eq=False)
class JsObjectExpression(Expression):
properties: list[JsProperty | JsSpreadElement | JsErrorNode] = field(default_factory=list)
terminated: bool = True
@dataclass(repr=False, eq=False)
class JsProperty(Node):
key: Expression | None = None
value: Expression | None = None
computed: bool = False
shorthand: bool = False
method: bool = False
kind: JsPropertyKind = JsPropertyKind.INIT
@dataclass(repr=False, eq=False)
class JsSpreadElement(Expression):
argument: Expression | None = None
@dataclass(repr=False, eq=False)
class JsFunctionExpression(Expression, spelling='source_text'):
id: JsIdentifier | None = None
params: list[Expression] = field(default_factory=list)
body: JsBlockStatement | None = None
generator: bool = False
is_async: bool = False
source_text: str | None = None
@dataclass(repr=False, eq=False)
class JsArrowFunctionExpression(Expression, spelling='source_text'):
params: list[Expression] = field(default_factory=list)
body: Expression | JsBlockStatement | None = None
is_async: bool = False
source_text: str | None = None
@dataclass(repr=False, eq=False)
class JsDecorator(Node):
expression: Expression | None = None
@dataclass(repr=False, eq=False)
class JsClassExpression(Expression):
id: JsIdentifier | None = None
super_class: Expression | None = None
body: JsClassBody | None = None
decorators: list[JsDecorator] = field(default_factory=list)
@dataclass(repr=False, eq=False)
class JsUnaryExpression(Expression):
operator: str = ''
operand: Expression | None = None
prefix: bool = True
@dataclass(repr=False, eq=False)
class JsUpdateExpression(Expression):
operator: str = ''
argument: Expression | None = None
prefix: bool = True
@dataclass(repr=False, eq=False)
class JsBinaryExpression(Expression):
left: Expression | None = None
operator: str = ''
right: Expression | None = None
@dataclass(repr=False, eq=False)
class JsLogicalExpression(Expression):
left: Expression | None = None
operator: str = ''
right: Expression | None = None
@dataclass(repr=False, eq=False)
class JsAssignmentExpression(Expression):
left: Expression | None = None
operator: str = '='
right: Expression | None = None
@dataclass(repr=False, eq=False)
class JsConditionalExpression(Expression):
test: Expression | None = None
consequent: Expression | None = None
alternate: Expression | None = None
@dataclass(repr=False, eq=False)
class JsMemberExpression(Expression):
object: Expression | None = None
property: Expression | None = None
computed: bool = False
optional: bool = False
@dataclass(repr=False, eq=False)
class JsCallExpression(Expression):
callee: Expression | None = None
arguments: list[Expression] = field(default_factory=list)
optional: bool = False
terminated: bool = True
@dataclass(repr=False, eq=False)
class JsNewExpression(Expression):
callee: Expression | None = None
arguments: list[Expression] = field(default_factory=list)
terminated: bool = True
@dataclass(repr=False, eq=False)
class JsSequenceExpression(Expression):
expressions: list[Expression] = field(default_factory=list)
@dataclass(repr=False, eq=False)
class JsYieldExpression(Expression):
argument: Expression | None = None
delegate: bool = False
@dataclass(repr=False, eq=False)
class JsAwaitExpression(Expression):
argument: Expression | None = None
@dataclass(repr=False, eq=False)
class JsTaggedTemplateExpression(Expression):
tag: Expression | None = None
quasi: JsTemplateLiteral | None = None
@dataclass(repr=False, eq=False)
class JsParenthesizedExpression(Expression):
expression: Expression | None = None
terminated: bool = True
@dataclass(repr=False, eq=False)
class JsArrayPattern(Expression):
elements: list[Expression | None] = field(default_factory=list)
terminated: bool = True
@dataclass(repr=False, eq=False)
class JsObjectPattern(Expression):
properties: list[JsProperty | JsRestElement | JsErrorNode] = field(default_factory=list)
terminated: bool = True
@dataclass(repr=False, eq=False)
class JsAssignmentPattern(Expression):
left: Expression | None = None
right: Expression | None = None
@dataclass(repr=False, eq=False)
class JsRestElement(Expression):
argument: Expression | None = None
@dataclass(repr=False, eq=False)
class JsClassBody(Node):
body: list[JsMethodDefinition | JsPropertyDefinition | JsStaticBlock | JsErrorNode] = field(default_factory=list)
#: Whether the closing brace was there. The file may end inside a class body, and a body the
#: file ends inside prints the elements it holds and nothing after them.
terminated: bool = True
@dataclass(repr=False, eq=False)
class JsMethodDefinition(Node):
key: Expression | None = None
value: JsFunctionExpression | None = None
kind: JsMethodKind = JsMethodKind.METHOD
computed: bool = False
is_static: bool = False
decorators: list[JsDecorator] = field(default_factory=list)
@dataclass(repr=False, eq=False)
class JsPropertyDefinition(Node):
key: Expression | None = None
value: Expression | None = None
computed: bool = False
is_static: bool = False
decorators: list[JsDecorator] = field(default_factory=list)
@dataclass(repr=False, eq=False)
class JsStaticBlock(Node):
body: list[Statement] = field(default_factory=list)
terminated: bool = True
@dataclass(repr=False, eq=False)
class JsExpressionStatement(Statement, spelling='directive'):
expression: Expression | None = None
#: Whether the source wrote this statement into a Directive Prologue. It records where the
#: statement came from and not what it computes, which is why it is a spelling field: two trees
#: that differ only here spell the same program. A clone carries it, deliberately — a directive
#: that is copied elsewhere was still written as one, and whether it *is* one is decided by
#: `refinery.lib.scripts.js.strict.is_prologue_host` at wherever it now stands.
directive: bool = False
@dataclass(repr=False, eq=False)
class JsBlockStatement(Statement):
body: list[Statement] = field(default_factory=list)
#: Whether the closing brace was there. A file carved out of memory ends inside a block more
#: often than anywhere else, and the block keeps the statements it holds and says that nothing
#: closed it: printing what it holds and nothing after it is what keeps the file's end where the
#: file had it. `early_errors` reports it.
terminated: bool = True
@dataclass(repr=False, eq=False)
class JsEmptyStatement(Statement):
pass
@dataclass(repr=False, eq=False)
class JsVariableDeclaration(Statement):
declarations: list[JsVariableDeclarator] = field(default_factory=list)
kind: JsVarKind = JsVarKind.VAR
@dataclass(repr=False, eq=False)
class JsVariableDeclarator(Node):
id: Expression | None = None
init: Expression | None = None
@dataclass(repr=False, eq=False)
class JsIfStatement(Statement):
test: Expression | None = None
consequent: Statement | None = None
alternate: Statement | None = None
@dataclass(repr=False, eq=False)
class JsWhileStatement(Statement):
test: Expression | None = None
body: Statement | None = None
@dataclass(repr=False, eq=False)
class JsDoWhileStatement(Statement):
test: Expression | None = None
body: Statement | None = None
@dataclass(repr=False, eq=False)
class JsForStatement(Statement):
init: Expression | Statement | None = None
test: Expression | None = None
update: Expression | None = None
body: Statement | None = None
@dataclass(repr=False, eq=False)
class JsForInStatement(Statement):
left: Expression | Statement | None = None
right: Expression | None = None
body: Statement | None = None
@dataclass(repr=False, eq=False)
class JsForOfStatement(Statement):
left: Expression | Statement | None = None
right: Expression | None = None
body: Statement | None = None
is_await: bool = False
@dataclass(repr=False, eq=False)
class JsSwitchStatement(Statement):
discriminant: Expression | None = None
cases: list[JsSwitchCase | JsErrorNode] = field(default_factory=list)
terminated: bool = True
@dataclass(repr=False, eq=False)
class JsSwitchCase(Node):
test: Expression | None = None
body: list[Statement] = field(default_factory=list)
@dataclass(repr=False, eq=False)
class JsTryStatement(Statement):
block: JsBlockStatement | None = None
handler: JsCatchClause | None = None
finalizer: JsBlockStatement | None = None
@dataclass(repr=False, eq=False)
class JsCatchClause(Node):
param: Expression | None = None
body: JsBlockStatement | None = None
@dataclass(repr=False, eq=False)
class JsThrowStatement(Statement):
argument: Expression | None = None
def has_spelling(self) -> bool:
"""
A `throw` takes its expression on the same line, and nothing else: the parser refuses a
`throw` with nothing behind it, and this is what says so if a transform assembles one.
"""
return self.argument is not None
@dataclass(repr=False, eq=False)
class JsReturnStatement(Statement):
argument: Expression | None = None
@dataclass(repr=False, eq=False)
class JsBreakStatement(Statement):
label: JsIdentifier | None = None
@dataclass(repr=False, eq=False)
class JsContinueStatement(Statement):
label: JsIdentifier | None = None
@dataclass(repr=False, eq=False)
class JsLabeledStatement(Statement):
label: JsIdentifier | None = None
body: Statement | None = None
@dataclass(repr=False, eq=False)
class JsWithStatement(Statement):
object: Expression | None = None
body: Statement | None = None
@dataclass(repr=False, eq=False)
class JsDebuggerStatement(Statement):
pass
@dataclass(repr=False, eq=False)
class JsFunctionDeclaration(Statement, spelling='source_text'):
id: JsIdentifier | None = None
params: list[Expression] = field(default_factory=list)
body: JsBlockStatement | None = None
generator: bool = False
is_async: bool = False
source_text: str | None = None
@dataclass(repr=False, eq=False)
class JsClassDeclaration(Statement):
id: JsIdentifier | None = None
super_class: Expression | None = None
body: JsClassBody | None = None
decorators: list[JsDecorator] = field(default_factory=list)
@dataclass(repr=False, eq=False)
class JsImportSpecifier(Node):
imported: Expression | None = None
local: Expression | None = None
@dataclass(repr=False, eq=False)
class JsImportDefaultSpecifier(Node):
local: Expression | None = None
@dataclass(repr=False, eq=False)
class JsImportNamespaceSpecifier(Node):
local: Expression | None = None
@dataclass(repr=False, eq=False)
class JsImportAttribute(Node):
key: Expression | None = None
value: Expression | None = None
@dataclass(repr=False, eq=False)
class JsImportDeclaration(Statement):
specifiers: list[
JsImportSpecifier | JsImportDefaultSpecifier | JsImportNamespaceSpecifier | JsErrorNode
] = field(default_factory=list)
source: JsStringLiteral | None = None
attributes: list[JsImportAttribute | JsErrorNode] = field(default_factory=list)
attributes_keyword: str = ''
@dataclass(repr=False, eq=False)
class JsImportExpression(Expression):
source: Expression | None = None
options: Expression | None = None
@dataclass(repr=False, eq=False)
class JsMetaProperty(Expression):
meta: str = ''
property: str = ''
@dataclass(repr=False, eq=False)
class JsExportSpecifier(Node):
local: Expression | None = None
exported: Expression | None = None
@dataclass(repr=False, eq=False)
class JsExportNamedDeclaration(Statement):
declaration: Statement | None = None
specifiers: list[JsExportSpecifier | JsErrorNode] = field(default_factory=list)
source: JsStringLiteral | None = None
attributes: list[JsImportAttribute | JsErrorNode] = field(default_factory=list)
attributes_keyword: str = ''
@dataclass(repr=False, eq=False)
class JsExportDefaultDeclaration(Statement):
declaration: Expression | Statement | None = None
@dataclass(repr=False, eq=False)
class JsExportAllDeclaration(Statement):
source: JsStringLiteral | None = None
exported: Expression | None = None
attributes: list[JsImportAttribute | JsErrorNode] = field(default_factory=list)
attributes_keyword: str = ''
@dataclass(repr=False, eq=False)
class JsScript(Statement, spelling=('module', 'recovered', 'html_comment')):
body: list[Statement] = field(default_factory=list)
#: Whether the source is module code, which the host decides (§16.1) and the syntax only reports:
#: an `import` or `export` declaration, or `import.meta`, can appear in nothing else. It is a
#: spelling field because two scripts differing only here hold the same text — what differs is how
#: a host loads it — and because a pass that cuts the last import out of a body does not turn a
#: module into a script.
module: bool = False
#: Whether the parser had to invent a token, or step over one, in order to read this file. It is
#: a spelling field for the reason `module` is: it records where the tree came from rather than
#: what it spells, so two scripts differing only here are the same program. Nothing ever clears
#: it, because no later pass can put back a token the source never held.
recovered: bool = False
#: The offset of the first HTML-like comment delimiter the lexer read in this file (§B.1.1), or
#: `None` where it read none. Module code refuses both delimiters, and the comment one opens may
#: stand where no statement carries it, so the fact is kept on the script rather than looked for
#: among the comments the tree holds. It is a spelling field for the reason `recovered` is.
html_comment: int | None = None
#: Whether the file ended outside every comment. A block comment the file ends inside runs to
#: the end of the file, is the last of the file's `trailing_comments`, and makes the file no
#: program, which `early_errors` reports.
terminated: bool = True
def is_recovered(self) -> bool:
return self.recovered
def early_errors(self) -> list[StrictViolation]:
"""
What the language refuses in the file under its own mode and goal: the early errors
`refinery.lib.scripts.js.strict.collect_strict_violations` reports over the tree read as a
script, or as a module where the file spells module syntax, and every construct the file
ended inside — a literal, a comment, a block, a class body or a switch — which an engine
refuses as an unexpected end of input.
"""
from refinery.lib.scripts.js.strict import collect_strict_violations
return collect_strict_violations(self, module=self.module)
#: The three nodes that hold a function body. A class or object method holds a
#: `JsFunctionExpression` as its value, so it needs no entry of its own.
FUNCTION_NODES = (JsFunctionDeclaration, JsFunctionExpression, JsArrowFunctionExpression)
JsFunctionNode = JsFunctionDeclaration | JsFunctionExpression | JsArrowFunctionExpression
#: The statements that run their body again: the three `for` forms, `while` and `do`-`while`.
LOOP_NODES = (JsWhileStatement, JsDoWhileStatement, JsForStatement, JsForInStatement, JsForOfStatement)
#: The assignment operators that store only where the value of their target asks for it.
LOGICAL_ASSIGNMENT_OPERATORS = frozenset({'&&=', '||=', '??='})
class AwaitReading(enum.Enum):
"""
What the word `await` is where a piece of code stands. It names a binding or a reference in a
script and in every function that is not `async`; it is the operator in an `async` function's
parameter list and body; and it is neither in a class static block or a static field
initializer, where the language refuses the word in every position.
"""
NAME = enum.auto()
OPERATOR = enum.auto()
RESERVED = enum.auto()
@dataclass(frozen=True)
class CodeContext:
"""
The grammar parameters a piece of code is read under: what `await` is, whether `yield` is the
operator rather than a name, whether `arguments` may be referred to at all, and whether the
code is the top level of a file. The parser descends it and the early-error collector threads
it, both through `code_context_within`, so that the tree a text is read into and the errors
reported over that tree agree on what every word is.
The top level is set apart because its goal symbol is not known while parsing: `await` is read
as a name there, as a script reads it, but a `for await` head is read as well, since that is
one way a module spells its top-level `await`. Below a function or a class element the goal
decides nothing, and a `for await` head stands only where `await` is the operator.
"""
await_reading: AwaitReading
yield_is_operator: bool
arguments_reserved: bool
top_level: bool
@property
def reads_for_await(self) -> bool:
"""
Whether a `for await` head is read here: where `await` is the operator, and at the top
level of a file, whose goal may make it one.
"""
return self.await_reading is AwaitReading.OPERATOR or self.top_level
SCRIPT_CONTEXT = CodeContext(AwaitReading.NAME, False, False, True)
"""
The context the top level of a file is read under: both words are names, `arguments` is free, and
the goal symbol is open.
"""
@functools.cache
def function_context(is_async: bool, is_generator: bool) -> CodeContext:
"""
The context the parameter list and the body of a function of the given kind are read under.
"""
return CodeContext(
AwaitReading.OPERATOR if is_async else AwaitReading.NAME,
is_generator,
False,
False,
)
@functools.cache
def class_element_context(static: bool) -> CodeContext:
"""
The context a class element's own code is read under: a field initializer, or a static block.
Each is a function context of its own that reserves `arguments` (§15.7.1) and reads `yield` as
a name; a static one refuses `await` outright, where an instance initializer reads it as a name.
"""
return CodeContext(
AwaitReading.RESERVED if static else AwaitReading.NAME,
False,
True,
False,
)
def arrow_body_context(is_async: bool, enclosing: CodeContext) -> CodeContext:
"""
The context an arrow function's body is read under, given that the arrow stands in
*enclosing*: the context a function of its kind gives its body, except that an arrow has no
`arguments` of its own (§15.7.1) and so keeps the reservation it stands in.
"""
return replace(function_context(is_async, False), arguments_reserved=enclosing.arguments_reserved)
def code_context_within(parent: Node, child: Node, enclosing: CodeContext) -> CodeContext:
"""
The context *child* is read under, given that *parent* is read under *enclosing*. This is the
one transition every reader of the context takes, so that the parser descending the tree, the
collector threading it, and `code_context_at` folding it agree on every node.
A function body takes the readings its own kind gives it, and so does the name of a function
expression, which is bound inside it (§15.2.1); a declaration's name is bound outside it and
keeps the enclosure's. An arrow's parameters are still the enclosing code and keep its
readings, except that an `async` arrow reads `await` as the operator there too; its body is
what `arrow_body_context` says. A class element's own code is what `class_element_context`
says, whatever encloses the class.
"""
if isinstance(parent, JsStaticBlock):
return class_element_context(static=True)
if isinstance(parent, JsPropertyDefinition):
return class_element_context(parent.is_static) if child is parent.value else enclosing
if isinstance(parent, JsArrowFunctionExpression):
if any(child is param for param in parent.params):
if parent.is_async and enclosing.await_reading is not AwaitReading.OPERATOR:
return replace(enclosing, await_reading=AwaitReading.OPERATOR)
return enclosing
return arrow_body_context(parent.is_async, enclosing)
if isinstance(parent, JsFunctionDeclaration):
return enclosing if child is parent.id else function_context(parent.is_async, parent.generator)
if isinstance(parent, JsFunctionExpression):
return function_context(parent.is_async, parent.generator)
return enclosing
def code_context_at(node: Node, root_context: CodeContext = SCRIPT_CONTEXT) -> CodeContext:
"""
The context *node* is read under, folded from the root of its tree down through
`code_context_within`. *root_context* is what the root itself stands in: the top level of a
file by default, and the splice site's context for a tree about to be inlined there.
"""
chain: list[Node] = []
cursor: Node | None = node
while cursor is not None:
chain.append(cursor)
cursor = cursor.parent
chain.reverse()
context = root_context
for parent, child in zip(chain, chain[1:]):
context = code_context_within(parent, child, context)
return context
def is_async_function(func: JsFunctionNode) -> bool:
return func.is_async
def is_generator_function(func: JsFunctionNode) -> bool:
"""
Whether *func* is written `function*`. An arrow holds no such field, because the language has no
generator arrow to write, and answers `False` rather than raising: a caller deciding what kind of
function to rebuild asks this about whatever it holds, and a raise there would be an arrow the
rebuild refuses rather than one it rebuilds as an arrow.
"""
return isinstance(func, (JsFunctionDeclaration, JsFunctionExpression)) and func.generator
def wraps_return(func: JsFunctionNode) -> bool:
"""
Whether calling *func* answers something wrapped around what the body returned: a promise for an
`async` function, a generator object for a generator, an async generator object for both. In none
of the three is the call the value the body returned, so a pass that answers such a call with the
body's return expression hands back a program computing something else.
"""
return is_async_function(func) or is_generator_function(func)
def strip_parens(node: Node | None) -> Node | None:
"""
The expression *node* denotes once any enclosing parentheses are removed, so that a parenthesized
operand is classified by the operator that actually applies to it rather than by the redundant
grouping the parser preserves. A grouping whose inner expression is absent strips to `None`, which
every caller treats as "not the node being matched".
"""
while isinstance(node, JsParenthesizedExpression):
node = node.expression
return node
def _stands_in_a_with_body(node: Node) -> bool:
"""
Whether *node* lies in the body of a `with` statement at any depth, function boundaries
included: a free name there, and in any closure written there, is looked up on the statement's
object before any binding.
"""
child, parent = node, node.parent
while parent is not None:
if isinstance(parent, JsWithStatement) and parent.body is child:
return True
child, parent = parent, parent.parent
return False
def callee_form_sensitive(callee: Node | None, position: Node) -> bool:
"""
Whether a call invoking *callee* directly, written where *position* stands, means something a
call reaching the same value through a neutral spelling does not. The language has three such
forms: a member access binds `this` to its object, a bare `eval` performs a *direct* eval
evaluated in the caller's own scope, and a bare name in the body of a `with` statement binds
`this` to the statement's object when that object holds the name. Any other callee invokes with
no receiver and no direct-eval effect, exactly as the same value called behind `(0, ...)` does,
so only these three forms constrain what may stand in a callee position.
The `with` body is read off the tree as it stands rather than off the scopes of the semantic
model, because every caller asks while it edits, and a node a pass has just written has no scope.
"""
inner = strip_parens(callee)
if isinstance(inner, JsMemberExpression):
return True
if not isinstance(inner, JsIdentifier):
return False
return inner.name == 'eval' or _stands_in_a_with_body(position)
def names_a_property(node: Node) -> bool:
"""
Whether *node* spells the name of a property and reads nothing. A member written with a dot, a
key of an object literal, the name of a class member, the key of an import attribute, and a
name on the far side of a module boundary are the positions the language has for such a name,
and in each of them the text is a name the value carries rather than one the program looks up.
A computed key is not one of these: what stands inside the brackets is an expression and is
read like any other. Neither is a shorthand property, which is written like a key and is both:
`{ x }` means `{ x: x }`, and the one node the parser builds for it is the read as much as it
is the key, so calling it a property name would excuse a reference the program really makes.
An import attribute answers `True` for a key of any kind, a string as readily as a name,
because a with-clause holds nothing a program could refer to:
import d from 'm' with { 'type': 'json' }
names an attribute and not a binding, and so does the same clause written without the quotes.
A name across the module boundary is an IdentifierName the grammar takes wider than a name the
file could bind: `import { yield as v }`, `export { v as yield }`, `export * as yield from`,
and both words of `export { yield } from "m"` name what another module carries. The shorthand
`import { yield }` is the one spelling that is the far side and the binding at once, and it
is read as the binding.
"""
parent = node.parent
if isinstance(parent, JsMemberExpression):
return parent.property is node and not parent.computed
if isinstance(parent, JsProperty):
return parent.key is node and not parent.computed and not parent.shorthand
if isinstance(parent, (JsMethodDefinition, JsPropertyDefinition)):
return parent.key is node and not parent.computed
if isinstance(parent, JsImportAttribute):
return parent.key is node
if isinstance(parent, JsImportSpecifier):
return parent.imported is node and parent.local is not node
if isinstance(parent, JsExportSpecifier):
declaration = parent.parent
if isinstance(declaration, JsExportNamedDeclaration) and declaration.source is not None:
return True
return parent.exported is node and parent.local is not node
if isinstance(parent, JsExportAllDeclaration):
return parent.exported is node
return False
ACCESSOR_INSTALL_METHODS = frozenset({
'defineProperty',
'defineProperties',
'__defineGetter__',
'__defineSetter__',
})
RECEIVER_INSTALL_METHODS = frozenset({'__defineGetter__', '__defineSetter__'})
"""
The installers that install on their receiver. Every other one of `CONVERSION_INSTALL_METHODS`
installs on its first argument.
"""
CONVERSION_INSTALL_METHODS = ACCESSOR_INSTALL_METHODS | frozenset({
'assign',
'setPrototypeOf',
})
"""
The methods that can give an object a property of its own or a new prototype under a key they are
handed: the accessor installers, `Object.assign`, which copies the own properties of its sources,
and `Object.setPrototypeOf`.
"""
def static_string(node: Node | None) -> str | None:
"""
The string *node* certainly evaluates to, or `None`. It reads a string literal, a
substitution-free template, and a concatenation of those with each other or with a number, a
boolean or `null` literal (`static_concatenation`).
This exists so that an analysis answer cannot change as folds fire: a property key the
simplifier will turn into `'defineProperty'` must already be read as that name, or a consumer
holding the answer across a pass would be told there is no install and then have one appear.
It is deliberately a *must* analysis — an unknown value yields `None`, and a key whose value
is unknown names no method, since only a key a fold can collapse can reveal an install
mid-pass.
"""
node = strip_parens(node)
if isinstance(node, JsStringLiteral):
return node.value
if isinstance(node, JsTemplateLiteral):
if node.expressions:
return None
if any(quasi.value is None for quasi in node.quasis):
return None
return ''.join(quasi.value or '' for quasi in node.quasis)
if isinstance(node, JsBinaryExpression) and node.operator == '+':
return static_concatenation(node, static_string(node.left), static_string(node.right))
return None
def static_concatenation(node: JsBinaryExpression, left: str | None, right: str | None) -> str | None:
"""
The string the `+` concatenation *node* certainly evaluates to, given the strings *left* and
*right* its two operands were read as (`static_string`), or `None`. One operand has to be a
string, and the other a string or a number, boolean or `null` literal.
"""
if left is None and right is None:
return None
if left is None:
left = _primitive_literal_text(node.left)
if right is None:
right = _primitive_literal_text(node.right)
if left is None or right is None:
return None
return left + right
def _primitive_literal_text(node: Node | None) -> str | None:
"""
The string a number, boolean or `null` literal converts to, or `None` for any other node.
"""
node = strip_parens(node)
if isinstance(node, JsNumericLiteral):
return js_number_to_string(node.value)
if isinstance(node, JsBooleanLiteral):
return 'true' if node.value else 'false'
if isinstance(node, JsNullLiteral):
return 'null'
return None
def static_property_key(node: JsMemberExpression) -> str | None:
"""
The property name *node* accesses, or `None` where no single static name is known: the
identifier of a dotted access, or the string a computed key certainly evaluates to
(`static_string`), so a key a fold would collapse to a literal already reads as that name.
"""
prop = node.property
if node.computed:
return static_string(prop)
return prop.name if isinstance(prop, JsIdentifier) else None
def _object_has_own_accessor(obj: JsObjectExpression) -> bool:
"""
Whether the object literal *obj* declares an own getter or setter (`{ get k(){...} }`,
`{ set k(v){...} }`). A read of such a property runs the getter and a write to it runs the
setter, so a member access on an otherwise fresh literal that has one carries a hidden effect
rather than a plain field read or store.
"""
return any(
isinstance(prop, JsProperty) and prop.kind in (JsPropertyKind.GET, JsPropertyKind.SET)
for prop in obj.properties
)
def object_sets_prototype(obj: JsObjectExpression) -> bool:
"""
Whether the object literal *obj* installs a custom prototype through the special `__proto__:`
property form (`{ __proto__: p }`, `{ '__proto__': p }`) — a plain, non-computed data property
whose key is `__proto__`. Such an object no longer inherits from `Object.prototype` alone, so a
plain-looking member read or write on it may run a getter or setter the installed prototype
carries rather than touch a data slot. A computed key (`{ ['__proto__']: p }`), a shorthand
(`{ __proto__ }`), a method, or an own `__proto__` accessor define an ordinary own property and
do not set the prototype.
"""
for prop in obj.properties:
if not isinstance(prop, JsProperty):
continue
if prop.kind is not JsPropertyKind.INIT or prop.computed or prop.shorthand or prop.method:
continue
key = prop.key
if isinstance(key, JsIdentifier) and key.name == '__proto__':
return True
if isinstance(key, JsStringLiteral) and key.value == '__proto__':
return True
return False
def object_member_access_runs_accessor(obj: JsObjectExpression) -> bool:
"""
Whether a plain member read or write on the object literal *obj* may run a user-defined accessor
instead of touching a data slot: it declares its own getter or setter, or it installs a custom
prototype through the `__proto__:` literal form that may carry an inherited one. A fresh literal
with neither behaves as a plain field container, so an access on it is observable only as the
field it names.
"""
return _object_has_own_accessor(obj) or object_sets_prototype(obj)
def value_is_discarded(node: Node) -> bool:
"""
Whether the context governing `node` throws its value away, so removing `node` changes no value
the program goes on to read: an expression statement, or a sequence operand other than the last,
whose value the sequence yields. Parentheses are looked through. A node whose value is consumed
— a declarator initializer, a call argument, a `return` — is not discardable, and removing it
would strand its consumer.
"""
cur = node
parent = cur.parent
while isinstance(parent, JsParenthesizedExpression):
cur, parent = parent, parent.parent
if isinstance(parent, JsExpressionStatement):
return True
if isinstance(parent, JsSequenceExpression):
return bool(parent.expressions) and parent.expressions[-1] is not cur
return False
Closable = (
JsStringLiteral
| JsRegExpLiteral
| JsTemplateElement
| JsArrayExpression
| JsObjectExpression
| JsParenthesizedExpression
| JsCallExpression
| JsNewExpression
| JsArrayPattern
| JsObjectPattern
| JsClassBody
| JsStaticBlock
| JsBlockStatement
| JsSwitchStatement
| JsScript
)
"""
The node kinds that carry `terminated`: a construct with a closing delimiter the file may end
before, which `file_ended_inside` reads.
"""
def file_ended_inside(node: Node) -> bool:
"""
Whether *node* is a construct the file ended inside: a literal, a bracketed list, a block, a
class body, a switch, or the file itself, whose closing delimiter the parser never saw because
the file ended first. Such a node holds what the file held and says that nothing closed it: a
printer writes what it holds and nothing after it, an engine refuses the file as an unexpected
end of input, and the parser sets the flag at the end of the file and nowhere else.
"""
return isinstance(node, Closable) and not node.terminated
Global variables
var FUNCTION_NODES-
The three nodes that hold a function body. A class or object method holds a
JsFunctionExpressionas its value, so it needs no entry of its own. var LOOP_NODES-
The statements that run their body again: the three
forforms,whileanddo-while. var LOGICAL_ASSIGNMENT_OPERATORS-
The assignment operators that store only where the value of their target asks for it.
var SCRIPT_CONTEXT-
The context the top level of a file is read under: both words are names,
argumentsis free, and the goal symbol is open. var RECEIVER_INSTALL_METHODS-
The installers that install on their receiver. Every other one of
CONVERSION_INSTALL_METHODSinstalls on its first argument. var CONVERSION_INSTALL_METHODS-
The methods that can give an object a property of its own or a new prototype under a key they are handed: the accessor installers,
Object.assign, which copies the own properties of its sources, andObject.setPrototypeOf. var Closable-
The node kinds that carry
terminated: a construct with a closing delimiter the file may end before, whichfile_ended_inside()reads.
Functions
def function_context(is_async, is_generator)-
The context the parameter list and the body of a function of the given kind are read under.
Expand source code Browse git
@functools.cache def function_context(is_async: bool, is_generator: bool) -> CodeContext: """ The context the parameter list and the body of a function of the given kind are read under. """ return CodeContext( AwaitReading.OPERATOR if is_async else AwaitReading.NAME, is_generator, False, False, ) def class_element_context(static)-
The context a class element's own code is read under: a field initializer, or a static block. Each is a function context of its own that reserves
arguments(§15.7.1) and readsyieldas a name; a static one refusesawaitoutright, where an instance initializer reads it as a name.Expand source code Browse git
@functools.cache def class_element_context(static: bool) -> CodeContext: """ The context a class element's own code is read under: a field initializer, or a static block. Each is a function context of its own that reserves `arguments` (§15.7.1) and reads `yield` as a name; a static one refuses `await` outright, where an instance initializer reads it as a name. """ return CodeContext( AwaitReading.RESERVED if static else AwaitReading.NAME, False, True, False, ) def arrow_body_context(is_async, enclosing)-
The context an arrow function's body is read under, given that the arrow stands in enclosing: the context a function of its kind gives its body, except that an arrow has no
argumentsof its own (§15.7.1) and so keeps the reservation it stands in.Expand source code Browse git
def arrow_body_context(is_async: bool, enclosing: CodeContext) -> CodeContext: """ The context an arrow function's body is read under, given that the arrow stands in *enclosing*: the context a function of its kind gives its body, except that an arrow has no `arguments` of its own (§15.7.1) and so keeps the reservation it stands in. """ return replace(function_context(is_async, False), arguments_reserved=enclosing.arguments_reserved) def code_context_within(parent, child, enclosing)-
The context child is read under, given that parent is read under enclosing. This is the one transition every reader of the context takes, so that the parser descending the tree, the collector threading it, and
code_context_at()folding it agree on every node.A function body takes the readings its own kind gives it, and so does the name of a function expression, which is bound inside it (§15.2.1); a declaration's name is bound outside it and keeps the enclosure's. An arrow's parameters are still the enclosing code and keep its readings, except that an
asyncarrow readsawaitas the operator there too; its body is whatarrow_body_context()says. A class element's own code is whatclass_element_context()says, whatever encloses the class.Expand source code Browse git
def code_context_within(parent: Node, child: Node, enclosing: CodeContext) -> CodeContext: """ The context *child* is read under, given that *parent* is read under *enclosing*. This is the one transition every reader of the context takes, so that the parser descending the tree, the collector threading it, and `code_context_at` folding it agree on every node. A function body takes the readings its own kind gives it, and so does the name of a function expression, which is bound inside it (§15.2.1); a declaration's name is bound outside it and keeps the enclosure's. An arrow's parameters are still the enclosing code and keep its readings, except that an `async` arrow reads `await` as the operator there too; its body is what `arrow_body_context` says. A class element's own code is what `class_element_context` says, whatever encloses the class. """ if isinstance(parent, JsStaticBlock): return class_element_context(static=True) if isinstance(parent, JsPropertyDefinition): return class_element_context(parent.is_static) if child is parent.value else enclosing if isinstance(parent, JsArrowFunctionExpression): if any(child is param for param in parent.params): if parent.is_async and enclosing.await_reading is not AwaitReading.OPERATOR: return replace(enclosing, await_reading=AwaitReading.OPERATOR) return enclosing return arrow_body_context(parent.is_async, enclosing) if isinstance(parent, JsFunctionDeclaration): return enclosing if child is parent.id else function_context(parent.is_async, parent.generator) if isinstance(parent, JsFunctionExpression): return function_context(parent.is_async, parent.generator) return enclosing def code_context_at(node, root_context=CodeContext(await_reading=<AwaitReading.NAME: 1>, yield_is_operator=False, arguments_reserved=False, top_level=True))-
The context node is read under, folded from the root of its tree down through
code_context_within(). root_context is what the root itself stands in: the top level of a file by default, and the splice site's context for a tree about to be inlined there.Expand source code Browse git
def code_context_at(node: Node, root_context: CodeContext = SCRIPT_CONTEXT) -> CodeContext: """ The context *node* is read under, folded from the root of its tree down through `code_context_within`. *root_context* is what the root itself stands in: the top level of a file by default, and the splice site's context for a tree about to be inlined there. """ chain: list[Node] = [] cursor: Node | None = node while cursor is not None: chain.append(cursor) cursor = cursor.parent chain.reverse() context = root_context for parent, child in zip(chain, chain[1:]): context = code_context_within(parent, child, context) return context def is_async_function(func)-
Expand source code Browse git
def is_async_function(func: JsFunctionNode) -> bool: return func.is_async def is_generator_function(func)-
Whether func is written
function*. An arrow holds no such field, because the language has no generator arrow to write, and answersFalserather than raising: a caller deciding what kind of function to rebuild asks this about whatever it holds, and a raise there would be an arrow the rebuild refuses rather than one it rebuilds as an arrow.Expand source code Browse git
def is_generator_function(func: JsFunctionNode) -> bool: """ Whether *func* is written `function*`. An arrow holds no such field, because the language has no generator arrow to write, and answers `False` rather than raising: a caller deciding what kind of function to rebuild asks this about whatever it holds, and a raise there would be an arrow the rebuild refuses rather than one it rebuilds as an arrow. """ return isinstance(func, (JsFunctionDeclaration, JsFunctionExpression)) and func.generator def wraps_return(func)-
Whether calling func answers something wrapped around what the body returned: a promise for an
asyncfunction, a generator object for a generator, an async generator object for both. In none of the three is the call the value the body returned, so a pass that answers such a call with the body's return expression hands back a program computing something else.Expand source code Browse git
def wraps_return(func: JsFunctionNode) -> bool: """ Whether calling *func* answers something wrapped around what the body returned: a promise for an `async` function, a generator object for a generator, an async generator object for both. In none of the three is the call the value the body returned, so a pass that answers such a call with the body's return expression hands back a program computing something else. """ return is_async_function(func) or is_generator_function(func) def strip_parens(node)-
The expression node denotes once any enclosing parentheses are removed, so that a parenthesized operand is classified by the operator that actually applies to it rather than by the redundant grouping the parser preserves. A grouping whose inner expression is absent strips to
None, which every caller treats as "not the node being matched".Expand source code Browse git
def strip_parens(node: Node | None) -> Node | None: """ The expression *node* denotes once any enclosing parentheses are removed, so that a parenthesized operand is classified by the operator that actually applies to it rather than by the redundant grouping the parser preserves. A grouping whose inner expression is absent strips to `None`, which every caller treats as "not the node being matched". """ while isinstance(node, JsParenthesizedExpression): node = node.expression return node def callee_form_sensitive(callee, position)-
Whether a call invoking callee directly, written where position stands, means something a call reaching the same value through a neutral spelling does not. The language has three such forms: a member access binds
thisto its object, a bareevalperforms a direct eval evaluated in the caller's own scope, and a bare name in the body of awithstatement bindsthisto the statement's object when that object holds the name. Any other callee invokes with no receiver and no direct-eval effect, exactly as the same value called behind(0, …)does, so only these three forms constrain what may stand in a callee position.The
withbody is read off the tree as it stands rather than off the scopes of the semantic model, because every caller asks while it edits, and a node a pass has just written has no scope.Expand source code Browse git
def callee_form_sensitive(callee: Node | None, position: Node) -> bool: """ Whether a call invoking *callee* directly, written where *position* stands, means something a call reaching the same value through a neutral spelling does not. The language has three such forms: a member access binds `this` to its object, a bare `eval` performs a *direct* eval evaluated in the caller's own scope, and a bare name in the body of a `with` statement binds `this` to the statement's object when that object holds the name. Any other callee invokes with no receiver and no direct-eval effect, exactly as the same value called behind `(0, ...)` does, so only these three forms constrain what may stand in a callee position. The `with` body is read off the tree as it stands rather than off the scopes of the semantic model, because every caller asks while it edits, and a node a pass has just written has no scope. """ inner = strip_parens(callee) if isinstance(inner, JsMemberExpression): return True if not isinstance(inner, JsIdentifier): return False return inner.name == 'eval' or _stands_in_a_with_body(position) def names_a_property(node)-
Whether node spells the name of a property and reads nothing. A member written with a dot, a key of an object literal, the name of a class member, the key of an import attribute, and a name on the far side of a module boundary are the positions the language has for such a name, and in each of them the text is a name the value carries rather than one the program looks up.
A computed key is not one of these: what stands inside the brackets is an expression and is read like any other. Neither is a shorthand property, which is written like a key and is both:
{ x }means{ x: x }, and the one node the parser builds for it is the read as much as it is the key, so calling it a property name would excuse a reference the program really makes.An import attribute answers
Truefor a key of any kind, a string as readily as a name, because a with-clause holds nothing a program could refer to:import d from 'm' with { 'type': 'json' }names an attribute and not a binding, and so does the same clause written without the quotes.
A name across the module boundary is an IdentifierName the grammar takes wider than a name the file could bind:
import { yield as v },export { v as yield },export * as yield from, and both words ofexport { yield } from "m"name what another module carries. The shorthandimport { yield }is the one spelling that is the far side and the binding at once, and it is read as the binding.Expand source code Browse git
def names_a_property(node: Node) -> bool: """ Whether *node* spells the name of a property and reads nothing. A member written with a dot, a key of an object literal, the name of a class member, the key of an import attribute, and a name on the far side of a module boundary are the positions the language has for such a name, and in each of them the text is a name the value carries rather than one the program looks up. A computed key is not one of these: what stands inside the brackets is an expression and is read like any other. Neither is a shorthand property, which is written like a key and is both: `{ x }` means `{ x: x }`, and the one node the parser builds for it is the read as much as it is the key, so calling it a property name would excuse a reference the program really makes. An import attribute answers `True` for a key of any kind, a string as readily as a name, because a with-clause holds nothing a program could refer to: import d from 'm' with { 'type': 'json' } names an attribute and not a binding, and so does the same clause written without the quotes. A name across the module boundary is an IdentifierName the grammar takes wider than a name the file could bind: `import { yield as v }`, `export { v as yield }`, `export * as yield from`, and both words of `export { yield } from "m"` name what another module carries. The shorthand `import { yield }` is the one spelling that is the far side and the binding at once, and it is read as the binding. """ parent = node.parent if isinstance(parent, JsMemberExpression): return parent.property is node and not parent.computed if isinstance(parent, JsProperty): return parent.key is node and not parent.computed and not parent.shorthand if isinstance(parent, (JsMethodDefinition, JsPropertyDefinition)): return parent.key is node and not parent.computed if isinstance(parent, JsImportAttribute): return parent.key is node if isinstance(parent, JsImportSpecifier): return parent.imported is node and parent.local is not node if isinstance(parent, JsExportSpecifier): declaration = parent.parent if isinstance(declaration, JsExportNamedDeclaration) and declaration.source is not None: return True return parent.exported is node and parent.local is not node if isinstance(parent, JsExportAllDeclaration): return parent.exported is node return False def static_string(node)-
The string node certainly evaluates to, or
None. It reads a string literal, a substitution-free template, and a concatenation of those with each other or with a number, a boolean ornullliteral (static_concatenation()).This exists so that an analysis answer cannot change as folds fire: a property key the simplifier will turn into
'defineProperty'must already be read as that name, or a consumer holding the answer across a pass would be told there is no install and then have one appear. It is deliberately a must analysis — an unknown value yieldsNone, and a key whose value is unknown names no method, since only a key a fold can collapse can reveal an install mid-pass.Expand source code Browse git
def static_string(node: Node | None) -> str | None: """ The string *node* certainly evaluates to, or `None`. It reads a string literal, a substitution-free template, and a concatenation of those with each other or with a number, a boolean or `null` literal (`static_concatenation`). This exists so that an analysis answer cannot change as folds fire: a property key the simplifier will turn into `'defineProperty'` must already be read as that name, or a consumer holding the answer across a pass would be told there is no install and then have one appear. It is deliberately a *must* analysis — an unknown value yields `None`, and a key whose value is unknown names no method, since only a key a fold can collapse can reveal an install mid-pass. """ node = strip_parens(node) if isinstance(node, JsStringLiteral): return node.value if isinstance(node, JsTemplateLiteral): if node.expressions: return None if any(quasi.value is None for quasi in node.quasis): return None return ''.join(quasi.value or '' for quasi in node.quasis) if isinstance(node, JsBinaryExpression) and node.operator == '+': return static_concatenation(node, static_string(node.left), static_string(node.right)) return None def static_concatenation(node, left, right)-
The string the
+concatenation node certainly evaluates to, given the strings left and right its two operands were read as (static_string()), orNone. One operand has to be a string, and the other a string or a number, boolean ornullliteral.Expand source code Browse git
def static_concatenation(node: JsBinaryExpression, left: str | None, right: str | None) -> str | None: """ The string the `+` concatenation *node* certainly evaluates to, given the strings *left* and *right* its two operands were read as (`static_string`), or `None`. One operand has to be a string, and the other a string or a number, boolean or `null` literal. """ if left is None and right is None: return None if left is None: left = _primitive_literal_text(node.left) if right is None: right = _primitive_literal_text(node.right) if left is None or right is None: return None return left + right def static_property_key(node)-
The property name node accesses, or
Nonewhere no single static name is known: the identifier of a dotted access, or the string a computed key certainly evaluates to (static_string()), so a key a fold would collapse to a literal already reads as that name.Expand source code Browse git
def static_property_key(node: JsMemberExpression) -> str | None: """ The property name *node* accesses, or `None` where no single static name is known: the identifier of a dotted access, or the string a computed key certainly evaluates to (`static_string`), so a key a fold would collapse to a literal already reads as that name. """ prop = node.property if node.computed: return static_string(prop) return prop.name if isinstance(prop, JsIdentifier) else None def object_sets_prototype(obj)-
Whether the object literal obj installs a custom prototype through the special
__proto__:property form ({ __proto__: p },{ '__proto__': p }) — a plain, non-computed data property whose key is__proto__. Such an object no longer inherits fromObject.prototypealone, so a plain-looking member read or write on it may run a getter or setter the installed prototype carries rather than touch a data slot. A computed key ({ ['__proto__']: p }), a shorthand ({ __proto__ }), a method, or an own__proto__accessor define an ordinary own property and do not set the prototype.Expand source code Browse git
def object_sets_prototype(obj: JsObjectExpression) -> bool: """ Whether the object literal *obj* installs a custom prototype through the special `__proto__:` property form (`{ __proto__: p }`, `{ '__proto__': p }`) — a plain, non-computed data property whose key is `__proto__`. Such an object no longer inherits from `Object.prototype` alone, so a plain-looking member read or write on it may run a getter or setter the installed prototype carries rather than touch a data slot. A computed key (`{ ['__proto__']: p }`), a shorthand (`{ __proto__ }`), a method, or an own `__proto__` accessor define an ordinary own property and do not set the prototype. """ for prop in obj.properties: if not isinstance(prop, JsProperty): continue if prop.kind is not JsPropertyKind.INIT or prop.computed or prop.shorthand or prop.method: continue key = prop.key if isinstance(key, JsIdentifier) and key.name == '__proto__': return True if isinstance(key, JsStringLiteral) and key.value == '__proto__': return True return False def object_member_access_runs_accessor(obj)-
Whether a plain member read or write on the object literal obj may run a user-defined accessor instead of touching a data slot: it declares its own getter or setter, or it installs a custom prototype through the
__proto__:literal form that may carry an inherited one. A fresh literal with neither behaves as a plain field container, so an access on it is observable only as the field it names.Expand source code Browse git
def object_member_access_runs_accessor(obj: JsObjectExpression) -> bool: """ Whether a plain member read or write on the object literal *obj* may run a user-defined accessor instead of touching a data slot: it declares its own getter or setter, or it installs a custom prototype through the `__proto__:` literal form that may carry an inherited one. A fresh literal with neither behaves as a plain field container, so an access on it is observable only as the field it names. """ return _object_has_own_accessor(obj) or object_sets_prototype(obj) def value_is_discarded(node)-
Whether the context governing
nodethrows its value away, so removingnodechanges no value the program goes on to read: an expression statement, or a sequence operand other than the last, whose value the sequence yields. Parentheses are looked through. A node whose value is consumed — a declarator initializer, a call argument, areturn— is not discardable, and removing it would strand its consumer.Expand source code Browse git
def value_is_discarded(node: Node) -> bool: """ Whether the context governing `node` throws its value away, so removing `node` changes no value the program goes on to read: an expression statement, or a sequence operand other than the last, whose value the sequence yields. Parentheses are looked through. A node whose value is consumed — a declarator initializer, a call argument, a `return` — is not discardable, and removing it would strand its consumer. """ cur = node parent = cur.parent while isinstance(parent, JsParenthesizedExpression): cur, parent = parent, parent.parent if isinstance(parent, JsExpressionStatement): return True if isinstance(parent, JsSequenceExpression): return bool(parent.expressions) and parent.expressions[-1] is not cur return False def file_ended_inside(node)-
Whether node is a construct the file ended inside: a literal, a bracketed list, a block, a class body, a switch, or the file itself, whose closing delimiter the parser never saw because the file ended first. Such a node holds what the file held and says that nothing closed it: a printer writes what it holds and nothing after it, an engine refuses the file as an unexpected end of input, and the parser sets the flag at the end of the file and nowhere else.
Expand source code Browse git
def file_ended_inside(node: Node) -> bool: """ Whether *node* is a construct the file ended inside: a literal, a bracketed list, a block, a class body, a switch, or the file itself, whose closing delimiter the parser never saw because the file ended first. Such a node holds what the file held and says that nothing closed it: a printer writes what it holds and nothing after it, an engine refuses the file as an unexpected end of input, and the parser sets the flag at the end of the file and nowhere else. """ return isinstance(node, Closable) and not node.terminated
Classes
class JsPropertyKind (*args, **kwds)-
Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access:
Color.RED
- value lookup:
Color(1)
- name lookup:
Color['RED']
Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Expand source code Browse git
class JsPropertyKind(enum.Enum): INIT = 'init' GET = 'get' # noqa SET = 'set' # noqaAncestors
- enum.Enum
Class variables
var INIT-
The type of the None singleton.
var GET-
The type of the None singleton.
var SET-
The type of the None singleton.
class JsMethodKind (*args, **kwds)-
Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access:
Color.RED
- value lookup:
Color(1)
- name lookup:
Color['RED']
Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Expand source code Browse git
class JsMethodKind(enum.Enum): METHOD = 'method' # noqa GET = 'get' # noqa SET = 'set' # noqa CONSTRUCTOR = 'constructor' # noqaAncestors
- enum.Enum
Class variables
var METHOD-
The type of the None singleton.
var GET-
The type of the None singleton.
var SET-
The type of the None singleton.
var CONSTRUCTOR-
The type of the None singleton.
class JsVarKind (*args, **kwds)-
Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access:
Color.RED
- value lookup:
Color(1)
- name lookup:
Color['RED']
Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Expand source code Browse git
class JsVarKind(enum.Enum): VAR = 'var' # noqa LET = 'let' # noqa CONST = 'const' # noqaAncestors
- enum.Enum
Class variables
var VAR-
The type of the None singleton.
var LET-
The type of the None singleton.
var CONST-
The type of the None singleton.
class JsErrorNode (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, text='', message='')-
A span of source the parser could not read, kept verbatim so that what an analyst gets back still contains what was written. It prints as
textand so reads back as whatever that text parses to, which is why a tree holding one states nothing about synthesizer fidelity.It stands in either position, because the recovery that builds it does not know which was expected. In statement position it is the statement, and is deliberately not wrapped in an expression statement: the wrapper prints a semicolon that nobody wrote, which grows the file by one character every time the tool reads its own output.
Expand source code Browse git
@dataclass(repr=False, eq=False) class JsErrorNode(Expression, Statement, unparsed=True): """ A span of source the parser could not read, kept verbatim so that what an analyst gets back still contains what was written. It prints as `text` and so reads back as whatever that text parses to, which is why a tree holding one states nothing about synthesizer fidelity. It stands in either position, because the recovery that builds it does not know which was expected. In statement position it is the statement, and is deliberately not wrapped in an expression statement: the wrapper prints a semicolon that nobody wrote, which grows the file by one character every time the tool reads its own output. """ text: str = '' message: str = ''Ancestors
Instance variables
var text-
The type of the None singleton.
var message-
The type of the None singleton.
Inherited members
class JsIdentifier (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, name='', raw='')-
A name.
nameis the name the source denotes andrawis the text it was written with, which part ways wherever a unicode escape stands between them:\u0061bcandabcare one binding written two ways, and every question about names is asked ofname.rawis empty wherever the two would be the same text, so it holds something only for a name the source wrote some other way. What it holds is trusted only for as long as it still spellsname, which is what leaves a pass renaming a node nothing to maintain: the synthesizer asks whether the spelling it was handed spells the name it is printing, and writes the name itself where it does not.Expand source code Browse git
@dataclass(repr=False, eq=False) class JsIdentifier(Expression, spelling='raw'): """ A name. `name` is the name the source denotes and `raw` is the text it was written with, which part ways wherever a unicode escape stands between them: `\\u0061bc` and `abc` are one binding written two ways, and every question about names is asked of `name`. `raw` is empty wherever the two would be the same text, so it holds something only for a name the source wrote some other way. What it holds is trusted only for as long as it still spells `name`, which is what leaves a pass renaming a node nothing to maintain: the synthesizer asks whether the spelling it was handed spells the name it is printing, and writes the name itself where it does not. """ name: str = '' raw: str = '' def has_spelling(self) -> bool: """ There is no name spelled by nothing. Printing one writes whatever stands around it and closes up over the gap, so `a.` becomes `a` and a program loses a member read; the parser builds an error node where it finds no name, and this is what says so if a transform ever assembles one anyway. """ return bool(self.name)Ancestors
Instance variables
var name-
The type of the None singleton.
var raw-
The type of the None singleton.
Methods
def has_spelling(self)-
There is no name spelled by nothing. Printing one writes whatever stands around it and closes up over the gap, so
a.becomesaand a program loses a member read; the parser builds an error node where it finds no name, and this is what says so if a transform ever assembles one anyway.Expand source code Browse git
def has_spelling(self) -> bool: """ There is no name spelled by nothing. Printing one writes whatever stands around it and closes up over the gap, so `a.` becomes `a` and a program loses a member read; the parser builds an error node where it finds no name, and this is what says so if a transform ever assembles one anyway. """ return bool(self.name)
Inherited members
class JsPrivateIdentifier (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, name='', raw='')-
A private name, written with the
#that opens it left out ofnameand out ofrawalike. An escape spells one of these as it spells any other name, sothis.#\u0061reads the member#adeclares.Expand source code Browse git
@dataclass(repr=False, eq=False) class JsPrivateIdentifier(Expression, spelling='raw'): """ A private name, written with the `#` that opens it left out of `name` and out of `raw` alike. An escape spells one of these as it spells any other name, so `this.#\\u0061` reads the member `#a` declares. """ name: str = '' raw: str = ''Ancestors
Instance variables
var name-
The type of the None singleton.
var raw-
The type of the None singleton.
Inherited members
class JsNumericLiteral (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, value=0.0, raw='0')-
A Number literal.
valueis the double the source denotes andrawis how that source spelled it; the two are independent because a spelling carries information the value does not, such as the base of0xFFor the sign of-0. Coercion happens here rather than at the call sites so that no construction anywhere can introduce a value JavaScript cannot hold.Expand source code Browse git
@dataclass(repr=False, eq=False) class JsNumericLiteral(Expression, spelling='raw'): """ A Number literal. `value` is the double the source denotes and `raw` is how that source spelled it; the two are independent because a spelling carries information the value does not, such as the base of `0xFF` or the sign of `-0`. Coercion happens here rather than at the call sites so that no construction anywhere can introduce a value JavaScript cannot hold. """ value: float = 0.0 raw: str = '0' def __post_init__(self): super().__post_init__() self.value = to_js_number(self.value)Ancestors
Instance variables
var value-
The type of the None singleton.
var raw-
The type of the None singleton.
Inherited members
class JsBigIntLiteral (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, raw='0n')-
A BigInt literal.
rawis how the source spelled it, and the exact integer it denotes is read off that spelling when it is asked for: converting a long decimal spelling is bounded by the interpreter's limit on the digits of an integer conversion, and reading a file must not be hostage to that limit for a value the file may never have read.Expand source code Browse git
@dataclass(repr=False, eq=False) class JsBigIntLiteral(Expression, spelling='raw'): """ A BigInt literal. `raw` is how the source spelled it, and the exact integer it denotes is read off that spelling when it is asked for: converting a long decimal spelling is bounded by the interpreter's limit on the digits of an integer conversion, and reading a file must not be hostage to that limit for a value the file may never have read. """ raw: str = '0n' @property def value(self) -> int: return integer_of_numeral(self.raw[:-1].replace('_', ''))Ancestors
Instance variables
var raw-
The type of the None singleton.
var value-
Expand source code Browse git
@property def value(self) -> int: return integer_of_numeral(self.raw[:-1].replace('_', ''))
Inherited members
class JsStringLiteral (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, value='', raw="''", terminated=True)-
A String literal.
valueis the text it denotes andrawis how the source spelled it, which part ways wherever an escape stands between them.valueisNonewhere the literal denotes nothing, which is a literal written with a\xor\uescape that names no character. A string keeps the legacy escapes Annex B holds open for sloppy code, so those still denote text; an escape no literal has at all denotes none, the way the same escape leaves aJsTemplateElementdenoting none.terminatedreports whether the closing quote was there. A literal the source never closed is not a form the language has, so no text spells it: printing what was written runs the literal on into whatever the synthesizer prints next, and printing the quote that is missing turns a file that does not parse into a program that runs.Expand source code Browse git
@dataclass(repr=False, eq=False) class JsStringLiteral(Expression, spelling='raw'): """ A String literal. `value` is the text it denotes and `raw` is how the source spelled it, which part ways wherever an escape stands between them. `value` is `None` where the literal denotes nothing, which is a literal written with a `\\x` or `\\u` escape that names no character. A string keeps the legacy escapes Annex B holds open for sloppy code, so those still denote text; an escape no literal has at all denotes none, the way the same escape leaves a `JsTemplateElement` denoting none. `terminated` reports whether the closing quote was there. A literal the source never closed is not a form the language has, so no text spells it: printing what was written runs the literal on into whatever the synthesizer prints next, and printing the quote that is missing turns a file that does not parse into a program that runs. """ value: str | None = '' raw: str = "''" terminated: bool = True @property def body(self) -> str: """ The source text between the quotes, every escape still spelled as it was written. A rule about how a literal was written reads this rather than `value`: a directive spelled with an escape in it denotes the text `use strict` and is not a Use Strict Directive, because what makes a directive is the spelling and not the value. """ return self.raw[1:-1] if self.terminated else self.raw[1:]Ancestors
Instance variables
var value-
The type of the None singleton.
var raw-
The type of the None singleton.
var terminated-
The type of the None singleton.
var body-
The source text between the quotes, every escape still spelled as it was written. A rule about how a literal was written reads this rather than
value: a directive spelled with an escape in it denotes the textuse strictand is not a Use Strict Directive, because what makes a directive is the spelling and not the value.Expand source code Browse git
@property def body(self) -> str: """ The source text between the quotes, every escape still spelled as it was written. A rule about how a literal was written reads this rather than `value`: a directive spelled with an escape in it denotes the text `use strict` and is not a Use Strict Directive, because what makes a directive is the spelling and not the value. """ return self.raw[1:-1] if self.terminated else self.raw[1:]
Inherited members
class JsRegExpLiteral (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, pattern='', flags='', raw='//', terminated=True)-
JsRegExpLiteral(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , pattern: 'str' = '', flags: 'str' = '', raw: 'str' = '//', terminated: 'bool' = True) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsRegExpLiteral(Expression, spelling='raw'): pattern: str = '' flags: str = '' raw: str = '//' terminated: bool = TrueAncestors
Instance variables
var pattern-
The type of the None singleton.
var flags-
The type of the None singleton.
var raw-
The type of the None singleton.
var terminated-
The type of the None singleton.
Inherited members
class JsTemplateLiteral (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, quasis=<factory>, expressions=<factory>)-
JsTemplateLiteral(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , quasis: 'list[JsTemplateElement]' = , expressions: 'list[Expression]' = ) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsTemplateLiteral(Expression): quasis: list[JsTemplateElement] = field(default_factory=list) expressions: list[Expression] = field(default_factory=list)Ancestors
Instance variables
var quasis-
The type of the None singleton.
var expressions-
The type of the None singleton.
Inherited members
class JsTemplateElement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, value='', raw='', tail=False, terminated=True, opened=True)-
One run of text in a template literal.
rawis that run as the source wrote it andvaluethe text it denotes; neither holds the delimiters that separate the runs from the expressions, because the literal prints those itself and a run is what stands between them.terminatedreports whether the delimiter that ends the run was there. Only a template can reach the end of the file unclosed, since no line terminator ends one, and a hole the source left open ends here as an empty run that closes nothing.valueisNonewhere the run denotes nothing, which is a run written with an escape the template grammar excludes. The language says the same thing by handing a tagundefinedfor such a run, and by refusing the untagged literal outright.Expand source code Browse git
@dataclass(repr=False, eq=False) class JsTemplateElement(Node, spelling='raw'): """ One run of text in a template literal. `raw` is that run as the source wrote it and `value` the text it denotes; neither holds the delimiters that separate the runs from the expressions, because the literal prints those itself and a run is what stands between them. `terminated` reports whether the delimiter that ends the run was there. Only a template can reach the end of the file unclosed, since no line terminator ends one, and a hole the source left open ends here as an empty run that closes nothing. `value` is `None` where the run denotes nothing, which is a run written with an escape the template grammar excludes. The language says the same thing by handing a tag `undefined` for such a run, and by refusing the untagged literal outright. """ value: str | None = '' raw: str = '' tail: bool = False terminated: bool = True #: Whether the `}` that closes the hole in front of this run was there. Only the run behind a #: hole the file ended inside lacks it, and such a run holds no text at all. opened: bool = TrueAncestors
Instance variables
var value-
The type of the None singleton.
var raw-
The type of the None singleton.
var tail-
The type of the None singleton.
var terminated-
The type of the None singleton.
var opened-
Whether the
}that closes the hole in front of this run was there. Only the run behind a hole the file ended inside lacks it, and such a run holds no text at all.
Inherited members
class JsBooleanLiteral (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, value=False)-
JsBooleanLiteral(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , value: 'bool' = False) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsBooleanLiteral(Expression): value: bool = FalseAncestors
Instance variables
var value-
The type of the None singleton.
Inherited members
class JsNullLiteral (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>)-
JsNullLiteral(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = ) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsNullLiteral(Expression): @property def value(self): return NoneAncestors
Instance variables
var value-
Expand source code Browse git
@property def value(self): return None
Inherited members
class JsThisExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>)-
JsThisExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = ) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsThisExpression(Expression): passAncestors
Inherited members
class JsArrayExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, elements=<factory>, terminated=True)-
JsArrayExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , elements: 'list[Expression | None]' = , terminated: 'bool' = True) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsArrayExpression(Expression): elements: list[Expression | None] = field(default_factory=list) #: Whether the closing bracket was there; `file_ended_inside` says what its absence means. terminated: bool = TrueAncestors
Instance variables
var elements-
The type of the None singleton.
var terminated-
Whether the closing bracket was there;
file_ended_inside()says what its absence means.
Inherited members
class JsObjectExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, properties=<factory>, terminated=True)-
JsObjectExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , properties: 'list[JsProperty | JsSpreadElement | JsErrorNode]' = , terminated: 'bool' = True) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsObjectExpression(Expression): properties: list[JsProperty | JsSpreadElement | JsErrorNode] = field(default_factory=list) terminated: bool = TrueAncestors
Instance variables
var properties-
The type of the None singleton.
var terminated-
The type of the None singleton.
Inherited members
class JsProperty (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, key=None, value=None, computed=False, shorthand=False, method=False, kind=JsPropertyKind.INIT)-
JsProperty(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , key: 'Expression | None' = None, value: 'Expression | None' = None, computed: 'bool' = False, shorthand: 'bool' = False, method: 'bool' = False, kind: 'JsPropertyKind' = <JsPropertyKind.INIT: 'init'>) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsProperty(Node): key: Expression | None = None value: Expression | None = None computed: bool = False shorthand: bool = False method: bool = False kind: JsPropertyKind = JsPropertyKind.INITAncestors
Instance variables
var key-
The type of the None singleton.
var value-
The type of the None singleton.
var computed-
The type of the None singleton.
var shorthand-
The type of the None singleton.
var method-
The type of the None singleton.
var kind-
The type of the None singleton.
Inherited members
class JsSpreadElement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, argument=None)-
JsSpreadElement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , argument: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsSpreadElement(Expression): argument: Expression | None = NoneAncestors
Instance variables
var argument-
The type of the None singleton.
Inherited members
class JsFunctionExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, id=None, params=<factory>, body=None, generator=False, is_async=False, source_text=None)-
JsFunctionExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , id: 'JsIdentifier | None' = None, params: 'list[Expression]' = , body: 'JsBlockStatement | None' = None, generator: 'bool' = False, is_async: 'bool' = False, source_text: 'str | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsFunctionExpression(Expression, spelling='source_text'): id: JsIdentifier | None = None params: list[Expression] = field(default_factory=list) body: JsBlockStatement | None = None generator: bool = False is_async: bool = False source_text: str | None = NoneAncestors
Instance variables
var params-
The type of the None singleton.
var id-
The type of the None singleton.
var body-
The type of the None singleton.
var generator-
The type of the None singleton.
var is_async-
The type of the None singleton.
var source_text-
The type of the None singleton.
Inherited members
class JsArrowFunctionExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, params=<factory>, body=None, is_async=False, source_text=None)-
JsArrowFunctionExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , params: 'list[Expression]' = , body: 'Expression | JsBlockStatement | None' = None, is_async: 'bool' = False, source_text: 'str | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsArrowFunctionExpression(Expression, spelling='source_text'): params: list[Expression] = field(default_factory=list) body: Expression | JsBlockStatement | None = None is_async: bool = False source_text: str | None = NoneAncestors
Instance variables
var params-
The type of the None singleton.
var body-
The type of the None singleton.
var is_async-
The type of the None singleton.
var source_text-
The type of the None singleton.
Inherited members
class JsDecorator (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, expression=None)-
JsDecorator(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , expression: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsDecorator(Node): expression: Expression | None = NoneAncestors
Instance variables
var expression-
The type of the None singleton.
Inherited members
class JsClassExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, id=None, super_class=None, body=None, decorators=<factory>)-
JsClassExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , id: 'JsIdentifier | None' = None, super_class: 'Expression | None' = None, body: 'JsClassBody | None' = None, decorators: 'list[JsDecorator]' = ) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsClassExpression(Expression): id: JsIdentifier | None = None super_class: Expression | None = None body: JsClassBody | None = None decorators: list[JsDecorator] = field(default_factory=list)Ancestors
Instance variables
var decorators-
The type of the None singleton.
var id-
The type of the None singleton.
var super_class-
The type of the None singleton.
var body-
The type of the None singleton.
Inherited members
class JsUnaryExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, operator='', operand=None, prefix=True)-
JsUnaryExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , operator: 'str' = '', operand: 'Expression | None' = None, prefix: 'bool' = True) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsUnaryExpression(Expression): operator: str = '' operand: Expression | None = None prefix: bool = TrueAncestors
Instance variables
var operator-
The type of the None singleton.
var operand-
The type of the None singleton.
var prefix-
The type of the None singleton.
Inherited members
class JsUpdateExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, operator='', argument=None, prefix=True)-
JsUpdateExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , operator: 'str' = '', argument: 'Expression | None' = None, prefix: 'bool' = True) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsUpdateExpression(Expression): operator: str = '' argument: Expression | None = None prefix: bool = TrueAncestors
Instance variables
var operator-
The type of the None singleton.
var argument-
The type of the None singleton.
var prefix-
The type of the None singleton.
Inherited members
class JsBinaryExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, left=None, operator='', right=None)-
JsBinaryExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , left: 'Expression | None' = None, operator: 'str' = '', right: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsBinaryExpression(Expression): left: Expression | None = None operator: str = '' right: Expression | None = NoneAncestors
Instance variables
var left-
The type of the None singleton.
var operator-
The type of the None singleton.
var right-
The type of the None singleton.
Inherited members
class JsLogicalExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, left=None, operator='', right=None)-
JsLogicalExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , left: 'Expression | None' = None, operator: 'str' = '', right: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsLogicalExpression(Expression): left: Expression | None = None operator: str = '' right: Expression | None = NoneAncestors
Instance variables
var left-
The type of the None singleton.
var operator-
The type of the None singleton.
var right-
The type of the None singleton.
Inherited members
class JsAssignmentExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, left=None, operator='=', right=None)-
JsAssignmentExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , left: 'Expression | None' = None, operator: 'str' = '=', right: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsAssignmentExpression(Expression): left: Expression | None = None operator: str = '=' right: Expression | None = NoneAncestors
Instance variables
var left-
The type of the None singleton.
var operator-
The type of the None singleton.
var right-
The type of the None singleton.
Inherited members
class JsConditionalExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, test=None, consequent=None, alternate=None)-
JsConditionalExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , test: 'Expression | None' = None, consequent: 'Expression | None' = None, alternate: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsConditionalExpression(Expression): test: Expression | None = None consequent: Expression | None = None alternate: Expression | None = NoneAncestors
Instance variables
var test-
The type of the None singleton.
var consequent-
The type of the None singleton.
var alternate-
The type of the None singleton.
Inherited members
class JsMemberExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, object=None, property=None, computed=False, optional=False)-
JsMemberExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , object: 'Expression | None' = None, property: 'Expression | None' = None, computed: 'bool' = False, optional: 'bool' = False) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsMemberExpression(Expression): object: Expression | None = None property: Expression | None = None computed: bool = False optional: bool = FalseAncestors
Instance variables
var object-
The type of the None singleton.
var property-
The type of the None singleton.
var computed-
The type of the None singleton.
var optional-
The type of the None singleton.
Inherited members
class JsCallExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, callee=None, arguments=<factory>, optional=False, terminated=True)-
JsCallExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , callee: 'Expression | None' = None, arguments: 'list[Expression]' = , optional: 'bool' = False, terminated: 'bool' = True) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsCallExpression(Expression): callee: Expression | None = None arguments: list[Expression] = field(default_factory=list) optional: bool = False terminated: bool = TrueAncestors
Instance variables
var arguments-
The type of the None singleton.
var callee-
The type of the None singleton.
var optional-
The type of the None singleton.
var terminated-
The type of the None singleton.
Inherited members
class JsNewExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, callee=None, arguments=<factory>, terminated=True)-
JsNewExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , callee: 'Expression | None' = None, arguments: 'list[Expression]' = , terminated: 'bool' = True) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsNewExpression(Expression): callee: Expression | None = None arguments: list[Expression] = field(default_factory=list) terminated: bool = TrueAncestors
Instance variables
var arguments-
The type of the None singleton.
var callee-
The type of the None singleton.
var terminated-
The type of the None singleton.
Inherited members
class JsSequenceExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, expressions=<factory>)-
JsSequenceExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , expressions: 'list[Expression]' = ) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsSequenceExpression(Expression): expressions: list[Expression] = field(default_factory=list)Ancestors
Instance variables
var expressions-
The type of the None singleton.
Inherited members
class JsYieldExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, argument=None, delegate=False)-
JsYieldExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , argument: 'Expression | None' = None, delegate: 'bool' = False) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsYieldExpression(Expression): argument: Expression | None = None delegate: bool = FalseAncestors
Instance variables
var argument-
The type of the None singleton.
var delegate-
The type of the None singleton.
Inherited members
class JsAwaitExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, argument=None)-
JsAwaitExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , argument: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsAwaitExpression(Expression): argument: Expression | None = NoneAncestors
Instance variables
var argument-
The type of the None singleton.
Inherited members
class JsTaggedTemplateExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, tag=None, quasi=None)-
JsTaggedTemplateExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , tag: 'Expression | None' = None, quasi: 'JsTemplateLiteral | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsTaggedTemplateExpression(Expression): tag: Expression | None = None quasi: JsTemplateLiteral | None = NoneAncestors
Instance variables
var tag-
The type of the None singleton.
var quasi-
The type of the None singleton.
Inherited members
class JsParenthesizedExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, expression=None, terminated=True)-
JsParenthesizedExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , expression: 'Expression | None' = None, terminated: 'bool' = True) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsParenthesizedExpression(Expression): expression: Expression | None = None terminated: bool = TrueAncestors
Instance variables
var expression-
The type of the None singleton.
var terminated-
The type of the None singleton.
Inherited members
class JsArrayPattern (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, elements=<factory>, terminated=True)-
JsArrayPattern(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , elements: 'list[Expression | None]' = , terminated: 'bool' = True) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsArrayPattern(Expression): elements: list[Expression | None] = field(default_factory=list) terminated: bool = TrueAncestors
Instance variables
var elements-
The type of the None singleton.
var terminated-
The type of the None singleton.
Inherited members
class JsObjectPattern (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, properties=<factory>, terminated=True)-
JsObjectPattern(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , properties: 'list[JsProperty | JsRestElement | JsErrorNode]' = , terminated: 'bool' = True) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsObjectPattern(Expression): properties: list[JsProperty | JsRestElement | JsErrorNode] = field(default_factory=list) terminated: bool = TrueAncestors
Instance variables
var properties-
The type of the None singleton.
var terminated-
The type of the None singleton.
Inherited members
class JsAssignmentPattern (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, left=None, right=None)-
JsAssignmentPattern(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , left: 'Expression | None' = None, right: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsAssignmentPattern(Expression): left: Expression | None = None right: Expression | None = NoneAncestors
Instance variables
var left-
The type of the None singleton.
var right-
The type of the None singleton.
Inherited members
class JsRestElement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, argument=None)-
JsRestElement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , argument: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsRestElement(Expression): argument: Expression | None = NoneAncestors
Instance variables
var argument-
The type of the None singleton.
Inherited members
class JsClassBody (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, body=<factory>, terminated=True)-
JsClassBody(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , body: 'list[JsMethodDefinition | JsPropertyDefinition | JsStaticBlock | JsErrorNode]' = , terminated: 'bool' = True) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsClassBody(Node): body: list[JsMethodDefinition | JsPropertyDefinition | JsStaticBlock | JsErrorNode] = field(default_factory=list) #: Whether the closing brace was there. The file may end inside a class body, and a body the #: file ends inside prints the elements it holds and nothing after them. terminated: bool = TrueAncestors
Instance variables
var body-
The type of the None singleton.
var terminated-
Whether the closing brace was there. The file may end inside a class body, and a body the file ends inside prints the elements it holds and nothing after them.
Inherited members
class JsMethodDefinition (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, key=None, value=None, kind=JsMethodKind.METHOD, computed=False, is_static=False, decorators=<factory>)-
JsMethodDefinition(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , key: 'Expression | None' = None, value: 'JsFunctionExpression | None' = None, kind: 'JsMethodKind' = <JsMethodKind.METHOD: 'method'>, computed: 'bool' = False, is_static: 'bool' = False, decorators: 'list[JsDecorator]' = ) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsMethodDefinition(Node): key: Expression | None = None value: JsFunctionExpression | None = None kind: JsMethodKind = JsMethodKind.METHOD computed: bool = False is_static: bool = False decorators: list[JsDecorator] = field(default_factory=list)Ancestors
Instance variables
var decorators-
The type of the None singleton.
var key-
The type of the None singleton.
var value-
The type of the None singleton.
var kind-
The type of the None singleton.
var computed-
The type of the None singleton.
var is_static-
The type of the None singleton.
Inherited members
class JsPropertyDefinition (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, key=None, value=None, computed=False, is_static=False, decorators=<factory>)-
JsPropertyDefinition(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , key: 'Expression | None' = None, value: 'Expression | None' = None, computed: 'bool' = False, is_static: 'bool' = False, decorators: 'list[JsDecorator]' = ) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsPropertyDefinition(Node): key: Expression | None = None value: Expression | None = None computed: bool = False is_static: bool = False decorators: list[JsDecorator] = field(default_factory=list)Ancestors
Instance variables
var decorators-
The type of the None singleton.
var key-
The type of the None singleton.
var value-
The type of the None singleton.
var computed-
The type of the None singleton.
var is_static-
The type of the None singleton.
Inherited members
class JsStaticBlock (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, body=<factory>, terminated=True)-
JsStaticBlock(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , body: 'list[Statement]' = , terminated: 'bool' = True) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsStaticBlock(Node): body: list[Statement] = field(default_factory=list) terminated: bool = TrueAncestors
Instance variables
var body-
The type of the None singleton.
var terminated-
The type of the None singleton.
Inherited members
class JsExpressionStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, expression=None, directive=False)-
JsExpressionStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , expression: 'Expression | None' = None, directive: 'bool' = False) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsExpressionStatement(Statement, spelling='directive'): expression: Expression | None = None #: Whether the source wrote this statement into a Directive Prologue. It records where the #: statement came from and not what it computes, which is why it is a spelling field: two trees #: that differ only here spell the same program. A clone carries it, deliberately — a directive #: that is copied elsewhere was still written as one, and whether it *is* one is decided by #: `refinery.lib.scripts.js.strict.is_prologue_host` at wherever it now stands. directive: bool = FalseAncestors
Instance variables
var expression-
The type of the None singleton.
var directive-
Whether the source wrote this statement into a Directive Prologue. It records where the statement came from and not what it computes, which is why it is a spelling field: two trees that differ only here spell the same program. A clone carries it, deliberately — a directive that is copied elsewhere was still written as one, and whether it is one is decided by
is_prologue_host()at wherever it now stands.
Inherited members
class JsBlockStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, body=<factory>, terminated=True)-
JsBlockStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , body: 'list[Statement]' = , terminated: 'bool' = True) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsBlockStatement(Statement): body: list[Statement] = field(default_factory=list) #: Whether the closing brace was there. A file carved out of memory ends inside a block more #: often than anywhere else, and the block keeps the statements it holds and says that nothing #: closed it: printing what it holds and nothing after it is what keeps the file's end where the #: file had it. `early_errors` reports it. terminated: bool = TrueAncestors
Instance variables
var body-
The type of the None singleton.
var terminated-
Whether the closing brace was there. A file carved out of memory ends inside a block more often than anywhere else, and the block keeps the statements it holds and says that nothing closed it: printing what it holds and nothing after it is what keeps the file's end where the file had it.
early_errorsreports it.
Inherited members
class JsEmptyStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>)-
JsEmptyStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = ) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsEmptyStatement(Statement): passAncestors
Inherited members
class JsVariableDeclaration (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, declarations=<factory>, kind=JsVarKind.VAR)-
JsVariableDeclaration(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , declarations: 'list[JsVariableDeclarator]' = , kind: 'JsVarKind' = <JsVarKind.VAR: 'var'>) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsVariableDeclaration(Statement): declarations: list[JsVariableDeclarator] = field(default_factory=list) kind: JsVarKind = JsVarKind.VARAncestors
Instance variables
var declarations-
The type of the None singleton.
var kind-
The type of the None singleton.
Inherited members
class JsVariableDeclarator (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, id=None, init=None)-
JsVariableDeclarator(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , id: 'Expression | None' = None, init: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsVariableDeclarator(Node): id: Expression | None = None init: Expression | None = NoneAncestors
Instance variables
var id-
The type of the None singleton.
var init-
The type of the None singleton.
Inherited members
class JsIfStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, test=None, consequent=None, alternate=None)-
JsIfStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , test: 'Expression | None' = None, consequent: 'Statement | None' = None, alternate: 'Statement | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsIfStatement(Statement): test: Expression | None = None consequent: Statement | None = None alternate: Statement | None = NoneAncestors
Instance variables
var test-
The type of the None singleton.
var consequent-
The type of the None singleton.
var alternate-
The type of the None singleton.
Inherited members
class JsWhileStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, test=None, body=None)-
JsWhileStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , test: 'Expression | None' = None, body: 'Statement | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsWhileStatement(Statement): test: Expression | None = None body: Statement | None = NoneAncestors
Instance variables
var test-
The type of the None singleton.
var body-
The type of the None singleton.
Inherited members
class JsDoWhileStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, test=None, body=None)-
JsDoWhileStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , test: 'Expression | None' = None, body: 'Statement | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsDoWhileStatement(Statement): test: Expression | None = None body: Statement | None = NoneAncestors
Instance variables
var test-
The type of the None singleton.
var body-
The type of the None singleton.
Inherited members
class JsForStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, init=None, test=None, update=None, body=None)-
JsForStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , init: 'Expression | Statement | None' = None, test: 'Expression | None' = None, update: 'Expression | None' = None, body: 'Statement | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsForStatement(Statement): init: Expression | Statement | None = None test: Expression | None = None update: Expression | None = None body: Statement | None = NoneAncestors
Instance variables
var init-
The type of the None singleton.
var test-
The type of the None singleton.
var update-
The type of the None singleton.
var body-
The type of the None singleton.
Inherited members
class JsForInStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, left=None, right=None, body=None)-
JsForInStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , left: 'Expression | Statement | None' = None, right: 'Expression | None' = None, body: 'Statement | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsForInStatement(Statement): left: Expression | Statement | None = None right: Expression | None = None body: Statement | None = NoneAncestors
Instance variables
var left-
The type of the None singleton.
var right-
The type of the None singleton.
var body-
The type of the None singleton.
Inherited members
class JsForOfStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, left=None, right=None, body=None, is_await=False)-
JsForOfStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , left: 'Expression | Statement | None' = None, right: 'Expression | None' = None, body: 'Statement | None' = None, is_await: 'bool' = False) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsForOfStatement(Statement): left: Expression | Statement | None = None right: Expression | None = None body: Statement | None = None is_await: bool = FalseAncestors
Instance variables
var left-
The type of the None singleton.
var right-
The type of the None singleton.
var body-
The type of the None singleton.
var is_await-
The type of the None singleton.
Inherited members
class JsSwitchStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, discriminant=None, cases=<factory>, terminated=True)-
JsSwitchStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , discriminant: 'Expression | None' = None, cases: 'list[JsSwitchCase | JsErrorNode]' = , terminated: 'bool' = True) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsSwitchStatement(Statement): discriminant: Expression | None = None cases: list[JsSwitchCase | JsErrorNode] = field(default_factory=list) terminated: bool = TrueAncestors
Instance variables
var cases-
The type of the None singleton.
var discriminant-
The type of the None singleton.
var terminated-
The type of the None singleton.
Inherited members
class JsSwitchCase (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, test=None, body=<factory>)-
JsSwitchCase(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , test: 'Expression | None' = None, body: 'list[Statement]' = ) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsSwitchCase(Node): test: Expression | None = None body: list[Statement] = field(default_factory=list)Ancestors
Instance variables
var body-
The type of the None singleton.
var test-
The type of the None singleton.
Inherited members
class JsTryStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, block=None, handler=None, finalizer=None)-
JsTryStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , block: 'JsBlockStatement | None' = None, handler: 'JsCatchClause | None' = None, finalizer: 'JsBlockStatement | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsTryStatement(Statement): block: JsBlockStatement | None = None handler: JsCatchClause | None = None finalizer: JsBlockStatement | None = NoneAncestors
Instance variables
var block-
The type of the None singleton.
var handler-
The type of the None singleton.
var finalizer-
The type of the None singleton.
Inherited members
class JsCatchClause (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, param=None, body=None)-
JsCatchClause(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , param: 'Expression | None' = None, body: 'JsBlockStatement | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsCatchClause(Node): param: Expression | None = None body: JsBlockStatement | None = NoneAncestors
Instance variables
var param-
The type of the None singleton.
var body-
The type of the None singleton.
Inherited members
class JsThrowStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, argument=None)-
JsThrowStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , argument: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsThrowStatement(Statement): argument: Expression | None = None def has_spelling(self) -> bool: """ A `throw` takes its expression on the same line, and nothing else: the parser refuses a `throw` with nothing behind it, and this is what says so if a transform assembles one. """ return self.argument is not NoneAncestors
Instance variables
var argument-
The type of the None singleton.
Methods
def has_spelling(self)-
A
throwtakes its expression on the same line, and nothing else: the parser refuses athrowwith nothing behind it, and this is what says so if a transform assembles one.Expand source code Browse git
def has_spelling(self) -> bool: """ A `throw` takes its expression on the same line, and nothing else: the parser refuses a `throw` with nothing behind it, and this is what says so if a transform assembles one. """ return self.argument is not None
Inherited members
class JsReturnStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, argument=None)-
JsReturnStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , argument: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsReturnStatement(Statement): argument: Expression | None = NoneAncestors
Instance variables
var argument-
The type of the None singleton.
Inherited members
class JsBreakStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, label=None)-
JsBreakStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , label: 'JsIdentifier | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsBreakStatement(Statement): label: JsIdentifier | None = NoneAncestors
Instance variables
var label-
The type of the None singleton.
Inherited members
class JsContinueStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, label=None)-
JsContinueStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , label: 'JsIdentifier | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsContinueStatement(Statement): label: JsIdentifier | None = NoneAncestors
Instance variables
var label-
The type of the None singleton.
Inherited members
class JsLabeledStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, label=None, body=None)-
JsLabeledStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , label: 'JsIdentifier | None' = None, body: 'Statement | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsLabeledStatement(Statement): label: JsIdentifier | None = None body: Statement | None = NoneAncestors
Instance variables
var label-
The type of the None singleton.
var body-
The type of the None singleton.
Inherited members
class JsWithStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, object=None, body=None)-
JsWithStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , object: 'Expression | None' = None, body: 'Statement | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsWithStatement(Statement): object: Expression | None = None body: Statement | None = NoneAncestors
Instance variables
var object-
The type of the None singleton.
var body-
The type of the None singleton.
Inherited members
class JsDebuggerStatement (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>)-
JsDebuggerStatement(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = ) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsDebuggerStatement(Statement): passAncestors
Inherited members
class JsFunctionDeclaration (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, id=None, params=<factory>, body=None, generator=False, is_async=False, source_text=None)-
JsFunctionDeclaration(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , id: 'JsIdentifier | None' = None, params: 'list[Expression]' = , body: 'JsBlockStatement | None' = None, generator: 'bool' = False, is_async: 'bool' = False, source_text: 'str | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsFunctionDeclaration(Statement, spelling='source_text'): id: JsIdentifier | None = None params: list[Expression] = field(default_factory=list) body: JsBlockStatement | None = None generator: bool = False is_async: bool = False source_text: str | None = NoneAncestors
Instance variables
var params-
The type of the None singleton.
var id-
The type of the None singleton.
var body-
The type of the None singleton.
var generator-
The type of the None singleton.
var is_async-
The type of the None singleton.
var source_text-
The type of the None singleton.
Inherited members
class JsClassDeclaration (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, id=None, super_class=None, body=None, decorators=<factory>)-
JsClassDeclaration(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , id: 'JsIdentifier | None' = None, super_class: 'Expression | None' = None, body: 'JsClassBody | None' = None, decorators: 'list[JsDecorator]' = ) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsClassDeclaration(Statement): id: JsIdentifier | None = None super_class: Expression | None = None body: JsClassBody | None = None decorators: list[JsDecorator] = field(default_factory=list)Ancestors
Instance variables
var decorators-
The type of the None singleton.
var id-
The type of the None singleton.
var super_class-
The type of the None singleton.
var body-
The type of the None singleton.
Inherited members
class JsImportSpecifier (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, imported=None, local=None)-
JsImportSpecifier(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , imported: 'Expression | None' = None, local: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsImportSpecifier(Node): imported: Expression | None = None local: Expression | None = NoneAncestors
Instance variables
var imported-
The type of the None singleton.
var local-
The type of the None singleton.
Inherited members
class JsImportDefaultSpecifier (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, local=None)-
JsImportDefaultSpecifier(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , local: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsImportDefaultSpecifier(Node): local: Expression | None = NoneAncestors
Instance variables
var local-
The type of the None singleton.
Inherited members
class JsImportNamespaceSpecifier (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, local=None)-
JsImportNamespaceSpecifier(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , local: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsImportNamespaceSpecifier(Node): local: Expression | None = NoneAncestors
Instance variables
var local-
The type of the None singleton.
Inherited members
class JsImportAttribute (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, key=None, value=None)-
JsImportAttribute(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , key: 'Expression | None' = None, value: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsImportAttribute(Node): key: Expression | None = None value: Expression | None = NoneAncestors
Instance variables
var key-
The type of the None singleton.
var value-
The type of the None singleton.
Inherited members
class JsImportDeclaration (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, specifiers=<factory>, source=None, attributes=<factory>, attributes_keyword='')-
JsImportDeclaration(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , specifiers: 'list[JsImportSpecifier | JsImportDefaultSpecifier | JsImportNamespaceSpecifier | JsErrorNode]' = , source: 'JsStringLiteral | None' = None, attributes: 'list[JsImportAttribute | JsErrorNode]' = , attributes_keyword: 'str' = '') Expand source code Browse git
@dataclass(repr=False, eq=False) class JsImportDeclaration(Statement): specifiers: list[ JsImportSpecifier | JsImportDefaultSpecifier | JsImportNamespaceSpecifier | JsErrorNode ] = field(default_factory=list) source: JsStringLiteral | None = None attributes: list[JsImportAttribute | JsErrorNode] = field(default_factory=list) attributes_keyword: str = ''Ancestors
Instance variables
var specifiers-
The type of the None singleton.
var attributes-
The type of the None singleton.
var source-
The type of the None singleton.
var attributes_keyword-
The type of the None singleton.
Inherited members
class JsImportExpression (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, source=None, options=None)-
JsImportExpression(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , source: 'Expression | None' = None, options: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsImportExpression(Expression): source: Expression | None = None options: Expression | None = NoneAncestors
Instance variables
var source-
The type of the None singleton.
var options-
The type of the None singleton.
Inherited members
class JsMetaProperty (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, meta='', property='')-
JsMetaProperty(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , meta: 'str' = '', property: 'str' = '') Expand source code Browse git
@dataclass(repr=False, eq=False) class JsMetaProperty(Expression): meta: str = '' property: str = ''Ancestors
Instance variables
var meta-
The type of the None singleton.
var property-
The type of the None singleton.
Inherited members
class JsExportSpecifier (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, local=None, exported=None)-
JsExportSpecifier(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , local: 'Expression | None' = None, exported: 'Expression | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsExportSpecifier(Node): local: Expression | None = None exported: Expression | None = NoneAncestors
Instance variables
var local-
The type of the None singleton.
var exported-
The type of the None singleton.
Inherited members
class JsExportNamedDeclaration (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, declaration=None, specifiers=<factory>, source=None, attributes=<factory>, attributes_keyword='')-
JsExportNamedDeclaration(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , declaration: 'Statement | None' = None, specifiers: 'list[JsExportSpecifier | JsErrorNode]' = , source: 'JsStringLiteral | None' = None, attributes: 'list[JsImportAttribute | JsErrorNode]' = , attributes_keyword: 'str' = '') Expand source code Browse git
@dataclass(repr=False, eq=False) class JsExportNamedDeclaration(Statement): declaration: Statement | None = None specifiers: list[JsExportSpecifier | JsErrorNode] = field(default_factory=list) source: JsStringLiteral | None = None attributes: list[JsImportAttribute | JsErrorNode] = field(default_factory=list) attributes_keyword: str = ''Ancestors
Instance variables
var specifiers-
The type of the None singleton.
var attributes-
The type of the None singleton.
var declaration-
The type of the None singleton.
var source-
The type of the None singleton.
var attributes_keyword-
The type of the None singleton.
Inherited members
class JsExportDefaultDeclaration (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, declaration=None)-
JsExportDefaultDeclaration(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , declaration: 'Expression | Statement | None' = None) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsExportDefaultDeclaration(Statement): declaration: Expression | Statement | None = NoneAncestors
Instance variables
var declaration-
The type of the None singleton.
Inherited members
class JsExportAllDeclaration (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, source=None, exported=None, attributes=<factory>, attributes_keyword='')-
JsExportAllDeclaration(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , source: 'JsStringLiteral | None' = None, exported: 'Expression | None' = None, attributes: 'list[JsImportAttribute | JsErrorNode]' = , attributes_keyword: 'str' = '') Expand source code Browse git
@dataclass(repr=False, eq=False) class JsExportAllDeclaration(Statement): source: JsStringLiteral | None = None exported: Expression | None = None attributes: list[JsImportAttribute | JsErrorNode] = field(default_factory=list) attributes_keyword: str = ''Ancestors
Instance variables
var attributes-
The type of the None singleton.
var source-
The type of the None singleton.
var exported-
The type of the None singleton.
var attributes_keyword-
The type of the None singleton.
Inherited members
class JsScript (offset=-1, parent=None, leading_comments=<factory>, trailing_comments=<factory>, body=<factory>, module=False, recovered=False, html_comment=None, terminated=True)-
JsScript(offset: 'int' = -1, parent: 'Node | None' = None, leading_comments: 'list[str]' =
, trailing_comments: 'list[str]' = , body: 'list[Statement]' = , module: 'bool' = False, recovered: 'bool' = False, html_comment: 'int | None' = None, terminated: 'bool' = True) Expand source code Browse git
@dataclass(repr=False, eq=False) class JsScript(Statement, spelling=('module', 'recovered', 'html_comment')): body: list[Statement] = field(default_factory=list) #: Whether the source is module code, which the host decides (§16.1) and the syntax only reports: #: an `import` or `export` declaration, or `import.meta`, can appear in nothing else. It is a #: spelling field because two scripts differing only here hold the same text — what differs is how #: a host loads it — and because a pass that cuts the last import out of a body does not turn a #: module into a script. module: bool = False #: Whether the parser had to invent a token, or step over one, in order to read this file. It is #: a spelling field for the reason `module` is: it records where the tree came from rather than #: what it spells, so two scripts differing only here are the same program. Nothing ever clears #: it, because no later pass can put back a token the source never held. recovered: bool = False #: The offset of the first HTML-like comment delimiter the lexer read in this file (§B.1.1), or #: `None` where it read none. Module code refuses both delimiters, and the comment one opens may #: stand where no statement carries it, so the fact is kept on the script rather than looked for #: among the comments the tree holds. It is a spelling field for the reason `recovered` is. html_comment: int | None = None #: Whether the file ended outside every comment. A block comment the file ends inside runs to #: the end of the file, is the last of the file's `trailing_comments`, and makes the file no #: program, which `early_errors` reports. terminated: bool = True def is_recovered(self) -> bool: return self.recovered def early_errors(self) -> list[StrictViolation]: """ What the language refuses in the file under its own mode and goal: the early errors `refinery.lib.scripts.js.strict.collect_strict_violations` reports over the tree read as a script, or as a module where the file spells module syntax, and every construct the file ended inside — a literal, a comment, a block, a class body or a switch — which an engine refuses as an unexpected end of input. """ from refinery.lib.scripts.js.strict import collect_strict_violations return collect_strict_violations(self, module=self.module)Ancestors
Instance variables
var body-
The type of the None singleton.
var module-
Whether the source is module code, which the host decides (§16.1) and the syntax only reports: an
importorexportdeclaration, orimport.meta, can appear in nothing else. It is a spelling field because two scripts differing only here hold the same text — what differs is how a host loads it — and because a pass that cuts the last import out of a body does not turn a module into a script. var recovered-
Whether the parser had to invent a token, or step over one, in order to read this file. It is a spelling field for the reason
moduleis: it records where the tree came from rather than what it spells, so two scripts differing only here are the same program. Nothing ever clears it, because no later pass can put back a token the source never held. var html_comment-
The offset of the first HTML-like comment delimiter the lexer read in this file (§B.1.1), or
Nonewhere it read none. Module code refuses both delimiters, and the comment one opens may stand where no statement carries it, so the fact is kept on the script rather than looked for among the comments the tree holds. It is a spelling field for the reasonrecoveredis. var terminated-
Whether the file ended outside every comment. A block comment the file ends inside runs to the end of the file, is the last of the file's
trailing_comments, and makes the file no program, whichearly_errorsreports.
Methods
def early_errors(self)-
What the language refuses in the file under its own mode and goal: the early errors
collect_strict_violations()reports over the tree read as a script, or as a module where the file spells module syntax, and every construct the file ended inside — a literal, a comment, a block, a class body or a switch — which an engine refuses as an unexpected end of input.Expand source code Browse git
def early_errors(self) -> list[StrictViolation]: """ What the language refuses in the file under its own mode and goal: the early errors `refinery.lib.scripts.js.strict.collect_strict_violations` reports over the tree read as a script, or as a module where the file spells module syntax, and every construct the file ended inside — a literal, a comment, a block, a class body or a switch — which an engine refuses as an unexpected end of input. """ from refinery.lib.scripts.js.strict import collect_strict_violations return collect_strict_violations(self, module=self.module)
Inherited members
class AwaitReading (*args, **kwds)-
What the word
awaitis where a piece of code stands. It names a binding or a reference in a script and in every function that is notasync; it is the operator in anasyncfunction's parameter list and body; and it is neither in a class static block or a static field initializer, where the language refuses the word in every position.Expand source code Browse git
class AwaitReading(enum.Enum): """ What the word `await` is where a piece of code stands. It names a binding or a reference in a script and in every function that is not `async`; it is the operator in an `async` function's parameter list and body; and it is neither in a class static block or a static field initializer, where the language refuses the word in every position. """ NAME = enum.auto() OPERATOR = enum.auto() RESERVED = enum.auto()Ancestors
- enum.Enum
Class variables
var NAME-
The type of the None singleton.
var OPERATOR-
The type of the None singleton.
var RESERVED-
The type of the None singleton.
class CodeContext (await_reading, yield_is_operator, arguments_reserved, top_level)-
The grammar parameters a piece of code is read under: what
awaitis, whetheryieldis the operator rather than a name, whetherargumentsmay be referred to at all, and whether the code is the top level of a file. The parser descends it and the early-error collector threads it, both throughcode_context_within(), so that the tree a text is read into and the errors reported over that tree agree on what every word is.The top level is set apart because its goal symbol is not known while parsing:
awaitis read as a name there, as a script reads it, but afor awaithead is read as well, since that is one way a module spells its top-levelawait. Below a function or a class element the goal decides nothing, and afor awaithead stands only whereawaitis the operator.Expand source code Browse git
@dataclass(frozen=True) class CodeContext: """ The grammar parameters a piece of code is read under: what `await` is, whether `yield` is the operator rather than a name, whether `arguments` may be referred to at all, and whether the code is the top level of a file. The parser descends it and the early-error collector threads it, both through `code_context_within`, so that the tree a text is read into and the errors reported over that tree agree on what every word is. The top level is set apart because its goal symbol is not known while parsing: `await` is read as a name there, as a script reads it, but a `for await` head is read as well, since that is one way a module spells its top-level `await`. Below a function or a class element the goal decides nothing, and a `for await` head stands only where `await` is the operator. """ await_reading: AwaitReading yield_is_operator: bool arguments_reserved: bool top_level: bool @property def reads_for_await(self) -> bool: """ Whether a `for await` head is read here: where `await` is the operator, and at the top level of a file, whose goal may make it one. """ return self.await_reading is AwaitReading.OPERATOR or self.top_levelInstance variables
var await_reading-
The type of the None singleton.
var yield_is_operator-
The type of the None singleton.
var arguments_reserved-
The type of the None singleton.
var top_level-
The type of the None singleton.
var reads_for_await-
Whether a
for awaithead is read here: whereawaitis the operator, and at the top level of a file, whose goal may make it one.Expand source code Browse git
@property def reads_for_await(self) -> bool: """ Whether a `for await` head is read here: where `await` is the operator, and at the top level of a file, whose goal may make it one. """ return self.await_reading is AwaitReading.OPERATOR or self.top_level