diff --git a/changelog_unreleased/flow/10505.md b/changelog_unreleased/flow/10505.md new file mode 100644 index 000000000..3e1bd25d6 --- /dev/null +++ b/changelog_unreleased/flow/10505.md @@ -0,0 +1,15 @@ +#### Fix range formatting issues (#10505 by @thorn0) + +Prettier had trouble formatting some ranges in function declarations. `SyntaxError` was thrown. Prettier main formats these cases without errors. Examples of problematic ranges are shown below: + + +```jsx +declare export function graphql> + // ^^^^^ range 1 + (query: GQLDocument, config?: Config>): + (Component: Component) => React$ComponentType<$Diff, { + data: Object|void, + // ^^^^ range 2 + mutate: Function|void + }>> +``` diff --git a/src/main/range-util.js b/src/main/range-util.js index 718026a55..3152e1168 100644 --- a/src/main/range-util.js +++ b/src/main/range-util.js @@ -79,7 +79,7 @@ function findNodeAtOffset( } } - if (!predicate || predicate(node)) { + if (!predicate || predicate(node, parentNodes[0])) { return { node, parentNodes, @@ -88,15 +88,17 @@ function findNodeAtOffset( } // See https://www.ecma-international.org/ecma-262/5.1/#sec-A.5 -function isJsSourceElement(type) { +function isJsSourceElement(type, parentType) { return ( - type === "Directive" || - type === "TypeAlias" || - type === "TSExportAssignment" || - type.startsWith("Declare") || - type.startsWith("TSDeclare") || - type.endsWith("Statement") || - type.endsWith("Declaration") + parentType !== "DeclareExportDeclaration" && + type !== "TypeParameterDeclaration" && + (type === "Directive" || + type === "TypeAlias" || + type === "TSExportAssignment" || + type.startsWith("Declare") || + type.startsWith("TSDeclare") || + type.endsWith("Statement") || + type.endsWith("Declaration")) ); } @@ -126,7 +128,7 @@ const graphqlSourceElements = new Set([ "UnionTypeDefinition", "ScalarTypeDefinition", ]); -function isSourceElement(opts, node) { +function isSourceElement(opts, node, parentNode) { /* istanbul ignore next */ if (!node) { return false; @@ -139,7 +141,7 @@ function isSourceElement(opts, node) { case "typescript": case "espree": case "meriyah": - return isJsSourceElement(node.type); + return isJsSourceElement(node.type, parentNode && parentNode.type); case "json": return jsonSourceElements.has(node.type); case "graphql": @@ -170,7 +172,7 @@ function calculateRange(text, opts, ast) { ast, start, opts, - (node) => isSourceElement(opts, node), + (node, parentNode) => isSourceElement(opts, node, parentNode), [], "rangeStart" ); diff --git a/tests/flow/range/__snapshots__/jsfmt.spec.js.snap b/tests/flow/range/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000..fe445368f --- /dev/null +++ b/tests/flow/range/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,83 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`declare-export-declaration.js format 1`] = ` +====================================options===================================== +parsers: ["flow"] +printWidth: 80 +rangeEnd: 277 +rangeStart: 273 + | | printWidth +=====================================input====================================== + 1 | declare export function graphql> + 2 | (query: GQLDocument, config?: Config>): + 3 | (Component: Component) => React$ComponentType<$Diff, { +> 4 | data: Object|void, + | ^^^^ + 5 | mutate: Function|void + 6 | }>> + 7 | + 8 | declare type FetchPolicy= "cache-first" | "cache-and-network" | "network-only" | "cache-only" + 9 | +=====================================output===================================== +declare export function graphql< + Props, + Variables, + Component: React$ComponentType +>( + query: GQLDocument, + config?: Config> +): (Component: Component) => React$ComponentType< + $Diff< + React$ElementConfig, + { + data: Object | void, + mutate: Function | void, + } + > +>; + +declare type FetchPolicy= "cache-first" | "cache-and-network" | "network-only" | "cache-only" + +================================================================================ +`; + +exports[`type-parameter-declaration.js format 1`] = ` +====================================options===================================== +parsers: ["flow"] +printWidth: 80 +rangeEnd: 48 +rangeStart: 39 + | | printWidth +=====================================input====================================== +> 1 | declare export function graphql> + | ^^^^^^^^^ + 2 | (query: GQLDocument, config?: Config>): + 3 | (Component: Component) => React$ComponentType<$Diff, { + 4 | data: Object|void, + 5 | mutate: Function|void + 6 | }>> + 7 | + 8 | declare type FetchPolicy= "cache-first" | "cache-and-network" | "network-only" | "cache-only" + 9 | +=====================================output===================================== +declare export function graphql< + Props, + Variables, + Component: React$ComponentType +>( + query: GQLDocument, + config?: Config> +): (Component: Component) => React$ComponentType< + $Diff< + React$ElementConfig, + { + data: Object | void, + mutate: Function | void, + } + > +>; + +declare type FetchPolicy= "cache-first" | "cache-and-network" | "network-only" | "cache-only" + +================================================================================ +`; diff --git a/tests/flow/range/declare-export-declaration.js b/tests/flow/range/declare-export-declaration.js new file mode 100644 index 000000000..aa8811588 --- /dev/null +++ b/tests/flow/range/declare-export-declaration.js @@ -0,0 +1,8 @@ +declare export function graphql> + (query: GQLDocument, config?: Config>): + (Component: Component) => React$ComponentType<$Diff, { + data: Object|<<>>void<<>>, + mutate: Function|void + }>> + +declare type FetchPolicy= "cache-first" | "cache-and-network" | "network-only" | "cache-only" diff --git a/tests/flow/range/jsfmt.spec.js b/tests/flow/range/jsfmt.spec.js new file mode 100644 index 000000000..b9a908981 --- /dev/null +++ b/tests/flow/range/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname, ["flow"]); diff --git a/tests/flow/range/type-parameter-declaration.js b/tests/flow/range/type-parameter-declaration.js new file mode 100644 index 000000000..860d143c4 --- /dev/null +++ b/tests/flow/range/type-parameter-declaration.js @@ -0,0 +1,8 @@ +declare export function graphql>>Variables<<>>, Component: React$ComponentType> + (query: GQLDocument, config?: Config>): + (Component: Component) => React$ComponentType<$Diff, { + data: Object|void, + mutate: Function|void + }>> + +declare type FetchPolicy= "cache-first" | "cache-and-network" | "network-only" | "cache-only"