docs(packages/codegen): add @params to JSDoc comments which had none (#27601)

Comments-only change.

Add documentation for all parameters to the JSDoc comment for every function.
This commit is contained in:
overlookmotel committed 2026-10-12 17:10:53 +00:00
1 parent 5ee0fc9758
commit 59472c5170
23 files changed
+461 -1

No files matched your search

@@ -17,6 +17,9 @@ import type * as ESTree from "../../../../npm/oxc-types/types.d.ts";
*
* Destructuring targets look like object and array literals but are a separate set of node types,
* with their own rules - which is why they are printed here rather than by the expression printer.
*
* @param node - Assignment target
* @param state - Printer state
*/
export function printAssignmentTarget(node: ESTree.AssignmentTarget, state: State): void {
switch (node.type) {
@@ -52,6 +55,9 @@ export function printAssignmentTarget(node: ESTree.AssignmentTarget, state: Stat
/**
* Print an object destructuring target, as in `({ a, b: c } = obj)`.
*
* @param node - Object assignment target
* @param state - Printer state
*/
function printObjectAssignmentTarget(node: ESTree.ObjectAssignmentTarget, state: State): void {
writeWithMap(state, "{", CAT_OTHER, node.start, node.end, node);
@@ -75,6 +81,9 @@ function printObjectAssignmentTarget(node: ESTree.ObjectAssignmentTarget, state:
/**
* Print one property of an object destructuring target, in shorthand where the AST says so.
*
* @param node - Assignment target property
* @param state - Printer state
*/
function printAssignmentTargetProperty(node: ESTree.AssignmentTargetProperty, state: State): void {
// Shorthand from the AST flag (assignment targets are not re-derived).
@@ -110,6 +119,9 @@ function printAssignmentTargetProperty(node: ESTree.AssignmentTargetProperty, st
/**
* Print a destructuring target which may carry a default, as the `a = 1` in `({ a = 1 } = obj)`.
*
* @param node - Assignment target, possibly with a default
* @param state - Printer state
*/
function printAssignmentTargetMaybeDefault(
node: ESTree.AssignmentTargetMaybeDefault,
@@ -126,6 +138,9 @@ function printAssignmentTargetMaybeDefault(
/**
* Print an array destructuring target, holes and rest element included.
*
* @param node - Array assignment target
* @param state - Printer state
*/
function printArrayAssignmentTarget(node: ESTree.ArrayAssignmentTarget, state: State): void {
const { elements } = node;
+5
View File
@@ -214,6 +214,8 @@ function binCheckAndPrepare(
/**
* Whether an operator is one of the three which `??` may not mix with unparenthesized.
*
* @param operator - Operator
*/
function isLogicalOperator(operator: string): boolean {
return operator === "&&" || operator === "||" || operator === "??";
@@ -224,6 +226,9 @@ function isLogicalOperator(operator: string): boolean {
*
* The operator is written space-padded as one token, which is why nothing here consults `last` -
* the spacing checks cannot observe an operator which already has a space either side of it.
*
* @param v - Level of the chain to finish
* @param state - Printer state
*/
function binVisitRightAndFinish(v: BinaryVisitor, state: State): void {
// The operator is always surrounded by spaces here, which makes the token glue checks
@@ -27,6 +27,9 @@ type BindingPatternNode =
/**
* Print anything which can be bound to - a name, a destructuring pattern, or one carrying a default.
*
* @param node - Binding pattern
* @param state - Printer state
*/
export function printBindingPattern(node: BindingPatternNode, state: State): void {
switch (node.type) {
@@ -63,6 +66,9 @@ export function printBindingPattern(node: BindingPatternNode, state: State): voi
/**
* Print an object destructuring pattern, as in `const { a, b } = obj`.
*
* @param node - Object pattern
* @param state - Printer state
*/
function printObjectBindingPattern(node: ESTree.ObjectPattern, state: State): void {
const { properties } = node;
@@ -91,6 +97,9 @@ function printObjectBindingPattern(node: ESTree.ObjectPattern, state: State): vo
/**
* Print one property of an object pattern, in shorthand where the key and the binding agree.
*
* @param node - Binding property
* @param state - Printer state
*/
function printBindingProperty(node: ESTree.BindingProperty, state: State): void {
// Shorthand is re-derived from names (matching Oxc), not from the flag.
@@ -129,6 +138,9 @@ function printBindingProperty(node: ESTree.BindingProperty, state: State): void
*
* The caller decides between this and printing the key as an expression in brackets,
* because whether a key must be computed depends on what it is, not on how the source wrote it.
*
* @param key - Property key
* @param state - Printer state
*/
export function printPropertyKey(key: ESTree.PropertyKey, state: State): void {
switch (key.type) {
@@ -153,6 +165,9 @@ export function printPropertyKey(key: ESTree.PropertyKey, state: State): void {
/**
* Print an array destructuring pattern, holes and rest element included.
*
* @param node - Array pattern
* @param state - Printer state
*/
function printArrayBindingPattern(node: ESTree.ArrayPattern, state: State): void {
// Oxc stores the rest element separately from the other elements.
+23
View File
@@ -49,6 +49,9 @@ import type * as ESTree from "../../../../npm/oxc-types/types.d.ts";
*
* A class expression is parenthesized where the statement or an `export default` starts with it,
* as `printFunction` does for functions.
*
* @param node - Class
* @param state - Printer state
*/
export function printClass(node: ESTree.Class, state: State): void {
let wrap = false;
@@ -117,6 +120,9 @@ export function printClass(node: ESTree.Class, state: State): void {
/**
* Print a run of decorators separated by spaces, parenthesizing any whose expression needs it.
*
* @param decorators - Decorators
* @param state - Printer state
*/
export function printDecorators(decorators: ESTree.Decorator[], state: State): void {
const { length } = decorators;
@@ -140,6 +146,8 @@ export function printDecorators(decorators: ESTree.Decorator[], state: State): v
*
* The grammar allows a name, a chain of plain member accesses, and a call on either, and nothing
* else - so a computed access needs parentheses even though a static one does not.
*
* @param expr - Decorator's expression
*/
function decoratorNeedsWrap(expr: ESTree.Expression): boolean {
for (;;) {
@@ -160,6 +168,9 @@ function decoratorNeedsWrap(expr: ESTree.Expression): boolean {
/**
* Print the members of a class in braces, empty ones tight.
*
* @param node - Class body
* @param state - Printer state
*/
function printClassBody(node: ESTree.ClassBody, state: State): void {
const { body } = node;
@@ -223,6 +234,9 @@ function printClassBody(node: ESTree.ClassBody, state: State): void {
/**
* Print a method, including getters, setters, constructors and their modifiers.
*
* @param node - Method definition
* @param state - Printer state
*/
function printMethodDefinition(node: MethodDefinitionNode, state: State): void {
markMapStart(state, node.start, node.end, node);
@@ -295,6 +309,9 @@ function printMethodDefinition(node: MethodDefinitionNode, state: State): void {
/**
* Print a class field, with its modifiers and initializer.
*
* @param node - Property definition
* @param state - Printer state
*/
function printPropertyDefinition(node: PropertyDefinitionNode, state: State): void {
markMapStart(state, node.start, node.end, node);
@@ -356,6 +373,9 @@ function printPropertyDefinition(node: PropertyDefinitionNode, state: State): vo
*
* Its body has no directive prologue, unlike a function body, so a string statement at the top of
* one needs no protection from being read back as a directive.
*
* @param node - Static block
* @param state - Printer state
*/
function printStaticBlock(node: ESTree.StaticBlock, state: State): void {
printSpaceBeforeIdentifier(state);
@@ -386,6 +406,9 @@ function printStaticBlock(node: ESTree.StaticBlock, state: State): void {
/**
* Print an `accessor` field.
*
* @param node - Accessor property
* @param state - Printer state
*/
function printAccessorProperty(node: AccessorPropertyNode, state: State): void {
markMapStart(state, node.start, node.end, node);
@@ -293,6 +293,10 @@ export function printExpression(
* Two shapes need more than precedence to stay valid:
* 1. A bare `let` as the object.
* 2. Member access straight onto an integer literal.
*
* @param node - Member expression
* @param state - Printer state
* @param ctx - `CTX_*` flags describing the enclosing position
*/
export function printMemberExpression(
node: ESTree.MemberExpression,
@@ -350,6 +354,11 @@ export function printMemberExpression(
*
* Writing that paren also re-marks the start of a statement or of an `export default`,
* so the callee inside the parens is still read as the leftmost token of the construct.
*
* @param node - Call expression
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
* @param ctx - `CTX_*` flags describing the enclosing position
*/
function printCallExpression(
node: ESTree.CallExpression,
@@ -388,6 +397,10 @@ function printCallExpression(
* The argument list shared by `printCallExpression` and `printNewExpression`.
*
* Arguments print at `PREC_COMMA`, so a sequence expression parenthesizes itself instead of reading as more arguments.
*
* @param node - Call, `new` expression or V8 runtime call the arguments belong to, which the closing `)` is mapped to
* @param args - Arguments
* @param state - Printer state
*/
function printArguments(
node: ESTree.CallExpression | ESTree.NewExpression | ESTree.V8IntrinsicExpression,
@@ -420,6 +433,10 @@ function printArguments(
* It sits at the `in` operator's own level, so it wraps from `PREC_COMPARE` upwards. The right
* operand also prints at `PREC_COMPARE`, preserving parentheses around relational and
* lower-precedence expressions, with `CTX_FORBID_IN` set.
*
* @param node - Private-in expression
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
*/
export function printPrivateInExpression(
node: ESTree.PrivateInExpression,
@@ -443,6 +460,9 @@ export function printPrivateInExpression(
*
* Layout follows the property count alone - two or more break across lines, exactly one prints
* inside spaces on a single line, and none gives `{}`.
*
* @param node - Object expression
* @param state - Printer state
*/
function printObjectExpression(node: ESTree.ObjectExpression, state: State): void {
debugAssertLastFresh(state);
@@ -485,6 +505,9 @@ function printObjectExpression(node: ESTree.ObjectExpression, state: State): voi
*
* Shorthand and computed-ness are both worked out here rather than taken from the AST,
* so the output stays valid however a transform left those flags.
*
* @param node - Object property or spread element
* @param state - Printer state
*/
function printObjectProperty(node: ESTree.ObjectPropertyKind, state: State): void {
if (node.type === "SpreadElement") {
@@ -610,6 +633,9 @@ function printObjectProperty(node: ESTree.ObjectPropertyKind, state: State): voi
*
* Holes print as nothing between the commas, and a hole in final position needs one further comma
* written after it, since `[a,]` holds one element and `[a,,]` holds two.
*
* @param node - Array expression
* @param state - Printer state
*/
function printArrayExpression(node: ESTree.ArrayExpression, state: State): void {
const { elements } = node;
@@ -688,6 +714,11 @@ function printAssignmentExpression(
*
* The operator's own category is recorded as it is written, which is how an adjacent `+` or `-`
* knows to leave a space rather than glue into `---x`.
*
* @param node - Update expression
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
* @param ctx - `CTX_*` flags describing the enclosing position
*/
function printUpdateExpression(
node: ESTree.UpdateExpression,
@@ -721,6 +752,11 @@ function printUpdateExpression(
*
* A `!` written straight after a `<` records a category of its own, so that a `--`
* printed next is spaced off it and cannot complete `<!--`.
*
* @param node - Unary expression
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
* @param ctx - `CTX_*` flags describing the enclosing position
*/
function printUnaryExpression(
node: ESTree.UnaryExpression,
@@ -764,6 +800,11 @@ function printUnaryExpression(
*
* The consequent is fenced by the `?` and `:` either side of it, so it alone never needs
* the `in` restriction passed down.
*
* @param node - Conditional expression
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
* @param ctx - `CTX_*` flags describing the enclosing position
*/
function printConditionalExpression(
node: ESTree.ConditionalExpression,
@@ -812,6 +853,11 @@ function printConditionalExpression(
* Wraps from `PREC_COMMA` upwards.
* `CTX_FORBID_CALL` is cleared for the elements, since every position which sets that flag
* also passes a precedence at or above `PREC_COMMA`, so the parens are already written by then.
*
* @param node - Sequence expression
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
* @param ctx - `CTX_*` flags describing the enclosing position
*/
function printSequenceExpression(
node: ESTree.SequenceExpression,
@@ -840,6 +886,11 @@ function printSequenceExpression(
* A concise body marks `last`, which is how an object literal body knows to parenthesize itself.
* A TS return type has to sit between the parameters and the arrow, so those are printed separately,
* instead of through `printParenParamsArrow`.
*
* @param node - Arrow function expression
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
* @param ctx - `CTX_*` flags describing the enclosing position
*/
function printArrowFunctionExpression(
node: ESTree.ArrowFunctionExpression,
@@ -884,6 +935,10 @@ function printArrowFunctionExpression(
*
* The callee prints at `PREC_NEW` with `CTX_FORBID_CALL`, so a call inside it parenthesizes itself,
* rather than being taken for this `new`'s own argument list.
*
* @param node - New expression
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
*/
function printNewExpression(node: ESTree.NewExpression, state: State, precedence: number): void {
const wrap = precedence >= PREC_CALL;
@@ -903,6 +958,9 @@ function printNewExpression(node: ESTree.NewExpression, state: State, precedence
* is written before the loop and each iteration ends with the chunk after its substitution.
*
* Substitutions print from `PREC_LOWEST` with no context flags, since `${` and `}` fence them from everything around.
*
* @param node - Template literal
* @param state - Printer state
*/
function printTemplateLiteral(node: ESTree.TemplateLiteral, state: State): void {
writeWithMapNoLast(state, "`", node.start, node.end, node);
@@ -933,6 +991,8 @@ function printTemplateLiteral(node: ESTree.TemplateLiteral, state: State): void
*
* It also runs the `</script` escape, since a template can hold that sequence verbatim
* and would otherwise close a surrounding script element.
*
* @param quasi - Template element
*/
function templateQuasiRaw(quasi: ESTree.TemplateElement): string {
// Line terminators in template raws are normalized to LF at parse time.
@@ -945,6 +1005,11 @@ function templateQuasiRaw(quasi: ESTree.TemplateElement): string {
/**
* Wraps from `PREC_PREFIX` upwards like the other unary operators, and prints its argument
* at `PREC_EXPONENTIATION` - `await a ** b` does not parse, so the `**` takes parens.
*
* @param node - Await expression
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
* @param ctx - `CTX_*` flags describing the enclosing position
*/
function printAwaitExpression(
node: ESTree.AwaitExpression,
@@ -965,6 +1030,11 @@ function printAwaitExpression(
/**
* Wraps from `PREC_ASSIGN` upwards. The argument prints at `PREC_YIELD`, one level below assignment,
* so a nested `yield` or an assignment stays bare while a comma sequence parenthesizes.
*
* @param node - Yield expression
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
* @param ctx - `CTX_*` flags describing the enclosing position
*/
function printYieldExpression(
node: ESTree.YieldExpression,
@@ -994,6 +1064,11 @@ function printYieldExpression(
* attach the argument list to the `new`.
*
* A `phase` prints as `import.<phase>(...)`, and import options follow the source as a second argument.
*
* @param node - Import expression
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
* @param ctx - `CTX_*` flags describing the enclosing position
*/
function printImportExpression(
node: ESTree.ImportExpression,
@@ -1030,6 +1105,11 @@ function printImportExpression(
* From `PREC_POSTFIX` upwards, or under `CTX_FORBID_CALL`, the whole chain is parenthesized
* and printed from `PREC_LOWEST` - the chain has to stop at the paren, instead of running on
* into the enclosing member access or `new`.
*
* @param node - Chain expression
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
* @param ctx - `CTX_*` flags describing the enclosing position
*/
function printChainExpression(
node: ESTree.ChainExpression,
@@ -1052,6 +1132,11 @@ function printChainExpression(
*
* Parenthesized wherever a postfix operator follows it - a member access, a call or a tagged template -
* and under `new`, as `oxc_codegen` does: `(%DebugPrint(x)).y`.
*
* @param node - V8 runtime call
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
* @param ctx - `CTX_*` flags describing the enclosing position
*/
function printV8IntrinsicExpression(
node: ESTree.V8IntrinsicExpression,
+4
View File
@@ -42,6 +42,8 @@ const SINK = { dummy: 0 };
* Flatten a rope in place.
*
* A no-op on a string which is already flat, apart from a short scan.
*
* @param s - String to flatten
*/
export function flattenString(s: string): void {
SINK.dummy ^= s.indexOf(" ");
@@ -81,6 +83,8 @@ export const OUTPUT_CHUNK_LENGTH = 16 * 1024;
* Flatten `output` into `state.outputChunks` and start a new chunk.
*
* The chunks array is created on the first spill, so a small print never allocates it.
*
* @param state - Printer state
*/
export function spillOutputChunk(state: State): void {
const { output } = state;
+15
View File
@@ -69,6 +69,9 @@ const ANONYMOUS_FUNCTION_PREFIXES = TS
*
* A function expression is parenthesized where the statement or an `export default` starts with it,
* since it would otherwise be read as a declaration.
*
* @param node - Function
* @param state - Printer state
*/
export function printFunction(node: ESTree.Function, state: State): void {
let wrap = false;
@@ -132,6 +135,9 @@ export function printFunction(node: ESTree.Function, state: State): void {
/**
* Print a parameter list in parentheses.
*
* @param params - Parameters
* @param state - Printer state
*/
export function printParenParams(params: ESTree.ParamPattern[], state: State): void {
// `(params)`, as a single write when there are none
@@ -150,6 +156,9 @@ export function printParenParams(params: ESTree.ParamPattern[], state: State): v
*
* TypeScript parameter properties carry the modifiers which make them a property as well as a
* parameter, and decorators can appear on either kind.
*
* @param params - Parameters
* @param state - Printer state
*/
function printParams(params: ESTree.ParamPattern[], state: State): void {
const { length } = params;
@@ -210,6 +219,9 @@ function printParams(params: ESTree.ParamPattern[], state: State): void {
*
* A function body has a directive prologue, so it goes through the same printer as a program does,
* rather than through the block statement printer.
*
* @param body - Function body
* @param state - Printer state
*/
export function printFunctionBody(body: ESTree.FunctionBody, state: State): void {
// `body` is a BlockStatement holding directives + statements.
@@ -233,6 +245,9 @@ export function printFunctionBody(body: ESTree.FunctionBody, state: State): void
* Print an arrow function's parameter list along with its `=>`.
*
* Oxc keeps the parentheses even around a lone parameter, so there is no single-parameter form.
*
* @param params - Parameters
* @param state - Printer state
*/
export function printParenParamsArrow(params: ESTree.ParamPattern[], state: State): void {
// `(params) => `, as a single write when there are none
+5
View File
@@ -16,6 +16,8 @@ import type { State } from "../state.ts";
* Write the indentation for the current level, or the pending single space in place of it.
*
* Inline statement bodies ask for a space where an indent would go, which keeps `if (x) foo()` on one line.
*
* @param state - Printer state
*/
export function printIndent(state: State): void {
// Flatten chunk if `state.output` has grown beyond limit.
@@ -41,6 +43,9 @@ export function printIndent(state: State): void {
* Extend the indent cache up to `level` and return the indent for it.
*
* Separate from `printIndent` so the cached lookup there stays small enough to inline.
*
* @param state - Printer state
* @param level - Indent level
*/
function growIndents(state: State, level: number): string {
const { indents, indentString } = state;
+21
View File
@@ -24,6 +24,9 @@ import type * as ESTree from "../../../../npm/oxc-types/types.d.ts";
*
* An element with no closing element is self-closing and gets ` />`, which is also the only place
* a space is required before the slash.
*
* @param node - JSX element
* @param state - Printer state
*/
export function printJSXElement(node: ESTree.JSXElement, state: State): void {
const { openingElement } = node;
@@ -68,6 +71,9 @@ export function printJSXElement(node: ESTree.JSXElement, state: State): void {
/**
* Print the name in an opening or closing tag - a name, a namespaced name, a member chain, or `this`.
*
* @param node - JSX element name, or `this`
* @param state - Printer state
*/
function printJSXElementName(
node: ESTree.JSXElementName | ESTree.ThisExpression,
@@ -103,6 +109,9 @@ function printJSXElementName(
/**
* Print one attribute, with its value where it has one - a bare attribute is `true`.
*
* @param node - JSX attribute
* @param state - Printer state
*/
function printJSXAttribute(node: ESTree.JSXAttribute, state: State): void {
// Attribute names never update `last`.
@@ -136,6 +145,9 @@ function printJSXAttribute(node: ESTree.JSXAttribute, state: State): void {
*
* A string value is printed from its raw text, not through the string escaper, because JSX attribute strings
* have no escape sequences - the quote is picked to suit the contents instead.
*
* @param node - JSX attribute value
* @param state - Printer state
*/
function printJSXAttributeValue(node: ESTree.JSXAttributeValue, state: State): void {
switch (node.type) {
@@ -173,6 +185,9 @@ function printJSXAttributeValue(node: ESTree.JSXAttributeValue, state: State): v
/**
* Print a `{ … }` container, which may hold nothing but a comment.
*
* @param node - JSX expression container
* @param state - Printer state
*/
function printJSXExpressionContainer(node: ESTree.JSXExpressionContainer, state: State): void {
write(state, "{", CAT_OTHER);
@@ -189,6 +204,9 @@ function printJSXExpressionContainer(node: ESTree.JSXExpressionContainer, state:
/**
* Print a `<>...</>` fragment.
*
* @param node - JSX fragment
* @param state - Printer state
*/
export function printJSXFragment(node: ESTree.JSXFragment, state: State): void {
writeWithMapNoLast(
@@ -220,6 +238,9 @@ export function printJSXFragment(node: ESTree.JSXFragment, state: State): void {
*
* Text is written from its raw source, since whitespace between elements is significant
* and any entities in it must survive untouched.
*
* @param node - JSX child
* @param state - Printer state
*/
function printJSXChild(node: ESTree.JSXChild, state: State): void {
switch (node.type) {
+17
View File
@@ -37,6 +37,11 @@ type LiteralNode =
*
* The kind is told apart by the type of `value` and by which extra property is present,
* since the node itself does not say.
*
* @param node - Literal
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
* @param ctx - `CTX_*` flags describing the enclosing position
*/
export function printLiteral(
node: LiteralNode,
@@ -84,6 +89,11 @@ export function printLiteral(
*
* In TypeScript positions the source text is printed back rather than the shortest form,
* so a type keeps the digits it was written with.
*
* @param node - Numeric literal
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
* @param ctx - `CTX_*` flags describing the enclosing position
*/
function printNumericLiteral(
node: ESTree.NumericLiteral,
@@ -152,6 +162,9 @@ function printNumericLiteral(
*
* A regex with no flags ends in `/`, which is recorded as its own category, because a `/`
* immediately after it would open a comment.
*
* @param node - Regular expression literal
* @param state - Printer state
*/
function printRegExpLiteral(node: ESTree.RegExpLiteral, state: State): void {
// Neither of the separating spaces below can be needed in pretty mode, so the check is not made.
@@ -193,6 +206,10 @@ function printRegExpLiteral(node: ESTree.RegExpLiteral, state: State): void {
*
* Also like `printNumericLiteral`, a negative one is spaced off a preceding `-` or `--`
* the same way a unary minus is, so `-(-1n)` prints as `- -1n`, not `--1n`.
*
* @param node - BigInt literal
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
*/
function printBigIntLiteral(node: ESTree.BigIntLiteral, state: State, precedence: number): void {
const value = node.bigint;
+17
View File
@@ -29,6 +29,9 @@ import type * as ESTree from "../../../../npm/oxc-types/types.d.ts";
*
* Default, namespace and named specifiers can be combined, and the named ones are the only kind in
* braces, so the braces are opened and closed around a run rather than around the whole list.
*
* @param node - Import declaration
* @param state - Printer state
*/
export function printImportDeclaration(node: ESTree.ImportDeclaration, state: State): void {
printIndent(state);
@@ -142,6 +145,9 @@ export function printImportDeclaration(node: ESTree.ImportDeclaration, state: St
*
* An empty clause is written where the AST says the source had one, since `with {}`
* and no clause are different programs.
*
* @param attributes - Import attributes, or `null` / `undefined` if there is no `with` clause
* @param state - Printer state
*/
function printImportAttributes(
attributes: ESTree.ImportAttribute[] | null | undefined,
@@ -188,6 +194,8 @@ function printImportAttributes(
* The name comes back because the caller compares the two sides to decide whether an `as` clause
* is needed at all, and it is cheaper to return it than to work it out twice.
*
* @param node - Module export name
* @param state - Printer state
* @returns The name printed
*/
function moduleExportName(node: ESTree.ModuleExportName, state: State): string {
@@ -204,6 +212,9 @@ function moduleExportName(node: ESTree.ModuleExportName, state: State): string {
/**
* Print an `export` statement which names what it exports, whether that is a declaration,
* a list of specifiers, or a list re-exported from another module.
*
* @param node - Export named declaration
* @param state - Printer state
*/
export function printExportNamedDeclaration(
node: ESTree.ExportNamedDeclaration,
@@ -310,6 +321,9 @@ export function printExportNamedDeclaration(
/**
* Print `export * from "…"`, with the `as name` form where the AST has one.
*
* @param node - Export all declaration
* @param state - Printer state
*/
export function printExportAllDeclaration(node: ESTree.ExportAllDeclaration, state: State): void {
printIndent(state);
@@ -339,6 +353,9 @@ export function printExportAllDeclaration(node: ESTree.ExportAllDeclaration, sta
*
* The output position is recorded before the value is printed, so that a function or class expression
* starting there knows to parenthesize itself.
*
* @param node - Export default declaration
* @param state - Printer state
*/
export function printExportDefaultDeclaration(
node: ESTree.ExportDefaultDeclaration,
+12
View File
@@ -24,6 +24,12 @@ import type * as ESTree from "../../../../npm/oxc-types/types.d.ts";
* `CAT_INT_DIGIT` goes only on plain digits. It is what forces the space in `0 .toExponential()`,
* and every other form ends in, or contains, a `.`, an `e` or an `x` which separates it
* from a following `.` already.
*
* @param state - Printer state
* @param value - Number to print, finite and not negative
* @param start - Start offset of `node` in the source, for the source mapping
* @param end - End offset of `node` in the source, for the source mapping
* @param node - Node the number is mapped to
*/
export function printNonNegativeFloat(
state: State,
@@ -50,6 +56,9 @@ export function printNonNegativeFloat(
*
* `String` gives plain digits below 1e21 and exponent notation from there up, which have different forms
* available to them, so they are separate cases. Both can go hexadecimal.
*
* @param state - Printer state
* @param value - Integer to print, 1000 or more
*/
function printShortestInteger(state: State, value: number): void {
const formatted = String(value);
@@ -90,6 +99,9 @@ function printShortestInteger(state: State, value: number): void {
* `String` gives `0.<digits>` from 1e-7 up to 1, `<digits>.<digits>` from 1 up, and exponent notation
* below 1e-7. The first always loses its leading zero, and may trade a run of zeros after the point
* for a negative exponent. The second is already as short as it gets.
*
* @param state - Printer state
* @param value - Non-integer to print
*/
function printShortestFraction(state: State, value: number): void {
const formatted = String(value);
@@ -128,6 +128,8 @@ export const PADDED_ASSIGN_OPERATORS = {
* to decide whether the next operator needs separating.
*
* `typeof`, `void` and `delete` never reach here - they end in an identifier character and are handled as words.
*
* @param operator - Unary operator
*/
export function unaryOperatorCode(operator: string): Category {
debugAssert(!["typeof", "void", "delete"].includes(operator));
@@ -146,6 +148,8 @@ export function unaryOperatorCode(operator: string): Category {
/**
* The category `++` or `--` leaves in `last`, as `unaryOperatorCode` does for unary operators.
*
* @param operator - `++` or `--`
*/
export function updateOperatorCode(operator: string): Category {
return operator === "++" ? CAT_OP_UPD_INC : CAT_OP_UPD_DEC;
+2
View File
@@ -7,6 +7,8 @@ import type * as ESTree from "../../../../npm/oxc-types/types.d.ts";
*
* Parsing with `preserveParens: false` produces none of these, but the printer accepts an AST
* which has them, and decides parenthesisation from precedence rather than from what the source had.
*
* @param node - Expression
*/
export function withoutParens(node: ESTree.Expression): ESTree.Expression {
while (node.type === "ParenthesizedExpression") {
@@ -280,6 +280,8 @@ export function generateSourceMap(state: State, output: string, options: Options
/**
* Build UTF-16 offsets to the start of every ECMAScript source line.
*
* @param sourceText - Source text
*/
function getLineStarts(sourceText: string): number[] {
const lineStarts = [0];
@@ -294,6 +296,10 @@ function getLineStarts(sourceText: string): number[] {
/**
* Find the source line containing `sourceOffset`, starting close to the previous result.
*
* @param lineStarts - Offset of the start of every source line, from `getLineStarts`
* @param sourceOffset - UTF-16 offset in the source
* @param previousLine - Line the previous call found, where the search starts
*/
function findSourceLine(lineStarts: number[], sourceOffset: number, previousLine: number): number {
// Source mappings normally advance through the original file. Search the next few lines linearly,
@@ -324,6 +330,10 @@ function findSourceLine(lineStarts: number[], sourceOffset: number, previousLine
/**
* Write one signed source-map delta as base64 VLQ, returning the next buffer position.
*
* @param buffer - Buffer to write into
* @param index - Position in `buffer` to write at
* @param value - Signed delta to write
*/
function writeVlq(buffer: Uint8Array, index: number, value: number): number {
let vlq = value < 0 ? -value * 2 + 1 : value * 2;
@@ -352,6 +362,9 @@ function writeVlq(buffer: Uint8Array, index: number, value: number): number {
* Grow the mappings buffer by doubling, preserving its written prefix.
*
* The returned buffer is guaranteed to have at least `MAX_MAPPING_SEGMENT_LENGTH` spare capacity.
*
* @param buffer - Mappings buffer
* @param writtenLength - Number of bytes written to `buffer` so far, which are copied into the new buffer
*/
function growMappingBuffer(buffer: Uint8Array, writtenLength: number): Uint8Array {
// Buffer starts with at least `MIN_MAPPING_BUFFER_LENGTH` bytes capacity.
@@ -364,6 +377,10 @@ function growMappingBuffer(buffer: Uint8Array, writtenLength: number): Uint8Arra
/**
* Find the UTF-16 offset after the next ECMAScript line terminator.
*
* @param output - Text to search - the generated code or the source text
* @param from - UTF-16 offset to search from
* @param useLineFeedFastPath - `true` if `\n` is the only line terminator to search for
*/
function findNextLineStart(output: string, from: number, useLineFeedFastPath: boolean): number {
if (useLineFeedFastPath) {
@@ -380,6 +397,8 @@ function findNextLineStart(output: string, from: number, useLineFeedFastPath: bo
/**
* Whether output contains a line terminator other than `\n`.
*
* @param output - Generated code
*/
function hasUncommonLineTerminator(output: string): boolean {
// V8's specialized substring search is substantially faster than a regexp scan here, even when
@@ -393,6 +412,8 @@ function hasUncommonLineTerminator(output: string): boolean {
/**
* Whether every source line terminator can be found by searching for `\n`.
*
* @param sourceText - Source text
*/
function hasOnlyLineFeedsAndCrLf(sourceText: string): boolean {
if (sourceText.indexOf("\u2028") !== -1 || sourceText.indexOf("\u2029") !== -1) return false;
+2
View File
@@ -41,6 +41,8 @@ if (DEBUG) {
* Call it before writing anything starting with an identifier character - a name, a keyword, or a
* number. The categories needing the space are the lowest codes in the numbering, so the test is
* one compare.
*
* @param state - Printer state
*/
export function printSpaceBeforeIdentifier(state: State): void {
debugAssertLastFresh(state);
@@ -51,6 +51,9 @@ import type * as ESTree from "../../../../npm/oxc-types/types.d.ts";
/**
* Entry point for a whole file.
* A hashbang is written ahead of everything else, since it is only legal on the first line.
*
* @param node - Program
* @param state - Printer state
*/
export function printProgram(node: ESTree.Program, state: State): void {
if (node.hashbang != null) {
@@ -68,6 +71,9 @@ export function printProgram(node: ESTree.Program, state: State): void {
*
* The handover is the delicate part - a string literal statement arriving right after the prologue
* has to be kept from being read back as one more directive.
*
* @param body - Directives and statements
* @param state - Printer state
*/
export function printDirectivesAndStatements(
body: Array<ESTree.Directive | ESTree.Statement>,
@@ -122,6 +128,9 @@ export function printDirectivesAndStatements(
* Directives print from their raw source text, so the quote has to be chosen to suit the text
* rather than the other way round - the scan takes the first unescaped `"` or `'` and quotes with
* the other one.
*
* @param stmt - Directive
* @param state - Printer state
*/
function printDirective(stmt: ESTree.Directive, state: State): void {
printIndent(state);
@@ -155,6 +164,9 @@ function printDirective(stmt: ESTree.Directive, state: State): void {
*
* Each case owns its own leading indent and its trailing newline, so a statement always leaves
* the output at the start of a fresh line for the next one.
*
* @param node - Statement
* @param state - Printer state
*/
export function printStatement(node: ESTree.Statement, state: State): void {
// Arms are ordered roughly in order of most common nodes.
@@ -340,6 +352,9 @@ export function printStatement(node: ESTree.Statement, state: State): void {
* printed there knows to parenthesize itself.
*
* The indent is written first, so the mark is the last thing to touch `last` before the expression.
*
* @param node - Expression statement
* @param state - Printer state
*/
function printExpressionStatement(node: ESTree.ExpressionStatement, state: State): void {
const mapsIndent = state.indentLevel > 0 || state.pendingIndentAsSpace;
@@ -410,6 +425,9 @@ export function printVariableDeclaration(
*
* Nothing is written before the opening brace or after the closing one, so callers can attach
* ` else`, ` catch` or a newline themselves.
*
* @param block - Block statement
* @param state - Printer state
*/
function printBlockStatement(block: ESTree.BlockStatement, state: State): void {
const { body } = block;
@@ -438,6 +456,9 @@ function printBlockStatement(block: ESTree.BlockStatement, state: State): void {
*
* A non-block consequent which trails off into a dangling `if` is given braces, so a following
* `else` cannot attach to the wrong one - see `wrapToAvoidAmbiguousElse`.
*
* @param node - If statement
* @param state - Printer state
*/
function printIf(node: ESTree.IfStatement, state: State): void {
printSpaceBeforeIdentifier(state);
@@ -490,6 +511,8 @@ function printIf(node: ESTree.IfStatement, state: State): void {
*
* Only the trailing position is followed - a loop, `with` or label body, and an `if` alternate -
* since that is where a following `else` would land.
*
* @param stmt - Statement
*/
function wrapToAvoidAmbiguousElse(stmt: ESTree.Statement): boolean {
for (;;) {
@@ -515,6 +538,9 @@ function wrapToAvoidAmbiguousElse(stmt: ESTree.Statement): boolean {
/**
* With an argument the space after `return` is part of the same write.
* With none, the keyword is recorded as an identifier, so anything printed after it keeps a separating space.
*
* @param node - Return statement
* @param state - Printer state
*/
function printReturnStatement(node: ESTree.ReturnStatement, state: State): void {
printIndent(state);
@@ -534,6 +560,9 @@ function printReturnStatement(node: ESTree.ReturnStatement, state: State): void
/**
* The catch binding is optional, so an absent `param` prints a bare `catch` block rather than an empty pair of parens.
* The handler and the finalizer are each written only if present.
*
* @param node - Try statement
* @param state - Printer state
*/
function printTryStatement(node: ESTree.TryStatement, state: State): void {
printIndent(state);
@@ -568,6 +597,9 @@ function printTryStatement(node: ESTree.TryStatement, state: State): void {
/**
* A switch with no cases prints as `{}` on the same line. Otherwise the cases sit one level in,
* and each indents its own statements again - see `printSwitchCase`.
*
* @param node - Switch statement
* @param state - Printer state
*/
function printSwitchStatement(node: ESTree.SwitchStatement, state: State): void {
printIndent(state);
@@ -600,6 +632,9 @@ function printSwitchStatement(node: ESTree.SwitchStatement, state: State): void
/**
* A case with exactly one statement hands it to `printBody`, which keeps it on the line of the `case`.
* Any other count goes onto separate lines a level deeper, so an empty case prints as just its label.
*
* @param node - Switch case
* @param state - Printer state
*/
function printSwitchCase(node: ESTree.SwitchCase, state: State): void {
printIndent(state);
@@ -633,6 +668,9 @@ function printSwitchCase(node: ESTree.SwitchCase, state: State): void {
/**
* The test is fenced by its own parens, so it prints from `PREC_LOWEST` with no context flags,
* and the body goes through `printBody` like every other loop here.
*
* @param node - While statement
* @param state - Printer state
*/
function printWhileStatement(node: ESTree.WhileStatement, state: State): void {
printIndent(state);
@@ -651,6 +689,9 @@ function printWhileStatement(node: ESTree.WhileStatement, state: State): void {
* with the `while` returned to the outer level.
*
* The closing `);` is always written out rather than left to ASI.
*
* @param node - Do-while statement
* @param state - Printer state
*/
function printDoWhileStatement(node: ESTree.DoWhileStatement, state: State): void {
printIndent(state);
@@ -686,6 +727,9 @@ function printDoWhileStatement(node: ESTree.DoWhileStatement, state: State): voi
*
* An absent test or update still writes its `;`, which is why those cases fold the separator,
* and for the update the closing paren too, into a single write.
*
* @param node - For statement
* @param state - Printer state
*/
function printForStatement(node: ESTree.ForStatement, state: State): void {
printIndent(state);
@@ -724,6 +768,9 @@ function printForStatement(node: ESTree.ForStatement, state: State): void {
/**
* The left side is either a declaration or an assignment target. A declaration prints with `CTX_FORBID_IN`,
* so an `in` inside its initializer parenthesizes itself instead of ending the head early.
*
* @param node - For-in statement
* @param state - Printer state
*/
function printForInStatement(node: ESTree.ForInStatement, state: State): void {
printIndent(state);
@@ -752,6 +799,9 @@ function printForInStatement(node: ESTree.ForInStatement, state: State): void {
*
* Nothing here needs `CTX_FORBID_IN`, unlike the `for` and `for-in` heads, and the right side
* prints at `PREC_COMMA` so a sequence takes parens.
*
* @param node - For-of statement
* @param state - Printer state
*/
function printForOfStatement(node: ESTree.ForOfStatement, state: State): void {
printIndent(state);
@@ -790,6 +840,10 @@ function printForOfStatement(node: ESTree.ForOfStatement, state: State): void {
*
* The restriction for `let` is on the first token of the head rather than on the target as a whole,
* so this walks down the leftmost spine - through member objects and parens - to whatever prints first.
*
* @param left - Left side of the `for of` head
* @param leftType - `left.type`
* @param wrapAsync - `true` if a bare `async` needs wrapping, which it does unless the loop is `for await`
*/
function forOfHeadNeedsWrapping(
left: ESTree.AssignmentTarget | ESTree.Expression,
@@ -839,6 +893,9 @@ function forOfHeadNeedsWrapping(
* A block is attached with a space and closed with a newline, an empty statement collapses to `;`,
* and anything else sets `pendingIndentAsSpace`, so its indent prints as a single space and it stays
* on the current line.
*
* @param stmt - Statement
* @param state - Printer state
*/
function printBody(stmt: ESTree.Statement, state: State): void {
const stmtType = stmt.type;
+11
View File
@@ -22,6 +22,12 @@ const STRING_ESCAPE_REGEX =
*
* Pretty mode always uses double quotes, matching Oxc's default options, so there is no quote to choose.
* Almost no string needs escaping, so the scan for characters or sequences which do is all that happens on the common path.
*
* @param state - Printer state
* @param value - String to print
* @param start - Start offset of `node` in the source, for the source mapping
* @param end - End offset of `node` in the source, for the source mapping
* @param node - Node the string is mapped to
*/
export function printString(
state: State,
@@ -48,6 +54,9 @@ export function printString(
*
* Runs of ordinary characters are copied in chunks rather than one at a time, so the cost is in
* the escapes rather than the length. Kept out of `printString` because it almost never runs.
*
* @param state - Printer state
* @param value - String to print, which needs escaping
*/
function printEscapedStringContents(state: State, value: string): void {
let chunkStart = 0;
@@ -146,6 +155,8 @@ function printEscapedStringContents(state: State, value: string): void {
*
* For template literal quasis, which are printed from their raw text and so never pass through the
* string escaper.
*
* @param text - Raw text
*/
export function escapeScriptCloseTag(text: string): string {
if (!text.includes("</")) return text;
+108
View File
@@ -50,6 +50,11 @@ import type * as ESTree from "../../../../npm/oxc-types/types.d.ts";
* The operand prints at `PREC_EXPONENTIATION`, which leaves a unary operand unwrapped while still parenthesizing
* anything looser, and the whole expression is wrapped once the surrounding precedence reaches `PREC_COMPARE`,
* which is where `as` binds.
*
* @param node - TS `as` or `satisfies` expression
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
* @param ctx - `CTX_*` flags describing the enclosing position
*/
export function printTSAsOrSatisfiesExpression(
node: ESTree.TSAsExpression | ESTree.TSSatisfiesExpression,
@@ -76,6 +81,9 @@ export function printTSAsOrSatisfiesExpression(
*
* A prefix `TSJSDocNullableType` spaces itself off a preceding `?`, as `?` followed by `?T`
* would otherwise merge into `??`.
*
* @param node - TS type
* @param state - Printer state
*/
function printTSType(node: ESTree.TSTupleElement | ESTree.TSQualifiedName, state: State): void {
switch (node.type) {
@@ -286,6 +294,9 @@ function printTSType(node: ESTree.TSTupleElement | ESTree.TSQualifiedName, state
* takes the space-before-identifier check - every other segment follows a `.`.
*
* `this` is one of the names a qualified name can be rooted at, hence the `ThisExpression` arm.
*
* @param node - TS type name
* @param state - Printer state
*/
function printTSTypeName(
node: ESTree.TSTypeName | ESTree.IdentifierName | ESTree.BindingIdentifier,
@@ -308,6 +319,9 @@ function printTSTypeName(
* The `<...>` on a type reference, call, `new` expression or JSX element name.
* Every one of those sites has the list as an optional field, so the null check lives here
* rather than at each call site.
*
* @param typeArguments - Type arguments, or `null` / `undefined` if there are none
* @param state - Printer state
*/
export function printTypeArguments(
typeArguments: ESTree.TSTypeParameterInstantiation | null | undefined,
@@ -332,6 +346,9 @@ export function printTypeArguments(
* print its raw text instead of a reformatted value.
*
* A unary operand such as `-1` prints at `PREC_COMMA` precedence so it is not wrapped, as in Oxc.
*
* @param literal - Literal type's literal
* @param state - Printer state
*/
function printTSLiteral(literal: ESTree.TSLiteral, state: State): void {
// A literal type holds a `Literal`, a `TemplateLiteral` or a `UnaryExpression` and nothing else,
@@ -352,6 +369,9 @@ function printTSLiteral(literal: ESTree.TSLiteral, state: State): void {
/**
* Members joined with `|`, each wrapped where `parenthesizeTypeOfUnionType` says so.
* No leading `|` is printed, so a union node holding a single member prints as that member alone.
*
* @param node - TS union type
* @param state - Printer state
*/
function printTSUnionType(node: ESTree.TSUnionType, state: State): void {
const { types } = node;
@@ -374,6 +394,8 @@ function printTSUnionType(node: ESTree.TSUnionType, state: State): void {
* `oxc_codegen` decides here whether a type prints starting with a non-identifier character,
* so a preceding keyword needs no separating space. In pretty mode a space is printed either way,
* so nothing computes it.
*
* @param ty - Union member
*/
function parenthesizeTypeOfUnionType(ty: ESTree.TSType): boolean {
switch (ty.type) {
@@ -392,6 +414,9 @@ function parenthesizeTypeOfUnionType(ty: ESTree.TSType): boolean {
/**
* The `&` counterpart of `printTSUnionType`, down to reusing the union's wrapping rule for members
* which are not themselves intersections.
*
* @param node - TS intersection type
* @param state - Printer state
*/
function printTSIntersectionType(node: ESTree.TSIntersectionType, state: State): void {
const { types } = node;
@@ -410,6 +435,8 @@ function printTSIntersectionType(node: ESTree.TSIntersectionType, state: State):
* A nested intersection of more than one member is wrapped, and anything else falls through to
* `parenthesizeTypeOfUnionType` - which is what parenthesizes a union inside an intersection, where
* `&` binds tighter than `|`.
*
* @param ty - Intersection member
*/
function parenthesizeTypeOfIntersectionType(ty: ESTree.TSType): boolean {
if (ty.type === "TSIntersectionType") return ty.types.length > 1;
@@ -420,6 +447,8 @@ function parenthesizeTypeOfIntersectionType(ty: ESTree.TSType): boolean {
* The wrapping rule for the operand of a postfix construct - `T[]`, `T[K]` and a tuple's `T?`. All of
* those bind tighter than the listed types, so an unwrapped operand would re-parse with the postfix
* applied to only its last member.
*
* @param ty - Operand of the postfix construct
*/
function parenthesizeTypeOfPostfixType(ty: ESTree.TSType): boolean {
switch (ty.type) {
@@ -439,6 +468,9 @@ function parenthesizeTypeOfPostfixType(ty: ESTree.TSType): boolean {
/**
* An empty type literal collapses to `{}`. Otherwise every member goes on its own indented line closed
* with `;`, and the closing brace is indented back to the level of whatever contains it.
*
* @param node - TS type literal
* @param state - Printer state
*/
function printTSTypeLiteral(node: ESTree.TSTypeLiteral, state: State): void {
const { members } = node;
@@ -469,6 +501,10 @@ function printTSTypeLiteral(node: ESTree.TSTypeLiteral, state: State): void {
*
* Accessor signatures keep their `get`/`set` prefix, index signatures go to `printTSIndexSignature`,
* and an unrecognized member type throws.
*
* @param node - TS signature
* @param state - Printer state
* @param ctx - `CTX_*` flags describing the enclosing position
*/
function printTSSignature(node: ESTree.TSSignature, state: State, ctx: number): void {
switch (node.type) {
@@ -529,6 +565,10 @@ function printTSSignature(node: ESTree.TSSignature, state: State, ctx: number):
* A signature's key.
* A string key is re-printed by `printString` rather than passed to the expression printer,
* so it comes out in the printer's own quotes instead of whatever the source used.
*
* @param key - Signature's key
* @param state - Printer state
* @param ctx - `CTX_*` flags describing the enclosing position
*/
function printSignatureKey(key: ESTree.PropertyKey, state: State, ctx: number): void {
switch (key.type) {
@@ -555,6 +595,9 @@ function printSignatureKey(key: ESTree.PropertyKey, state: State, ctx: number):
* The `: T` half of an annotated binding, parameter, property or return type.
* Takes the wrapper node the AST stores rather than the type inside it, so a caller
* can pass the field straight through.
*
* @param annotation - Type annotation
* @param state - Printer state
*/
export function printTypeAnnotation(annotation: ESTree.TSTypeAnnotation, state: State): void {
write(state, ": ", CAT_OTHER);
@@ -565,6 +608,8 @@ export function printTypeAnnotation(annotation: ESTree.TSTypeAnnotation, state:
* TS-ESTree wraps types in a `TSTypeAnnotation` node.
* Fields vary in whether they hold that wrapper or a bare type, so every read which could be either
* goes through here instead of the callers knowing which.
*
* @param annotation - Type annotation, or a bare type
*/
function tsTypeAnnotationOf(annotation: ESTree.TSTypeAnnotation | ESTree.TSType): ESTree.TSType {
return annotation.type === "TSTypeAnnotation" ? annotation.typeAnnotation : annotation;
@@ -576,6 +621,9 @@ function tsTypeAnnotationOf(annotation: ESTree.TSTypeAnnotation | ESTree.TSType)
*
* ESTree models the parameter as a list, but an index signature has exactly one -
* Oxc's own AST stores a single parameter - so only the first entry is read.
*
* @param node - TS index signature
* @param state - Printer state
*/
export function printTSIndexSignature(node: ESTree.TSIndexSignature, state: State): void {
if (node.static) write(state, "static ", CAT_OTHER);
@@ -600,6 +648,9 @@ export function printTSIndexSignature(node: ESTree.TSIndexSignature, state: Stat
* Two or more parameters print one per indented line while a single one stays inline,
* which is Oxc's rule rather than a decision taken from the printed width.
* As with `printTypeArguments`, a missing list is not an error.
*
* @param typeParameters - Type parameters, or `null` / `undefined` if there are none
* @param state - Printer state
*/
export function printTypeParameters(
typeParameters: ESTree.TSTypeParameterDeclaration | null | undefined,
@@ -641,6 +692,9 @@ export function printTypeParameters(
/**
* One type parameter with its modifiers, constraint and default. The modifiers are independent flags, so
* the fixed print order here - `const`, `in`, `out` - is what gives them an order at all.
*
* @param node - TS type parameter
* @param state - Printer state
*/
function printTSTypeParameter(node: ESTree.TSTypeParameter, state: State): void {
// No `printSpaceBeforeIdentifier` needed, either here or before the name.
@@ -675,6 +729,9 @@ function printTSTypeParameter(node: ESTree.TSTypeParameter, state: State): void
* `<T>(a: A) => R`.
* The arrow comes from `printParenParamsArrow`, so the return type is printed as a bare type
* rather than through `printTypeAnnotation`, which would put a `:` in front of it.
*
* @param node - TS function type
* @param state - Printer state
*/
function printTSFunctionType(node: ESTree.TSFunctionType, state: State): void {
printTypeParameters(node.typeParameters, state);
@@ -687,6 +744,9 @@ function printTSFunctionType(node: ESTree.TSFunctionType, state: State): void {
* Anything else falls through to `printTSType`.
*
* The optional form borrows the postfix wrapping rule, since a trailing `?` binds as tightly as `[]`.
*
* @param node - TS tuple element
* @param state - Printer state
*/
function printTSTupleElement(node: ESTree.TSTupleElement, state: State): void {
switch (node.type) {
@@ -717,6 +777,9 @@ function printTSTupleElement(node: ESTree.TSTupleElement, state: State): void {
* `C extends E ? T : F`. The check type is wrapped when it is a function, constructor or conditional
* type, and the extends type only when it is itself conditional - otherwise its `?` would be read as
* this conditional's.
*
* @param node - TS conditional type
* @param state - Printer state
*/
function printTSConditionalType(node: ESTree.TSConditionalType, state: State): void {
const { checkType, extendsType } = node;
@@ -751,6 +814,9 @@ function printTSConditionalType(node: ESTree.TSConditionalType, state: State): v
* and the type annotation is optional.
*
* The braces are padded with spaces and the whole type stays on one line, however large it is.
*
* @param node - TS mapped type
* @param state - Printer state
*/
function printTSMappedType(node: ESTree.TSMappedType, state: State): void {
writeNoLast(state, "{ ");
@@ -798,6 +864,9 @@ function printTSMappedType(node: ESTree.TSMappedType, state: State): void {
* `keyof T`, `unique symbol` and `readonly T[]`. The operator is written as an identifier so a keyword
* before it keeps its separating space, and the operand is wrapped where the operator would otherwise
* bind to only part of it.
*
* @param node - TS type operator
* @param state - Printer state
*/
function printTSTypeOperator(node: ESTree.TSTypeOperator, state: State): void {
writeIdent(state, node.operator);
@@ -821,6 +890,9 @@ function printTSTypeOperator(node: ESTree.TSTypeOperator, state: State): void {
/**
* `x is T`, with the optional `asserts` prefix.
* The `is T` half is optional too, which is what makes a bare `asserts x` print.
*
* @param node - TS type predicate
* @param state - Printer state
*/
function printTSTypePredicate(node: ESTree.TSTypePredicate, state: State): void {
if (node.asserts) write(state, "asserts ", CAT_OTHER);
@@ -848,6 +920,9 @@ function printTSTypePredicate(node: ESTree.TSTypePredicate, state: State): void
/**
* The operand of `typeof`, which is a name in every case but `import("...")` -
* an import type can stand where a name would.
*
* @param node - TS type query expression name
* @param state - Printer state
*/
function printTSTypeQueryExprName(node: ESTree.TSTypeQueryExprName, state: State): void {
if (node.type === "TSImportType") {
@@ -865,6 +940,9 @@ function printTSTypeQueryExprName(node: ESTree.TSTypeQueryExprName, state: State
*
* The options argument prints at `PREC_LOWEST` through the expression printer,
* and both the qualifier and the type arguments are optional.
*
* @param node - TS import type
* @param state - Printer state
*/
function printTSImportType(node: ESTree.TSImportType, state: State): void {
write(state, "import(", CAT_OTHER);
@@ -890,6 +968,9 @@ function printTSImportType(node: ESTree.TSImportType, state: State): void {
* The dotted chain after `import(...)`.
* Every segment follows a `.` written by the caller, so unlike `printTSTypeName`,
* no space-before-identifier check is needed.
*
* @param node - TS import type qualifier
* @param state - Printer state
*/
function printTSImportTypeQualifier(node: ESTree.TSImportTypeQualifier, state: State): void {
if (node.type === "TSQualifiedName") {
@@ -907,6 +988,11 @@ function printTSImportTypeQualifier(node: ESTree.TSImportTypeQualifier, state: S
* A `<` written immediately before would merge into `<<`, so `last` is checked and a space inserted -
* Oxc does the same by looking at the last byte written. The operand prints at `PREC_EXPONENTIATION`,
* which leaves `<T>-x` unwrapped.
*
* @param node - TS type assertion
* @param state - Printer state
* @param precedence - Precedence of the position this expression sits in
* @param ctx - `CTX_*` flags describing the enclosing position
*/
export function printTSTypeAssertion(
node: ESTree.TSTypeAssertion,
@@ -937,6 +1023,9 @@ export function printTSTypeAssertion(
* `global` is the one kind with no name of its own, so nothing is printed where the id would go.
*
* A missing body is the declaration form and ends in `;` instead of a block.
*
* @param node - TS module or global declaration
* @param state - Printer state
*/
export function printTSModuleDeclaration(
node: ESTree.TSModuleDeclaration | ESTree.TSGlobalDeclaration,
@@ -971,6 +1060,9 @@ export function printTSModuleDeclaration(
/**
* The body of a namespace or module. It goes through `printDirectivesAndStatements` rather than a
* plain statement loop, so a directive prologue inside a module block is still recognized.
*
* @param body - Module block
* @param state - Printer state
*/
function printModuleBlock(body: ESTree.TSModuleBlock, state: State): void {
const statements = body.body;
@@ -997,6 +1089,9 @@ function printModuleBlock(body: ESTree.TSModuleBlock, state: State): void {
*
* The body uses the same one-member-per-line layout as `printTSTypeLiteral`,
* including the `{}` form when there are no members.
*
* @param node - TS interface declaration
* @param state - Printer state
*/
export function printTSInterfaceDeclaration(
node: ESTree.TSInterfaceDeclaration,
@@ -1053,6 +1148,9 @@ export function printTSInterfaceDeclaration(
* `type X<T> = ...`, including the `declare` form.
* An alias body is the one position where a type can need parentheses purely because of what it starts with -
* see `isLeftmostIntrinsicReference`.
*
* @param node - TS type alias declaration
* @param state - Printer state
*/
export function printTSTypeAliasDeclaration(
node: ESTree.TSTypeAliasDeclaration,
@@ -1083,6 +1181,8 @@ export function printTSTypeAliasDeclaration(
*
* The leftmost edge is walked with a loop rather than recursion - through array and indexed-access
* object types, the first member of a union or intersection, and a conditional's check type.
*
* @param ty - Type alias's body
*/
function isLeftmostIntrinsicReference(ty: ESTree.TSType): boolean {
for (;;) {
@@ -1118,6 +1218,8 @@ function isLeftmostIntrinsicReference(ty: ESTree.TSType): boolean {
* Members print one per indented line with a comma after all but the last, and an enum with no members
* collapses to `{}`.
*
* @param node - TS enum declaration
* @param state - Printer state
*/
export function printTSEnumDeclaration(node: ESTree.TSEnumDeclaration, state: State): void {
printSpaceBeforeIdentifier(state);
@@ -1159,6 +1261,9 @@ export function printTSEnumDeclaration(node: ESTree.TSEnumDeclaration, state: St
* A member name is written bare when it is an identifier and quoted when it is a string, so `A` and `"a"`
* stay distinct. A template name prints only its first quasi, as such a name has to be a constant string
* and so has no substitutions.
*
* @param node - TS enum member
* @param state - Printer state
*/
function printTSEnumMember(node: ESTree.TSEnumMember, state: State): void {
const { id } = node;
@@ -1191,6 +1296,9 @@ function printTSEnumMember(node: ESTree.TSEnumMember, state: State): void {
* `import X = require("mod")` and `import X = A.B`, which share everything up to the `=`.
*
* The `type` modifier goes after `import`, as `import type X = require("mod")` is the spelling TypeScript accepts.
*
* @param node - TS import equals declaration
* @param state - Printer state
*/
export function printTSImportEqualsDeclaration(
node: ESTree.TSImportEqualsDeclaration,
+4
View File
@@ -626,6 +626,10 @@ function recordMapping(state: State, sourceOffset: number): void {
/**
* Is `originalName` the same token as `printedName`, taking into account leading `#` if `hashLength === 1`.
*
* @param originalName - Name in the source
* @param printedName - Name as printed
* @param hashLength - `1` if `originalName` has a leading `#` which `printedName` doesn't, otherwise `0`
*/
function isSameToken(originalName: string, printedName: string, hashLength: 0 | 1): boolean {
if (hashLength === 0) return originalName === printedName;
+6 -1
View File
@@ -136,7 +136,12 @@ function checkCases(cases: Case[]): void {
// --- Tests ----------------------------------------------------------------------------------
describe("single statements", () => {
/** Parse one source statement for public-API tests which do not print a whole program. */
/**
* Parse one source statement for public-API tests which do not print a whole program.
*
* @param filename - Filename, which decides the language
* @param sourceText - Source text
*/
function parseStatement(filename: string, sourceText: string): ESTree.Statement {
const { program: parsed, errors } = parseSync(filename, sourceText, PARSE_OPTIONS);
if (errors.length > 0) throw new Error(`fixture parse failed: ${errors[0].message}`);
+10
View File
@@ -380,6 +380,8 @@ interface Recorded {
/**
* Decode a Source Map v3 mapping string for the local invariant checks below.
*
* @param map - Source map
*/
function decodeSourceMap(map: SourceMap): Recorded[] {
const mappings: Recorded[] = [];
@@ -419,6 +421,8 @@ function decodeSourceMap(map: SourceMap): Recorded[] {
/**
* Decode one comma-delimited source-map segment.
*
* @param segment - Segment
*/
function decodeVlqSegment(segment: string): number[] {
const values: number[] = [];
@@ -633,6 +637,10 @@ describe("indent option", () => {
/**
* Rename every private identifier called `from` to `to`, as a mangler would.
*
* @param node - Node, or any value which might contain one
* @param from - Name to rename
* @param to - New name
*/
function renamePrivateIdentifiers(node: unknown, from: string, to: string): void {
if (node === null || typeof node !== "object") return;
@@ -658,6 +666,8 @@ type RewritableMemberExpression = Omit<ESTree.StaticMemberExpression, "property"
/**
* The member expression a class's first method returns, for tests which rewrite its property.
*
* @param program - Program
*/
function memberExpressionInFirstMethod(program: Program): RewritableMemberExpression {
const statement = program.body[0];
+2
View File
@@ -50,6 +50,8 @@ const PRESERVE_PARENS_MODES = [false, true];
/**
* Split source text on every ECMAScript line terminator and retain each line's UTF-16 start offset.
*
* @param sourceText - Source text
*/
export function getEcmaScriptLineTable(sourceText: string): {
lines: string[];