Skip to content

Commit 706aa4e

Browse files
authored
Switch js parse postprocess to onEnter (#18382)
1 parent d3eb2b2 commit 706aa4e

File tree

7 files changed

+70
-49
lines changed

7 files changed

+70
-49
lines changed

src/language-css/parse/parse-value.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import PostcssValuesParser from "postcss-values-parser/lib/parser.js";
2+
import isObject from "../../utilities/is-object.js";
23
import getFunctionArgumentsText from "../utilities/get-function-arguments-text.js";
34
import getValueRoot from "../utilities/get-value-root.js";
45
import hasSCSSInterpolation from "../utilities/has-scss-interpolation.js";
@@ -156,7 +157,7 @@ function flattenGroups(node) {
156157
}
157158

158159
function parseNestedValue(node, options) {
159-
if (node && typeof node === "object") {
160+
if (isObject(node)) {
160161
for (const key in node) {
161162
if (key !== "parent") {
162163
parseNestedValue(node[key], options);

src/language-css/parse/utilities.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import isObject from "../../utilities/is-object.js";
2+
13
function addTypePrefix(node, prefix, skipPrefix) {
2-
if (node && typeof node === "object") {
4+
if (isObject(node)) {
35
delete node.parent;
46
for (const key in node) {
57
addTypePrefix(node[key], prefix, skipPrefix);
@@ -17,7 +19,7 @@ function addTypePrefix(node, prefix, skipPrefix) {
1719
}
1820

1921
function addMissingType(node) {
20-
if (node && typeof node === "object") {
22+
if (isObject(node)) {
2123
delete node.parent;
2224
for (const key in node) {
2325
addMissingType(node[key]);

src/language-css/parser-postcss.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import postcssLess from "postcss-less";
33
import postcssScssParse from "postcss-scss/lib/scss-parse";
44
import createError from "../common/parser-create-error.js";
55
import { parseFrontMatter } from "../main/front-matter/index.js";
6+
import isObject from "../utilities/is-object.js";
67
import {
78
calculateLoc,
89
locEnd,
@@ -21,7 +22,7 @@ const DEFAULT_SCSS_DIRECTIVE = /(\s*)(!default).*$/u;
2122
const GLOBAL_SCSS_DIRECTIVE = /(\s*)(!global).*$/u;
2223

2324
function parseNestedCSS(node, options) {
24-
if (node && typeof node === "object") {
25+
if (isObject(node)) {
2526
delete node.parent;
2627

2728
for (const key in node) {

src/language-js/parse/postprocess/index.js

Lines changed: 44 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,31 @@ function postprocess(ast, options) {
4343

4444
mergeNestledJsdocComments(comments);
4545

46+
// `InterpreterDirective` from babel parser and flow parser
47+
// Other parsers parse it as comment, babel treat it as comment too
48+
// https://github.com/babel/babel/issues/15116
49+
const program = ast.type === "File" ? ast.program : ast;
50+
if (program.interpreter) {
51+
comments.unshift(program.interpreter);
52+
delete program.interpreter;
53+
}
54+
55+
if (isOxcTs && ast.hashbang) {
56+
comments.unshift(ast.hashbang);
57+
delete ast.hashbang;
58+
}
59+
60+
// In `typescript` and `flow`, `Program` doesn't count whitespace and comments
61+
// See https://github.com/typescript-eslint/typescript-eslint/issues/11026
62+
// See https://github.com/facebook/flow/issues/8537
63+
if (ast.type === "Program") {
64+
ast.range = [0, text.length];
65+
}
66+
4667
let typeCastCommentsEnds;
4768

4869
ast = visitNode(ast, {
49-
onLeave(node) {
70+
onEnter(node) {
5071
switch (node.type) {
5172
case "ParenthesizedExpression": {
5273
const { expression } = node;
@@ -58,7 +79,7 @@ function postprocess(ast, options) {
5879
return expression;
5980
}
6081

61-
let keepTypeCast = false;
82+
let shouldKeepParenthesizedExpression = false;
6283
if (!isOxcTs) {
6384
if (!typeCastCommentsEnds) {
6485
typeCastCommentsEnds = [];
@@ -74,27 +95,21 @@ function postprocess(ast, options) {
7495
const previousCommentEnd = typeCastCommentsEnds.findLast(
7596
(end) => end <= start,
7697
);
77-
keepTypeCast =
98+
shouldKeepParenthesizedExpression =
7899
previousCommentEnd &&
79100
// check that there are only white spaces between the comment and the parenthesis
80101
text.slice(previousCommentEnd, start).trim().length === 0;
81102
}
82103

83-
if (!keepTypeCast) {
84-
expression.extra = { ...expression.extra, parenthesized: true };
85-
return expression;
104+
if (shouldKeepParenthesizedExpression) {
105+
return;
86106
}
87-
break;
88-
}
89107

90-
case "LogicalExpression":
91-
// We remove unneeded parens around same-operator LogicalExpressions
92-
if (isUnbalancedLogicalTree(node)) {
93-
return rebalanceLogicalTree(node);
94-
}
95-
break;
108+
expression.extra = { ...expression.extra, parenthesized: true };
109+
return expression;
110+
}
96111

97-
// This happens when use `oxc-parser` to parse `` `${foo satisfies bar}`; ``
112+
// This happened when use `oxc-parser` to parse `` `${foo satisfies bar}`; ``
98113
// https://github.com/oxc-project/oxc/issues/11313
99114
case "TemplateLiteral":
100115
/* c8 ignore next 3 */
@@ -128,16 +143,15 @@ function postprocess(ast, options) {
128143
}
129144
break;
130145
}
146+
131147
// remove redundant TypeScript nodes
132148
case "TSParenthesizedType":
133149
return node.typeAnnotation;
134150

135151
// For hack-style pipeline
136152
case "TopicReference":
137153
ast.extra = { ...ast.extra, __isUsingHackPipeline: true };
138-
break;
139-
140-
// In Flow parser, it doesn't generate union/intersection types for single type
154+
break; // In Flow parser, it doesn't generate union/intersection types for single type
141155
case "TSUnionType":
142156
case "TSIntersectionType":
143157
if (node.types.length === 1) {
@@ -151,9 +165,21 @@ function postprocess(ast, options) {
151165
node.options = node.attributes;
152166
}
153167
break;
168+
}
169+
},
170+
onLeave(node) {
171+
switch (node.type) {
172+
// Children can be parenthesized, need do this in `onLeave`
173+
case "LogicalExpression":
174+
// We remove unneeded parens around same-operator LogicalExpressions
175+
if (isUnbalancedLogicalTree(node)) {
176+
return rebalanceLogicalTree(node);
177+
}
178+
break;
154179

155180
// https://github.com/babel/babel/issues/17506
156181
// https://github.com/oxc-project/oxc/issues/16074
182+
// It's possible to have parenthesized `argument`, need do this in `onLeave`
157183
case "TSImportType":
158184
if (!node.source && node.argument.type === "TSLiteralType") {
159185
node.source = node.argument.literal;
@@ -169,31 +195,10 @@ function postprocess(ast, options) {
169195
},
170196
});
171197

172-
// `InterpreterDirective` from babel parser and flow parser
173-
// Other parsers parse it as comment, babel treat it as comment too
174-
// https://github.com/babel/babel/issues/15116
175-
const program = ast.type === "File" ? ast.program : ast;
176-
if (program.interpreter) {
177-
comments.unshift(program.interpreter);
178-
delete program.interpreter;
179-
}
180-
181-
if (isOxcTs && ast.hashbang) {
182-
comments.unshift(ast.hashbang);
183-
delete ast.hashbang;
184-
}
185-
186198
/* c8 ignore next 3 */
187199
if (process.env.NODE_ENV !== "production") {
188200
assertComments(comments, text);
189201
}
190-
191-
// In `typescript` and `flow`, `Program` doesn't count whitespace and comments
192-
// See https://github.com/typescript-eslint/typescript-eslint/issues/11026
193-
// See https://github.com/facebook/flow/issues/8537
194-
if (ast.type === "Program") {
195-
ast.range = [0, text.length];
196-
}
197202
return ast;
198203
}
199204

src/language-js/parse/postprocess/visit-node.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import isObject from "../../../utilities/is-object.js";
12
import getVisitorKeys from "../../traverse/get-visitor-keys.js";
23

34
function visitNode(node, options) {
4-
if (!(node !== null && typeof node === "object")) {
5+
if (!isObject(node)) {
56
return node;
67
}
78

@@ -16,15 +17,25 @@ function visitNode(node, options) {
1617
}
1718

1819
if (options.onEnter) {
19-
node = options.onEnter(node) || node;
20+
const result = options.onEnter(node) ?? node;
21+
// If node is replaced, re-enter
22+
if (result !== node) {
23+
return visitNode(result, options);
24+
}
25+
26+
node = result;
2027
}
2128

2229
const keys = getVisitorKeys(node);
2330
for (let i = 0; i < keys.length; i++) {
2431
node[keys[i]] = visitNode(node[keys[i]], options);
2532
}
2633

27-
return options.onLeave(node) || node;
34+
if (options.onLeave) {
35+
node = options.onLeave(node) || node;
36+
}
37+
38+
return node;
2839
}
2940

3041
export default visitNode;

src/language-js/utilities/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import getStringWidth from "../../utilities/get-string-width.js";
33
import hasNewline from "../../utilities/has-newline.js";
44
import isNextLineEmptyAfterIndex from "../../utilities/is-next-line-empty.js";
55
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
6+
import isObject from "../../utilities/is-object.js";
67
import printString from "../../utilities/print-string.js";
78
import { hasSameLocStart, locEnd, locStart } from "../loc.js";
89
import getVisitorKeys from "../traverse/get-visitor-keys.js";
@@ -417,7 +418,7 @@ function getExpressionInnerNodeCount(node, maxCount) {
417418
for (const k in node) {
418419
const prop = node[k];
419420

420-
if (prop && typeof prop === "object" && typeof prop.type === "string") {
421+
if (isObject(prop) && typeof prop.type === "string") {
421422
count++;
422423
count += getExpressionInnerNodeCount(prop, maxCount - count);
423424
}

src/main/ast-to-doc.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import AstPath from "../common/ast-path.js";
22
import { cursor, inheritLabel } from "../document/index.js";
3+
import isObject from "../utilities/is-object.js";
34
import { attachComments } from "./comments/attach.js";
45
import { ensureAllCommentsPrinted, printComments } from "./comments/print.js";
56
import createPrintPreCheckFunction from "./create-print-pre-check-function.js";
@@ -82,8 +83,7 @@ async function printAstToDoc(ast, options) {
8283
return "";
8384
}
8485

85-
const shouldCache =
86-
value && typeof value === "object" && args === undefined;
86+
const shouldCache = isObject(value) && args === undefined;
8787

8888
if (shouldCache && cache.has(value)) {
8989
return cache.get(value);

0 commit comments

Comments
 (0)