prettier-plugin-apex
Advanced tools
Comparing version 1.0.0-alpha.7 to 1.0.0-alpha.8
## Unreleased | ||
## 1.0.0-alpha.8 | ||
- Fix comments not being printed if they appear before the root node ([issue](https://github.com/dangmai/prettier-plugin-apex/issues/17)). | ||
- Fix dangling comments not being printed for Class, Interface, Enum and Block Statement ([issue](https://github.com/dangmai/prettier-plugin-apex/issues/13)). | ||
- Add new lines in empty blocks ([issue](https://github.com/dangmai/prettier-plugin-apex/issues/15)). | ||
- Fix trailing comment being mistaken as leading comment in certain situations, | ||
because `jorje` provides wrong start and end indexes for some node types ([issue](https://github.com/dangmai/prettier-plugin-apex/issues/19)). | ||
## 1.0.0-alpha.7 | ||
@@ -4,0 +11,0 @@ - Fix Annotated Declaration being indented too far ([issue](https://github.com/dangmai/prettier-plugin-apex/issues/18)). |
{ | ||
"name": "prettier-plugin-apex", | ||
"version": "1.0.0-alpha.7", | ||
"version": "1.0.0-alpha.8", | ||
"description": "Salesforce Apex plugin for Prettier", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
@@ -72,6 +72,10 @@ # Prettier Apex [![Build Status](https://travis-ci.org/dangmai/prettier-plugin-apex.svg)](https://travis-ci.org/dangmai/prettier-plugin-apex) | ||
"tabWidth": 2, | ||
"printWidth": 80 | ||
"printWidth": 80, | ||
"useTab": false | ||
} | ||
``` | ||
Which means that by default, the formatted code will use 2 spaces for indentation, | ||
and will try to format every line to contain under 80 characters. | ||
## Performance Tips/3rd party integration | ||
@@ -78,0 +82,0 @@ |
@@ -47,3 +47,25 @@ /* eslint no-param-reassign: 0, no-plusplus: 0, no-else-return: 0, consistent-return: 0 */ | ||
function decorateComment(node, comment) { | ||
function getRootNodeLocation(ast) { | ||
// Some root node like TriggerDeclUnit has the `loc` property directly on it, | ||
// while others has it in the `body` property. This function abstracts away | ||
// that difference. | ||
if (ast[apexNames.PARSER_OUTPUT].unit.loc) { | ||
return ast[apexNames.PARSER_OUTPUT].unit.loc; | ||
} | ||
if (ast[apexNames.PARSER_OUTPUT].unit.body.loc) { | ||
return ast[apexNames.PARSER_OUTPUT].unit.body.loc; | ||
} | ||
throw new Error( | ||
"Cannot find the root node location. Please file a bug report with your code sample", | ||
); | ||
} | ||
function decorateComment(node, comment, ast) { | ||
// Special case: Comment is the first thing in the document, | ||
// then "unit" node would be the followingNode to it. | ||
if (comment.location.endIndex < getRootNodeLocation(ast).startIndex) { | ||
comment.followingNode = ast[apexNames.PARSER_OUTPUT].unit; | ||
return; | ||
} | ||
// Handling the normal cases | ||
const childNodes = getSortedChildNodes(node); | ||
@@ -65,3 +87,21 @@ | ||
comment.enclosingNode = child; | ||
decorateComment(child, comment); | ||
// Special case: if the child is a declaration type and has no members, | ||
// we should go no deeper; otherwise the `name` node will mistakenly | ||
// be decorated as the preceding node to this comment. | ||
const declarationUnits = [ | ||
apexNames.CLASS_DECLARATION, | ||
apexNames.TRIGGER_DECLARATION_UNIT, | ||
apexNames.ENUM_DECLARATION, | ||
apexNames.INTERFACE_DECLARATION, | ||
]; | ||
if ( | ||
declarationUnits.includes(child["@class"]) && | ||
child.members.length === 0 | ||
) { | ||
return; | ||
} | ||
// Standard case: recursively decorating the children nodes | ||
decorateComment(child, comment, ast); | ||
return; // Abandon the binary search at this level | ||
@@ -192,3 +232,3 @@ } | ||
comments.forEach(comment => { | ||
decorateComment(ast[apexNames.PARSER_OUTPUT].unit, comment); | ||
decorateComment(ast[apexNames.PARSER_OUTPUT].unit, comment, ast); | ||
@@ -279,3 +319,2 @@ const pn = comment.precedingNode; | ||
} | ||
comment.printed = true; | ||
return concat(parts); | ||
@@ -320,6 +359,30 @@ } | ||
comment.printed = true; | ||
return concat(parts); | ||
} | ||
function printDanglingComment(commentPath, options, print) { | ||
const sourceCode = options.originalText; | ||
const comment = commentPath.getValue(commentPath); | ||
const loc = comment.location; | ||
const isFirstComment = commentPath.getName() === 0; | ||
const parts = []; | ||
const fromPos = | ||
skipWhitespace(sourceCode, loc.startIndex - 1, { | ||
backwards: true, | ||
}) + 1; | ||
const leadingSpace = sourceCode.slice(fromPos, loc.startIndex); | ||
const numberOfNewLines = isFirstComment | ||
? 0 | ||
: (leadingSpace.match(/\n/g) || []).length; | ||
if (numberOfNewLines > 0) { | ||
// If the leading space contains newlines, then add at most 2 new lines | ||
const numberOfNewLinesToInsert = Math.min(numberOfNewLines, 2); | ||
parts.push(...Array(numberOfNewLinesToInsert).fill(hardline)); | ||
} | ||
parts.push(print(commentPath)); | ||
return concat(parts); | ||
} | ||
function allowTrailingComments(apexClass) { | ||
@@ -349,3 +412,3 @@ let trailingCommentsAllowed = false; | ||
if (!comments || comments.length === 0) { | ||
if (!comments || comments.filter(comment => !comment.printed).length === 0) { | ||
return innerLines; | ||
@@ -409,2 +472,3 @@ } | ||
printComments, | ||
printDanglingComment, | ||
}; |
@@ -1,2 +0,2 @@ | ||
/* eslint no-param-reassign:0 */ | ||
/* eslint no-param-reassign: 0 no-underscore-dangle: 0 */ | ||
@@ -47,2 +47,14 @@ const childProcess = require("child_process"); | ||
// jorje calls the location node differently for different types of nodes, | ||
// so we use this method to abstract away that difference | ||
function _getNodeLocation(node) { | ||
if (node.loc) { | ||
return node.loc; | ||
} | ||
if (node.location) { | ||
return node.location; | ||
} | ||
return null; | ||
} | ||
// The serialized string given back contains references (to avoid circular references), | ||
@@ -70,2 +82,53 @@ // which need to be resolved. This method recursively walks through the | ||
/** | ||
* Sometimes jorje lies about a node location, so we will fix it here before | ||
* using that information. We do it by enforcing that a parent node start | ||
* index is always <= any child node start index, and a parent node end index | ||
* is always >= any child node end index. | ||
* @param node the node being visited. | ||
*/ | ||
function fixNodeLocation(node) { | ||
let currentLocation; | ||
Object.keys(node).forEach(key => { | ||
if (typeof node[key] === "object") { | ||
const location = fixNodeLocation(node[key]); | ||
if (location && currentLocation) { | ||
if (currentLocation.startIndex > location.startIndex) { | ||
currentLocation.startIndex = location.startIndex; | ||
} | ||
if (currentLocation.endIndex < location.endIndex) { | ||
currentLocation.endIndex = location.endIndex; | ||
} | ||
} | ||
if (location && !currentLocation) { | ||
currentLocation = location; | ||
} | ||
} | ||
}); | ||
if ( | ||
node.loc && | ||
currentLocation && | ||
node.loc.startIndex > currentLocation.startIndex | ||
) { | ||
node.loc.startIndex = currentLocation.startIndex; | ||
} | ||
if ( | ||
node.loc && | ||
currentLocation && | ||
node.loc.endIndex < currentLocation.endIndex | ||
) { | ||
node.loc.endIndex = currentLocation.endIndex; | ||
} | ||
if (currentLocation) { | ||
return currentLocation; | ||
} | ||
if (node.loc) { | ||
return { | ||
startIndex: node.loc.startIndex, | ||
endIndex: node.loc.endIndex, | ||
}; | ||
} | ||
return null; | ||
} | ||
/** | ||
* Certain node types do not get their endIndex reported from the jorje compiler, | ||
@@ -168,3 +231,3 @@ * or the number they report is not the end of the entire block, | ||
} else if (!nodeLoc && !lastNodeLoc) { | ||
lastNodeLoc = node.loc; | ||
lastNodeLoc = _getNodeLocation(node); | ||
} | ||
@@ -180,5 +243,6 @@ } | ||
} | ||
const nodeLoc = _getNodeLocation(node); | ||
if ( | ||
apexClass && | ||
(node.loc || node.lastNodeLoc) && | ||
(nodeLoc || node.lastNodeLoc) && | ||
allowTrailingEmptyLine && | ||
@@ -196,3 +260,3 @@ !node.isLastNodeInArray | ||
? node.lastNodeLoc.endLine + 1 | ||
: node.loc.endLine + 1; | ||
: nodeLoc.endLine + 1; | ||
const nextEmptyLine = emptyLineLocations.indexOf(nextLine); | ||
@@ -205,6 +269,6 @@ if (trailingEmptyLineAllowed && nextEmptyLine !== -1) { | ||
? emptyLineNodeMap[nextLine].lastNodeLoc.endIndex | ||
: emptyLineNodeMap[nextLine].loc.endIndex; | ||
: _getNodeLocation(emptyLineNodeMap[nextLine]).endIndex; | ||
const thisEndIndex = node.lastNodeLoc | ||
? node.lastNodeLoc.endIndex | ||
: node.loc.endIndex; | ||
: nodeLoc.endIndex; | ||
@@ -225,3 +289,3 @@ if (nodeMapEndIndex > thisEndIndex) { | ||
} | ||
return node.loc; | ||
return nodeLoc; | ||
} | ||
@@ -234,6 +298,13 @@ | ||
function resolveLineIndexes(node, lineIndexes) { | ||
const nodeLoc = node.loc; | ||
const nodeLoc = _getNodeLocation(node); | ||
if (nodeLoc) { | ||
nodeLoc.endLine = | ||
lineIndexes.findIndex(index => index > nodeLoc.endIndex) - 1; | ||
// Edge case: root node | ||
if (nodeLoc.endLine < 0) { | ||
nodeLoc.endLine = lineIndexes.length - 1; | ||
} | ||
// Edge case: Trigger Declaration Unit. | ||
// Somehow jorje thinks this node ends after the word `trigger`. | ||
} | ||
@@ -303,2 +374,3 @@ Object.keys(node).forEach(key => { | ||
ast = resolveAstReferences(ast, {}); | ||
fixNodeLocation(ast); | ||
ast = resolveLineIndexes(ast, lineIndexes); | ||
@@ -305,0 +377,0 @@ generateExtraMetadata( |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
11739156
3426
113