private static SuggestedFix getFixForUnsortedRequiresOrProvides( String closureFunction, JSError error, AbstractCompiler compiler) { SuggestedFix.Builder fix = new SuggestedFix.Builder(); fix.setOriginalMatchedNode(error.node); Node script = NodeUtil.getEnclosingScript(error.node); RequireProvideSorter cb = new RequireProvideSorter(closureFunction); NodeTraversal.traverseEs6(compiler, script, cb); Node first = cb.calls.get(0); Node last = Iterables.getLast(cb.calls); cb.sortCallsAlphabetically(); StringBuilder sb = new StringBuilder(); for (Node n : cb.calls) { String statement = fix.generateCode(compiler, n); JSDocInfo jsDoc = NodeUtil.getBestJSDocInfo(n); if (jsDoc != null) { statement = jsDoc.getOriginalCommentString() + "\n" + statement; } sb.append(statement); } // Trim to remove the newline after the last goog.require/provide. String newContent = sb.toString().trim(); return fix.replaceRange(first, last, newContent).build(); }
private static SuggestedFix getFixForMissingRequire(JSError error, AbstractCompiler compiler) { Matcher regexMatcher = MISSING_REQUIRE.matcher(error.description); Preconditions.checkState(regexMatcher.matches(), "Unexpected error description: %s", error.description); String namespaceToRequire = regexMatcher.group(1); NodeMetadata metadata = new NodeMetadata(compiler); Match match = new Match(error.node, metadata); return new SuggestedFix.Builder() .setOriginalMatchedNode(error.node) .addGoogRequire(match, namespaceToRequire) .build(); }
Node node = m.getNode(); NodeMetadata metadata = m.getMetadata(); Node existingNode = findGoogRequireNode(m.getNode(), metadata, namespace); if (existingNode != null) { return this; startPosition, 0, generateCode(m.getMetadata().getCompiler(), googRequireNode))); return this; } else { } else { replacements.put(script.getSourceFileName(), new CodeReplacement( 0, 0, generateCode(m.getMetadata().getCompiler(), googRequireNode))); return this; return insertBefore( nodeToInsertBefore, googRequireNode, m.getMetadata().getCompiler(), namespace);
/** * Replaces the provided node with new node in the source file. */ public Builder replace(Node original, Node newNode, AbstractCompiler compiler) { Node parent = original.getParent(); // EXPR_RESULT nodes will contain the trailing semicolons, but the child node // will not. Replace the EXPR_RESULT node to ensure that the semicolons are // correct in the final output. if (original.getParent().isExprResult()) { original = original.getParent(); } // TODO(mknichel): Move this logic to CodePrinter. String newCode = generateCode(compiler, newNode); // The generated code may contain a trailing newline but that is never wanted. if (newCode.endsWith("\n")) { newCode = newCode.substring(0, newCode.length() - 1); } // Most replacements don't need the semicolon in the new generated code - however, some // statements that are blocks or expressions will need the semicolon. boolean needsSemicolon = parent.isExprResult() || parent.isBlock() || parent.isScript(); if (newCode.endsWith(";") && !needsSemicolon) { newCode = newCode.substring(0, newCode.length() - 1); } replacements.put( original.getSourceFileName(), new CodeReplacement(original.getSourceOffset(), original.getLength(), newCode)); return this; }
@Override public List<SuggestedFix> processMatch(Match match) { SuggestedFix.Builder fix = new SuggestedFix.Builder(); Node newNode = transformNode( matchedTemplate.afterTemplate.getLastChild(), matchedTemplate.matcher.getTemplateNodeToMatchMap()); Node nodeToReplace = match.getNode(); fix.setOriginalMatchedNode(nodeToReplace); fix.replace(nodeToReplace, newNode, match.getMetadata().getCompiler()); // If the template is a multiline template, make sure to delete the same number of sibling nodes // as the template has. Node n = match.getNode().getNext(); for (int i = 1; i < matchedTemplate.beforeTemplate.getLastChild().getChildCount(); i++) { Preconditions.checkNotNull( n, "Found mismatched sibling count between before template and matched node.\n" + "Template: %s\nMatch: %s", matchedTemplate.beforeTemplate.getLastChild(), match.getNode()); fix.delete(n); n = n.getNext(); } // Add/remove any goog.requires for (String require : matchedTemplate.getGoogRequiresToAdd()) { fix.addGoogRequire(match, require); } for (String require : matchedTemplate.getGoogRequiresToRemove()) { fix.removeGoogRequire(match, require); } return ImmutableList.of(fix.build()); }
private static List<SuggestedFix> getFixesForImplicitlyNullableJsDoc(JSError error) { SuggestedFix qmark = new SuggestedFix.Builder() .setOriginalMatchedNode(error.node) .insertBefore(error.node, "?") .setDescription("Make nullability explicit") .build(); SuggestedFix bang = new SuggestedFix.Builder() .setOriginalMatchedNode(error.node) .insertBefore(error.node, "!") .setDescription("Make type non-nullable") .build(); return ImmutableList.of(qmark, bang); }
/** * Adds a cast of the given type to the provided node. */ public Builder addCast(Node n, AbstractCompiler compiler, String type) { // TODO(mknichel): Figure out the best way to output the typecast. replacements.put( n.getSourceFileName(), new CodeReplacement( n.getSourceOffset(), n.getLength(), "/** @type {" + type + "} */ (" + generateCode(compiler, n) + ")")); return this; }
/** * Inserts a string before the provided node. This is useful for inserting * comments into a file since the JS Compiler doesn't currently support * printing comments. */ public Builder insertBefore(Node nodeToInsertBefore, String content) { return insertBefore(nodeToInsertBefore, content, ""); }
private Builder insertBefore( Node nodeToInsertBefore, Node n, AbstractCompiler compiler, String sortKey) { return insertBefore(nodeToInsertBefore, generateCode(compiler, n), sortKey); }
private static SuggestedFix getFixForExtraRequire(JSError error, AbstractCompiler compiler) { Matcher regexMatcher = EXTRA_REQUIRE.matcher(error.description); Preconditions.checkState(regexMatcher.matches(), "Unexpected error description: %s", error.description); String namespace = regexMatcher.group(1); NodeMetadata metadata = new NodeMetadata(compiler); Match match = new Match(error.node, metadata); return new SuggestedFix.Builder() .setOriginalMatchedNode(error.node) .removeGoogRequire(match, namespace) .build(); }
private static SuggestedFix getFixForInvalidSuper(JSError error, AbstractCompiler compiler) { Matcher m = DID_YOU_MEAN.matcher(error.description); if (m.matches()) { return new SuggestedFix.Builder() .setOriginalMatchedNode(error.node) .replace(error.node, NodeUtil.newQName(compiler, m.group(1)), compiler) .build(); } return null; }
private static SuggestedFix getFixForInexistentProperty(JSError error) { Matcher m = DID_YOU_MEAN.matcher(error.description); if (m.matches()) { String suggestedPropName = m.group(1); return new SuggestedFix.Builder() .setOriginalMatchedNode(error.node) .rename(error.node, suggestedPropName).build(); } return null; }
private static SuggestedFix getFixForMissingSuper(JSError error) { Node body = NodeUtil.getFunctionBody(error.node); return new SuggestedFix.Builder() .setOriginalMatchedNode(error.node) .addChildToFront(body, "super();") .build(); }
private static SuggestedFix removeNode(JSError error) { return new SuggestedFix.Builder() .setOriginalMatchedNode(error.node) .delete(error.node).build(); }
/** * Deletes a node and its contents from the source file. */ public Builder deleteWithoutRemovingWhitespaceBefore(Node n) { return delete(n, false); }
/** * Inserts a new node before the provided node. */ public Builder insertBefore(Node nodeToInsertBefore, Node n, AbstractCompiler compiler) { return insertBefore(nodeToInsertBefore, n, compiler, ""); }
/** * Removes a goog.require for the given namespace to the file if it * already exists. */ public Builder removeGoogRequire(Match m, String namespace) { Node googRequireNode = findGoogRequireNode(m.getNode(), m.getMetadata(), namespace); if (googRequireNode != null) { return deleteWithoutRemovingWhitespaceBefore(googRequireNode); } return this; }
/** * Deletes a node and its contents from the source file. If the node is a child of a * block or top level statement, this will also delete the whitespace before the node. */ public Builder delete(Node n) { return delete(n, true); }
private static SuggestedFix getFixForMissingSemicolon(JSError error) { return new SuggestedFix.Builder() .setOriginalMatchedNode(error.node) .insertAfter(error.node, ";") .build(); }