mirror of
https://github.com/aphrody-labs/oxc.git
synced 2026-10-15 14:49:36 +00:00
perf(packages/codegen): add functions for writing/marking unnamed mappings (#25975)
Small optimization to sourcemap builds. Add functions for writing with a source mapping, where it's known from what's being written that the mapping cannot need a name, because `node.name` is never a string, and change all call sites to use the appropriate function. This allows removing 2 checks from ``recordSourceMapping``: - `typeof node.name === "string"` - because that's now statically known. - `printedName.length > 0` - because identifiers cannot be length. All `write` and `markMap` functions take a `NamedMappableNode` or `UnnamedMappableNode`, which makes it a type error to call the wrong function. `markMapNamed` becomes dead code, and is removed.
This commit is contained in:
1 parent
343e1aa80c
commit
215a6a51ad
16 files changed
+260
-166
No files matched your search
+16
-11
@@ -255,17 +255,22 @@ No operator merges with a plain `!`, so storing it must not cost `printSpaceBefo
|
||||
Not every write needs to update `last`.
|
||||
|
||||
When one token is written in pieces - a string's opening quote, its contents, its closing quote -
|
||||
only the last piece's category can possibly be read. Hence five write primitives in [`print/write.ts`]:
|
||||
only the last piece's category can possibly be read. Hence seven write primitives in [`print/write.ts`]:
|
||||
|
||||
| Function | Updates `last` | Records a source mapping |
|
||||
| :------------------------ | :------------- | :--------------------------- |
|
||||
| `write` | Yes | No |
|
||||
| `writeWithMapNamed` | Yes | At the node's start |
|
||||
| `writeWithMapEnd` | Yes | At the node's last character |
|
||||
| `writeNoLast` | No | No |
|
||||
| `writeWithMapNamedNoLast` | No | At the node's start |
|
||||
| Function | Updates `last` | Records a source mapping |
|
||||
| :------------------------ | :------------- | :----------------------------- |
|
||||
| `write` | Yes | No |
|
||||
| `writeWithMap` | Yes | At the node's start |
|
||||
| `writeWithMapNamed` | Yes | At the node's start, with name |
|
||||
| `writeWithMapEnd` | Yes | At the node's last character |
|
||||
| `writeNoLast` | No | No |
|
||||
| `writeWithMapNoLast` | No | At the node's start |
|
||||
| `writeWithMapNamedNoLast` | No | At the node's start, with name |
|
||||
|
||||
- The four `markMap*` functions record a mapping without writing anything, so `last` is not theirs to update.
|
||||
- The `*Named` functions record the name the node had in the source, and take a `NamedMappableNode`,
|
||||
which covers nodes with a string `name`.
|
||||
- The other `writeWithMap*` functions take an `UnnamedMappableNode` which covers nodes without a string `name`.
|
||||
- The three `markMap*` functions record a mapping without writing anything, so `last` is not theirs to update.
|
||||
- The rule is exact: **only sound where the value of `last` is provably dead**.
|
||||
Another real write must follow before anything reads it.
|
||||
- JSX carries the longest runs. Printing `<a.b x="1">hi</a.b>` updates `last` exactly once, on the final `>`.
|
||||
@@ -365,8 +370,8 @@ A plugin silently doing nothing is a failure mode worth guarding against.
|
||||
#### `unmap_writes`
|
||||
|
||||
Rewrites every mapped write into the plain one it becomes with no mapping to record - so
|
||||
`writeWithMapNamed(state, code, cat, node)` turns into `write(state, code, cat)` - and rewrites the import
|
||||
to match. `writeWithMapEnd` becomes `write` too, and `writeWithMapNamedNoLast` becomes `writeNoLast`.
|
||||
`writeWithMap(state, code, cat, node)` turns into `write(state, code, cat)` - and rewrites the import to match.
|
||||
`writeWithMapNamed` and `writeWithMapEnd` become `write` too, and both `NoLast` forms become `writeNoLast`.
|
||||
|
||||
`printString` and `printNonNegativeFloat` take a node only to hand on to a mapped write. They keep their names,
|
||||
but the argument comes off every call, and the parameter off their declarations - which, unlike the mapped writes,
|
||||
|
||||
@@ -2,7 +2,14 @@
|
||||
|
||||
import { typeAssertIs } from "../asserts.ts";
|
||||
import { printPropertyKey } from "./binding_pattern.ts";
|
||||
import { CAT_CLOSE_BRACKET, CAT_IDENT, CAT_OTHER, write, writeWithMapNamed } from "./write.ts";
|
||||
import {
|
||||
CAT_CLOSE_BRACKET,
|
||||
CAT_IDENT,
|
||||
CAT_OTHER,
|
||||
write,
|
||||
writeWithMap,
|
||||
writeWithMapNamed,
|
||||
} from "./write.ts";
|
||||
import { printExpression, printMemberExpression } from "./expression.ts";
|
||||
import { printSpaceBeforeIdentifier } from "./space.ts";
|
||||
import { CTX_NONE } from "./operators.ts";
|
||||
@@ -53,7 +60,7 @@ export function printAssignmentTarget(node: ESTree.AssignmentTarget, state: Stat
|
||||
* Print an object destructuring target, as in `({ a, b: c } = obj)`.
|
||||
*/
|
||||
function printObjectAssignmentTarget(node: ESTree.ObjectAssignmentTarget, state: State): void {
|
||||
writeWithMapNamed(state, "{", CAT_OTHER, node);
|
||||
writeWithMap(state, "{", CAT_OTHER, node);
|
||||
|
||||
const { properties } = node;
|
||||
const { length } = properties;
|
||||
@@ -62,7 +69,7 @@ function printObjectAssignmentTarget(node: ESTree.ObjectAssignmentTarget, state:
|
||||
|
||||
const property = properties[i];
|
||||
if (property.type === "RestElement") {
|
||||
writeWithMapNamed(state, "...", CAT_OTHER, property);
|
||||
writeWithMap(state, "...", CAT_OTHER, property);
|
||||
printAssignmentTarget(property.argument, state);
|
||||
} else {
|
||||
printAssignmentTargetProperty(property, state);
|
||||
@@ -139,7 +146,7 @@ function printArrayAssignmentTarget(node: ESTree.ArrayAssignmentTarget, state: S
|
||||
}
|
||||
}
|
||||
|
||||
writeWithMapNamed(state, "[", CAT_OTHER, node);
|
||||
writeWithMap(state, "[", CAT_OTHER, node);
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (i !== 0) write(state, ", ", CAT_OTHER);
|
||||
@@ -155,7 +162,7 @@ function printArrayAssignmentTarget(node: ESTree.ArrayAssignmentTarget, state: S
|
||||
|
||||
if (rest !== null) {
|
||||
if (length > 0) write(state, " ", CAT_OTHER);
|
||||
writeWithMapNamed(state, "...", CAT_OTHER, rest);
|
||||
writeWithMap(state, "...", CAT_OTHER, rest);
|
||||
printAssignmentTarget(rest.argument, state);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
CAT_OTHER,
|
||||
CAT_QUESTION,
|
||||
write,
|
||||
writeWithMap,
|
||||
writeWithMapNamed,
|
||||
writeWithMapNamedNoLast,
|
||||
} from "./write.ts";
|
||||
@@ -59,7 +60,7 @@ export function printBindingPattern(node: BindingPatternNode | UnknownNode, stat
|
||||
printExpression(node.right, state, PREC_COMMA, CTX_NONE);
|
||||
break;
|
||||
case "RestElement":
|
||||
writeWithMapNamed(state, "...", CAT_OTHER, node);
|
||||
writeWithMap(state, "...", CAT_OTHER, node);
|
||||
printBindingPattern(node.argument, state);
|
||||
if (TS && node.typeAnnotation != null) printTypeAnnotation(node.typeAnnotation, state);
|
||||
break;
|
||||
@@ -76,17 +77,17 @@ function printObjectBindingPattern(node: ESTree.ObjectPattern, state: State): vo
|
||||
const { length } = properties;
|
||||
|
||||
if (length === 0) {
|
||||
writeWithMapNamed(state, "{}", CAT_OTHER, node);
|
||||
writeWithMap(state, "{}", CAT_OTHER, node);
|
||||
return;
|
||||
}
|
||||
|
||||
writeWithMapNamed(state, "{ ", CAT_OTHER, node);
|
||||
writeWithMap(state, "{ ", CAT_OTHER, node);
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (i > 0) write(state, ", ", CAT_OTHER);
|
||||
const property = properties[i];
|
||||
if (property.type === "RestElement") {
|
||||
writeWithMapNamed(state, "...", CAT_OTHER, property);
|
||||
writeWithMap(state, "...", CAT_OTHER, property);
|
||||
printBindingPattern(property.argument, state);
|
||||
} else {
|
||||
printBindingProperty(property, state);
|
||||
@@ -177,7 +178,7 @@ function printArrayBindingPattern(node: ESTree.ArrayPattern, state: State): void
|
||||
}
|
||||
}
|
||||
|
||||
writeWithMapNamed(state, "[", CAT_OTHER, node);
|
||||
writeWithMap(state, "[", CAT_OTHER, node);
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (i !== 0) write(state, ", ", CAT_OTHER);
|
||||
|
||||
@@ -10,12 +10,13 @@ import {
|
||||
CAT_QUESTION,
|
||||
CAT_START_OF_STMT,
|
||||
debugAssertLastFresh,
|
||||
markMapNamed,
|
||||
markMapStart,
|
||||
write,
|
||||
writeNoLast,
|
||||
writeWithMapNamed,
|
||||
writeWithMap,
|
||||
writeWithMapEnd,
|
||||
writeWithMapNamedNoLast,
|
||||
writeWithMapNamed,
|
||||
writeWithMapNoLast,
|
||||
} from "./write.ts";
|
||||
import { printExpression } from "./expression.ts";
|
||||
import { printFunctionBody, printParenParams } from "./function.ts";
|
||||
@@ -64,18 +65,18 @@ export function printClass(node: ESTree.Class, state: State): void {
|
||||
const abstract = TS && node.abstract;
|
||||
|
||||
// The node's mapping goes on whichever of these is written first
|
||||
if (declare) writeWithMapNamed(state, "declare ", CAT_OTHER, node);
|
||||
if (declare) writeWithMap(state, "declare ", CAT_OTHER, node);
|
||||
if (abstract) {
|
||||
if (declare) {
|
||||
write(state, "abstract ", CAT_OTHER);
|
||||
} else {
|
||||
writeWithMapNamed(state, "abstract ", CAT_OTHER, node);
|
||||
writeWithMap(state, "abstract ", CAT_OTHER, node);
|
||||
}
|
||||
}
|
||||
if (declare || abstract) {
|
||||
write(state, "class", CAT_IDENT);
|
||||
} else {
|
||||
writeWithMapNamed(state, "class", CAT_IDENT, node);
|
||||
writeWithMap(state, "class", CAT_IDENT, node);
|
||||
}
|
||||
|
||||
if (node.id != null) {
|
||||
@@ -119,7 +120,7 @@ export function printDecorators(decorators: ESTree.Decorator[], state: State): v
|
||||
for (let i = 0; i < length; i++) {
|
||||
const decorator = decorators[i];
|
||||
|
||||
writeWithMapNamed(state, "@", CAT_OTHER, decorator);
|
||||
writeWithMap(state, "@", CAT_OTHER, decorator);
|
||||
|
||||
const { expression } = decorator;
|
||||
const wrap = decoratorNeedsWrap(expression);
|
||||
@@ -161,12 +162,12 @@ function printClassBody(node: ClassBodyNode, state: State): void {
|
||||
const { body } = node;
|
||||
const { length } = body;
|
||||
if (length === 0) {
|
||||
writeWithMapNamedNoLast(state, "{", node);
|
||||
writeWithMapNoLast(state, "{", node);
|
||||
writeWithMapEnd(state, "}", CAT_OTHER, node);
|
||||
return;
|
||||
}
|
||||
|
||||
writeWithMapNamed(state, "{\n", CAT_OTHER, node);
|
||||
writeWithMap(state, "{\n", CAT_OTHER, node);
|
||||
|
||||
state.indentLevel++;
|
||||
|
||||
@@ -221,7 +222,7 @@ function printClassBody(node: ClassBodyNode, state: State): void {
|
||||
* Print a method, including getters, setters, constructors and their modifiers.
|
||||
*/
|
||||
function printMethodDefinition(node: MethodDefinitionNode, state: State): void {
|
||||
markMapNamed(state, node);
|
||||
markMapStart(state, node);
|
||||
|
||||
const { decorators } = node;
|
||||
if (decorators != null && decorators.length > 0) printDecorators(decorators, state);
|
||||
@@ -293,7 +294,7 @@ function printMethodDefinition(node: MethodDefinitionNode, state: State): void {
|
||||
* Print a class field, with its modifiers and initializer.
|
||||
*/
|
||||
function printPropertyDefinition(node: PropertyDefinitionNode, state: State): void {
|
||||
markMapNamed(state, node);
|
||||
markMapStart(state, node);
|
||||
|
||||
const { decorators } = node;
|
||||
if (decorators != null && decorators.length > 0) printDecorators(decorators, state);
|
||||
@@ -356,17 +357,17 @@ function printPropertyDefinition(node: PropertyDefinitionNode, state: State): vo
|
||||
function printStaticBlock(node: ESTree.StaticBlock, state: State): void {
|
||||
printSpaceBeforeIdentifier(state);
|
||||
|
||||
writeWithMapNamed(state, "static ", CAT_OTHER, node);
|
||||
writeWithMap(state, "static ", CAT_OTHER, node);
|
||||
|
||||
const { body } = node;
|
||||
const { length } = body;
|
||||
if (length === 0) {
|
||||
writeWithMapNamedNoLast(state, "{", node);
|
||||
writeWithMapNoLast(state, "{", node);
|
||||
writeWithMapEnd(state, "}", CAT_OTHER, node);
|
||||
return;
|
||||
}
|
||||
|
||||
writeWithMapNamed(state, "{\n", CAT_OTHER, node);
|
||||
writeWithMap(state, "{\n", CAT_OTHER, node);
|
||||
|
||||
state.indentLevel++;
|
||||
|
||||
@@ -384,7 +385,7 @@ function printStaticBlock(node: ESTree.StaticBlock, state: State): void {
|
||||
* Print an `accessor` field.
|
||||
*/
|
||||
function printAccessorProperty(node: AccessorPropertyNode, state: State): void {
|
||||
markMapNamed(state, node);
|
||||
markMapStart(state, node);
|
||||
|
||||
const { decorators } = node;
|
||||
if (decorators != null && decorators.length > 0) printDecorators(decorators, state);
|
||||
|
||||
@@ -16,14 +16,16 @@ import {
|
||||
CAT_START_OF_ARROW_EXPR,
|
||||
CAT_START_OF_STMT,
|
||||
debugAssertLastFresh,
|
||||
markMapNamed,
|
||||
markMapAfter,
|
||||
markMapAtStartOffset,
|
||||
markMapStart,
|
||||
write,
|
||||
writeNoLast,
|
||||
writeWithMapNamed,
|
||||
writeWithMap,
|
||||
writeWithMapEnd,
|
||||
writeWithMapNamed,
|
||||
writeWithMapNamedNoLast,
|
||||
writeWithMapNoLast,
|
||||
} from "./write.ts";
|
||||
import { printClass } from "./class.ts";
|
||||
import {
|
||||
@@ -148,11 +150,11 @@ export function printExpression(
|
||||
break;
|
||||
case "ThisExpression":
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "this", CAT_IDENT, node);
|
||||
writeWithMap(state, "this", CAT_IDENT, node);
|
||||
break;
|
||||
case "Super":
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "super", CAT_IDENT, node);
|
||||
writeWithMap(state, "super", CAT_IDENT, node);
|
||||
break;
|
||||
case "NewExpression":
|
||||
printNewExpression(node, state, precedence);
|
||||
@@ -161,7 +163,7 @@ export function printExpression(
|
||||
printTemplateLiteral(node, state);
|
||||
break;
|
||||
case "TaggedTemplateExpression":
|
||||
markMapNamed(state, node);
|
||||
markMapStart(state, node);
|
||||
printExpression(node.tag, state, PREC_POSTFIX, ctx & CTX_FORBID_CALL);
|
||||
if (TS) printTypeArguments(node.typeArguments, state);
|
||||
printTemplateLiteral(node.quasi, state);
|
||||
@@ -180,7 +182,7 @@ export function printExpression(
|
||||
break;
|
||||
case "MetaProperty":
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamedNoLast(state, node.meta.name, node);
|
||||
writeWithMapNoLast(state, node.meta.name, node);
|
||||
writeNoLast(state, ".");
|
||||
write(state, node.property.name, CAT_IDENT);
|
||||
break;
|
||||
@@ -363,7 +365,7 @@ function printArguments(
|
||||
|
||||
const arg = args[i];
|
||||
if (arg.type === "SpreadElement") {
|
||||
writeWithMapNamed(state, "...", CAT_OTHER, arg);
|
||||
writeWithMap(state, "...", CAT_OTHER, arg);
|
||||
printExpression(arg.argument, state, PREC_COMMA, CTX_NONE);
|
||||
} else {
|
||||
printExpression(arg, state, PREC_COMMA, CTX_NONE);
|
||||
@@ -388,7 +390,7 @@ export function printPrivateInExpression(
|
||||
const wrap = precedence >= PREC_COMPARE;
|
||||
if (wrap) write(state, "(", CAT_OTHER);
|
||||
|
||||
markMapNamed(state, node);
|
||||
markMapStart(state, node);
|
||||
writeWithMapNamedNoLast(state, "#", node.left);
|
||||
write(state, node.left.name, CAT_IDENT);
|
||||
write(state, " in ", CAT_OTHER);
|
||||
@@ -415,7 +417,7 @@ function printObjectExpression(node: ESTree.ObjectExpression, state: State): voi
|
||||
const { length } = properties;
|
||||
const isMultiLine = length > 1;
|
||||
|
||||
writeWithMapNamed(state, "{", CAT_OTHER, node);
|
||||
writeWithMap(state, "{", CAT_OTHER, node);
|
||||
|
||||
if (isMultiLine) {
|
||||
state.indentLevel++;
|
||||
@@ -448,7 +450,7 @@ function printObjectExpression(node: ESTree.ObjectExpression, state: State): voi
|
||||
*/
|
||||
function printObjectProperty(node: ESTree.ObjectPropertyKind, state: State): void {
|
||||
if (node.type === "SpreadElement") {
|
||||
writeWithMapNamed(state, "...", CAT_OTHER, node);
|
||||
writeWithMap(state, "...", CAT_OTHER, node);
|
||||
printExpression(node.argument, state, PREC_COMMA, CTX_NONE);
|
||||
return;
|
||||
}
|
||||
@@ -458,7 +460,7 @@ function printObjectProperty(node: ESTree.ObjectPropertyKind, state: State): voi
|
||||
value.type === "FunctionExpression"
|
||||
|| (TS && value.type === "TSEmptyBodyFunctionExpression")
|
||||
) {
|
||||
markMapNamed(state, node);
|
||||
markMapStart(state, node);
|
||||
|
||||
const { kind } = node;
|
||||
const isGetter = kind === "get";
|
||||
@@ -561,7 +563,7 @@ function printArrayExpression(node: ESTree.ArrayExpression, state: State): void
|
||||
const { length } = elements;
|
||||
const isMultiLine = length > 2;
|
||||
|
||||
writeWithMapNamed(state, "[", CAT_OTHER, node);
|
||||
writeWithMap(state, "[", CAT_OTHER, node);
|
||||
|
||||
if (isMultiLine) state.indentLevel++;
|
||||
|
||||
@@ -576,7 +578,7 @@ function printArrayExpression(node: ESTree.ArrayExpression, state: State): void
|
||||
const element = elements[i];
|
||||
if (element != null) {
|
||||
if (element.type === "SpreadElement") {
|
||||
writeWithMapNamed(state, "...", CAT_OTHER, element);
|
||||
writeWithMap(state, "...", CAT_OTHER, element);
|
||||
printExpression(element.argument, state, PREC_COMMA, CTX_NONE);
|
||||
} else {
|
||||
printExpression(element, state, PREC_COMMA, CTX_NONE);
|
||||
@@ -621,7 +623,7 @@ function printAssignmentExpression(
|
||||
|
||||
if (wrap) write(state, "(", CAT_OTHER);
|
||||
|
||||
markMapNamed(state, node);
|
||||
markMapStart(state, node);
|
||||
|
||||
printAssignmentTarget(left, state);
|
||||
write(state, PADDED_ASSIGN_OPERATORS[node.operator], CAT_OTHER);
|
||||
@@ -651,10 +653,10 @@ function printUpdateExpression(
|
||||
|
||||
if (node.prefix) {
|
||||
printSpaceBeforeOperator(state, operatorCode);
|
||||
writeWithMapNamed(state, node.operator, operatorCode, node);
|
||||
writeWithMap(state, node.operator, operatorCode, node);
|
||||
printExpression(node.argument, state, PREC_PREFIX, ctx);
|
||||
} else {
|
||||
markMapNamed(state, node);
|
||||
markMapStart(state, node);
|
||||
printExpression(node.argument, state, PREC_POSTFIX, ctx);
|
||||
printSpaceBeforeOperator(state, operatorCode);
|
||||
write(state, node.operator, operatorCode);
|
||||
@@ -684,7 +686,7 @@ function printUnaryExpression(
|
||||
if (operator.length > 1) {
|
||||
// typeof, void, delete
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, operator, CAT_IDENT, node);
|
||||
writeWithMap(state, operator, CAT_IDENT, node);
|
||||
write(state, " ", CAT_OTHER);
|
||||
// `delete Infinity` is a syntax error in strict mode
|
||||
isDeleteInfinity =
|
||||
@@ -696,7 +698,7 @@ function printUnaryExpression(
|
||||
if (operatorCode === CAT_OP_UN_NOT && state.last === CAT_LT) {
|
||||
operatorCode = CAT_OP_UN_NOT_AFTER_LT;
|
||||
}
|
||||
writeWithMapNamed(state, operator, operatorCode, node);
|
||||
writeWithMap(state, operator, operatorCode, node);
|
||||
}
|
||||
|
||||
if (isDeleteInfinity) write(state, "(0, ", CAT_OTHER);
|
||||
@@ -796,7 +798,7 @@ function printArrowFunctionExpression(
|
||||
|
||||
if (node.async) {
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "async ", CAT_OTHER, node);
|
||||
writeWithMap(state, "async ", CAT_OTHER, node);
|
||||
}
|
||||
|
||||
if (TS) printTypeParameters(node.typeParameters, state);
|
||||
@@ -832,7 +834,7 @@ function printNewExpression(node: ESTree.NewExpression, state: State, precedence
|
||||
if (wrap) write(state, "(", CAT_OTHER);
|
||||
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "new ", CAT_OTHER, node);
|
||||
writeWithMap(state, "new ", CAT_OTHER, node);
|
||||
printExpression(node.callee, state, PREC_NEW, CTX_FORBID_CALL);
|
||||
if (TS) printTypeArguments(node.typeArguments, state);
|
||||
printArguments(node, node.arguments, state);
|
||||
@@ -847,7 +849,7 @@ function printNewExpression(node: ESTree.NewExpression, state: State, precedence
|
||||
* Substitutions print from `PREC_LOWEST` with no context flags, since `${` and `}` fence them from everything around.
|
||||
*/
|
||||
function printTemplateLiteral(node: ESTree.TemplateLiteral, state: State): void {
|
||||
writeWithMapNamedNoLast(state, "`", node);
|
||||
writeWithMapNoLast(state, "`", node);
|
||||
|
||||
const { quasis, expressions } = node;
|
||||
const { length } = expressions;
|
||||
@@ -898,7 +900,7 @@ function printAwaitExpression(
|
||||
if (wrap) write(state, "(", CAT_OTHER);
|
||||
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "await ", CAT_OTHER, node);
|
||||
writeWithMap(state, "await ", CAT_OTHER, node);
|
||||
printExpression(node.argument, state, PREC_EXPONENTIATION, ctx);
|
||||
|
||||
if (wrap) write(state, ")", CAT_CLOSE_BRACKET);
|
||||
@@ -917,7 +919,7 @@ function printYieldExpression(
|
||||
if (wrap) write(state, "(", CAT_OTHER);
|
||||
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "yield", CAT_IDENT, node);
|
||||
writeWithMap(state, "yield", CAT_IDENT, node);
|
||||
|
||||
if (node.delegate) write(state, "*", CAT_OTHER);
|
||||
|
||||
@@ -945,7 +947,7 @@ function printImportExpression(
|
||||
if (wrap) write(state, "(", CAT_OTHER);
|
||||
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "import", CAT_IDENT, node);
|
||||
writeWithMap(state, "import", CAT_IDENT, node);
|
||||
|
||||
if (node.phase != null) {
|
||||
writeNoLast(state, ".");
|
||||
|
||||
@@ -11,9 +11,10 @@ import {
|
||||
markMapStart,
|
||||
write,
|
||||
writeNoLast,
|
||||
writeWithMapNamed,
|
||||
writeWithMap,
|
||||
writeWithMapEnd,
|
||||
writeWithMapNamedNoLast,
|
||||
writeWithMapNamed,
|
||||
writeWithMapNoLast,
|
||||
} from "./write.ts";
|
||||
import { printDecorators } from "./class.ts";
|
||||
import { printSpaceBeforeIdentifier } from "./space.ts";
|
||||
@@ -45,10 +46,10 @@ export function printFunction(node: ESTree.Function, state: State): void {
|
||||
// The node's mapping goes on whichever of these is written first
|
||||
const declare = TS && node.declare;
|
||||
if (declare) {
|
||||
writeWithMapNamed(state, "declare ", CAT_OTHER, node);
|
||||
writeWithMap(state, "declare ", CAT_OTHER, node);
|
||||
write(state, node.async ? "async function" : "function", CAT_IDENT);
|
||||
} else {
|
||||
writeWithMapNamed(state, node.async ? "async function" : "function", CAT_IDENT, node);
|
||||
writeWithMap(state, node.async ? "async function" : "function", CAT_IDENT, node);
|
||||
}
|
||||
|
||||
if (node.generator) write(state, "* ", CAT_OTHER);
|
||||
@@ -152,12 +153,12 @@ export function printFunctionBody(body: ESTree.FunctionBody, state: State): void
|
||||
// `body` is a BlockStatement holding directives + statements.
|
||||
const statements = body.body;
|
||||
if (statements.length === 0) {
|
||||
writeWithMapNamedNoLast(state, "{", body);
|
||||
writeWithMapNoLast(state, "{", body);
|
||||
writeWithMapEnd(state, "}", CAT_OTHER, body);
|
||||
return;
|
||||
}
|
||||
|
||||
writeWithMapNamed(state, "{\n", CAT_OTHER, body);
|
||||
writeWithMap(state, "{\n", CAT_OTHER, body);
|
||||
state.indentLevel++;
|
||||
printDirectivesAndStatements(statements, state);
|
||||
state.indentLevel--;
|
||||
|
||||
@@ -5,9 +5,10 @@ import {
|
||||
CAT_OTHER,
|
||||
write,
|
||||
writeNoLast,
|
||||
writeWithMapNamed,
|
||||
writeWithMap,
|
||||
writeWithMapEnd,
|
||||
writeWithMapNamedNoLast,
|
||||
writeWithMapNoLast,
|
||||
} from "./write.ts";
|
||||
import { printExpression } from "./expression.ts";
|
||||
import { CTX_NONE } from "./operators.ts";
|
||||
@@ -27,7 +28,7 @@ import type * as ESTree from "../../../../npm/oxc-types/types.d.ts";
|
||||
export function printJSXElement(node: ESTree.JSXElement, state: State): void {
|
||||
const { openingElement } = node;
|
||||
|
||||
writeWithMapNamedNoLast(state, "<", openingElement);
|
||||
writeWithMapNoLast(state, "<", openingElement);
|
||||
printJSXElementName(openingElement.name, state);
|
||||
|
||||
if (TS) printTypeArguments(openingElement.typeArguments, state);
|
||||
@@ -38,7 +39,7 @@ export function printJSXElement(node: ESTree.JSXElement, state: State): void {
|
||||
writeNoLast(state, " ");
|
||||
const attribute = attributes[i];
|
||||
if (attribute.type === "JSXSpreadAttribute") {
|
||||
writeWithMapNamed(state, "{...", CAT_OTHER, attribute);
|
||||
writeWithMap(state, "{...", CAT_OTHER, attribute);
|
||||
printExpression(attribute.argument, state, PREC_COMMA, CTX_NONE);
|
||||
writeWithMapEnd(state, "}", CAT_OTHER, attribute);
|
||||
} else {
|
||||
@@ -60,7 +61,7 @@ export function printJSXElement(node: ESTree.JSXElement, state: State): void {
|
||||
printJSXChild(children[i], state);
|
||||
}
|
||||
|
||||
writeWithMapNamedNoLast(state, "</", closingElement);
|
||||
writeWithMapNoLast(state, "</", closingElement);
|
||||
printJSXElementName(closingElement.name, state);
|
||||
write(state, ">", CAT_OTHER);
|
||||
}
|
||||
@@ -87,7 +88,7 @@ function printJSXElementName(
|
||||
writeWithMapNamedNoLast(state, node.name.name, node.name);
|
||||
break;
|
||||
case "ThisExpression":
|
||||
writeWithMapNamedNoLast(state, "this", node);
|
||||
writeWithMapNoLast(state, "this", node);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown JSX name type: ${node.type}`);
|
||||
@@ -178,7 +179,7 @@ function printJSXExpressionContainer(node: ESTree.JSXExpressionContainer, state:
|
||||
* Print a `<>...</>` fragment.
|
||||
*/
|
||||
export function printJSXFragment(node: ESTree.JSXFragment, state: State): void {
|
||||
writeWithMapNamedNoLast(state, "<>", node.openingFragment);
|
||||
writeWithMapNoLast(state, "<>", node.openingFragment);
|
||||
|
||||
const { children } = node;
|
||||
const { length } = children;
|
||||
@@ -186,7 +187,7 @@ export function printJSXFragment(node: ESTree.JSXFragment, state: State): void {
|
||||
printJSXChild(children[i], state);
|
||||
}
|
||||
|
||||
writeWithMapNamed(state, "</>", CAT_OTHER, node.closingFragment);
|
||||
writeWithMap(state, "</>", CAT_OTHER, node.closingFragment);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,7 +199,7 @@ export function printJSXFragment(node: ESTree.JSXFragment, state: State): void {
|
||||
function printJSXChild(node: ESTree.JSXChild | UnknownNode, state: State): void {
|
||||
switch (node.type) {
|
||||
case "JSXText":
|
||||
writeWithMapNamedNoLast(state, node.raw != null ? node.raw : node.value, node);
|
||||
writeWithMapNoLast(state, node.raw != null ? node.raw : node.value, node);
|
||||
break;
|
||||
case "JSXExpressionContainer":
|
||||
printJSXExpressionContainer(node, state);
|
||||
|
||||
@@ -10,8 +10,8 @@ import {
|
||||
CAT_REGEX_SLASH,
|
||||
write,
|
||||
writeNoLast,
|
||||
writeWithMapNamed,
|
||||
writeWithMapNamedNoLast,
|
||||
writeWithMap,
|
||||
writeWithMapNoLast,
|
||||
} from "./write.ts";
|
||||
import { printSpaceBeforeIdentifier, printSpaceBeforeOperator } from "./space.ts";
|
||||
import { printNonNegativeFloat } from "./number.ts";
|
||||
@@ -60,7 +60,7 @@ export function printLiteral(
|
||||
break;
|
||||
case "boolean":
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, value ? "true" : "false", CAT_IDENT, node);
|
||||
writeWithMap(state, value ? "true" : "false", CAT_IDENT, node);
|
||||
break;
|
||||
default:
|
||||
typeAssertIs<LiteralExtras>(node);
|
||||
@@ -73,7 +73,7 @@ export function printLiteral(
|
||||
} else {
|
||||
// `null`
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "null", CAT_IDENT, node);
|
||||
writeWithMap(state, "null", CAT_IDENT, node);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -102,7 +102,7 @@ function printNumericLiteral(
|
||||
// `CAT_IDENT` rather than `CAT_INT_DIGIT` - raw text only prints inside a TS type,
|
||||
// where no member `.` can follow, so there is no `0 .toExponential()` hazard to separate.
|
||||
const { raw } = node;
|
||||
writeWithMapNamed(state, raw, raw[raw.length - 1] === "." ? CAT_OTHER : CAT_IDENT, node);
|
||||
writeWithMap(state, raw, raw[raw.length - 1] === "." ? CAT_OTHER : CAT_IDENT, node);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ function printNumericLiteral(
|
||||
printNonNegativeFloat(state, value, node);
|
||||
} else if (Number.isNaN(value)) {
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "NaN", CAT_IDENT, node);
|
||||
writeWithMap(state, "NaN", CAT_IDENT, node);
|
||||
} else if (!Number.isFinite(value)) {
|
||||
const negative = value < 0;
|
||||
const wrap = negative && precedence >= PREC_PREFIX;
|
||||
@@ -125,13 +125,13 @@ function printNumericLiteral(
|
||||
} else {
|
||||
printSpaceBeforeIdentifier(state);
|
||||
}
|
||||
writeWithMapNamed(state, "Infinity", CAT_IDENT, node);
|
||||
writeWithMap(state, "Infinity", CAT_IDENT, node);
|
||||
|
||||
if (wrap) write(state, ")", CAT_CLOSE_BRACKET);
|
||||
} else if (Object.is(value, 0)) {
|
||||
// +0 exactly - `Object.is` rejects `-0`, which the negative paths below print as `-0`
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "0", CAT_INT_DIGIT, node);
|
||||
writeWithMap(state, "0", CAT_INT_DIGIT, node);
|
||||
} else if (precedence >= PREC_PREFIX) {
|
||||
writeNoLast(state, "(-");
|
||||
printNonNegativeFloat(state, -value, node);
|
||||
@@ -169,7 +169,7 @@ function printRegExpLiteral(node: ESTree.RegExpLiteral, state: State): void {
|
||||
// * `last === CAT_REGEX_SLASH` keeps `/a//b/` from lexing as a line comment
|
||||
// * `CAT_LT` arm keeps `<` followed by `/script...` from closing a host `<script>` element.
|
||||
|
||||
writeWithMapNamedNoLast(state, "/", node);
|
||||
writeWithMapNoLast(state, "/", node);
|
||||
writeNoLast(state, node.regex.pattern);
|
||||
|
||||
// `CAT_REGEX_SLASH` rather than `CAT_OTHER`. It means "a regex just closed", which is what the
|
||||
@@ -192,11 +192,11 @@ function printBigIntLiteral(node: ESTree.BigIntLiteral, state: State, precedence
|
||||
|
||||
const value = node.bigint;
|
||||
if (value.startsWith("-") && precedence >= PREC_PREFIX) {
|
||||
writeWithMapNamedNoLast(state, "(", node);
|
||||
writeWithMapNoLast(state, "(", node);
|
||||
writeNoLast(state, value);
|
||||
write(state, "n)", CAT_CLOSE_BRACKET);
|
||||
} else {
|
||||
writeWithMapNamedNoLast(state, value, node);
|
||||
writeWithMapNoLast(state, value, node);
|
||||
write(state, "n", CAT_IDENT);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
CAT_START_OF_DEFAULT_EXPORT,
|
||||
write,
|
||||
writeNoLast,
|
||||
writeWithMap,
|
||||
writeWithMapNamed,
|
||||
} from "./write.ts";
|
||||
import { printClass } from "./class.ts";
|
||||
@@ -39,7 +40,7 @@ export function printImportDeclaration(node: ESTree.ImportDeclaration, state: St
|
||||
printIndent(state);
|
||||
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "import", CAT_IDENT, node);
|
||||
writeWithMap(state, "import", CAT_IDENT, node);
|
||||
|
||||
if (TS && node.importKind === "type") write(state, " type", CAT_IDENT);
|
||||
|
||||
@@ -74,7 +75,7 @@ export function printImportDeclaration(node: ESTree.ImportDeclaration, state: St
|
||||
}
|
||||
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, specifier.local.name, CAT_IDENT, specifier);
|
||||
writeWithMap(state, specifier.local.name, CAT_IDENT, specifier);
|
||||
|
||||
if (i === length - 1) write(state, " ", CAT_OTHER);
|
||||
|
||||
@@ -142,7 +143,7 @@ function printImportAttributes(
|
||||
// ESTree omits the `WithClause` wrapper. The Rust reference normalizes its mapping anchor
|
||||
// to the first attribute, which is the first location both representations carry.
|
||||
writeNoLast(state, " ");
|
||||
writeWithMapNamed(state, "with { ", CAT_OTHER, attributes[0]);
|
||||
writeWithMap(state, "with { ", CAT_OTHER, attributes[0]);
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (i > 0) write(state, ", ", CAT_OTHER);
|
||||
@@ -189,7 +190,7 @@ function moduleExportName(node: ESTree.ModuleExportName, state: State): string {
|
||||
export function printExportNamedDeclaration(node: ExportNamedDeclarationNode, state: State): void {
|
||||
printIndent(state);
|
||||
|
||||
writeWithMapNamed(state, "export ", CAT_OTHER, node);
|
||||
writeWithMap(state, "export ", CAT_OTHER, node);
|
||||
|
||||
const { declaration } = node;
|
||||
if (declaration != null) {
|
||||
@@ -281,7 +282,7 @@ export function printExportNamedDeclaration(node: ExportNamedDeclarationNode, st
|
||||
export function printExportAllDeclaration(node: ESTree.ExportAllDeclaration, state: State): void {
|
||||
printIndent(state);
|
||||
|
||||
writeWithMapNamed(
|
||||
writeWithMap(
|
||||
state,
|
||||
TS && node.exportKind === "type" ? "export type *" : "export *",
|
||||
CAT_OTHER,
|
||||
@@ -311,7 +312,7 @@ export function printExportDefaultDeclaration(
|
||||
): void {
|
||||
printIndent(state);
|
||||
|
||||
writeWithMapNamed(state, "export default ", CAT_OTHER, node);
|
||||
writeWithMap(state, "export default ", CAT_OTHER, node);
|
||||
|
||||
const { declaration } = node;
|
||||
switch (declaration.type) {
|
||||
|
||||
@@ -9,12 +9,13 @@ import {
|
||||
CAT_OP_UN_NOT,
|
||||
CAT_OTHER,
|
||||
CAT_START_OF_STMT,
|
||||
markMapNamed,
|
||||
markMapStart,
|
||||
write,
|
||||
writeNoLast,
|
||||
writeWithMapNamed,
|
||||
writeWithMap,
|
||||
writeWithMapEnd,
|
||||
writeWithMapNamedNoLast,
|
||||
writeWithMapNamed,
|
||||
writeWithMapNoLast,
|
||||
} from "./write.ts";
|
||||
import { printClass } from "./class.ts";
|
||||
import { printExpression } from "./expression.ts";
|
||||
@@ -87,7 +88,7 @@ export function printDirectivesAndStatements(
|
||||
if (inner.type === "Literal" && typeof inner.value === "string") {
|
||||
const mapsIndent = state.indentLevel > 0 || state.pendingIndentAsSpace;
|
||||
printIndent(state);
|
||||
if (mapsIndent) markMapNamed(state, stmt);
|
||||
if (mapsIndent) markMapStart(state, stmt);
|
||||
writeNoLast(state, "(");
|
||||
printString(state, inner.value, inner);
|
||||
write(state, ");\n", CAT_OTHER);
|
||||
@@ -128,7 +129,7 @@ function printDirective(stmt: ESTree.Directive, state: State): void {
|
||||
}
|
||||
}
|
||||
|
||||
writeWithMapNamedNoLast(state, quote, stmt);
|
||||
writeWithMapNoLast(state, quote, stmt);
|
||||
writeNoLast(state, directive);
|
||||
writeNoLast(state, quote);
|
||||
write(state, ";\n", CAT_OTHER);
|
||||
@@ -185,7 +186,7 @@ export function printStatement(node: ESTree.Statement | UnknownNode, state: Stat
|
||||
case "BreakStatement":
|
||||
printIndent(state);
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "break", CAT_IDENT, node);
|
||||
writeWithMap(state, "break", CAT_IDENT, node);
|
||||
if (node.label != null) {
|
||||
write(state, " ", CAT_OTHER);
|
||||
writeWithMapNamed(state, node.label.name, CAT_IDENT, node.label);
|
||||
@@ -195,7 +196,7 @@ export function printStatement(node: ESTree.Statement | UnknownNode, state: Stat
|
||||
case "ContinueStatement":
|
||||
printIndent(state);
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "continue", CAT_IDENT, node);
|
||||
writeWithMap(state, "continue", CAT_IDENT, node);
|
||||
if (node.label != null) {
|
||||
write(state, " ", CAT_OTHER);
|
||||
writeWithMapNamed(state, node.label.name, CAT_IDENT, node.label);
|
||||
@@ -208,7 +209,7 @@ export function printStatement(node: ESTree.Statement | UnknownNode, state: Stat
|
||||
case "ThrowStatement":
|
||||
printIndent(state);
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "throw ", CAT_OTHER, node);
|
||||
writeWithMap(state, "throw ", CAT_OTHER, node);
|
||||
printExpression(node.argument, state, PREC_LOWEST, CTX_NONE);
|
||||
write(state, ";\n", CAT_OTHER);
|
||||
break;
|
||||
@@ -226,14 +227,14 @@ export function printStatement(node: ESTree.Statement | UnknownNode, state: Stat
|
||||
case "LabeledStatement":
|
||||
printIndent(state);
|
||||
printSpaceBeforeIdentifier(state);
|
||||
markMapNamed(state, node);
|
||||
markMapStart(state, node);
|
||||
writeWithMapNamed(state, node.label.name, CAT_IDENT, node.label);
|
||||
write(state, ":", CAT_OTHER);
|
||||
printBody(node.body, state);
|
||||
break;
|
||||
case "EmptyStatement":
|
||||
printIndent(state);
|
||||
writeWithMapNamed(state, ";\n", CAT_OTHER, node);
|
||||
writeWithMap(state, ";\n", CAT_OTHER, node);
|
||||
break;
|
||||
case "ImportDeclaration":
|
||||
printImportDeclaration(node, state);
|
||||
@@ -250,7 +251,7 @@ export function printStatement(node: ESTree.Statement | UnknownNode, state: Stat
|
||||
case "WithStatement":
|
||||
printIndent(state);
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "with(", CAT_OTHER, node);
|
||||
writeWithMap(state, "with(", CAT_OTHER, node);
|
||||
printExpression(node.object, state, PREC_LOWEST, CTX_NONE);
|
||||
write(state, ")", CAT_CLOSE_BRACKET);
|
||||
printBody(node.body, state);
|
||||
@@ -258,7 +259,7 @@ export function printStatement(node: ESTree.Statement | UnknownNode, state: Stat
|
||||
case "DebuggerStatement":
|
||||
printIndent(state);
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "debugger;\n", CAT_OTHER, node);
|
||||
writeWithMap(state, "debugger;\n", CAT_OTHER, node);
|
||||
break;
|
||||
/* IF TS */
|
||||
case "TSModuleDeclaration":
|
||||
@@ -318,7 +319,7 @@ export function printStatement(node: ESTree.Statement | UnknownNode, state: Stat
|
||||
function printExpressionStatement(node: ESTree.ExpressionStatement, state: State): void {
|
||||
const mapsIndent = state.indentLevel > 0 || state.pendingIndentAsSpace;
|
||||
printIndent(state);
|
||||
if (mapsIndent) markMapNamed(state, node);
|
||||
if (mapsIndent) markMapStart(state, node);
|
||||
state.last = CAT_START_OF_STMT;
|
||||
printExpression(node.expression, state, PREC_LOWEST, CTX_NONE);
|
||||
write(state, ";\n", CAT_OTHER);
|
||||
@@ -341,10 +342,10 @@ export function printVariableDeclaration(
|
||||
// The node's mapping goes on whichever of these is written first
|
||||
const declare = TS && node.declare;
|
||||
if (declare) {
|
||||
writeWithMapNamed(state, "declare ", CAT_OTHER, node);
|
||||
writeWithMap(state, "declare ", CAT_OTHER, node);
|
||||
write(state, node.kind, CAT_IDENT);
|
||||
} else {
|
||||
writeWithMapNamed(state, node.kind, CAT_IDENT, node);
|
||||
writeWithMap(state, node.kind, CAT_IDENT, node);
|
||||
}
|
||||
|
||||
const { declarations } = node;
|
||||
@@ -387,12 +388,12 @@ function printBlockStatement(block: ESTree.BlockStatement, state: State): void {
|
||||
const { body } = block;
|
||||
const { length } = body;
|
||||
if (length === 0) {
|
||||
writeWithMapNamedNoLast(state, "{", block);
|
||||
writeWithMapNoLast(state, "{", block);
|
||||
writeWithMapEnd(state, "}", CAT_OTHER, block);
|
||||
return;
|
||||
}
|
||||
|
||||
writeWithMapNamed(state, "{\n", CAT_OTHER, block);
|
||||
writeWithMap(state, "{\n", CAT_OTHER, block);
|
||||
state.indentLevel++;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
@@ -414,7 +415,7 @@ function printBlockStatement(block: ESTree.BlockStatement, state: State): void {
|
||||
function printIf(node: ESTree.IfStatement, state: State): void {
|
||||
printSpaceBeforeIdentifier(state);
|
||||
|
||||
writeWithMapNamed(state, "if (", CAT_OTHER, node);
|
||||
writeWithMap(state, "if (", CAT_OTHER, node);
|
||||
|
||||
printExpression(node.test, state, PREC_LOWEST, CTX_NONE);
|
||||
|
||||
@@ -425,7 +426,7 @@ function printIf(node: ESTree.IfStatement, state: State): void {
|
||||
write(state, alternate != null ? " " : "\n", CAT_OTHER);
|
||||
} else if (wrapToAvoidAmbiguousElse(consequent)) {
|
||||
writeNoLast(state, ") ");
|
||||
writeWithMapNamed(state, "{\n", CAT_OTHER, consequent);
|
||||
writeWithMap(state, "{\n", CAT_OTHER, consequent);
|
||||
state.indentLevel++;
|
||||
printStatement(consequent, state);
|
||||
state.indentLevel--;
|
||||
@@ -493,10 +494,10 @@ function printReturnStatement(node: ESTree.ReturnStatement, state: State): void
|
||||
|
||||
const { argument } = node;
|
||||
if (argument != null) {
|
||||
writeWithMapNamed(state, "return ", CAT_OTHER, node);
|
||||
writeWithMap(state, "return ", CAT_OTHER, node);
|
||||
printExpression(argument, state, PREC_LOWEST, CTX_NONE);
|
||||
} else {
|
||||
writeWithMapNamed(state, "return", CAT_IDENT, node);
|
||||
writeWithMap(state, "return", CAT_IDENT, node);
|
||||
}
|
||||
|
||||
write(state, ";\n", CAT_OTHER);
|
||||
@@ -510,7 +511,7 @@ function printTryStatement(node: ESTree.TryStatement, state: State): void {
|
||||
printIndent(state);
|
||||
printSpaceBeforeIdentifier(state);
|
||||
|
||||
writeWithMapNamed(state, "try ", CAT_OTHER, node);
|
||||
writeWithMap(state, "try ", CAT_OTHER, node);
|
||||
|
||||
printBlockStatement(node.block, state);
|
||||
|
||||
@@ -544,19 +545,19 @@ function printSwitchStatement(node: ESTree.SwitchStatement, state: State): void
|
||||
printIndent(state);
|
||||
printSpaceBeforeIdentifier(state);
|
||||
|
||||
writeWithMapNamed(state, "switch (", CAT_OTHER, node);
|
||||
writeWithMap(state, "switch (", CAT_OTHER, node);
|
||||
printExpression(node.discriminant, state, PREC_LOWEST, CTX_NONE);
|
||||
write(state, ") ", CAT_OTHER);
|
||||
|
||||
const { cases } = node;
|
||||
const { length } = cases;
|
||||
if (length === 0) {
|
||||
writeWithMapNamedNoLast(state, "{", node);
|
||||
writeWithMapNoLast(state, "{", node);
|
||||
writeWithMapEnd(state, "}\n", CAT_OTHER, node);
|
||||
return;
|
||||
}
|
||||
|
||||
writeWithMapNamed(state, "{\n", CAT_OTHER, node);
|
||||
writeWithMap(state, "{\n", CAT_OTHER, node);
|
||||
state.indentLevel++;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
@@ -576,10 +577,10 @@ function printSwitchCase(node: ESTree.SwitchCase, state: State): void {
|
||||
printIndent(state);
|
||||
|
||||
if (node.test != null) {
|
||||
writeWithMapNamed(state, "case ", CAT_OTHER, node);
|
||||
writeWithMap(state, "case ", CAT_OTHER, node);
|
||||
printExpression(node.test, state, PREC_LOWEST, CTX_NONE);
|
||||
} else {
|
||||
writeWithMapNamed(state, "default", CAT_IDENT, node);
|
||||
writeWithMap(state, "default", CAT_IDENT, node);
|
||||
}
|
||||
|
||||
write(state, ":", CAT_OTHER);
|
||||
@@ -609,7 +610,7 @@ function printWhileStatement(node: ESTree.WhileStatement, state: State): void {
|
||||
printIndent(state);
|
||||
printSpaceBeforeIdentifier(state);
|
||||
|
||||
writeWithMapNamed(state, "while (", CAT_OTHER, node);
|
||||
writeWithMap(state, "while (", CAT_OTHER, node);
|
||||
printExpression(node.test, state, PREC_LOWEST, CTX_NONE);
|
||||
write(state, ")", CAT_CLOSE_BRACKET);
|
||||
|
||||
@@ -627,7 +628,7 @@ function printDoWhileStatement(node: ESTree.DoWhileStatement, state: State): voi
|
||||
printIndent(state);
|
||||
printSpaceBeforeIdentifier(state);
|
||||
|
||||
writeWithMapNamed(state, "do", CAT_IDENT, node);
|
||||
writeWithMap(state, "do", CAT_IDENT, node);
|
||||
|
||||
const { body } = node;
|
||||
if (body.type === "BlockStatement") {
|
||||
@@ -636,7 +637,7 @@ function printDoWhileStatement(node: ESTree.DoWhileStatement, state: State): voi
|
||||
write(state, " ", CAT_OTHER);
|
||||
} else if (body.type === "EmptyStatement") {
|
||||
printIndent(state);
|
||||
writeWithMapNamed(state, ";\n", CAT_OTHER, body);
|
||||
writeWithMap(state, ";\n", CAT_OTHER, body);
|
||||
} else {
|
||||
write(state, "\n", CAT_OTHER);
|
||||
state.indentLevel++;
|
||||
@@ -661,7 +662,7 @@ function printForStatement(node: ESTree.ForStatement, state: State): void {
|
||||
printIndent(state);
|
||||
printSpaceBeforeIdentifier(state);
|
||||
|
||||
writeWithMapNamed(state, "for (", CAT_OTHER, node);
|
||||
writeWithMap(state, "for (", CAT_OTHER, node);
|
||||
|
||||
const { init } = node;
|
||||
if (init != null) {
|
||||
@@ -699,7 +700,7 @@ function printForInStatement(node: ESTree.ForInStatement, state: State): void {
|
||||
printIndent(state);
|
||||
printSpaceBeforeIdentifier(state);
|
||||
|
||||
writeWithMapNamed(state, "for (", CAT_OTHER, node);
|
||||
writeWithMap(state, "for (", CAT_OTHER, node);
|
||||
|
||||
const { left } = node;
|
||||
if (left.type === "VariableDeclaration") {
|
||||
@@ -727,7 +728,7 @@ function printForOfStatement(node: ESTree.ForOfStatement, state: State): void {
|
||||
printIndent(state);
|
||||
printSpaceBeforeIdentifier(state);
|
||||
|
||||
writeWithMapNamed(state, "for", CAT_IDENT, node);
|
||||
writeWithMap(state, "for", CAT_IDENT, node);
|
||||
|
||||
if (node.await) write(state, " await", CAT_IDENT);
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// String literal printing (port of `str.rs`, pretty mode: fixed quote).
|
||||
|
||||
import { CAT_OTHER, write, writeNoLast, writeWithMapNamedNoLast } from "./write.ts";
|
||||
import { CAT_OTHER, write, writeNoLast, writeWithMapNoLast } from "./write.ts";
|
||||
import { debugAssert } from "../asserts.ts";
|
||||
|
||||
import type { State } from "../state.ts";
|
||||
import type * as ESTree from "../../../../npm/oxc-types/types.d.ts";
|
||||
import type { UnnamedMappableNode } from "./types.ts";
|
||||
|
||||
/**
|
||||
* Characters or sequences which may need escaping or special handling.
|
||||
@@ -22,9 +22,9 @@ 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.
|
||||
*/
|
||||
export function printString(state: State, value: string, node: ESTree.Node): void {
|
||||
export function printString(state: State, value: string, node: UnnamedMappableNode): void {
|
||||
// Quote is fixed - double, matching `oxc_codegen`'s default option
|
||||
writeWithMapNamedNoLast(state, '"', node);
|
||||
writeWithMapNoLast(state, '"', node);
|
||||
|
||||
// Almost no string needs escaping, so the loop which performs escaping sits in its own function
|
||||
if (!STRING_ESCAPE_REGEX.test(value)) {
|
||||
|
||||
@@ -58,10 +58,34 @@ export type ExportNamedDeclarationNode = Omit<ESTree.ExportNamedDeclaration, "de
|
||||
|
||||
/**
|
||||
* A node carrying the offsets needed for source mappings.
|
||||
*
|
||||
* No `name` - a mapping recorded for one of these carries none. `NamedMappableNode` below is the
|
||||
* shape the named forms take, and requiring `name` on it is what steers a named call which cannot
|
||||
* produce a name to the plain form instead.
|
||||
*/
|
||||
export interface MappableNode {
|
||||
type: string;
|
||||
name?: unknown;
|
||||
start?: number;
|
||||
end?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A node whose mapping records the name it had in the source.
|
||||
*
|
||||
* These are the identifier kinds Rust `oxc_codegen` names mappings for - identifier references and
|
||||
* names, binding, label, JSX and private identifiers.
|
||||
*/
|
||||
export interface NamedMappableNode extends MappableNode {
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A node whose mapping records no name, because it has no string `name` to record.
|
||||
*
|
||||
* `name?: object` is how a node which does have one is rejected - `string` is not assignable to it.
|
||||
* A `name` holding a node rather than a string, as a JSX element's does, is not a name a mapping could record,
|
||||
* and stays allowed.
|
||||
*/
|
||||
export interface UnnamedMappableNode extends MappableNode {
|
||||
name?: object;
|
||||
}
|
||||
@@ -12,9 +12,11 @@ import {
|
||||
markMapAtStartOffset,
|
||||
write,
|
||||
writeNoLast,
|
||||
writeWithMapNamed,
|
||||
writeWithMap,
|
||||
writeWithMapEnd,
|
||||
writeWithMapNamed,
|
||||
writeWithMapNamedNoLast,
|
||||
writeWithMapNoLast,
|
||||
} from "./write.ts";
|
||||
import { printExpression } from "./expression.ts";
|
||||
import { printParenParams, printParenParamsArrow } from "./function.ts";
|
||||
@@ -285,7 +287,7 @@ function printTSTypeName(
|
||||
writeWithMapNamed(state, node.right.name, CAT_IDENT, node.right);
|
||||
} else if (node.type === "ThisExpression") {
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, "this", CAT_IDENT, node);
|
||||
writeWithMap(state, "this", CAT_IDENT, node);
|
||||
} else {
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, node.name, CAT_IDENT, node);
|
||||
@@ -432,12 +434,12 @@ function printTSTypeLiteral(node: ESTree.TSTypeLiteral, state: State): void {
|
||||
const { members } = node;
|
||||
const { length } = members;
|
||||
if (length === 0) {
|
||||
writeWithMapNamedNoLast(state, "{", node);
|
||||
writeWithMapNoLast(state, "{", node);
|
||||
writeWithMapEnd(state, "}", CAT_OTHER, node);
|
||||
return;
|
||||
}
|
||||
|
||||
writeWithMapNamed(state, "{\n", CAT_OTHER, node);
|
||||
writeWithMap(state, "{\n", CAT_OTHER, node);
|
||||
state.indentLevel++;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
@@ -957,12 +959,12 @@ export function printTSModuleDeclaration(
|
||||
function printModuleBlock(body: ESTree.TSModuleBlock, state: State): void {
|
||||
const statements = body.body;
|
||||
if (statements.length === 0) {
|
||||
writeWithMapNamedNoLast(state, "{", body);
|
||||
writeWithMapNoLast(state, "{", body);
|
||||
writeWithMapEnd(state, "}", CAT_OTHER, body);
|
||||
return;
|
||||
}
|
||||
|
||||
writeWithMapNamed(state, "{\n", CAT_OTHER, body);
|
||||
writeWithMap(state, "{\n", CAT_OTHER, body);
|
||||
|
||||
state.indentLevel++;
|
||||
printDirectivesAndStatements(statements, state);
|
||||
@@ -1012,12 +1014,12 @@ export function printTSInterfaceDeclaration(
|
||||
const members = node.body.body;
|
||||
const { length } = members;
|
||||
if (length === 0) {
|
||||
writeWithMapNamedNoLast(state, "{", node.body);
|
||||
writeWithMapNoLast(state, "{", node.body);
|
||||
writeWithMapEnd(state, "}", CAT_OTHER, node.body);
|
||||
return;
|
||||
}
|
||||
|
||||
writeWithMapNamed(state, "{\n", CAT_OTHER, node.body);
|
||||
writeWithMap(state, "{\n", CAT_OTHER, node.body);
|
||||
state.indentLevel++;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
@@ -1117,12 +1119,12 @@ export function printTSEnumDeclaration(node: ESTree.TSEnumDeclaration, state: St
|
||||
const { members } = body;
|
||||
const { length } = members;
|
||||
if (length === 0) {
|
||||
writeWithMapNamedNoLast(state, "{", body);
|
||||
writeWithMapNoLast(state, "{", body);
|
||||
writeWithMapEnd(state, "}", CAT_OTHER, body);
|
||||
return;
|
||||
}
|
||||
|
||||
writeWithMapNamed(state, "{\n", CAT_OTHER, body);
|
||||
writeWithMap(state, "{\n", CAT_OTHER, body);
|
||||
state.indentLevel++;
|
||||
|
||||
const lastIndex = length - 1;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { debugAssert } from "../asserts.ts";
|
||||
|
||||
import type { MappableNode } from "./types.ts";
|
||||
import type { MappableNode, NamedMappableNode, UnnamedMappableNode } from "./types.ts";
|
||||
import type { State } from "../state.ts";
|
||||
|
||||
// `state.last` records what was written last, by category, not the last character itself.
|
||||
@@ -260,7 +260,40 @@ export function write(state: State, code: string, last: Category): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Append `code` to the output, record what it ends with, and record a source mapping for `node`.
|
||||
* Append `code` to the output, record what it ends with, and record an unnamed source mapping for `node`.
|
||||
*
|
||||
* The mapping is only recorded where the caller asked for source maps and `node` carries `start` / `end` offsets.
|
||||
*
|
||||
* Builds without source map support have no use for this. For those builds, TSDown plugin rewrites every call
|
||||
* into `write` and drops the `node` argument, leaving this unreferenced for the minifier to remove.
|
||||
*
|
||||
* @param state - Printer state
|
||||
* @param code - Text to append, never empty
|
||||
* @param last - Category of the last character of `code`
|
||||
* @param node - Node this text came from
|
||||
*/
|
||||
export function writeWithMap(
|
||||
state: State,
|
||||
code: string,
|
||||
last: Category,
|
||||
node: UnnamedMappableNode,
|
||||
): void {
|
||||
debugAssert(code.length > 0, "`code` should not be an empty string");
|
||||
debugAssertCategoryMatches(state, code, last);
|
||||
|
||||
recordSourceMapping(state, node, LOCATION_START);
|
||||
|
||||
state.last = last;
|
||||
state.output += code;
|
||||
|
||||
if (DEBUG) {
|
||||
state.lastIsStale = false;
|
||||
state.lastCharWritten = code[code.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append `code` to the output, record what it ends with, and record a named source mapping for `node`.
|
||||
*
|
||||
* The mapping is only recorded where the caller asked for source maps and `node` carries `start` / `end` offsets.
|
||||
*
|
||||
@@ -276,7 +309,7 @@ export function writeWithMapNamed(
|
||||
state: State,
|
||||
code: string,
|
||||
last: Category,
|
||||
node: MappableNode,
|
||||
node: NamedMappableNode,
|
||||
): void {
|
||||
debugAssert(code.length > 0, "`code` should not be an empty string");
|
||||
debugAssertCategoryMatches(state, code, last);
|
||||
@@ -317,7 +350,34 @@ export function writeNoLast(state: State, code: string): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Append `code` and record a source mapping for `node`, leaving `state.last` alone.
|
||||
* Append `code` and record an unnamed source mapping for `node`, leaving `state.last` alone.
|
||||
*
|
||||
* The mapping is only recorded where the caller asked for source maps and `node` carries `start` / `end` offsets.
|
||||
*
|
||||
* `writeNoLast`'s rule about `last` applies here too - another write must follow before anything reads it.
|
||||
*
|
||||
* Builds without source map support have no use for this. For those builds, TSDown plugin rewrites every call
|
||||
* into `writeNoLast` and drops the `node` argument, leaving this unreferenced for the minifier to remove.
|
||||
*
|
||||
* @param state - Printer state
|
||||
* @param code - Text to append, which unlike `writeWithMap` may be empty
|
||||
* @param node - Node this text came from
|
||||
*/
|
||||
export function writeWithMapNoLast(state: State, code: string, node: UnnamedMappableNode): void {
|
||||
recordSourceMapping(state, node, LOCATION_START);
|
||||
|
||||
state.output += code;
|
||||
|
||||
if (DEBUG) {
|
||||
state.lastIsStale = true;
|
||||
if (code.length > 0) state.lastCharWritten = code[code.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append `code` and record a named source mapping for `node`, leaving `state.last` alone.
|
||||
*
|
||||
* The mapping is only recorded where the caller asked for source maps and `node` carries `start` / `end` offsets.
|
||||
*
|
||||
* `writeNoLast`'s rule about `last` applies here too - another write must follow before anything reads it.
|
||||
*
|
||||
@@ -328,7 +388,7 @@ export function writeNoLast(state: State, code: string): void {
|
||||
* @param code - Text to append, which unlike `writeWithMapNamed` may be empty
|
||||
* @param node - Node this text came from
|
||||
*/
|
||||
export function writeWithMapNamedNoLast(state: State, code: string, node: MappableNode): void {
|
||||
export function writeWithMapNamedNoLast(state: State, code: string, node: NamedMappableNode): void {
|
||||
recordSourceMapping(state, node, LOCATION_NAMED);
|
||||
|
||||
state.output += code;
|
||||
@@ -375,21 +435,6 @@ export function writeWithMapEnd(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a mapping for `node`'s start offset at the current output position, with a name.
|
||||
*
|
||||
* Where `node` is an identifier, the mapping carries the name it had in the source.
|
||||
*
|
||||
* The mapping is only recorded where the caller asked for source maps and `node` carries `start` / `end` offsets.
|
||||
* Builds without source map support have no use for this. In those builds, minifier removes it.
|
||||
*
|
||||
* @param state - Printer state
|
||||
* @param node - Node the mapping points at
|
||||
*/
|
||||
export function markMapNamed(state: State, node: MappableNode): void {
|
||||
if (SOURCEMAPS) recordSourceMapping(state, node, LOCATION_NAMED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a mapping for `node`'s start offset at the current output position.
|
||||
*
|
||||
@@ -499,7 +544,10 @@ function recordSourceMapping(state: State, node: MappableNode, location: Locatio
|
||||
// recovering a name or retaining the mapping, since member-level marks commonly duplicate keys.
|
||||
if (state.mapPositions[state.mapPositions.length - 1] === sourceOffset) return;
|
||||
|
||||
if (location === LOCATION_NAMED && typeof node.name === "string") {
|
||||
if (location === LOCATION_NAMED) {
|
||||
// Only the named forms pass `LOCATION_NAMED`, and they take a `NamedMappableNode`
|
||||
debugAssert("name" in node && typeof node.name === "string");
|
||||
|
||||
// A mapping carries a name only when the identifier printed differs from the one in the source.
|
||||
// When possible, the mapping records the name from source, but if the source range is invalid,
|
||||
// it falls back to the printed name.
|
||||
@@ -524,8 +572,7 @@ function recordSourceMapping(state: State, node: MappableNode, location: Locatio
|
||||
const nameStart = start + hashLength;
|
||||
const nameEnd = nameStart + printedName.length;
|
||||
const matchesSource =
|
||||
printedName.length > 0
|
||||
&& end <= sourceText.length
|
||||
end <= sourceText.length
|
||||
&& nameEnd <= end
|
||||
&& (hashLength === 0 || sourceText.charCodeAt(start) === 35) /* # */
|
||||
&& sourceText.startsWith(printedName, nameStart)
|
||||
|
||||
@@ -71,8 +71,8 @@ const minifyConfig = DEBUG
|
||||
// `src-js/index.ts` loads whichever build the caller's options call for.
|
||||
//
|
||||
// In builds without source maps, nothing reads the `node` argument the mapping writes take,
|
||||
// so `unmap_writes` rewrites every `writeWithMapNamed` / `writeWithMapNamedNoLast` call, and the imports
|
||||
// which bring them in, into the plain `write` / `writeNoLast` they become without it.
|
||||
// so `unmap_writes` rewrites every mapped write call, and the imports which bring them in,
|
||||
// into the plain `write` / `writeNoLast` they become without it.
|
||||
const printerConfig = (name: string, { sourcemaps, ts }: { sourcemaps: boolean; ts: boolean }) => ({
|
||||
...commonConfig,
|
||||
minify: minifyConfig,
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { Plugin } from "rolldown";
|
||||
*
|
||||
* ```ts
|
||||
* // Original code
|
||||
* writeWithMapNamed(state, "declare ", CAT_OTHER, node);
|
||||
* writeWithMap(state, "declare ", CAT_OTHER, node);
|
||||
*
|
||||
* // After transform
|
||||
* write(state, "declare ", CAT_OTHER);
|
||||
@@ -35,11 +35,12 @@ import type { Plugin } from "rolldown";
|
||||
*/
|
||||
const REWRITES = {
|
||||
// `write` takes the `last` category between the code and the node, `writeNoLast` does not
|
||||
writeWithMap: { arity: 4, remove: 1, rename: "write" },
|
||||
writeWithMapNamed: { arity: 4, remove: 1, rename: "write" },
|
||||
writeWithMapNoLast: { arity: 3, remove: 1, rename: "writeNoLast" },
|
||||
writeWithMapNamedNoLast: { arity: 3, remove: 1, rename: "writeNoLast" },
|
||||
writeWithMapEnd: { arity: 4, remove: 1, rename: "write" },
|
||||
// `rename: null` because a standalone mark has no non-sourcemap equivalent
|
||||
markMapNamed: { arity: 2, remove: 1, rename: null },
|
||||
markMapStart: { arity: 2, remove: 1, rename: null },
|
||||
markMapAfter: { arity: 2, remove: 1, rename: null },
|
||||
markMapAtStartOffset: { arity: 3, remove: 2, rename: null },
|
||||
|
||||
Reference in new issue
Block a user