Exclude node at rangeStart (#9704)
This commit is contained in:
1 parent
902d524d2f
commit
05d20a63a4
11 files changed
+245
-29
No files matched your search
@@ -0,0 +1,19 @@
|
|||||||
|
#### Fix node ends at `rangeStart` was formatted (#9704 by @fisker)
|
||||||
|
|
||||||
|
Previously a node ends at `rangeStart` in considered in range, now it's excluded.
|
||||||
|
|
||||||
|
<!-- prettier-ignore -->
|
||||||
|
```js
|
||||||
|
// Prettier stable
|
||||||
|
foo = 1.0000;bar = 1.0000;baz=1.0000;
|
||||||
|
^^^^^^^^^^^^^ Range
|
||||||
|
|
||||||
|
// Prettier stable
|
||||||
|
foo = 1.0;
|
||||||
|
bar = 1.0;baz=1.0000;
|
||||||
|
|
||||||
|
// Prettier master
|
||||||
|
foo = 1.0000;bar = 1.0;baz=1.0000;
|
||||||
|
```
|
||||||
|
|
||||||
|
_This effect other languages support range format too._
|
||||||
@@ -278,6 +278,13 @@ function format(originalText, originalOptions) {
|
|||||||
normalizeOptions(originalOptions)
|
normalizeOptions(originalOptions)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (options.rangeStart >= options.rangeEnd && text !== "") {
|
||||||
|
return {
|
||||||
|
formatted: originalText,
|
||||||
|
cursorOffset: originalOptions.cursorOffset,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const selectedParser = parser.resolveParser(options);
|
const selectedParser = parser.resolveParser(options);
|
||||||
const hasPragma = !selectedParser.hasPragma || selectedParser.hasPragma(text);
|
const hasPragma = !selectedParser.hasPragma || selectedParser.hasPragma(text);
|
||||||
if (options.requirePragma && !hasPragma) {
|
if (options.requirePragma && !hasPragma) {
|
||||||
|
|||||||
+49
-27
@@ -1,5 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
const assert = require("assert");
|
||||||
const comments = require("./comments");
|
const comments = require("./comments");
|
||||||
|
|
||||||
function findSiblingAncestors(startNodeAndParents, endNodeAndParents, opts) {
|
function findSiblingAncestors(startNodeAndParents, endNodeAndParents, opts) {
|
||||||
@@ -43,8 +44,24 @@ function findSiblingAncestors(startNodeAndParents, endNodeAndParents, opts) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function findNodeAtOffset(node, offset, options, predicate, parentNodes = []) {
|
function findNodeAtOffset(
|
||||||
if (offset < options.locStart(node) || offset > options.locEnd(node)) {
|
node,
|
||||||
|
offset,
|
||||||
|
options,
|
||||||
|
predicate,
|
||||||
|
parentNodes = [],
|
||||||
|
type
|
||||||
|
) {
|
||||||
|
const { locStart, locEnd } = options;
|
||||||
|
const start = locStart(node);
|
||||||
|
const end = locEnd(node);
|
||||||
|
|
||||||
|
if (
|
||||||
|
offset > end ||
|
||||||
|
offset < start ||
|
||||||
|
(type === "rangeEnd" && offset === start) ||
|
||||||
|
(type === "rangeStart" && offset === end)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +71,8 @@ function findNodeAtOffset(node, offset, options, predicate, parentNodes = []) {
|
|||||||
offset,
|
offset,
|
||||||
options,
|
options,
|
||||||
predicate,
|
predicate,
|
||||||
[node, ...parentNodes]
|
[node, ...parentNodes],
|
||||||
|
type
|
||||||
);
|
);
|
||||||
if (childResult) {
|
if (childResult) {
|
||||||
return childResult;
|
return childResult;
|
||||||
@@ -133,37 +151,41 @@ function isSourceElement(opts, node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function calculateRange(text, opts, ast) {
|
function calculateRange(text, opts, ast) {
|
||||||
|
let { rangeStart: start, rangeEnd: end, locStart, locEnd } = opts;
|
||||||
|
assert.ok(end > start);
|
||||||
// Contract the range so that it has non-whitespace characters at its endpoints.
|
// Contract the range so that it has non-whitespace characters at its endpoints.
|
||||||
// This ensures we can format a range that doesn't end on a node.
|
// This ensures we can format a range that doesn't end on a node.
|
||||||
const rangeStringOrig = text.slice(opts.rangeStart, opts.rangeEnd);
|
const firstNonWhitespaceCharacterIndex = text.slice(start, end).search(/\S/);
|
||||||
const startNonWhitespace = Math.max(
|
const isAllWhitespace = firstNonWhitespaceCharacterIndex === -1;
|
||||||
opts.rangeStart + rangeStringOrig.search(/\S/),
|
if (!isAllWhitespace) {
|
||||||
opts.rangeStart
|
start += firstNonWhitespaceCharacterIndex;
|
||||||
);
|
for (; end > start; --end) {
|
||||||
let endNonWhitespace;
|
if (/\S/.test(text[end - 1])) {
|
||||||
for (
|
break;
|
||||||
endNonWhitespace = opts.rangeEnd;
|
}
|
||||||
endNonWhitespace > opts.rangeStart;
|
|
||||||
--endNonWhitespace
|
|
||||||
) {
|
|
||||||
if (/\S/.test(text[endNonWhitespace - 1])) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const startNodeAndParents = findNodeAtOffset(
|
const startNodeAndParents = findNodeAtOffset(
|
||||||
ast,
|
ast,
|
||||||
startNonWhitespace,
|
start,
|
||||||
opts,
|
opts,
|
||||||
(node) => isSourceElement(opts, node)
|
(node) => isSourceElement(opts, node),
|
||||||
|
[],
|
||||||
|
"rangeStart"
|
||||||
);
|
);
|
||||||
const endNodeAndParents = findNodeAtOffset(
|
const endNodeAndParents =
|
||||||
ast,
|
// No need find Node at `end`, it will be the same as `startNodeAndParents`
|
||||||
endNonWhitespace,
|
isAllWhitespace
|
||||||
opts,
|
? startNodeAndParents
|
||||||
(node) => isSourceElement(opts, node)
|
: findNodeAtOffset(
|
||||||
);
|
ast,
|
||||||
|
end,
|
||||||
|
opts,
|
||||||
|
(node) => isSourceElement(opts, node),
|
||||||
|
[],
|
||||||
|
"rangeEnd"
|
||||||
|
);
|
||||||
if (!startNodeAndParents || !endNodeAndParents) {
|
if (!startNodeAndParents || !endNodeAndParents) {
|
||||||
return {
|
return {
|
||||||
rangeStart: 0,
|
rangeStart: 0,
|
||||||
@@ -178,8 +200,8 @@ function calculateRange(text, opts, ast) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
rangeStart: Math.min(opts.locStart(startNode), opts.locStart(endNode)),
|
rangeStart: Math.min(locStart(startNode), locStart(endNode)),
|
||||||
rangeEnd: Math.max(opts.locEnd(startNode), opts.locEnd(endNode)),
|
rangeEnd: Math.max(locEnd(startNode), locEnd(endNode)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,88 @@ a = [, , , , , , , a];
|
|||||||
================================================================================
|
================================================================================
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`boundary.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["babel", "flow", "typescript"]
|
||||||
|
printWidth: 80
|
||||||
|
rangeEnd: 26
|
||||||
|
rangeStart: 13
|
||||||
|
| | printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
> 1 | foo = 1.0000;bar = 1.0000;baz=1.0000;
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
2 | // The range will be 13~26
|
||||||
|
3 | // \`foo\` ends at 13, should not format
|
||||||
|
4 | // \`bar\` ends at 26, should format
|
||||||
|
5 |
|
||||||
|
=====================================output=====================================
|
||||||
|
foo = 1.0000;bar = 1.0;baz=1.0000;
|
||||||
|
// The range will be 13~26
|
||||||
|
// \`foo\` ends at 13, should not format
|
||||||
|
// \`bar\` ends at 26, should format
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`boundary-2.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["babel", "flow", "typescript"]
|
||||||
|
printWidth: 80
|
||||||
|
rangeEnd: 45
|
||||||
|
rangeStart: 28
|
||||||
|
| | printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
1 | function a(
|
||||||
|
2 | ){
|
||||||
|
3 | a (
|
||||||
|
4 | );
|
||||||
|
5 | b (
|
||||||
|
> 6 | ); c (
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
7 | ); d(
|
||||||
|
8 | );
|
||||||
|
9 |
|
||||||
|
10 | }
|
||||||
|
11 |
|
||||||
|
=====================================output=====================================
|
||||||
|
function a(
|
||||||
|
){
|
||||||
|
a();
|
||||||
|
b();
|
||||||
|
c();
|
||||||
|
d();
|
||||||
|
}
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`boundary-3.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["babel", "flow", "typescript"]
|
||||||
|
printWidth: 80
|
||||||
|
rangeEnd: 30
|
||||||
|
rangeStart: 13
|
||||||
|
| | printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
1 | a (
|
||||||
|
2 | );
|
||||||
|
3 | b (
|
||||||
|
> 4 | ); c (
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
5 | ); d(
|
||||||
|
6 | );
|
||||||
|
7 |
|
||||||
|
=====================================output=====================================
|
||||||
|
a (
|
||||||
|
);
|
||||||
|
b (
|
||||||
|
); c (
|
||||||
|
); d(
|
||||||
|
);
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`class-declaration.js format 1`] = `
|
exports[`class-declaration.js format 1`] = `
|
||||||
====================================options=====================================
|
====================================options=====================================
|
||||||
parsers: ["babel", "flow", "typescript"]
|
parsers: ["babel", "flow", "typescript"]
|
||||||
@@ -851,6 +933,44 @@ call(
|
|||||||
================================================================================
|
================================================================================
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`reversed-range.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["babel", "flow", "typescript"]
|
||||||
|
printWidth: 80
|
||||||
|
rangeEnd: 13
|
||||||
|
rangeStart: 26
|
||||||
|
| | printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
> 1 | foo = 1.0000;bar = 1.0000;baz=1.0000;
|
||||||
|
| ^^^^^^^^^^^^^ [Reversed range]
|
||||||
|
2 | // The range will be 26~13, should not format anything
|
||||||
|
3 |
|
||||||
|
=====================================output=====================================
|
||||||
|
foo = 1.0000;bar = 1.0000;baz=1.0000;
|
||||||
|
// The range will be 26~13, should not format anything
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`start-equals-end.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["babel", "flow", "typescript"]
|
||||||
|
printWidth: 80
|
||||||
|
rangeEnd: 13
|
||||||
|
rangeStart: 13
|
||||||
|
| | printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
> 1 | foo = 1.0000;bar = 1.0000;baz=1.0000;
|
||||||
|
| ^
|
||||||
|
2 | // The range will be 13~13, should not format anything
|
||||||
|
3 |
|
||||||
|
=====================================output=====================================
|
||||||
|
foo = 1.0000;bar = 1.0000;baz=1.0000;
|
||||||
|
// The range will be 13~13, should not format anything
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`try-catch.js format 1`] = `
|
exports[`try-catch.js format 1`] = `
|
||||||
====================================options=====================================
|
====================================options=====================================
|
||||||
parsers: ["babel", "flow", "typescript"]
|
parsers: ["babel", "flow", "typescript"]
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
function a(
|
||||||
|
){
|
||||||
|
a (
|
||||||
|
);
|
||||||
|
b (
|
||||||
|
);<<<PRETTIER_RANGE_START>>> <<<PRETTIER_RANGE_END>>>c (
|
||||||
|
); d(
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
a (
|
||||||
|
);
|
||||||
|
b (
|
||||||
|
);<<<PRETTIER_RANGE_START>>> <<<PRETTIER_RANGE_END>>>c (
|
||||||
|
); d(
|
||||||
|
);
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
foo = 1.0000;<<<PRETTIER_RANGE_START>>>bar = 1.0000;<<<PRETTIER_RANGE_END>>>baz=1.0000;
|
||||||
|
// The range will be 13~26
|
||||||
|
// `foo` ends at 13, should not format
|
||||||
|
// `bar` ends at 26, should format
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
foo = 1.0000;<<<PRETTIER_RANGE_END>>>bar = 1.0000;<<<PRETTIER_RANGE_START>>>baz=1.0000;
|
||||||
|
// The range will be 26~13, should not format anything
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
foo = 1.0000;<<<PRETTIER_RANGE_START>>><<<PRETTIER_RANGE_END>>>bar = 1.0000;baz=1.0000;
|
||||||
|
// The range will be 13~13, should not format anything
|
||||||
@@ -334,7 +334,7 @@ function runTest({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!code.includes("\r") && !formatOptions.requirePragma) {
|
if (!shouldSkipEolTest(code, formatResult.options)) {
|
||||||
for (const eol of ["\r\n", "\r"]) {
|
for (const eol of ["\r\n", "\r"]) {
|
||||||
test(`[${parser}] EOL ${JSON.stringify(eol)}`, () => {
|
test(`[${parser}] EOL ${JSON.stringify(eol)}`, () => {
|
||||||
const output = format(code.replace(/\n/g, eol), formatOptions)
|
const output = format(code.replace(/\n/g, eol), formatOptions)
|
||||||
@@ -361,6 +361,25 @@ function runTest({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shouldSkipEolTest(code, options) {
|
||||||
|
if (code.includes("\r")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const { requirePragma, rangeStart, rangeEnd } = options;
|
||||||
|
if (requirePragma) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof rangeStart === "number" &&
|
||||||
|
typeof rangeEnd === "number" &&
|
||||||
|
rangeStart >= rangeEnd
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function parse(source, options) {
|
function parse(source, options) {
|
||||||
return prettier.__debug.parse(source, options, /* massage */ true).ast;
|
return prettier.__debug.parse(source, options, /* massage */ true).ast;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ const { codeFrameColumns } = require("@babel/code-frame");
|
|||||||
const codeFrameColumnsOptions = { linesAbove: Infinity, linesBelow: Infinity };
|
const codeFrameColumnsOptions = { linesAbove: Infinity, linesBelow: Infinity };
|
||||||
|
|
||||||
const locationForRange = (text, rangeStart, rangeEnd) => {
|
const locationForRange = (text, rangeStart, rangeEnd) => {
|
||||||
|
if (rangeStart > rangeEnd) {
|
||||||
|
[rangeStart, rangeEnd] = [rangeEnd, rangeStart];
|
||||||
|
}
|
||||||
const lines = new LinesAndColumns(text);
|
const lines = new LinesAndColumns(text);
|
||||||
const start = lines.locationForIndex(rangeStart);
|
const start = lines.locationForIndex(rangeStart);
|
||||||
const end = lines.locationForIndex(rangeEnd);
|
const end = lines.locationForIndex(rangeEnd);
|
||||||
@@ -26,7 +29,9 @@ const visualizeRange = (text, { rangeStart = 0, rangeEnd = text.length }) =>
|
|||||||
codeFrameColumns(
|
codeFrameColumns(
|
||||||
text,
|
text,
|
||||||
locationForRange(text, rangeStart, rangeEnd),
|
locationForRange(text, rangeStart, rangeEnd),
|
||||||
codeFrameColumnsOptions
|
rangeStart > rangeEnd
|
||||||
|
? { ...codeFrameColumnsOptions, message: "[Reversed range]" }
|
||||||
|
: codeFrameColumnsOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
module.exports = visualizeRange;
|
module.exports = visualizeRange;
|
||||||
Reference in new issue
Block a user