use of com.google.javascript.rhino.NonJSDocComment in project closure-compiler by google.
the class IRFactory method parseNonJSDocCommentAt.
/**
* Creates a single NonJSDocComment from every comment associated with this node; or null if there
* are no such comments.
*
* <p>It would be legal to replace all comments associated with this node with that one string.
*/
@Nullable
private NonJSDocComment parseNonJSDocCommentAt(SourcePosition pos, boolean isInline) {
if (config.jsDocParsingMode() != JsDocParsing.INCLUDE_ALL_COMMENTS) {
return null;
}
if (!this.nonJsdocTracker.hasPendingCommentBefore(pos)) {
return null;
}
StringBuilder result = new StringBuilder();
Comment firstComment = this.nonJsdocTracker.current();
Comment lastComment = null;
while (this.nonJsdocTracker.hasPendingCommentBefore(pos)) {
Comment currentComment = this.nonJsdocTracker.current();
if (lastComment != null) {
for (int blankCount = currentComment.location.start.line - lastComment.location.end.line; blankCount > 0; blankCount--) {
result.append("\n");
}
}
result.append(currentComment.value);
lastComment = currentComment;
this.nonJsdocTracker.advance();
}
NonJSDocComment nonJSDocComment = new NonJSDocComment(firstComment.location.start, lastComment.location.end, result.toString());
nonJSDocComment.setEndsAsLineComment(lastComment.type == Comment.Type.LINE);
nonJSDocComment.setIsInline(isInline);
return nonJSDocComment;
}
use of com.google.javascript.rhino.NonJSDocComment in project closure-compiler by google.
the class IRFactory method transformNodeWithInlineComments.
/**
* Names and destructuring patterns, in parameters or variable declarations are special, because
* they can have inline type docs attached.
*
* <pre>function f(/** string */ x) {}</pre>
*
* annotates 'x' as a string.
*
* @see <a href="http://code.google.com/p/jsdoc-toolkit/wiki/InlineDocs">Using Inline Doc
* Comments</a>
*/
Node transformNodeWithInlineComments(ParseTree tree) {
JSDocInfo info = parseInlineJSDocAt(tree.getStart());
NonJSDocComment comment = parseNonJSDocCommentAt(tree.getStart(), true);
Node node = transformDispatcher.process(tree);
if (info != null) {
node.setJSDocInfo(info);
}
if (comment != null) {
node.setNonJSDocComment(comment);
}
setSourceInfo(node, tree);
return node;
}
use of com.google.javascript.rhino.NonJSDocComment in project closure-compiler by google.
the class SuggestedFix method getStartPositionForNodeConsideringComments.
/**
* Helper function to return the source offset of this node considering that JSDoc comments,
* non-JDDoc comments, or both may or may not be attached.
*/
private static int getStartPositionForNodeConsideringComments(Node node) {
JSDocInfo jsdoc = NodeUtil.getBestJSDocInfo(node);
NonJSDocComment associatedNonJSDocComment = node.getNonJSDocComment();
int start = node.getSourceOffset();
if (jsdoc != null) {
start = jsdoc.getOriginalCommentPosition();
}
if (associatedNonJSDocComment != null) {
start = min(start, associatedNonJSDocComment.getStartPosition().getOffset());
}
return start;
}
use of com.google.javascript.rhino.NonJSDocComment in project closure-compiler by google.
the class CodeGenerator method add.
protected void add(Node node, Context context) {
if (!cc.continueProcessing()) {
return;
}
if (preserveTypeAnnotations && node.getJSDocInfo() != null) {
String jsdocAsString = jsDocInfoPrinter.print(node.getJSDocInfo());
// Don't print an empty jsdoc
if (!jsdocAsString.equals("/** */ ")) {
add(jsdocAsString);
if (!node.isCast()) {
cc.endLine();
}
}
}
// print any non-trailing non-JSDoc comment attached to this node
if (printNonJSDocComments) {
NonJSDocComment nonJSDocComment = node.getNonJSDocComment();
if (nonJSDocComment != null && !nonJSDocComment.isTrailing()) {
String nonJSDocCommentString = node.getNonJSDocCommentString();
if (!nonJSDocCommentString.isEmpty()) {
addNonJsDoc_nonTrailing(node, nonJSDocComment);
}
}
}
Token type = node.getToken();
String opstr = NodeUtil.opToStr(type);
int childCount = node.getChildCount();
Node first = node.getFirstChild();
Node last = node.getLastChild();
// Handle all binary operators
if (opstr != null && first != last) {
Preconditions.checkState(childCount == 2, "Bad binary operator \"%s\": expected 2 arguments but got %s", opstr, childCount);
int p = precedence(node);
// For right-hand-side of operations, only pass context if it's
// the IN_FOR_INIT_CLAUSE one.
Context rhsContext = getContextForNoInOperator(context);
boolean needsParens = (context == Context.START_OF_EXPR || context.atArrowFunctionBody()) && first.isObjectPattern();
if (node.isAssign() && needsParens) {
add("(");
}
if (NodeUtil.isAssignmentOp(node) || type == Token.EXPONENT) {
// Assignment operators and '**' are the only right-associative binary operators
addExpr(first, p + 1, context);
cc.addOp(opstr, true);
addExpr(last, p, rhsContext);
} else {
unrollBinaryOperator(node, type, opstr, context, rhsContext, p, p + 1);
}
if (node.isAssign() && needsParens) {
add(")");
}
return;
}
cc.startSourceMapping(node);
switch(type) {
case TRY:
{
checkState(first.getNext().isBlock() && !first.getNext().hasMoreThanOneChild());
checkState(childCount >= 2 && childCount <= 3);
add("try");
add(first);
// second child contains the catch block, or nothing if there
// isn't a catch block
Node catchblock = first.getNext().getFirstChild();
if (catchblock != null) {
add(catchblock);
}
if (childCount == 3) {
cc.maybeInsertSpace();
add("finally");
add(last);
}
break;
}
case CATCH:
Preconditions.checkState(childCount == 2, node);
cc.maybeInsertSpace();
add("catch");
cc.maybeInsertSpace();
if (!first.isEmpty()) {
// optional catch binding
add("(");
add(first);
add(")");
}
add(last);
break;
case THROW:
Preconditions.checkState(childCount == 1, node);
add("throw");
cc.maybeInsertSpace();
add(first);
// Must have a ';' after a throw statement, otherwise safari can't
// parse this.
cc.endStatement(true);
break;
case RETURN:
add("return");
if (childCount == 1) {
cc.maybeInsertSpace();
if (preserveTypeAnnotations && first.getJSDocInfo() != null) {
add("(");
add(first);
add(")");
} else {
add(first);
}
} else {
checkState(childCount == 0, node);
}
cc.endStatement();
break;
case VAR:
add("var ");
addList(first, false, getContextForNoInOperator(context), ",");
if (node.getParent() == null || NodeUtil.isStatement(node)) {
cc.endStatement();
}
break;
case CONST:
add("const ");
addList(first, false, getContextForNoInOperator(context), ",");
if (node.getParent() == null || NodeUtil.isStatement(node)) {
cc.endStatement();
}
break;
case LET:
add("let ");
addList(first, false, getContextForNoInOperator(context), ",");
if (node.getParent() == null || NodeUtil.isStatement(node)) {
cc.endStatement();
}
break;
case LABEL_NAME:
Preconditions.checkState(!node.getString().isEmpty(), node);
addIdentifier(node.getString());
break;
case DESTRUCTURING_LHS:
add(first);
if (first != last) {
checkState(childCount == 2, node);
cc.addOp("=", true);
addExpr(last, NodeUtil.precedence(Token.ASSIGN), getContextForNoInOperator(context));
}
break;
case NAME:
if (useOriginalName && node.getOriginalName() != null) {
addIdentifier(node.getOriginalName());
} else {
addIdentifier(node.getString());
}
maybeAddOptional(node);
maybeAddTypeDecl(node);
if (first != null && !first.isEmpty()) {
checkState(childCount == 1, node);
cc.addOp("=", true);
addExpr(first, NodeUtil.precedence(Token.ASSIGN), getContextForNoInOperator(context));
}
break;
case ARRAYLIT:
add("[");
addArrayList(first);
add("]");
break;
case ARRAY_PATTERN:
add("[");
addArrayList(first);
add("]");
maybeAddTypeDecl(node);
break;
case PARAM_LIST:
// If this is the list for a non-TypeScript arrow function with one simple name param.
if (node.getParent().isArrowFunction() && node.hasOneChild() && first.isName() && !outputFeatureSet.has(Feature.TYPE_ANNOTATION)) {
add(first);
} else {
add("(");
addList(first);
add(")");
}
break;
case DEFAULT_VALUE:
add(first);
maybeAddTypeDecl(node);
cc.addOp("=", true);
addExpr(first.getNext(), 1, Context.OTHER);
break;
case COMMA:
Preconditions.checkState(childCount == 2, node);
unrollBinaryOperator(node, Token.COMMA, ",", context, getContextForNoInOperator(context), 0, 0);
break;
case NUMBER:
Preconditions.checkState(childCount == 0, node);
cc.addNumber(node.getDouble(), node);
break;
case BIGINT:
Preconditions.checkState(childCount == 0, node);
cc.add(node.getBigInt() + "n");
break;
case TYPEOF:
case VOID:
case NOT:
case BITNOT:
case POS:
case NEG:
{
// All of these unary operators are right-associative
checkState(childCount == 1, node);
cc.addOp(NodeUtil.opToStrNoFail(type), false);
addExpr(first, NodeUtil.precedence(type), Context.OTHER);
break;
}
case HOOK:
{
checkState(childCount == 3, "%s wrong number of children: %s", node, childCount);
int p = NodeUtil.precedence(type);
Context rhsContext = getContextForNoInOperator(context);
addExpr(first, p + 1, context);
cc.addOp("?", true);
addExpr(first.getNext(), 1, rhsContext);
cc.addOp(":", true);
addExpr(last, 1, rhsContext);
break;
}
case REGEXP:
if (!first.isStringLit() || !last.isStringLit()) {
throw new Error("Expected children to be strings");
}
String regexp = regexpEscape(first.getString());
// I only use one .add because whitespace matters
if (childCount == 2) {
add(regexp + last.getString());
} else {
checkState(childCount == 1, node);
add(regexp);
}
break;
case FUNCTION:
{
if (node.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
checkState(childCount == 3, node);
if (node.isArrowFunction()) {
addArrowFunction(node, first, last, context);
} else {
addFunction(node, first, last, context);
}
break;
}
case ITER_REST:
case OBJECT_REST:
add("...");
add(first);
maybeAddTypeDecl(node);
break;
case ITER_SPREAD:
case OBJECT_SPREAD:
add("...");
addExpr(first, NodeUtil.precedence(type), Context.OTHER);
break;
case EXPORT:
add("export");
if (node.getBooleanProp(Node.EXPORT_DEFAULT)) {
add("default");
}
if (node.getBooleanProp(Node.EXPORT_ALL_FROM)) {
add("*");
checkState(first != null && first.isEmpty(), node);
} else {
add(first);
}
if (childCount == 2) {
add("from");
add(last);
}
processEnd(first, context);
break;
case IMPORT:
add("import");
Node second = first.getNext();
if (!first.isEmpty()) {
add(first);
if (!second.isEmpty()) {
cc.listSeparator();
}
}
if (!second.isEmpty()) {
add(second);
}
if (!first.isEmpty() || !second.isEmpty()) {
add("from");
}
add(last);
cc.endStatement();
break;
case EXPORT_SPECS:
case IMPORT_SPECS:
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
add(c);
}
add("}");
break;
case EXPORT_SPEC:
case IMPORT_SPEC:
add(first);
if (node.isShorthandProperty() && first.getString().equals(last.getString())) {
break;
}
add("as");
add(last);
break;
case IMPORT_STAR:
add("*");
add("as");
add(node.getString());
break;
case DYNAMIC_IMPORT:
add("import(");
addExpr(first, NodeUtil.precedence(type), context);
add(")");
break;
case IMPORT_META:
add("import.meta");
break;
// CLASS -> NAME,EXPR|EMPTY,BLOCK
case CLASS:
{
checkState(childCount == 3, node);
boolean classNeedsParens = (context == Context.START_OF_EXPR);
if (classNeedsParens) {
add("(");
}
Node name = first;
Node superClass = first.getNext();
Node members = last;
add("class");
if (!name.isEmpty()) {
add(name);
}
maybeAddGenericTypes(first);
if (!superClass.isEmpty()) {
add("extends");
add(superClass);
}
Node interfaces = (Node) node.getProp(Node.IMPLEMENTS);
if (interfaces != null) {
add("implements");
Node child = interfaces.getFirstChild();
add(child);
while ((child = child.getNext()) != null) {
add(",");
cc.maybeInsertSpace();
add(child);
}
}
add(members);
cc.endClass(context == Context.STATEMENT);
if (classNeedsParens) {
add(")");
}
}
break;
case CLASS_MEMBERS:
case INTERFACE_MEMBERS:
case NAMESPACE_ELEMENTS:
cc.beginBlock();
for (Node c = first; c != null; c = c.getNext()) {
add(c);
processEnd(c, context);
cc.endLine();
}
cc.endBlock(false);
break;
case ENUM_MEMBERS:
cc.beginBlock();
for (Node c = first; c != null; c = c.getNext()) {
add(c);
if (c.getNext() != null) {
add(",");
}
cc.endLine();
}
cc.endBlock(false);
break;
case GETTER_DEF:
case SETTER_DEF:
case MEMBER_FUNCTION_DEF:
case MEMBER_VARIABLE_DEF:
{
checkState(node.getParent().isObjectLit() || node.getParent().isClassMembers() || node.getParent().isInterfaceMembers() || node.getParent().isRecordType() || node.getParent().isIndexSignature());
maybeAddAccessibilityModifier(node);
if (node.isStaticMember()) {
add("static ");
}
if (node.isMemberFunctionDef() && node.getFirstChild().isAsyncFunction()) {
add("async ");
}
if (!node.isMemberVariableDef() && node.getFirstChild().isGeneratorFunction()) {
checkState(type == Token.MEMBER_FUNCTION_DEF, node);
add("*");
}
switch(type) {
case GETTER_DEF:
// Get methods have no parameters.
Preconditions.checkState(!first.getSecondChild().hasChildren(), node);
add("get ");
break;
case SETTER_DEF:
// Set methods have one parameter.
Preconditions.checkState(first.getSecondChild().hasOneChild(), node);
add("set ");
break;
case MEMBER_FUNCTION_DEF:
case MEMBER_VARIABLE_DEF:
// nothing to do.
break;
default:
break;
}
// The name is on the GET or SET node.
String name = node.getString();
if (node.isMemberVariableDef()) {
add(node.getString());
maybeAddOptional(node);
maybeAddTypeDecl(node);
} else {
checkState(childCount == 1, node);
checkState(first.isFunction(), first);
// The function referenced by the definition should always be unnamed.
checkState(first.getFirstChild().getString().isEmpty(), first);
Node fn = first;
Node parameters = fn.getSecondChild();
Node body = fn.getLastChild();
// Add the property name.
if (!node.isQuotedString() && TokenStream.isJSIdentifier(name) && // Unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
maybeAddGenericTypes(fn.getFirstChild());
} else {
// Determine if the string is a simple number.
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d, node);
} else {
addJsString(node);
}
}
maybeAddOptional(fn);
add(parameters);
maybeAddTypeDecl(fn);
add(body);
}
break;
}
case MEMBER_FIELD_DEF:
case COMPUTED_FIELD_DEF:
{
checkState(node.getParent().isClassMembers());
if (node.getBooleanProp(Node.STATIC_MEMBER)) {
add("static ");
}
Node init = null;
switch(type) {
case MEMBER_FIELD_DEF:
String propertyName = node.getString();
add(propertyName);
init = first;
break;
case COMPUTED_FIELD_DEF:
add("[");
// Must use addExpr() with a priority of 1, because comma expressions aren't allowed.
// https://www.ecma-international.org/ecma-262/9.0/index.html#prod-ComputedPropertyName
addExpr(first, 1, Context.OTHER);
add("]");
init = node.getSecondChild();
break;
default:
break;
}
if (init != null) {
add("=");
addExpr(init, 1, Context.OTHER);
}
add(";");
break;
}
case SCRIPT:
case MODULE_BODY:
case BLOCK:
case ROOT:
{
if (node.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = node.isBlock() && !node.isSyntheticBlock();
if (preserveBlock) {
cc.beginBlock();
}
boolean preferLineBreaks = type == Token.SCRIPT || (type == Token.BLOCK && !preserveBlock && node.getParent().isScript());
for (Node c = first; c != null; c = c.getNext()) {
add(c, Context.STATEMENT);
if (c.isFunction() || c.isClass()) {
cc.maybeLineBreak();
}
// because top-level statements are more homogeneous.
if (preferLineBreaks) {
cc.notePreferredLineBreak();
}
}
if (preserveBlock) {
cc.endBlock(cc.breakAfterBlockFor(node, context == Context.STATEMENT));
}
break;
}
case FOR:
Preconditions.checkState(childCount == 4, node);
add("for");
cc.maybeInsertSpace();
add("(");
if (NodeUtil.isNameDeclaration(first)) {
add(first, Context.IN_FOR_INIT_CLAUSE);
} else {
addExpr(first, 0, Context.IN_FOR_INIT_CLAUSE);
}
add(";");
if (!first.getNext().isEmpty()) {
cc.maybeInsertSpace();
}
add(first.getNext());
add(";");
if (!first.getNext().getNext().isEmpty()) {
cc.maybeInsertSpace();
}
add(first.getNext().getNext());
add(")");
addNonEmptyStatement(last, getContextForNonEmptyExpression(context), false);
break;
case FOR_IN:
Preconditions.checkState(childCount == 3, node);
add("for");
cc.maybeInsertSpace();
add("(");
add(first);
add("in");
add(first.getNext());
add(")");
addNonEmptyStatement(last, getContextForNonEmptyExpression(context), false);
break;
case FOR_OF:
Preconditions.checkState(childCount == 3, node);
add("for");
cc.maybeInsertSpace();
add("(");
add(first);
cc.maybeInsertSpace();
add("of");
cc.maybeInsertSpace();
// the iterable must be an AssignmentExpression
addExpr(first.getNext(), NodeUtil.precedence(Token.ASSIGN), Context.OTHER);
add(")");
addNonEmptyStatement(last, getContextForNonEmptyExpression(context), false);
break;
case FOR_AWAIT_OF:
Preconditions.checkState(childCount == 3, node);
add("for await");
cc.maybeInsertSpace();
add("(");
add(first);
cc.maybeInsertSpace();
add("of");
cc.maybeInsertSpace();
// the iterable must be an AssignmentExpression
addExpr(first.getNext(), NodeUtil.precedence(Token.ASSIGN), Context.OTHER);
add(")");
addNonEmptyStatement(last, getContextForNonEmptyExpression(context), false);
break;
case DO:
Preconditions.checkState(childCount == 2, node);
add("do");
addNonEmptyStatement(first, Context.OTHER, false);
cc.maybeInsertSpace();
add("while");
cc.maybeInsertSpace();
add("(");
add(last);
add(")");
cc.endStatement();
break;
case WHILE:
Preconditions.checkState(childCount == 2, node);
add("while");
cc.maybeInsertSpace();
add("(");
add(first);
add(")");
addNonEmptyStatement(last, getContextForNonEmptyExpression(context), false);
break;
case EMPTY:
Preconditions.checkState(childCount == 0, node);
break;
case OPTCHAIN_GETPROP:
{
addExpr(first, NodeUtil.precedence(type), context);
add(node.isOptionalChainStart() ? "?." : ".");
addGetpropIdentifier(node);
break;
}
case GETPROP:
{
// qualified names.
if (useOriginalName && node.getOriginalName() != null) {
// rewrite it back to the original code.
if (node.getFirstChild().matchesQualifiedName("$jscomp.scope") && node.getParent().isAssign()) {
add("var ");
}
addGetpropIdentifier(node);
break;
}
// We need parentheses to distinguish
// `a?.b.c` from `(a?.b).c`
boolean breakOutOfOptionalChain = NodeUtil.isOptChainNode(first);
// `2.toString()` is invalid - it must be `(2).toString()`
boolean needsParens = first.isNumber() || breakOutOfOptionalChain;
if (needsParens) {
add("(");
}
addExpr(first, NodeUtil.precedence(type), context);
if (needsParens) {
add(")");
}
if (quoteKeywordProperties && TokenStream.isKeyword(node.getString())) {
// NOTE: We don't have to worry about quoting keyword properties in the
// OPTCHAIN_GETPROP case above, because we only need to quote keywords for
// ES3-compatible output.
//
// Must be a single call to `add` otherwise the generator will add a trailing space.
add("[\"" + node.getString() + "\"]");
} else {
add(".");
addGetpropIdentifier(node);
}
break;
}
case OPTCHAIN_GETELEM:
{
checkState(childCount == 2, "Bad GETELEM node: Expected 2 children but got %s. For node: %s", childCount, node);
addExpr(first, NodeUtil.precedence(type), context);
if (node.isOptionalChainStart()) {
add("?.");
}
add("[");
add(first.getNext());
add("]");
break;
}
case GETELEM:
{
checkState(childCount == 2, "Bad GETELEM node: Expected 2 children but got %s. For node: %s", childCount, node);
boolean needsParens = NodeUtil.isOptChainNode(first);
if (needsParens) {
add("(");
}
addExpr(first, NodeUtil.precedence(type), context);
if (needsParens) {
add(")");
}
add("[");
add(first.getNext());
add("]");
break;
}
case WITH:
Preconditions.checkState(childCount == 2, node);
add("with(");
add(first);
add(")");
addNonEmptyStatement(last, getContextForNonEmptyExpression(context), false);
break;
case INC:
case DEC:
{
checkState(childCount == 1, node);
String o = type == Token.INC ? "++" : "--";
boolean postProp = node.getBooleanProp(Node.INCRDECR_PROP);
if (postProp) {
addExpr(first, NodeUtil.precedence(type), context);
cc.addOp(o, false);
} else {
cc.addOp(o, false);
add(first);
}
break;
}
case OPTCHAIN_CALL:
{
// that must be preserved.
if (isIndirectEval(first) || (node.getBooleanProp(Node.FREE_CALL) && NodeUtil.isNormalOrOptChainGet(first))) {
add("(0,");
addExpr(first, NodeUtil.precedence(Token.COMMA), Context.OTHER);
add(")");
} else {
addExpr(first, NodeUtil.precedence(type), context);
}
Node args = first.getNext();
if (node.isOptionalChainStart()) {
add("?.");
}
add("(");
addList(args);
add(")");
break;
}
case CALL:
this.addInvocationTarget(node, context);
add("(");
addList(first.getNext());
add(")");
break;
case IF:
Preconditions.checkState(childCount == 2 || childCount == 3, node);
boolean hasElse = childCount == 3;
boolean ambiguousElseClause = context == Context.BEFORE_DANGLING_ELSE && !hasElse;
if (ambiguousElseClause) {
cc.beginBlock();
}
add("if");
cc.maybeInsertSpace();
add("(");
add(first);
add(")");
if (hasElse) {
addNonEmptyStatement(first.getNext(), Context.BEFORE_DANGLING_ELSE, false);
cc.maybeInsertSpace();
add("else");
addNonEmptyStatement(last, getContextForNonEmptyExpression(context), false);
} else {
addNonEmptyStatement(first.getNext(), Context.OTHER, false);
}
if (ambiguousElseClause) {
cc.endBlock();
}
break;
case NULL:
Preconditions.checkState(childCount == 0, node);
cc.addConstant("null");
break;
case THIS:
Preconditions.checkState(childCount == 0, node);
add("this");
break;
case SUPER:
Preconditions.checkState(childCount == 0, node);
add("super");
break;
case NEW_TARGET:
Preconditions.checkState(childCount == 0, node);
add("new.target");
break;
case YIELD:
add("yield");
if (node.isYieldAll()) {
checkNotNull(first);
add("*");
}
if (first != null) {
cc.maybeInsertSpace();
addExpr(first, NodeUtil.precedence(type), Context.OTHER);
}
break;
case AWAIT:
add("await ");
addExpr(first, NodeUtil.precedence(type), Context.OTHER);
break;
case FALSE:
Preconditions.checkState(childCount == 0, node);
cc.addConstant("false");
break;
case TRUE:
Preconditions.checkState(childCount == 0, node);
cc.addConstant("true");
break;
case CONTINUE:
Preconditions.checkState(childCount <= 1, node);
add("continue");
if (childCount == 1) {
if (!first.isLabelName()) {
throw new Error("Unexpected token type. Should be LABEL_NAME.");
}
add(" ");
add(first);
}
cc.endStatement();
break;
case DEBUGGER:
Preconditions.checkState(childCount == 0, node);
add("debugger");
cc.endStatement();
break;
case BREAK:
Preconditions.checkState(childCount <= 1, node);
add("break");
if (childCount == 1) {
if (!first.isLabelName()) {
throw new Error("Unexpected token type. Should be LABEL_NAME.");
}
add(" ");
add(first);
}
cc.endStatement();
break;
case EXPR_RESULT:
Preconditions.checkState(childCount == 1, node);
add(first, Context.START_OF_EXPR);
cc.endStatement();
break;
case NEW:
add("new ");
int precedence = NodeUtil.precedence(type);
// `new void 0` is a syntax error add parenthese in this case. This is only particularly
// interesting for code in dead branches.
int precedenceOfFirst = NodeUtil.precedence(first.getToken());
if (precedenceOfFirst == precedence) {
precedence = precedence + 1;
}
// If the first child is an arrow function, then parentheses is needed
if (NodeUtil.has(first, Node::isCall, NodeUtil.MATCH_NOT_FUNCTION) || NodeUtil.isOptChainNode(first)) {
precedence = NodeUtil.precedence(first.getToken()) + 1;
}
addExpr(first, precedence, Context.OTHER);
// '()' is optional when no arguments are present
Node next = first.getNext();
if (next != null) {
add("(");
addList(next);
add(")");
} else {
if (cc.shouldPreserveExtras(node)) {
add("(");
add(")");
}
}
break;
case STRING_KEY:
addStringKey(node);
break;
case STRINGLIT:
Preconditions.checkState(childCount == 0, "String node %s may not have children", node);
addJsString(node);
break;
case DELPROP:
Preconditions.checkState(childCount == 1, node);
add("delete ");
add(first);
break;
case OBJECTLIT:
{
boolean needsParens = context == Context.START_OF_EXPR || context.atArrowFunctionBody();
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
checkState(NodeUtil.isObjLitProperty(c) || c.isSpread(), c);
add(c);
}
if (first != null && node.hasTrailingComma()) {
cc.optionalListSeparator();
}
add("}");
if (needsParens) {
add(")");
}
break;
}
case COMPUTED_PROP:
maybeAddAccessibilityModifier(node);
if (node.getBooleanProp(Node.STATIC_MEMBER)) {
add("static ");
}
if (node.getBooleanProp(Node.COMPUTED_PROP_GETTER)) {
add("get ");
} else if (node.getBooleanProp(Node.COMPUTED_PROP_SETTER)) {
add("set ");
} else if (node.getBooleanProp(Node.COMPUTED_PROP_METHOD)) {
if (last.isAsyncFunction()) {
add("async");
}
if (last.getBooleanProp(Node.GENERATOR_FN)) {
add("*");
}
}
add("[");
// Must use addExpr() with a priority of 1, because comma expressions aren't allowed.
// https://www.ecma-international.org/ecma-262/9.0/index.html#prod-ComputedPropertyName
addExpr(first, 1, Context.OTHER);
add("]");
// TODO(martinprobst): There's currently no syntax for properties in object literals that
// have type declarations on them (a la `{foo: number: 12}`). This comes up for, e.g.,
// function parameters with default values. Support when figured out.
maybeAddTypeDecl(node);
if (node.getBooleanProp(Node.COMPUTED_PROP_METHOD) || node.getBooleanProp(Node.COMPUTED_PROP_GETTER) || node.getBooleanProp(Node.COMPUTED_PROP_SETTER)) {
Node function = first.getNext();
Node params = function.getSecondChild();
Node body = function.getLastChild();
add(params);
add(body);
} else {
// This is a field or object literal property.
boolean isInClass = node.getParent().isClassMembers();
Node initializer = first.getNext();
if (initializer != null) {
// Object literal value.
checkState(!isInClass, "initializers should only exist in object literals, not classes");
cc.add(":");
// Must use addExpr() with a priority of 1, because a comma expression here would cause
// a syntax error within the object literal.
addExpr(initializer, 1, Context.OTHER);
} else {
// Computed properties must either have an initializer or be computed member-variable
// properties that exist for their type declaration.
checkState(node.getBooleanProp(Node.COMPUTED_PROP_VARIABLE), node);
}
}
break;
case OBJECT_PATTERN:
addObjectPattern(node);
maybeAddTypeDecl(node);
break;
case SWITCH:
add("switch(");
add(first);
add(")");
cc.beginBlock();
addAllSiblings(first.getNext());
cc.endBlock(context == Context.STATEMENT);
break;
case CASE:
Preconditions.checkState(childCount == 2, node);
add("case ");
add(first);
addCaseBody(last);
break;
case DEFAULT_CASE:
Preconditions.checkState(childCount == 1, node);
add("default");
addCaseBody(first);
break;
case LABEL:
Preconditions.checkState(childCount == 2, node);
if (!first.isLabelName()) {
throw new Error("Unexpected token type. Should be LABEL_NAME.");
}
add(first);
add(":");
if (!last.isBlock()) {
cc.maybeInsertSpace();
}
addNonEmptyStatement(last, getContextForNonEmptyExpression(context), true);
break;
case CAST:
if (preserveTypeAnnotations) {
add("(");
// drop context because of added parentheses
add(first);
add(")");
} else {
// preserve context
add(first, context);
}
break;
case TAGGED_TEMPLATELIT:
this.addInvocationTarget(node, context);
add(first.getNext());
break;
case TEMPLATELIT:
cc.beginTemplateLit();
for (Node c = first; c != null; c = c.getNext()) {
if (c.isTemplateLitString()) {
add(escapeUnrecognizedCharacters(c.getRawString()));
} else {
cc.beginTemplateLitSub();
add(c.getFirstChild(), Context.START_OF_EXPR);
cc.endTemplateLitSub();
}
}
cc.endTemplateLit();
break;
// Type Declaration ASTs.
case STRING_TYPE:
add("string");
break;
case BOOLEAN_TYPE:
add("boolean");
break;
case NUMBER_TYPE:
add("number");
break;
case ANY_TYPE:
add("any");
break;
case VOID_TYPE:
add("void");
break;
case NAMED_TYPE:
// Children are a chain of getprop nodes.
add(first);
break;
case ARRAY_TYPE:
addExpr(first, NodeUtil.precedence(Token.ARRAY_TYPE), context);
add("[]");
break;
case FUNCTION_TYPE:
Node returnType = first;
add("(");
addList(first.getNext());
add(")");
cc.addOp("=>", true);
add(returnType);
break;
case UNION_TYPE:
addList(first, "|");
break;
case RECORD_TYPE:
add("{");
addList(first, false, Context.OTHER, ",");
add("}");
break;
case PARAMETERIZED_TYPE:
// First child is the type that's parameterized, later children are the arguments.
add(first);
add("<");
addList(first.getNext());
add(">");
break;
// CLASS -> NAME,EXPR|EMPTY,BLOCK
case GENERIC_TYPE_LIST:
add("<");
addList(first, false, Context.STATEMENT, ",");
add(">");
break;
case GENERIC_TYPE:
addIdentifier(node.getString());
if (node.hasChildren()) {
add("extends");
cc.maybeInsertSpace();
add(node.getFirstChild());
}
break;
case INTERFACE:
{
checkState(childCount == 3, node);
Node name = first;
Node superTypes = first.getNext();
Node members = last;
add("interface");
add(name);
maybeAddGenericTypes(name);
if (!superTypes.isEmpty()) {
add("extends");
Node superType = superTypes.getFirstChild();
add(superType);
while ((superType = superType.getNext()) != null) {
add(",");
cc.maybeInsertSpace();
add(superType);
}
}
add(members);
}
break;
case ENUM:
{
checkState(childCount == 2, node);
Node name = first;
Node members = last;
add("enum");
add(name);
add(members);
break;
}
case NAMESPACE:
{
checkState(childCount == 2, node);
Node name = first;
Node elements = last;
add("namespace");
add(name);
add(elements);
break;
}
case TYPE_ALIAS:
add("type");
add(node.getString());
cc.addOp("=", true);
add(last);
cc.endStatement(true);
break;
case DECLARE:
add("declare");
add(first);
processEnd(node, context);
break;
case INDEX_SIGNATURE:
add("[");
add(first);
add("]");
maybeAddTypeDecl(node);
cc.endStatement(true);
break;
case CALL_SIGNATURE:
if (node.getBooleanProp(Node.CONSTRUCT_SIGNATURE)) {
add("new ");
}
maybeAddGenericTypes(node);
add(first);
maybeAddTypeDecl(node);
cc.endStatement(true);
break;
default:
throw new IllegalStateException("Unknown token " + type + "\n" + node.toStringTree());
}
// print any trailing nonJSDoc comment attached to this node
if (printNonJSDocComments) {
NonJSDocComment nonJSDocComment = node.getNonJSDocComment();
if (nonJSDocComment != null && nonJSDocComment.isTrailing()) {
String nonJSDocCommentString = node.getNonJSDocCommentString();
if (!nonJSDocCommentString.isEmpty()) {
addNonJsDoctrailing(nonJSDocComment);
}
}
}
cc.endSourceMapping(node);
}
use of com.google.javascript.rhino.NonJSDocComment in project closure-compiler by google.
the class ParserTest method testNoInlineNonJSDocCommentAttachmentWithoutParsingMode.
@Test
public void testNoInlineNonJSDocCommentAttachmentWithoutParsingMode() {
Node letNode = parse("let /* blah */ x = 'a';").getFirstChild();
assertNode(letNode).hasType(Token.LET);
NonJSDocComment nonJSDocComment = letNode.getFirstChild().getNonJSDocComment();
assertThat(nonJSDocComment).isNull();
}
Aggregations