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 out(ast->lbracketToken);
136 int baseIndent = lw.increaseIndent(1);
138 accept(ast->elements);
139 out(ast->commaToken);
140 auto lastElement = lastListElement(ast->elements);
141 if (lastElement->element && cast<ObjectPattern *>(lastElement->element->initializer)) {
145 out(ast->commaToken);
147 lw.decreaseIndent(1, baseIndent);
148 out(ast->rbracketToken);
152bool ScriptFormatter::visit(ObjectPattern *ast)
154 out(ast->lbraceToken);
156 if (ast->properties) {
157 lnAcceptIndented(ast->properties);
161 out(ast->rbraceToken);
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)
175 if (it->elision && it->element) {
176 outWithComments(it->elision->commaToken, it);
177 ensureSpaceIfNoComment();
182 outWithComments(it->next->commaToken, it);
183 ensureSpaceIfNoComment();
184 if (isObjectInitializer)
191bool ScriptFormatter::visit(PatternPropertyList *ast)
193 for (PatternPropertyList *it = ast; it; it = it->next) {
194 accept(it->property);
204bool ScriptFormatter::visit(AST::PatternProperty *property)
206 if (property->type == PatternElement::Getter || property->type == PatternElement::Setter
207 || property->type == PatternElement::Method) {
212 if (property->type == PatternProperty::Getter) {
214 ensureSpaceIfNoComment();
215 }
else if (property->type == PatternProperty::Setter) {
217 ensureSpaceIfNoComment();
219 FunctionExpression *f = AST::cast<FunctionExpression *>(property->initializer);
220 if (f->isGenerator) {
223 accept(property->name);
227 ensureSpaceIfNoComment();
229 const bool scoped = f->lbraceToken.isValid();
233 if (f->body->next || scoped) {
234 lnAcceptIndented(f->body);
237 auto baseIndent = lw.increaseIndent(1);
239 lw.decreaseIndent(1, baseIndent);
249 accept(property->name);
250 bool useInitializer =
false;
251 const bool bindingIdentifierExist = !property->bindingIdentifier.isEmpty();
252 if (property->colonToken.isValid()) {
255 ensureSpaceIfNoComment();
256 useInitializer =
true;
257 if (bindingIdentifierExist)
258 out(property->bindingIdentifier);
259 if (property->bindingTarget)
260 accept(property->bindingTarget);
263 if (property->initializer) {
265 if (bindingIdentifierExist) {
266 ensureSpaceIfNoComment();
268 ensureSpaceIfNoComment();
269 useInitializer =
true;
272 accept(property->initializer);
277bool ScriptFormatter::visit(NestedExpression *ast)
279 out(ast->lparenToken);
280 int baseIndent = lw.increaseIndent(1);
281 accept(ast->expression);
282 lw.decreaseIndent(1, baseIndent);
283 out(ast->rparenToken);
287bool ScriptFormatter::visit(IdentifierPropertyName *ast)
289 out(ast->id.toString());
292bool ScriptFormatter::visit(StringLiteralPropertyName *ast)
294 out(ast->propertyNameToken);
297bool ScriptFormatter::visit(NumericLiteralPropertyName *ast)
299 out(QString::number(ast->id));
303bool ScriptFormatter::visit(TemplateLiteral *ast)
306 if (ast->literalToken.length != 0) {
307 QStringView str = m_script->loc2Str(ast->literalToken);
308 if (lw.indentNextlines && str.contains(QLatin1Char(
'\n'))) {
310 lw.indentNextlines =
false;
312 lw.indentNextlines =
true;
317 accept(ast->expression);
321bool ScriptFormatter::visit(ArrayMemberExpression *ast)
324 out(ast->optionalToken);
325 out(ast->lbracketToken);
326 int indent = lw.increaseIndent(1);
327 accept(ast->expression);
328 lw.decreaseIndent(1, indent);
329 out(ast->rbracketToken);
333bool ScriptFormatter::visit(FieldMemberExpression *ast)
337 out(ast->identifierToken);
341bool ScriptFormatter::visit(NewMemberExpression *ast)
344 ensureSpaceIfNoComment();
346 out(ast->lparenToken);
347 accept(ast->arguments);
348 out(ast->rparenToken);
352bool ScriptFormatter::visit(NewExpression *ast)
355 ensureSpaceIfNoComment();
356 accept(ast->expression);
360bool ScriptFormatter::visit(CallExpression *ast)
363 out(ast->optionalToken);
364 out(ast->lparenToken);
365 accept(ast->arguments);
366 out(ast->rparenToken);
370bool ScriptFormatter::visit(PostIncrementExpression *ast)
373 out(ast->incrementToken);
377bool ScriptFormatter::visit(PostDecrementExpression *ast)
380 out(ast->decrementToken);
384bool ScriptFormatter::visit(PreIncrementExpression *ast)
386 out(ast->incrementToken);
387 accept(ast->expression);
391bool ScriptFormatter::visit(PreDecrementExpression *ast)
393 out(ast->decrementToken);
394 accept(ast->expression);
398bool ScriptFormatter::visit(DeleteExpression *ast)
401 ensureSpaceIfNoComment();
402 accept(ast->expression);
406bool ScriptFormatter::visit(VoidExpression *ast)
409 ensureSpaceIfNoComment();
410 accept(ast->expression);
414bool ScriptFormatter::visit(TypeOfExpression *ast)
417 ensureSpaceIfNoComment();
418 accept(ast->expression);
422bool ScriptFormatter::visit(UnaryPlusExpression *ast)
425 accept(ast->expression);
429bool ScriptFormatter::visit(UnaryMinusExpression *ast)
431 out(ast->minusToken);
432 accept(ast->expression);
436bool ScriptFormatter::visit(TildeExpression *ast)
438 out(ast->tildeToken);
439 accept(ast->expression);
443bool ScriptFormatter::visit(NotExpression *ast)
446 accept(ast->expression);
450bool ScriptFormatter::visit(BinaryExpression *ast)
453 ensureSpaceIfNoComment();
454 out(ast->operatorToken);
455 ensureSpaceIfNoComment();
460bool ScriptFormatter::visit(ConditionalExpression *ast)
462 accept(ast->expression);
463 ensureSpaceIfNoComment();
465 ensureSpaceIfNoComment();
467 ensureSpaceIfNoComment();
469 ensureSpaceIfNoComment();
474bool ScriptFormatter::visit(Block *ast)
477 const CommentedElement *c =
478 comments->commentForNode(ast, CommentAnchor::from(ast->lbraceToken));
481 out(ast->lbraceToken);
482 const int indent = lw.increaseIndent();
486 if (ast->statements) {
489 accept(ast->statements);
496 c = comments->commentForNode(ast, CommentAnchor::from(ast->rbraceToken));
499 lw.decreaseIndent(1, indent);
500 out(ast->rbraceToken);
506bool ScriptFormatter::visit(VariableStatement *ast)
508 out(ast->declarationKindToken);
509 ensureSpaceIfNoComment();
510 accept(ast->declarations);
512 writeOutSemicolon(ast);
516bool ScriptFormatter::visit(PatternElement *ast)
519 case PatternElement::Literal:
520 case PatternElement::Method:
521 case PatternElement::Binding:
523 case PatternElement::Getter:
525 ensureSpaceIfNoComment();
527 case PatternElement::Setter:
529 ensureSpaceIfNoComment();
531 case PatternElement::SpreadElement:
536 accept(ast->bindingTarget);
537 if (!ast->destructuringPattern())
538 out(ast->identifierToken);
539 if (ast->initializer) {
540 if (ast->isVariableDeclaration() || ast->type == AST::PatternElement::Binding) {
541 ensureSpaceIfNoComment();
542 outWithComments(ast->equalToken, ast);
543 ensureSpaceIfNoComment();
545 accept(ast->initializer);
547 accept(ast->typeAnnotation);
551bool ScriptFormatter::visit(TypeAnnotation *ast)
553 out(ast->colonToken);
554 ensureSpaceIfNoComment();
559bool ScriptFormatter::visit(Type *ast)
562 if (ast->typeArgument) {
563 outWithComments(ast->lAngleBracketToken, ast);
564 accept(ast->typeArgument);
565 outWithComments(ast->rAngleBracketToken, ast);
570bool ScriptFormatter::visit(UiQualifiedId *ast)
572 for (UiQualifiedId *it = ast; it; it = it->next) {
573 outWithComments(it->dotToken, it);
574 outWithComments(it->identifierToken, it);
579bool ScriptFormatter::visit(EmptyStatement *)
581 lw.lineWriter.ensureSemicolon();
585bool ScriptFormatter::visit(IfStatement *ast)
588 ensureSpaceIfNoComment();
589 out(ast->lparenToken);
590 preVisit(ast->expression);
591 ast->expression->accept0(
this);
592 out(ast->rparenToken);
593 postVisit(ast->expression);
594 acceptBlockOrIndented(ast->ok, ast->ko);
597 if (cast<Block *>(ast->ko) || cast<IfStatement *>(ast->ko)) {
598 ensureSpaceIfNoComment();
601 lnAcceptIndented(ast->ko);
607bool ScriptFormatter::visit(DoWhileStatement *ast)
610 acceptBlockOrIndented(ast->statement,
true);
611 out(ast->whileToken);
612 ensureSpaceIfNoComment();
613 outWithComments(ast->lparenToken, ast);
614 accept(ast->expression);
615 outWithComments(ast->rparenToken, ast);
619bool ScriptFormatter::visit(WhileStatement *ast)
621 out(ast->whileToken);
622 ensureSpaceIfNoComment();
623 outWithComments(ast->lparenToken, ast);
624 accept(ast->expression);
625 outWithComments(ast->rparenToken, ast);
626 acceptBlockOrIndented(ast->statement);
630bool ScriptFormatter::visit(ForStatement *ast)
633 ensureSpaceIfNoComment();
634 outWithComments(ast->lparenToken, ast);
635 if (ast->initialiser) {
636 accept(ast->initialiser);
637 }
else if (ast->declarations) {
638 if (
auto pe = ast->declarations->declaration) {
639 out(pe->declarationKindToken);
640 ensureSpaceIfNoComment();
643 for (VariableDeclarationList *it = ast->declarations; it; it = it->next) {
644 if (!std::exchange(first,
false)) {
646 ensureSpaceIfNoComment();
648 accept(it->declaration);
654 ensureSpaceIfNoComment();
655 accept(ast->condition);
657 ensureSpaceIfNoComment();
658 accept(ast->expression);
659 outWithComments(ast->rparenToken, ast);
660 acceptBlockOrIndented(ast->statement);
664bool ScriptFormatter::visit(ForEachStatement *ast)
667 ensureSpaceIfNoComment();
668 out(ast->lparenToken);
669 if (
auto pe = AST::cast<PatternElement *>(ast->lhs)) {
670 out(pe->declarationKindToken);
671 ensureSpaceIfNoComment();
674 ensureSpaceIfNoComment();
676 ensureSpaceIfNoComment();
677 accept(ast->expression);
678 out(ast->rparenToken);
679 acceptBlockOrIndented(ast->statement);
683bool ScriptFormatter::visit(ContinueStatement *ast)
685 out(ast->continueToken);
686 if (!ast->label.isNull()) {
687 ensureSpaceIfNoComment();
688 out(ast->identifierToken);
691 writeOutSemicolon(ast);
695bool ScriptFormatter::visit(BreakStatement *ast)
697 out(ast->breakToken);
698 if (!ast->label.isNull()) {
699 ensureSpaceIfNoComment();
700 out(ast->identifierToken);
703 writeOutSemicolon(ast);
707bool ScriptFormatter::visit(ReturnStatement *ast)
709 out(ast->returnToken);
710 if (ast->expression) {
711 if (ast->returnToken.length != 0)
712 ensureSpaceIfNoComment();
713 accept(ast->expression);
715 if (ast->returnToken.length > 0 && addSemicolons())
716 writeOutSemicolon(ast);
720bool ScriptFormatter::visit(YieldExpression *ast)
722 out(ast->yieldToken);
723 if (ast->isYieldStar)
725 if (ast->expression) {
726 if (ast->yieldToken.isValid())
727 ensureSpaceIfNoComment();
728 accept(ast->expression);
733bool ScriptFormatter::visit(ThrowStatement *ast)
735 out(ast->throwToken);
736 if (ast->expression) {
737 ensureSpaceIfNoComment();
738 accept(ast->expression);
741 writeOutSemicolon(ast);
745bool ScriptFormatter::visit(WithStatement *ast)
748 ensureSpaceIfNoComment();
749 out(ast->lparenToken);
750 accept(ast->expression);
751 out(ast->rparenToken);
752 acceptBlockOrIndented(ast->statement);
756bool ScriptFormatter::visit(SwitchStatement *ast)
758 out(ast->switchToken);
759 ensureSpaceIfNoComment();
760 out(ast->lparenToken);
761 accept(ast->expression);
762 out(ast->rparenToken);
763 ensureSpaceIfNoComment();
768bool ScriptFormatter::visit(CaseBlock *ast)
770 out(ast->lbraceToken);
773 accept(ast->clauses);
774 if (ast->clauses && ast->defaultClause)
776 accept(ast->defaultClause);
777 if (ast->moreClauses)
779 accept(ast->moreClauses);
782 out(ast->rbraceToken);
786bool ScriptFormatter::visit(CaseClause *ast)
789 ensureSpaceIfNoComment();
790 accept(ast->expression);
791 outWithComments(ast->colonToken, ast);
793 lnAcceptIndented(ast->statements);
797bool ScriptFormatter::visit(DefaultClause *ast)
799 out(ast->defaultToken);
800 out(ast->colonToken);
801 lnAcceptIndented(ast->statements);
805bool ScriptFormatter::visit(LabelledStatement *ast)
807 out(ast->identifierToken);
809 ensureSpaceIfNoComment();
810 accept(ast->statement);
814bool ScriptFormatter::visit(TryStatement *ast)
817 ensureSpaceIfNoComment();
818 accept(ast->statement);
819 if (ast->catchExpression) {
820 ensureSpaceIfNoComment();
821 accept(ast->catchExpression);
823 if (ast->finallyExpression) {
824 ensureSpaceIfNoComment();
825 accept(ast->finallyExpression);
830bool ScriptFormatter::visit(Catch *ast)
832 out(ast->catchToken);
833 ensureSpaceIfNoComment();
834 out(ast->lparenToken);
835 out(ast->identifierToken);
837 ensureSpaceIfNoComment();
838 accept(ast->statement);
842bool ScriptFormatter::visit(Finally *ast)
845 ensureSpaceIfNoComment();
846 accept(ast->statement);
850bool ScriptFormatter::visit(FunctionDeclaration *ast)
852 return ScriptFormatter::visit(
static_cast<FunctionExpression *>(ast));
855bool ScriptFormatter::visit(FunctionExpression *ast)
857 if (!ast->isArrowFunction) {
858 if (ast->isGenerator) {
860 ensureSpaceIfNoComment();
863 ensureSpaceIfNoComment();
865 outWithComments(ast->identifierToken, ast);
868 const bool removeParentheses = ast->isArrowFunction && ast->formals && !ast->formals->next
869 && (ast->formals->element && !ast->formals->element->bindingTarget);
873 outWithComments(ast->lparenToken, ast, removeParentheses ? OnlyComments : TokenAndComment);
874 int baseIndent = lw.increaseIndent(1);
875 accept(ast->formals);
876 lw.decreaseIndent(1, baseIndent);
877 outWithComments(ast->rparenToken, ast, removeParentheses ? OnlyComments : TokenAndComment);
878 accept(ast->typeAnnotation);
879 ensureSpaceIfNoComment();
880 if (ast->isArrowFunction) {
882 ensureSpaceIfNoComment();
884 outWithComments(ast->lbraceToken, ast);
885 if (ast->lbraceToken.length != 0)
888 if (ast->body->next || ast->lbraceToken.length != 0) {
889 lnAcceptIndented(ast->body);
893 baseIndent = lw.increaseIndent(1);
895 lw.decreaseIndent(1, baseIndent);
898 if (ast->lbraceToken.length != 0)
900 outWithComments(ast->rbraceToken, ast);
904bool ScriptFormatter::visit(Elision *ast)
906 for (Elision *it = ast; it; it = it->next) {
909 ensureSpaceIfNoComment();
915bool ScriptFormatter::visit(ArgumentList *ast)
917 for (ArgumentList *it = ast; it; it = it->next) {
918 if (it->isSpreadElement)
920 accept(it->expression);
923 ensureSpaceIfNoComment();
929bool ScriptFormatter::visit(StatementList *ast)
932 for (StatementList *it = ast; it; it = it->next) {
934 if (EmptyStatement *emptyStatement = cast<EmptyStatement *>(it->statement)) {
935 if (m_script->loc2Str(emptyStatement->semicolonToken) != QLatin1String(
";"))
939 accept(it->statement);
947 auto *commentForCurrentStatement =
948 comments->commentForNode(it->statement, CommentAnchor{});
949 auto *commentForNextStatement =
950 comments->commentForNode(it->next->statement, CommentAnchor{});
953 (commentForCurrentStatement && !commentForCurrentStatement->postComments().empty())
954 || (commentForNextStatement && !commentForNextStatement->preComments().empty())
957 quint32 lineDelta = it->next->firstSourceLocation().startLine
958 - it->statement->lastSourceLocation().startLine;
959 lineDelta = std::clamp(lineDelta, quint32{ 1 }, quint32{ 2 });
961 ensureNewline(lineDelta);
968bool ScriptFormatter::visit(VariableDeclarationList *ast)
970 for (VariableDeclarationList *it = ast; it; it = it->next) {
971 accept(it->declaration);
974 ensureSpaceIfNoComment();
980bool ScriptFormatter::visit(CaseClauses *ast)
982 for (CaseClauses *it = ast; it; it = it->next) {
990bool ScriptFormatter::visit(FormalParameterList *ast)
992 for (FormalParameterList *it = ast; it; it = it->next) {
994 if (it->commaToken.isValid()) {
995 outWithComments(it->commaToken, it);
996 ensureSpaceIfNoComment();
1003bool ScriptFormatter::visit(SuperLiteral *)
1008bool ScriptFormatter::visit(ComputedPropertyName *)
1013bool ScriptFormatter::visit(CommaExpression *el)
1017 ensureSpaceIfNoComment();
1021bool ScriptFormatter::visit(ExpressionStatement *el)
1023 if (addSemicolons())
1024 postOps[el->expression].append([
this, el]() { writeOutSemicolon(el); });
1029bool ScriptFormatter::visit(ClassDeclaration *ast)
1031 out(ast->classToken);
1032 ensureSpaceIfNoComment();
1033 outWithComments(ast->identifierToken, ast);
1034 if (ast->heritage) {
1035 ensureSpaceIfNoComment();
1037 ensureSpaceIfNoComment();
1038 accept(ast->heritage);
1040 ensureSpaceIfNoComment();
1041 outWithComments(ast->lbraceToken, ast);
1042 int baseIndent = lw.increaseIndent();
1043 for (ClassElementList *it = ast->elements; it; it = it->next) {
1047 ensureSpaceIfNoComment();
1049 accept(it->property);
1052 lw.decreaseIndent(1, baseIndent);
1053 outWithComments(ast->rbraceToken, ast);
1057bool ScriptFormatter::visit(AST::ImportDeclaration *ast)
1059 out(ast->importToken);
1060 ensureSpaceIfNoComment();
1061 if (!ast->moduleSpecifier.isNull()) {
1062 out(ast->moduleSpecifierToken);
1067bool ScriptFormatter::visit(AST::ImportSpecifier *ast)
1069 if (!ast->identifier.isNull()) {
1070 out(ast->identifierToken);
1071 ensureSpaceIfNoComment();
1073 ensureSpaceIfNoComment();
1075 out(ast->importedBindingToken);
1079bool ScriptFormatter::visit(AST::NameSpaceImport *ast)
1081 out(ast->starToken);
1082 ensureSpaceIfNoComment();
1084 ensureSpaceIfNoComment();
1085 out(ast->importedBindingToken);
1089bool ScriptFormatter::visit(AST::ImportsList *ast)
1091 for (ImportsList *it = ast; it; it = it->next) {
1092 accept(it->importSpecifier);
1095 ensureSpaceIfNoComment();
1100bool ScriptFormatter::visit(AST::NamedImports *ast)
1102 out(ast->leftBraceToken);
1103 if (ast->importsList) {
1104 ensureSpaceIfNoComment();
1109bool ScriptFormatter::visit(AST::ImportClause *ast)
1111 if (!ast->importedDefaultBinding.isNull()) {
1112 out(ast->importedDefaultBindingToken);
1113 if (ast->nameSpaceImport || ast->namedImports) {
1115 ensureSpaceIfNoComment();
1121bool ScriptFormatter::visit(AST::ExportDeclaration *ast)
1123 out(ast->exportToken);
1124 ensureSpaceIfNoComment();
1125 if (ast->exportDefault) {
1127 ensureSpaceIfNoComment();
1129 if (ast->exportsAll()) {
1135bool ScriptFormatter::visit(AST::ExportClause *ast)
1137 out(ast->leftBraceToken);
1138 if (ast->exportsList) {
1139 ensureSpaceIfNoComment();
1144bool ScriptFormatter::visit(AST::ExportSpecifier *ast)
1146 out(ast->identifier);
1147 if (ast->exportedIdentifierToken.isValid()) {
1148 ensureSpaceIfNoComment();
1150 ensureSpaceIfNoComment();
1151 out(ast->exportedIdentifier);
1156bool ScriptFormatter::visit(AST::ExportsList *ast)
1158 for (ExportsList *it = ast; it; it = it->next) {
1159 accept(it->exportSpecifier);
1162 ensureSpaceIfNoComment();
1168bool ScriptFormatter::visit(AST::FromClause *ast)
1170 ensureSpaceIfNoComment();
1171 out(ast->fromToken);
1172 ensureSpaceIfNoComment();
1173 out(ast->moduleSpecifierToken);
1177void ScriptFormatter::endVisit(ComputedPropertyName *)
1182void ScriptFormatter::endVisit(AST::ExportDeclaration *ast)
1187 if (ast->fromClause) {
1188 writeOutSemicolon(ast);
1193 if (ast->exportClause && !ast->fromClause) {
1194 writeOutSemicolon(ast);
1199 if (ast->exportDefault && ast->variableStatementOrDeclaration) {
1201 if (!(ast->variableStatementOrDeclaration->kind == Node::Kind_FunctionDeclaration
1202 || ast->variableStatementOrDeclaration->kind == Node::Kind_ClassDeclaration)) {
1203 writeOutSemicolon(ast);
1208 if (ast->variableStatementOrDeclaration->kind == Node::Kind_FunctionDeclaration
1209 &&
static_cast<AST::FunctionDeclaration *>(ast->variableStatementOrDeclaration)
1210 ->isArrowFunction) {
1211 writeOutSemicolon(ast);
1216void ScriptFormatter::endVisit(AST::ExportClause *ast)
1218 if (ast->exportsList) {
1219 ensureSpaceIfNoComment();
1221 out(ast->rightBraceToken);
1224void ScriptFormatter::endVisit(AST::NamedImports *ast)
1226 if (ast->importsList) {
1227 ensureSpaceIfNoComment();
1229 out(ast->rightBraceToken);
1232void ScriptFormatter::endVisit(AST::ImportDeclaration *id)
1234 writeOutSemicolon(id);
1237void ScriptFormatter::throwRecursionDepthError()
1239 out(
"/* ERROR: Hit recursion limit ScriptFormatter::visiting AST, rewrite failed */");
1245static constexpr QStringView restrictedChars = u"([/+-";
1248bool ScriptFormatter::canRemoveSemicolon(AST::Node *node)
1250 const auto canRelyOnASI = [
this](Node *node) {
1251 auto nodeLoc = node->lastSourceLocation().offset + 1;
1252 auto code = m_script->engine()->code();
1254 if (qsizetype(nodeLoc) >= code.size())
1256 auto startIt = code.begin() + nodeLoc;
1257 auto endIt = std::find_first_of(startIt, code.end(), restrictedChars.begin(),
1258 restrictedChars.end());
1260 if (endIt == code.end())
1265 bool hasOtherChars =
1266 std::any_of(startIt, endIt, [](QChar ch) {
return !(ch.isSpace() || ch == u';'); });
1272 return std::none_of(startIt, endIt, [](QChar c) {
return c == u'\n'; });
1276 switch (node->kind) {
1277 case AST::Node::Kind_ExpressionStatement:
1278 return canRelyOnASI(cast<ExpressionStatement *>(node));
1279 case AST::Node::Kind_VariableStatement:
1280 return canRelyOnASI(cast<VariableStatement *>(node));
1281 case AST::Node::Kind_EmptyStatement:
1283 case AST::Node::Kind_ContinueStatement:
1284 case AST::Node::Kind_BreakStatement:
1285 case AST::Node::Kind_ReturnStatement:
1286 case AST::Node::Kind_ThrowStatement:
1287 case AST::Node::Kind_ExportDeclaration:
1288 case AST::Node::Kind_ImportDeclaration:
1289 case AST::Node::Kind_FromClause:
1290 case AST::Node::Kind_ExportClause:
1296OutWriter &ScriptFormatter::writeOutSemicolon(AST::Node *node)
1300 switch (lw.lineWriter.options().semicolonRule) {
1301 case LineWriterOptions::SemicolonRule::Essential:
1302 if (!canRemoveSemicolon(node))
1306 case LineWriterOptions::SemicolonRule::Always:
1310 Q_UNREACHABLE_RETURN(lw);
1314void reformatAst(OutWriter &lw,
const QQmlJS::Dom::ScriptExpression *
const script)
1317 ScriptFormatter formatter(lw, script);