7#include <QtQml/private/qqmljsast_p.h>
8#include <QtQml/private/qqmljsastvisitor_p.h>
9#include <QtQml/private/qqmljsengine_p.h>
10#include <QtQml/private/qqmljslexer_p.h>
21bool ScriptFormatter::preVisit(Node *n)
23 const CommentedElement *c = comments->commentForNode(n, CommentAnchor{});
27 if (!c->preComments().empty()) {
29 for (
const auto &preComment : c->preComments())
30 lw.maybeWriteComment(preComment);
33 postOps[n].append([c,
this]() {
34 if (!c->postComments().empty()) {
36 for (
const auto &postComment : c->postComments())
37 lw.maybeWriteComment(postComment);
43void ScriptFormatter::postVisit(Node *n)
45 for (
auto &op : postOps[n]) {
51void ScriptFormatter::lnAcceptIndented(Node *node)
53 int indent = lw.increaseIndent(1);
56 lw.decreaseIndent(1, indent);
59bool ScriptFormatter::acceptBlockOrIndented(Node *ast,
bool finishWithSpaceOrNewline)
61 if (
auto *es = cast<EmptyStatement *>(ast)) {
62 writeOutSemicolon(es);
65 if (cast<Block *>(ast)) {
66 ensureSpaceIfNoComment();
68 if (finishWithSpaceOrNewline)
69 ensureSpaceIfNoComment();
72 if (finishWithSpaceOrNewline)
73 postOps[ast].append([
this]() { ensureNewline(); });
74 lnAcceptIndented(ast);
79bool ScriptFormatter::visit(ThisExpression *ast)
85bool ScriptFormatter::visit(NullExpression *ast)
90bool ScriptFormatter::visit(TrueLiteral *ast)
95bool ScriptFormatter::visit(FalseLiteral *ast)
101bool ScriptFormatter::visit(IdentifierExpression *ast)
103 out(ast->identifierToken);
106bool ScriptFormatter::visit(StringLiteral *ast)
109 if (ast->literalToken.length == 0)
111 QStringView str = m_script->loc2Str(ast->literalToken);
112 if (lw.indentNextlines && str.contains(QLatin1Char(
'\n'))) {
114 lw.indentNextlines =
false;
116 lw.indentNextlines =
true;
122bool ScriptFormatter::visit(NumericLiteral *ast)
124 outWithComments(ast->literalToken, ast);
127bool ScriptFormatter::visit(RegExpLiteral *ast)
129 out(ast->literalToken);
133bool ScriptFormatter::visit(ArrayPattern *ast)
135 outWithComments(ast->lbracketToken, ast);
136 int baseIndent = lw.increaseIndent(1);
138 accept(ast->elements);
139 outWithComments(ast->commaToken, ast);
140 auto lastElement = lastListElement(ast->elements);
141 if (lastElement->element && cast<ObjectPattern *>(lastElement->element->initializer)) {
145 outWithComments(ast->commaToken, ast);
147 lw.decreaseIndent(1, baseIndent);
148 outWithComments(ast->rbracketToken, ast);
152bool ScriptFormatter::visit(ObjectPattern *ast)
154 outWithComments(ast->lbraceToken, ast);
156 if (ast->properties) {
157 lnAcceptIndented(ast->properties);
161 outWithComments(ast->rbraceToken, ast);
165bool ScriptFormatter::visit(PatternElementList *ast)
167 for (PatternElementList *it = ast; it; it = it->next) {
168 const bool isObjectInitializer =
169 it->element && cast<ObjectPattern *>(it->element->initializer);
170 if (isObjectInitializer)
178 outWithComments(it->next->commaToken, it);
179 ensureSpaceIfNoComment();
180 if (isObjectInitializer)
187bool ScriptFormatter::visit(PatternPropertyList *ast)
189 for (PatternPropertyList *it = ast; it; it = it->next) {
190 accept(it->property);
200bool ScriptFormatter::visit(AST::PatternProperty *property)
202 if (property->type == PatternElement::Getter || property->type == PatternElement::Setter
203 || property->type == PatternElement::Method) {
208 if (property->type == PatternProperty::Getter) {
210 ensureSpaceIfNoComment();
211 }
else if (property->type == PatternProperty::Setter) {
213 ensureSpaceIfNoComment();
215 FunctionExpression *f = AST::cast<FunctionExpression *>(property->initializer);
216 if (f->isGenerator) {
219 accept(property->name);
223 ensureSpaceIfNoComment();
225 const bool scoped = f->lbraceToken.isValid();
229 if (f->body->next || scoped) {
230 lnAcceptIndented(f->body);
233 auto baseIndent = lw.increaseIndent(1);
235 lw.decreaseIndent(1, baseIndent);
245 accept(property->name);
246 bool useInitializer =
false;
247 const bool bindingIdentifierExist = !property->bindingIdentifier.isEmpty();
248 if (property->colonToken.isValid()) {
251 ensureSpaceIfNoComment();
252 useInitializer =
true;
253 if (bindingIdentifierExist)
254 out(property->bindingIdentifier);
255 if (property->bindingTarget)
256 accept(property->bindingTarget);
259 if (property->initializer) {
261 if (bindingIdentifierExist) {
262 ensureSpaceIfNoComment();
264 ensureSpaceIfNoComment();
265 useInitializer =
true;
268 accept(property->initializer);
273bool ScriptFormatter::visit(NestedExpression *ast)
275 out(ast->lparenToken);
276 int baseIndent = lw.increaseIndent(1);
277 accept(ast->expression);
278 lw.decreaseIndent(1, baseIndent);
279 out(ast->rparenToken);
283bool ScriptFormatter::visit(IdentifierPropertyName *ast)
285 out(ast->id.toString());
288bool ScriptFormatter::visit(StringLiteralPropertyName *ast)
290 out(ast->propertyNameToken);
293bool ScriptFormatter::visit(NumericLiteralPropertyName *ast)
295 out(QString::number(ast->id));
299bool ScriptFormatter::visit(TemplateLiteral *ast)
302 if (ast->literalToken.length != 0) {
303 QStringView str = m_script->loc2Str(ast->literalToken);
304 if (lw.indentNextlines && str.contains(QLatin1Char(
'\n'))) {
306 lw.indentNextlines =
false;
308 lw.indentNextlines =
true;
313 accept(ast->expression);
317bool ScriptFormatter::visit(ArrayMemberExpression *ast)
320 out(ast->optionalToken);
321 out(ast->lbracketToken);
322 int indent = lw.increaseIndent(1);
323 accept(ast->expression);
324 lw.decreaseIndent(1, indent);
325 out(ast->rbracketToken);
329bool ScriptFormatter::visit(FieldMemberExpression *ast)
333 out(ast->identifierToken);
337bool ScriptFormatter::visit(NewMemberExpression *ast)
340 ensureSpaceIfNoComment();
342 out(ast->lparenToken);
343 accept(ast->arguments);
344 out(ast->rparenToken);
348bool ScriptFormatter::visit(NewExpression *ast)
351 ensureSpaceIfNoComment();
352 accept(ast->expression);
356bool ScriptFormatter::visit(CallExpression *ast)
359 out(ast->optionalToken);
360 out(ast->lparenToken);
361 accept(ast->arguments);
362 out(ast->rparenToken);
366bool ScriptFormatter::visit(PostIncrementExpression *ast)
369 out(ast->incrementToken);
373bool ScriptFormatter::visit(PostDecrementExpression *ast)
376 out(ast->decrementToken);
380bool ScriptFormatter::visit(PreIncrementExpression *ast)
382 out(ast->incrementToken);
383 accept(ast->expression);
387bool ScriptFormatter::visit(PreDecrementExpression *ast)
389 out(ast->decrementToken);
390 accept(ast->expression);
394bool ScriptFormatter::visit(DeleteExpression *ast)
397 ensureSpaceIfNoComment();
398 accept(ast->expression);
402bool ScriptFormatter::visit(VoidExpression *ast)
405 ensureSpaceIfNoComment();
406 accept(ast->expression);
410bool ScriptFormatter::visit(TypeOfExpression *ast)
413 ensureSpaceIfNoComment();
414 accept(ast->expression);
418bool ScriptFormatter::visit(UnaryPlusExpression *ast)
421 accept(ast->expression);
425bool ScriptFormatter::visit(UnaryMinusExpression *ast)
427 out(ast->minusToken);
428 accept(ast->expression);
432bool ScriptFormatter::visit(TildeExpression *ast)
434 out(ast->tildeToken);
435 accept(ast->expression);
439bool ScriptFormatter::visit(NotExpression *ast)
442 accept(ast->expression);
446bool ScriptFormatter::visit(BinaryExpression *ast)
449 ensureSpaceIfNoComment();
450 out(ast->operatorToken);
451 ensureSpaceIfNoComment();
456bool ScriptFormatter::visit(ConditionalExpression *ast)
458 accept(ast->expression);
459 ensureSpaceIfNoComment();
461 ensureSpaceIfNoComment();
463 ensureSpaceIfNoComment();
465 ensureSpaceIfNoComment();
470bool ScriptFormatter::visit(Block *ast)
473 const CommentedElement *c =
474 comments->commentForNode(ast, CommentAnchor::from(ast->lbraceToken));
477 out(ast->lbraceToken);
478 const int indent = lw.increaseIndent();
482 if (ast->statements) {
485 accept(ast->statements);
492 c = comments->commentForNode(ast, CommentAnchor::from(ast->rbraceToken));
495 lw.decreaseIndent(1, indent);
496 out(ast->rbraceToken);
502bool ScriptFormatter::visit(VariableStatement *ast)
504 out(ast->declarationKindToken);
505 ensureSpaceIfNoComment();
506 accept(ast->declarations);
508 writeOutSemicolon(ast);
512bool ScriptFormatter::visit(PatternElement *ast)
515 case PatternElement::Literal:
516 case PatternElement::Method:
517 case PatternElement::Binding:
519 case PatternElement::Getter:
521 ensureSpaceIfNoComment();
523 case PatternElement::Setter:
525 ensureSpaceIfNoComment();
527 case PatternElement::SpreadElement:
532 accept(ast->bindingTarget);
533 if (!ast->destructuringPattern())
534 out(ast->identifierToken);
535 if (ast->initializer) {
536 if (ast->isVariableDeclaration() || ast->type == AST::PatternElement::Binding) {
537 ensureSpaceIfNoComment();
538 outWithComments(ast->equalToken, ast);
539 ensureSpaceIfNoComment();
541 accept(ast->initializer);
543 accept(ast->typeAnnotation);
547bool ScriptFormatter::visit(TypeAnnotation *ast)
549 out(ast->colonToken);
550 ensureSpaceIfNoComment();
555bool ScriptFormatter::visit(Type *ast)
558 if (ast->typeArgument) {
559 outWithComments(ast->lAngleBracketToken, ast);
560 accept(ast->typeArgument);
561 outWithComments(ast->rAngleBracketToken, ast);
566bool ScriptFormatter::visit(UiQualifiedId *ast)
568 for (UiQualifiedId *it = ast; it; it = it->next) {
569 outWithComments(it->dotToken, it);
570 outWithComments(it->identifierToken, it);
575bool ScriptFormatter::visit(EmptyStatement *)
577 lw.lineWriter.ensureSemicolon();
581bool ScriptFormatter::visit(IfStatement *ast)
584 ensureSpaceIfNoComment();
585 out(ast->lparenToken);
586 preVisit(ast->expression);
587 ast->expression->accept0(
this);
588 out(ast->rparenToken);
589 postVisit(ast->expression);
590 acceptBlockOrIndented(ast->ok, ast->ko);
593 if (cast<Block *>(ast->ko) || cast<IfStatement *>(ast->ko)) {
594 ensureSpaceIfNoComment();
597 lnAcceptIndented(ast->ko);
603bool ScriptFormatter::visit(DoWhileStatement *ast)
606 acceptBlockOrIndented(ast->statement,
true);
607 out(ast->whileToken);
608 ensureSpaceIfNoComment();
609 outWithComments(ast->lparenToken, ast);
610 accept(ast->expression);
611 outWithComments(ast->rparenToken, ast);
615bool ScriptFormatter::visit(WhileStatement *ast)
617 out(ast->whileToken);
618 ensureSpaceIfNoComment();
619 outWithComments(ast->lparenToken, ast);
620 accept(ast->expression);
621 outWithComments(ast->rparenToken, ast);
622 acceptBlockOrIndented(ast->statement);
626bool ScriptFormatter::visit(ForStatement *ast)
629 ensureSpaceIfNoComment();
630 outWithComments(ast->lparenToken, ast);
631 if (ast->initialiser) {
632 accept(ast->initialiser);
633 }
else if (ast->declarations) {
634 if (
auto pe = ast->declarations->declaration) {
635 out(pe->declarationKindToken);
636 ensureSpaceIfNoComment();
639 for (VariableDeclarationList *it = ast->declarations; it; it = it->next) {
640 if (!std::exchange(first,
false)) {
642 ensureSpaceIfNoComment();
644 accept(it->declaration);
650 ensureSpaceIfNoComment();
651 accept(ast->condition);
653 ensureSpaceIfNoComment();
654 accept(ast->expression);
655 outWithComments(ast->rparenToken, ast);
656 acceptBlockOrIndented(ast->statement);
660bool ScriptFormatter::visit(ForEachStatement *ast)
663 ensureSpaceIfNoComment();
664 out(ast->lparenToken);
665 if (
auto pe = AST::cast<PatternElement *>(ast->lhs)) {
666 out(pe->declarationKindToken);
667 ensureSpaceIfNoComment();
670 ensureSpaceIfNoComment();
672 ensureSpaceIfNoComment();
673 accept(ast->expression);
674 out(ast->rparenToken);
675 acceptBlockOrIndented(ast->statement);
679bool ScriptFormatter::visit(ContinueStatement *ast)
681 out(ast->continueToken);
682 if (!ast->label.isNull()) {
683 ensureSpaceIfNoComment();
684 out(ast->identifierToken);
687 writeOutSemicolon(ast);
691bool ScriptFormatter::visit(BreakStatement *ast)
693 out(ast->breakToken);
694 if (!ast->label.isNull()) {
695 ensureSpaceIfNoComment();
696 out(ast->identifierToken);
699 writeOutSemicolon(ast);
703bool ScriptFormatter::visit(ReturnStatement *ast)
705 out(ast->returnToken);
706 if (ast->expression) {
707 if (ast->returnToken.length != 0)
708 ensureSpaceIfNoComment();
709 accept(ast->expression);
711 if (ast->returnToken.length > 0 && addSemicolons())
712 writeOutSemicolon(ast);
716bool ScriptFormatter::visit(YieldExpression *ast)
718 out(ast->yieldToken);
719 if (ast->isYieldStar)
721 if (ast->expression) {
722 if (ast->yieldToken.isValid())
723 ensureSpaceIfNoComment();
724 accept(ast->expression);
729bool ScriptFormatter::visit(ThrowStatement *ast)
731 out(ast->throwToken);
732 if (ast->expression) {
733 ensureSpaceIfNoComment();
734 accept(ast->expression);
737 writeOutSemicolon(ast);
741bool ScriptFormatter::visit(WithStatement *ast)
744 ensureSpaceIfNoComment();
745 out(ast->lparenToken);
746 accept(ast->expression);
747 out(ast->rparenToken);
748 acceptBlockOrIndented(ast->statement);
752bool ScriptFormatter::visit(SwitchStatement *ast)
754 out(ast->switchToken);
755 ensureSpaceIfNoComment();
756 out(ast->lparenToken);
757 accept(ast->expression);
758 out(ast->rparenToken);
759 ensureSpaceIfNoComment();
764bool ScriptFormatter::visit(CaseBlock *ast)
766 out(ast->lbraceToken);
769 accept(ast->clauses);
770 if (ast->clauses && ast->defaultClause)
772 accept(ast->defaultClause);
773 if (ast->moreClauses)
775 accept(ast->moreClauses);
778 out(ast->rbraceToken);
782bool ScriptFormatter::visit(CaseClause *ast)
785 ensureSpaceIfNoComment();
786 accept(ast->expression);
787 outWithComments(ast->colonToken, ast);
789 lnAcceptIndented(ast->statements);
793bool ScriptFormatter::visit(DefaultClause *ast)
795 out(ast->defaultToken);
796 out(ast->colonToken);
797 lnAcceptIndented(ast->statements);
801bool ScriptFormatter::visit(LabelledStatement *ast)
803 out(ast->identifierToken);
805 ensureSpaceIfNoComment();
806 accept(ast->statement);
810bool ScriptFormatter::visit(TryStatement *ast)
812 outWithComments(ast->tryToken, ast);
813 ensureSpaceIfNoComment();
814 accept(ast->statement);
815 if (ast->catchExpression) {
816 ensureSpaceIfNoComment();
817 accept(ast->catchExpression);
819 if (ast->finallyExpression) {
820 ensureSpaceIfNoComment();
821 accept(ast->finallyExpression);
826bool ScriptFormatter::visit(Catch *ast)
828 outWithComments(ast->catchToken, ast);
829 ensureSpaceIfNoComment();
830 outWithComments(ast->lparenToken, ast);
831 outWithComments(ast->identifierToken, ast);
832 outWithComments(ast->rparenToken, ast);
833 ensureSpaceIfNoComment();
834 accept(ast->statement);
838bool ScriptFormatter::visit(Finally *ast)
840 outWithComments(ast->finallyToken, ast);
841 ensureSpaceIfNoComment();
842 accept(ast->statement);
846bool ScriptFormatter::visit(FunctionDeclaration *ast)
848 return ScriptFormatter::visit(
static_cast<FunctionExpression *>(ast));
851bool ScriptFormatter::visit(FunctionExpression *ast)
853 if (!ast->isArrowFunction) {
854 outWithComments(ast->functionToken, ast);
855 if (ast->isGenerator)
856 outWithComments(ast->starToken, ast);
857 ensureSpaceIfNoComment();
858 outWithComments(ast->identifierToken, ast);
861 const bool removeParentheses = ast->isArrowFunction && ast->formals && !ast->formals->next
862 && (ast->formals->element && !ast->formals->element->bindingTarget);
866 outWithComments(ast->lparenToken, ast, removeParentheses ? OnlyComments : TokenAndComment);
867 int baseIndent = lw.increaseIndent(1);
868 accept(ast->formals);
869 lw.decreaseIndent(1, baseIndent);
870 outWithComments(ast->rparenToken, ast, removeParentheses ? OnlyComments : TokenAndComment);
871 accept(ast->typeAnnotation);
872 ensureSpaceIfNoComment();
873 if (ast->isArrowFunction) {
875 ensureSpaceIfNoComment();
877 outWithComments(ast->lbraceToken, ast);
878 if (ast->lbraceToken.length != 0)
881 if (ast->body->next || ast->lbraceToken.length != 0) {
882 lnAcceptIndented(ast->body);
886 baseIndent = lw.increaseIndent(1);
888 lw.decreaseIndent(1, baseIndent);
891 if (ast->lbraceToken.length != 0)
893 outWithComments(ast->rbraceToken, ast);
897bool ScriptFormatter::visit(Elision *ast)
899 for (Elision *it = ast; it; it = it->next) {
900 if (ast->commaToken.isValid()) {
901 outWithComments(ast->commaToken, ast);
902 ensureSpaceIfNoComment();
908bool ScriptFormatter::visit(ArgumentList *ast)
910 for (ArgumentList *it = ast; it; it = it->next) {
911 if (it->isSpreadElement)
913 accept(it->expression);
916 ensureSpaceIfNoComment();
922bool ScriptFormatter::visit(StatementList *ast)
925 for (StatementList *it = ast; it; it = it->next) {
927 if (EmptyStatement *emptyStatement = cast<EmptyStatement *>(it->statement)) {
928 if (m_script->loc2Str(emptyStatement->semicolonToken) != QLatin1String(
";"))
932 accept(it->statement);
940 auto *commentForCurrentStatement =
941 comments->commentForNode(it->statement, CommentAnchor{});
942 auto *commentForNextStatement =
943 comments->commentForNode(it->next->statement, CommentAnchor{});
946 (commentForCurrentStatement && !commentForCurrentStatement->postComments().empty())
947 || (commentForNextStatement && !commentForNextStatement->preComments().empty())
950 quint32 lineDelta = it->next->firstSourceLocation().startLine
951 - it->statement->lastSourceLocation().startLine;
952 lineDelta = std::clamp(lineDelta, quint32{ 1 }, quint32{ 2 });
954 ensureNewline(lineDelta);
961bool ScriptFormatter::visit(VariableDeclarationList *ast)
963 for (VariableDeclarationList *it = ast; it; it = it->next) {
964 accept(it->declaration);
967 ensureSpaceIfNoComment();
973bool ScriptFormatter::visit(CaseClauses *ast)
975 for (CaseClauses *it = ast; it; it = it->next) {
983bool ScriptFormatter::visit(FormalParameterList *ast)
985 for (FormalParameterList *it = ast; it; it = it->next) {
987 if (it->commaToken.isValid()) {
988 outWithComments(it->commaToken, it);
989 ensureSpaceIfNoComment();
996bool ScriptFormatter::visit(SuperLiteral *)
1001bool ScriptFormatter::visit(ComputedPropertyName *)
1006bool ScriptFormatter::visit(CommaExpression *el)
1010 ensureSpaceIfNoComment();
1014bool ScriptFormatter::visit(ExpressionStatement *el)
1016 if (addSemicolons())
1017 postOps[el->expression].append([
this, el]() { writeOutSemicolon(el); });
1022bool ScriptFormatter::visit(ClassDeclaration *ast)
1024 out(ast->classToken);
1025 ensureSpaceIfNoComment();
1026 outWithComments(ast->identifierToken, ast);
1027 if (ast->heritage) {
1028 ensureSpaceIfNoComment();
1030 ensureSpaceIfNoComment();
1031 accept(ast->heritage);
1033 ensureSpaceIfNoComment();
1034 outWithComments(ast->lbraceToken, ast);
1035 int baseIndent = lw.increaseIndent();
1036 for (ClassElementList *it = ast->elements; it; it = it->next) {
1040 ensureSpaceIfNoComment();
1042 accept(it->property);
1045 lw.decreaseIndent(1, baseIndent);
1046 outWithComments(ast->rbraceToken, ast);
1050bool ScriptFormatter::visit(AST::ImportDeclaration *ast)
1052 out(ast->importToken);
1053 ensureSpaceIfNoComment();
1054 if (!ast->moduleSpecifier.isNull()) {
1055 out(ast->moduleSpecifierToken);
1060bool ScriptFormatter::visit(AST::ImportSpecifier *ast)
1062 if (!ast->identifier.isNull()) {
1063 out(ast->identifierToken);
1064 ensureSpaceIfNoComment();
1066 ensureSpaceIfNoComment();
1068 out(ast->importedBindingToken);
1072bool ScriptFormatter::visit(AST::NameSpaceImport *ast)
1074 out(ast->starToken);
1075 ensureSpaceIfNoComment();
1077 ensureSpaceIfNoComment();
1078 out(ast->importedBindingToken);
1082bool ScriptFormatter::visit(AST::ImportsList *ast)
1084 for (ImportsList *it = ast; it; it = it->next) {
1085 accept(it->importSpecifier);
1088 ensureSpaceIfNoComment();
1093bool ScriptFormatter::visit(AST::NamedImports *ast)
1095 out(ast->leftBraceToken);
1096 if (ast->importsList) {
1097 ensureSpaceIfNoComment();
1102bool ScriptFormatter::visit(AST::ImportClause *ast)
1104 if (!ast->importedDefaultBinding.isNull()) {
1105 out(ast->importedDefaultBindingToken);
1106 if (ast->nameSpaceImport || ast->namedImports) {
1108 ensureSpaceIfNoComment();
1114bool ScriptFormatter::visit(AST::ExportDeclaration *ast)
1116 out(ast->exportToken);
1117 ensureSpaceIfNoComment();
1118 if (ast->exportDefault) {
1120 ensureSpaceIfNoComment();
1122 if (ast->exportsAll()) {
1128bool ScriptFormatter::visit(AST::ExportClause *ast)
1130 out(ast->leftBraceToken);
1131 if (ast->exportsList) {
1132 ensureSpaceIfNoComment();
1137bool ScriptFormatter::visit(AST::ExportSpecifier *ast)
1139 out(ast->identifier);
1140 if (ast->exportedIdentifierToken.isValid()) {
1141 ensureSpaceIfNoComment();
1143 ensureSpaceIfNoComment();
1144 out(ast->exportedIdentifier);
1149bool ScriptFormatter::visit(AST::ExportsList *ast)
1151 for (ExportsList *it = ast; it; it = it->next) {
1152 accept(it->exportSpecifier);
1155 ensureSpaceIfNoComment();
1161bool ScriptFormatter::visit(AST::FromClause *ast)
1163 ensureSpaceIfNoComment();
1164 out(ast->fromToken);
1165 ensureSpaceIfNoComment();
1166 out(ast->moduleSpecifierToken);
1170void ScriptFormatter::endVisit(ComputedPropertyName *)
1175void ScriptFormatter::endVisit(AST::ExportDeclaration *ast)
1180 if (ast->fromClause) {
1181 writeOutSemicolon(ast);
1186 if (ast->exportClause && !ast->fromClause) {
1187 writeOutSemicolon(ast);
1192 if (ast->exportDefault && ast->variableStatementOrDeclaration) {
1194 if (!(ast->variableStatementOrDeclaration->kind == Node::Kind_FunctionDeclaration
1195 || ast->variableStatementOrDeclaration->kind == Node::Kind_ClassDeclaration)) {
1196 writeOutSemicolon(ast);
1201 if (ast->variableStatementOrDeclaration->kind == Node::Kind_FunctionDeclaration
1202 &&
static_cast<AST::FunctionDeclaration *>(ast->variableStatementOrDeclaration)
1203 ->isArrowFunction) {
1204 writeOutSemicolon(ast);
1209void ScriptFormatter::endVisit(AST::ExportClause *ast)
1211 if (ast->exportsList) {
1212 ensureSpaceIfNoComment();
1214 out(ast->rightBraceToken);
1217void ScriptFormatter::endVisit(AST::NamedImports *ast)
1219 if (ast->importsList) {
1220 ensureSpaceIfNoComment();
1222 out(ast->rightBraceToken);
1225void ScriptFormatter::endVisit(AST::ImportDeclaration *id)
1227 writeOutSemicolon(id);
1230void ScriptFormatter::throwRecursionDepthError()
1232 out(
"/* ERROR: Hit recursion limit ScriptFormatter::visiting AST, rewrite failed */");
1238static constexpr QStringView restrictedChars = u"([/+-";
1241bool ScriptFormatter::canRemoveSemicolon(AST::Node *node)
1243 const auto canRelyOnASI = [
this](Node *node) {
1244 auto nodeLoc = node->lastSourceLocation().offset + 1;
1245 auto code = m_script->engine()->code();
1247 if (qsizetype(nodeLoc) >= code.size())
1249 auto startIt = code.begin() + nodeLoc;
1250 auto endIt = std::find_first_of(startIt, code.end(), restrictedChars.begin(),
1251 restrictedChars.end());
1253 if (endIt == code.end())
1258 bool hasOtherChars =
1259 std::any_of(startIt, endIt, [](QChar ch) {
return !(ch.isSpace() || ch == u';'); });
1265 return std::none_of(startIt, endIt, [](QChar c) {
return c == u'\n'; });
1269 switch (node->kind) {
1270 case AST::Node::Kind_ExpressionStatement:
1271 return canRelyOnASI(cast<ExpressionStatement *>(node));
1272 case AST::Node::Kind_VariableStatement:
1273 return canRelyOnASI(cast<VariableStatement *>(node));
1274 case AST::Node::Kind_EmptyStatement:
1276 case AST::Node::Kind_ContinueStatement:
1277 case AST::Node::Kind_BreakStatement:
1278 case AST::Node::Kind_ReturnStatement:
1279 case AST::Node::Kind_ThrowStatement:
1280 case AST::Node::Kind_ExportDeclaration:
1281 case AST::Node::Kind_ImportDeclaration:
1282 case AST::Node::Kind_FromClause:
1283 case AST::Node::Kind_ExportClause:
1289OutWriter &ScriptFormatter::writeOutSemicolon(AST::Node *node)
1293 switch (lw.lineWriter.options().semicolonRule) {
1294 case LineWriterOptions::SemicolonRule::Essential:
1295 if (!canRemoveSemicolon(node))
1299 case LineWriterOptions::SemicolonRule::Always:
1303 Q_UNREACHABLE_RETURN(lw);
1307void reformatAst(OutWriter &lw,
const QQmlJS::Dom::ScriptExpression *
const script)
1310 ScriptFormatter formatter(lw, script);