Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | 55x 55x 2277x 2277x 2277x 2277x 1725x 290x 125x 65x 1290x 585x 20x 670x 670x 670x 1222x 55x 1987x 4364x 1987x 1987x 1987x 55x 2277x 2277x 460x 2277x 2277x 55x | const { doc: { builders: { group, indent, label, softline } } } = require('prettier'); const isEndOfChain = (node, path) => { let i = 0; let currentNode = node; let parentNode = path.getParentNode(i); while ( parentNode && [ 'FunctionCall', 'IndexAccess', 'NameValueExpression', 'MemberAccess' ].includes(parentNode.type) ) { switch (parentNode.type) { case 'MemberAccess': // If direct ParentNode is a MemberAccess we are not at the end of the // chain. return false; case 'IndexAccess': // If direct ParentNode is an IndexAccess and currentNode is not the base // then it must be the index in which case it is the end of the chain. if (currentNode !== parentNode.base) return true; break; case 'FunctionCall': // If direct ParentNode is a FunctionCall and currentNode is not the // expression then it must be and argument in which case it is the end // of the chain. if (currentNode !== parentNode.expression) return true; break; default: break; } i += 1; currentNode = parentNode; parentNode = path.getParentNode(i); } return true; }; /** * processChain expects the doc[] of the full chain of MemberAccess. * * It uses the separator label to split the chain into 2 arrays. * The first array is the doc[] corresponding to the first element before the * first separator. * The second array contains the rest of the chain. * * The second array is grouped and indented, while the first element's * formatting logic remains separated. * * That way the first element can safely split into multiple lines and the rest * of the chain will continue its formatting rules as normal. * * i.e. * ``` * functionCall(arg1, arg2).rest.of.chain * * functionCall(arg1, arg2) * .long * .rest * .of * .chain * * functionCall( * arg1, * arg2 * ).rest.of.chain * * functionCall( * arg1, * arg2 * ) * .long * .rest * .of * .chain * ``` * * NOTE: As described in the examples above, the rest of the chain will be grouped * and try to stay in the same line as the end of the first element. * * @param {doc[]} chain is the full chain of MemberAccess * @returns a processed doc[] with the proper grouping and indentation ready to * be printed. */ const processChain = (chain) => { const firstSeparatorIndex = chain.findIndex( (element) => element.label === 'separator' ); // The doc[] before the first separator const firstExpression = chain.slice(0, firstSeparatorIndex); // The doc[] containing the rest of the chain const restOfChain = group(indent(chain.slice(firstSeparatorIndex))); // We wrap the expression in a label in case there is an IndexAccess or // a FunctionCall following this MemberAccess. return label('MemberAccessChain', group([firstExpression, restOfChain])); }; const MemberAccess = { print: ({ node, path, print }) => { let expressionDoc = path.call(print, 'expression'); if (Array.isArray(expressionDoc)) { expressionDoc = expressionDoc.flat(); } const doc = [ expressionDoc, label('separator', [softline, '.']), node.memberName ].flat(); return isEndOfChain(node, path) ? processChain(doc) : doc; } }; module.exports = MemberAccess; |