Support flow "match" syntax (#17681)
This commit is contained in:
1 parent
6c0c37a00c
commit
acd25a9aa6
41 files changed
+4824
-34
No files matched your search
@@ -0,0 +1,26 @@
|
|||||||
|
#### Add basic support for "match" syntax (#17681 by @fisker)
|
||||||
|
|
||||||
|
<!-- prettier-ignore -->
|
||||||
|
```jsx
|
||||||
|
// Input
|
||||||
|
const e = match (a) {
|
||||||
|
1 => true,
|
||||||
|
'foo' => false,
|
||||||
|
2 => {obj: 'literal'},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Prettier stable
|
||||||
|
SyntaxError: Unexpected token `{`, expected the token `;` (1:21)
|
||||||
|
> 1 | const e = match (a) {
|
||||||
|
| ^
|
||||||
|
2 | 1 => true,
|
||||||
|
3 | 'foo' => false,
|
||||||
|
4 | 2 => {obj: 'literal'},
|
||||||
|
|
||||||
|
// Prettier main
|
||||||
|
const e = match (a) {
|
||||||
|
1 => true,
|
||||||
|
"foo" => false,
|
||||||
|
2 => { obj: "literal" },
|
||||||
|
};
|
||||||
|
```
|
||||||
@@ -61,6 +61,7 @@ function handleOwnLineComment(context) {
|
|||||||
handleClassComments,
|
handleClassComments,
|
||||||
handleForComments,
|
handleForComments,
|
||||||
handleUnionTypeComments,
|
handleUnionTypeComments,
|
||||||
|
handleMatchOrPatternComments,
|
||||||
handleOnlyComments,
|
handleOnlyComments,
|
||||||
handleModuleSpecifiersComments,
|
handleModuleSpecifiersComments,
|
||||||
handleAssignmentPatternComments,
|
handleAssignmentPatternComments,
|
||||||
@@ -770,6 +771,36 @@ function handleUnionTypeComments({
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleMatchOrPatternComments({
|
||||||
|
comment,
|
||||||
|
precedingNode,
|
||||||
|
enclosingNode,
|
||||||
|
followingNode,
|
||||||
|
}) {
|
||||||
|
if (enclosingNode && enclosingNode.type === "MatchOrPattern") {
|
||||||
|
if (isPrettierIgnoreComment(comment)) {
|
||||||
|
followingNode.prettierIgnore = true;
|
||||||
|
comment.unignore = true;
|
||||||
|
}
|
||||||
|
if (precedingNode) {
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
followingNode &&
|
||||||
|
followingNode.type === "MatchOrPattern" &&
|
||||||
|
isPrettierIgnoreComment(comment)
|
||||||
|
) {
|
||||||
|
followingNode.types[0].prettierIgnore = true;
|
||||||
|
comment.unignore = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function handlePropertyComments({ comment, enclosingNode }) {
|
function handlePropertyComments({ comment, enclosingNode }) {
|
||||||
if (isObjectProperty(enclosingNode)) {
|
if (isObjectProperty(enclosingNode)) {
|
||||||
addLeadingComment(enclosingNode, comment);
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ function willPrintOwnComments(path) {
|
|||||||
(parent.type === "JSXSpreadAttribute" ||
|
(parent.type === "JSXSpreadAttribute" ||
|
||||||
parent.type === "JSXSpreadChild" ||
|
parent.type === "JSXSpreadChild" ||
|
||||||
isUnionType(parent) ||
|
isUnionType(parent) ||
|
||||||
|
parent.type === "MatchOrPattern" ||
|
||||||
((parent.type === "ClassDeclaration" ||
|
((parent.type === "ClassDeclaration" ||
|
||||||
parent.type === "ClassExpression") &&
|
parent.type === "ClassExpression") &&
|
||||||
parent.superClass === node)))) &&
|
parent.superClass === node)))) &&
|
||||||
|
|||||||
@@ -621,6 +621,7 @@ function needsParens(path, options) {
|
|||||||
case "UnionTypeAnnotation":
|
case "UnionTypeAnnotation":
|
||||||
return (
|
return (
|
||||||
parent.type === "TypeOperator" ||
|
parent.type === "TypeOperator" ||
|
||||||
|
parent.type === "KeyofTypeAnnotation" ||
|
||||||
parent.type === "ArrayTypeAnnotation" ||
|
parent.type === "ArrayTypeAnnotation" ||
|
||||||
parent.type === "NullableTypeAnnotation" ||
|
parent.type === "NullableTypeAnnotation" ||
|
||||||
parent.type === "IntersectionTypeAnnotation" ||
|
parent.type === "IntersectionTypeAnnotation" ||
|
||||||
@@ -877,6 +878,7 @@ function needsParens(path, options) {
|
|||||||
case "LogicalExpression":
|
case "LogicalExpression":
|
||||||
case "AwaitExpression":
|
case "AwaitExpression":
|
||||||
case "TSTypeAssertion":
|
case "TSTypeAssertion":
|
||||||
|
case "MatchExpressionCase":
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case "ConditionalExpression":
|
case "ConditionalExpression":
|
||||||
@@ -985,11 +987,15 @@ function needsParens(path, options) {
|
|||||||
parent.type !== "ThrowStatement" &&
|
parent.type !== "ThrowStatement" &&
|
||||||
parent.type !== "TypeCastExpression" &&
|
parent.type !== "TypeCastExpression" &&
|
||||||
parent.type !== "VariableDeclarator" &&
|
parent.type !== "VariableDeclarator" &&
|
||||||
parent.type !== "YieldExpression")
|
parent.type !== "YieldExpression" &&
|
||||||
|
parent.type !== "MatchExpressionCase")
|
||||||
);
|
);
|
||||||
|
|
||||||
case "TSInstantiationExpression":
|
case "TSInstantiationExpression":
|
||||||
return key === "object" && isMemberExpression(parent);
|
return key === "object" && isMemberExpression(parent);
|
||||||
|
|
||||||
|
case "MatchOrPattern":
|
||||||
|
return parent.type === "MatchAsPattern";
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ const parseOptions = {
|
|||||||
esproposal_decorators: true,
|
esproposal_decorators: true,
|
||||||
// `esproposal_export_star_as` (boolean, default `false`) - enable parsing of `export * as` syntax
|
// `esproposal_export_star_as` (boolean, default `false`) - enable parsing of `export * as` syntax
|
||||||
esproposal_export_star_as: true,
|
esproposal_export_star_as: true,
|
||||||
|
// Undocumented
|
||||||
|
pattern_matching: true,
|
||||||
// `types` (boolean, default `true`) - enable parsing of Flow types
|
// `types` (boolean, default `true`) - enable parsing of Flow types
|
||||||
// types: true,
|
// types: true,
|
||||||
// `use_strict` (boolean, default `false`) - treat the file as strict, without needing a "use strict" directive
|
// `use_strict` (boolean, default `false`) - treat the file as strict, without needing a "use strict" directive
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ function createParseError(error) {
|
|||||||
const parseOptions = {
|
const parseOptions = {
|
||||||
flow: "all",
|
flow: "all",
|
||||||
babel: false,
|
babel: false,
|
||||||
// Not supported yet
|
// enableExperimentalComponentSyntax: true, // Enable by default
|
||||||
enableExperimentalFlowMatchSyntax: false,
|
// enableExperimentalFlowMatchSyntax: true, // Enable by default
|
||||||
tokens: false,
|
tokens: false,
|
||||||
allowReturnOutsideFunction: true,
|
allowReturnOutsideFunction: true,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -175,15 +175,24 @@ function isConciselyPrintedArray(node, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isLineAfterElementEmpty({ node }, { originalText: text }) {
|
function isLineAfterElementEmpty({ node }, { originalText: text }) {
|
||||||
const skipComment = (idx) =>
|
let currentIdx = locEnd(node);
|
||||||
skipInlineComment(text, skipTrailingComment(text, idx));
|
if (currentIdx === locStart(node)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const skipToComma = (currentIdx) =>
|
const { length } = text;
|
||||||
text[currentIdx] === ","
|
while (currentIdx < length) {
|
||||||
? currentIdx
|
if (text[currentIdx] === ",") {
|
||||||
: skipToComma(skipComment(currentIdx + 1));
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return isNextLineEmptyAfterIndex(text, skipToComma(locEnd(node)));
|
currentIdx = skipInlineComment(
|
||||||
|
text,
|
||||||
|
skipTrailingComment(text, currentIdx + 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return isNextLineEmptyAfterIndex(text, currentIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
function printArrayElements(path, options, print, elementsProperty, inexact) {
|
function printArrayElements(path, options, print, elementsProperty, inexact) {
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ function printBlock(path, options, print) {
|
|||||||
parent.type === "ModuleExpression" ||
|
parent.type === "ModuleExpression" ||
|
||||||
(parent.type === "CatchClause" && !parentParent.finalizer) ||
|
(parent.type === "CatchClause" && !parentParent.finalizer) ||
|
||||||
parent.type === "TSModuleDeclaration" ||
|
parent.type === "TSModuleDeclaration" ||
|
||||||
|
parent.type === "MatchStatementCase" ||
|
||||||
node.type === "StaticBlock"
|
node.type === "StaticBlock"
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import {
|
|||||||
import { printInterface } from "./interface.js";
|
import { printInterface } from "./interface.js";
|
||||||
import { printBigInt } from "./literal.js";
|
import { printBigInt } from "./literal.js";
|
||||||
import { printFlowMappedTypeProperty } from "./mapped-type.js";
|
import { printFlowMappedTypeProperty } from "./mapped-type.js";
|
||||||
|
import { printMatch, printMatchCase, printMatchPattern } from "./match.js";
|
||||||
import {
|
import {
|
||||||
printDeclareToken,
|
printDeclareToken,
|
||||||
printOptionalToken,
|
printOptionalToken,
|
||||||
@@ -323,6 +324,26 @@ function printFlow(path, options, print) {
|
|||||||
case "AsConstExpression":
|
case "AsConstExpression":
|
||||||
case "SatisfiesExpression":
|
case "SatisfiesExpression":
|
||||||
return printBinaryCastExpression(path, options, print);
|
return printBinaryCastExpression(path, options, print);
|
||||||
|
|
||||||
|
case "MatchExpression":
|
||||||
|
case "MatchStatement":
|
||||||
|
return printMatch(path, options, print);
|
||||||
|
case "MatchExpressionCase":
|
||||||
|
case "MatchStatementCase":
|
||||||
|
return printMatchCase(path, options, print);
|
||||||
|
case "MatchOrPattern":
|
||||||
|
case "MatchAsPattern":
|
||||||
|
case "MatchWildcardPattern":
|
||||||
|
case "MatchLiteralPattern":
|
||||||
|
case "MatchUnaryPattern":
|
||||||
|
case "MatchIdentifierPattern":
|
||||||
|
case "MatchMemberPattern":
|
||||||
|
case "MatchBindingPattern":
|
||||||
|
case "MatchObjectPattern":
|
||||||
|
case "MatchObjectPatternProperty":
|
||||||
|
case "MatchRestPattern":
|
||||||
|
case "MatchArrayPattern":
|
||||||
|
return printMatchPattern(path, options, print);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -496,6 +496,7 @@ const NO_WRAP_PARENTS = new Set([
|
|||||||
"OptionalCallExpression",
|
"OptionalCallExpression",
|
||||||
"ConditionalExpression",
|
"ConditionalExpression",
|
||||||
"JsExpressionRoot",
|
"JsExpressionRoot",
|
||||||
|
"MatchExpressionCase",
|
||||||
]);
|
]);
|
||||||
function maybeWrapJsxElementInParens(path, elem, options) {
|
function maybeWrapJsxElementInParens(path, elem, options) {
|
||||||
const { parent } = path;
|
const { parent } = path;
|
||||||
|
|||||||
@@ -0,0 +1,249 @@
|
|||||||
|
import {
|
||||||
|
align,
|
||||||
|
group,
|
||||||
|
hardline,
|
||||||
|
ifBreak,
|
||||||
|
indent,
|
||||||
|
join,
|
||||||
|
line,
|
||||||
|
softline,
|
||||||
|
} from "../../document/builders.js";
|
||||||
|
import {
|
||||||
|
printComments,
|
||||||
|
printDanglingComments,
|
||||||
|
} from "../../main/comments/print.js";
|
||||||
|
import pathNeedsParens from "../needs-parens.js";
|
||||||
|
import {
|
||||||
|
CommentCheckFlags,
|
||||||
|
createTypeCheckFunction,
|
||||||
|
hasComment,
|
||||||
|
hasLeadingOwnLineComment,
|
||||||
|
isNextLineEmpty,
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
|
/*
|
||||||
|
- `MatchExpression` (Flow)
|
||||||
|
- `MatchStatement` (Flow)
|
||||||
|
*/
|
||||||
|
export function printMatch(path, options, print) {
|
||||||
|
const { node } = path;
|
||||||
|
return [
|
||||||
|
group(["match (", indent([softline, print("argument")]), softline, ")"]),
|
||||||
|
" {",
|
||||||
|
node.cases.length > 0
|
||||||
|
? indent([
|
||||||
|
hardline,
|
||||||
|
join(
|
||||||
|
hardline,
|
||||||
|
path.map(
|
||||||
|
({ node, isLast }) => [
|
||||||
|
print(),
|
||||||
|
!isLast && isNextLineEmpty(node, options) ? hardline : "",
|
||||||
|
],
|
||||||
|
"cases",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
: "",
|
||||||
|
hardline,
|
||||||
|
"}",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
- `MatchExpressionCase` (Flow)
|
||||||
|
- `MatchStatementCase` (Flow)
|
||||||
|
*/
|
||||||
|
export function printMatchCase(path, options, print) {
|
||||||
|
const { node } = path;
|
||||||
|
|
||||||
|
const comment = hasComment(node, CommentCheckFlags.Dangling)
|
||||||
|
? [" ", printDanglingComments(path, options)]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const body =
|
||||||
|
node.type === "MatchStatementCase"
|
||||||
|
? [" ", print("body")]
|
||||||
|
: indent([line, print("body"), ","]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
print("pattern"),
|
||||||
|
node.guard ? group([indent([line, "if (", print("guard"), ")"])]) : "",
|
||||||
|
group([" =>", comment, body]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
- `MatchOrPattern` (Flow)
|
||||||
|
- `MatchAsPattern` (Flow)
|
||||||
|
- `MatchWildcardPattern` (Flow)
|
||||||
|
- `MatchLiteralPattern` (Flow)
|
||||||
|
- `MatchUnaryPattern` (Flow)
|
||||||
|
- `MatchIdentifierPattern` (Flow)
|
||||||
|
- `MatchMemberPattern` (Flow)
|
||||||
|
- `MatchBindingPattern` (Flow)
|
||||||
|
- `MatchObjectPattern` (Flow)
|
||||||
|
- `MatchArrayPattern` (Flow)
|
||||||
|
- `MatchObjectPatternProperty` (Flow)
|
||||||
|
- `MatchRestPattern` (Flow)
|
||||||
|
*/
|
||||||
|
export function printMatchPattern(path, options, print) {
|
||||||
|
const { node } = path;
|
||||||
|
|
||||||
|
switch (node.type) {
|
||||||
|
case "MatchOrPattern":
|
||||||
|
return printMatchOrPattern(path, options, print);
|
||||||
|
case "MatchAsPattern":
|
||||||
|
return [print("pattern"), " as ", print("target")];
|
||||||
|
case "MatchWildcardPattern":
|
||||||
|
return ["_"];
|
||||||
|
case "MatchLiteralPattern":
|
||||||
|
return print("literal");
|
||||||
|
case "MatchUnaryPattern":
|
||||||
|
return [node.operator, print("argument")];
|
||||||
|
case "MatchIdentifierPattern":
|
||||||
|
return print("id");
|
||||||
|
case "MatchMemberPattern": {
|
||||||
|
const property =
|
||||||
|
node.property.type === "Identifier"
|
||||||
|
? [".", print("property")]
|
||||||
|
: ["[", indent([softline, print("property")]), softline, "]"];
|
||||||
|
return group([print("base"), property]);
|
||||||
|
}
|
||||||
|
case "MatchBindingPattern":
|
||||||
|
return [node.kind, " ", print("id")];
|
||||||
|
case "MatchObjectPattern": {
|
||||||
|
const properties = path.map(print, "properties");
|
||||||
|
if (node.rest) {
|
||||||
|
properties.push(print("rest"));
|
||||||
|
}
|
||||||
|
return group([
|
||||||
|
"{",
|
||||||
|
indent([softline, join([",", line], properties)]),
|
||||||
|
node.rest ? "" : ifBreak(","),
|
||||||
|
softline,
|
||||||
|
"}",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
case "MatchArrayPattern": {
|
||||||
|
const elements = path.map(print, "elements");
|
||||||
|
if (node.rest) {
|
||||||
|
elements.push(print("rest"));
|
||||||
|
}
|
||||||
|
return group([
|
||||||
|
"[",
|
||||||
|
indent([softline, join([",", line], elements)]),
|
||||||
|
node.rest ? "" : ifBreak(","),
|
||||||
|
softline,
|
||||||
|
"]",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
case "MatchObjectPatternProperty":
|
||||||
|
if (node.shorthand) {
|
||||||
|
return print("pattern");
|
||||||
|
}
|
||||||
|
return group([print("key"), ":", indent([line, print("pattern")])]);
|
||||||
|
case "MatchRestPattern": {
|
||||||
|
const parts = ["..."];
|
||||||
|
if (node.argument) {
|
||||||
|
parts.push(print("argument"));
|
||||||
|
}
|
||||||
|
return parts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isSimpleMatchPattern = createTypeCheckFunction([
|
||||||
|
"MatchWildcardPattern",
|
||||||
|
"MatchLiteralPattern",
|
||||||
|
"MatchUnaryPattern",
|
||||||
|
"MatchIdentifierPattern",
|
||||||
|
]);
|
||||||
|
|
||||||
|
function shouldHugMatchOrPattern(node) {
|
||||||
|
const { patterns } = node;
|
||||||
|
if (patterns.some((node) => hasComment(node))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const objectPattern = patterns.find(
|
||||||
|
(node) => node.type === "MatchObjectPattern",
|
||||||
|
);
|
||||||
|
if (!objectPattern) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return patterns.every(
|
||||||
|
(node) => node === objectPattern || isSimpleMatchPattern(node),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldHugMatchPattern(node) {
|
||||||
|
if (isSimpleMatchPattern(node) || node.type === "MatchObjectPattern") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.type === "MatchOrPattern") {
|
||||||
|
return shouldHugMatchOrPattern(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function printMatchOrPattern(path, options, print) {
|
||||||
|
const { node } = path;
|
||||||
|
// single-line variation
|
||||||
|
// A | B | C
|
||||||
|
|
||||||
|
// multi-line variation
|
||||||
|
// | A
|
||||||
|
// | B
|
||||||
|
// | C
|
||||||
|
|
||||||
|
const { parent } = path;
|
||||||
|
|
||||||
|
const shouldIndent =
|
||||||
|
parent.type !== "MatchStatementCase" &&
|
||||||
|
parent.type !== "MatchExpressionCase" &&
|
||||||
|
parent.type !== "MatchArrayPattern" &&
|
||||||
|
parent.type !== "MatchObjectPatternProperty" &&
|
||||||
|
!hasLeadingOwnLineComment(options.originalText, node);
|
||||||
|
|
||||||
|
// {
|
||||||
|
// a: foo
|
||||||
|
// } | null | void
|
||||||
|
// should be inlined and not be printed in the multi-line variant
|
||||||
|
const shouldHug = shouldHugMatchPattern(node);
|
||||||
|
|
||||||
|
// We want to align the children but without its comment, so it looks like
|
||||||
|
// | child1
|
||||||
|
// // comment
|
||||||
|
// | child2
|
||||||
|
const printed = path.map((patternPath) => {
|
||||||
|
let printedPattern = print();
|
||||||
|
if (!shouldHug) {
|
||||||
|
printedPattern = align(2, printedPattern);
|
||||||
|
}
|
||||||
|
return printComments(patternPath, printedPattern, options);
|
||||||
|
}, "patterns");
|
||||||
|
|
||||||
|
if (shouldHug) {
|
||||||
|
return join(" | ", printed);
|
||||||
|
}
|
||||||
|
|
||||||
|
const code = [ifBreak(["| "]), join([line, "| "], printed)];
|
||||||
|
|
||||||
|
if (pathNeedsParens(path, options)) {
|
||||||
|
return group([indent([ifBreak([softline]), code]), softline]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent.type === "MatchArrayPattern" && parent.elements.length > 1) {
|
||||||
|
return group([
|
||||||
|
indent([ifBreak(["(", softline]), code]),
|
||||||
|
softline,
|
||||||
|
ifBreak(")"),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return group(shouldIndent ? indent(code) : code);
|
||||||
|
}
|
||||||
@@ -67,24 +67,6 @@ const excludeNodeTypes = new Set([
|
|||||||
// Babel, Won't exist since we use `createImportExpressions` when parsing with babel
|
// Babel, Won't exist since we use `createImportExpressions` when parsing with babel
|
||||||
"Import",
|
"Import",
|
||||||
|
|
||||||
// Flow, not supported
|
|
||||||
"MatchArrayPattern",
|
|
||||||
"MatchAsPattern",
|
|
||||||
"MatchBindingPattern",
|
|
||||||
"MatchExpression",
|
|
||||||
"MatchExpressionCase",
|
|
||||||
"MatchIdentifierPattern",
|
|
||||||
"MatchLiteralPattern",
|
|
||||||
"MatchMemberPattern",
|
|
||||||
"MatchObjectPattern",
|
|
||||||
"MatchObjectPatternProperty",
|
|
||||||
"MatchOrPattern",
|
|
||||||
"MatchRestPattern",
|
|
||||||
"MatchStatement",
|
|
||||||
"MatchStatementCase",
|
|
||||||
"MatchUnaryPattern",
|
|
||||||
"MatchWildcardPattern",
|
|
||||||
|
|
||||||
// Babel v7.28.0
|
// Babel v7.28.0
|
||||||
// https://github.com/prettier/prettier/pull/17696
|
// https://github.com/prettier/prettier/pull/17696
|
||||||
"VoidPattern",
|
"VoidPattern",
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,153 @@
|
|||||||
|
// Type of body and abnormal handling
|
||||||
|
{
|
||||||
|
declare const x: empty;
|
||||||
|
const out = match (x) {};
|
||||||
|
|
||||||
|
out as empty; // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
declare const x: 1 | 2;
|
||||||
|
|
||||||
|
{
|
||||||
|
const out = match (x) {
|
||||||
|
1 => true,
|
||||||
|
2 => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
out as boolean; // OK
|
||||||
|
out as empty; // ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const out = match (x) {
|
||||||
|
1 => true,
|
||||||
|
2 => 's',
|
||||||
|
};
|
||||||
|
out as boolean | string; // OK
|
||||||
|
out as empty; // ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
declare function invariant(boolean): empty;
|
||||||
|
|
||||||
|
{
|
||||||
|
const out = match (x) {
|
||||||
|
1 => true,
|
||||||
|
2 => invariant(false),
|
||||||
|
};
|
||||||
|
out as boolean; // OK
|
||||||
|
out as empty; // ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
function f1() {
|
||||||
|
const out = match (x) {
|
||||||
|
1 => invariant(false),
|
||||||
|
2 => invariant(false),
|
||||||
|
};
|
||||||
|
out; // ERROR: unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throws in guards
|
||||||
|
function f2() {
|
||||||
|
const out = match (x) {
|
||||||
|
1 if (invariant(false)) => true,
|
||||||
|
_ => 's',
|
||||||
|
};
|
||||||
|
out as string; // OK
|
||||||
|
out as empty; // ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nested matches
|
||||||
|
{
|
||||||
|
const out = match (x) {
|
||||||
|
1 => 1,
|
||||||
|
const a => match (a) {
|
||||||
|
const a => a,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
out as number; // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guards can refine values which are not the argument
|
||||||
|
{
|
||||||
|
declare const y: number | string;
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
1 if (typeof y === 'number') => y as number, // OK
|
||||||
|
const a if (a === 1) => a as 1,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case body provider and refinement analysis
|
||||||
|
{
|
||||||
|
let target;
|
||||||
|
const out = match (x) {
|
||||||
|
1 => target = "foo",
|
||||||
|
2 => target = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
target as string | boolean; // OK
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let target;
|
||||||
|
const out = match (x) {
|
||||||
|
const a => target = "foo" as const,
|
||||||
|
};
|
||||||
|
a; // ERROR
|
||||||
|
|
||||||
|
target as "foo"; // OK
|
||||||
|
}
|
||||||
|
{
|
||||||
|
declare const x: [number] | number;
|
||||||
|
let target = null;
|
||||||
|
const out = match (x) {
|
||||||
|
[const a] => target = "foo",
|
||||||
|
const a => target = true,
|
||||||
|
};
|
||||||
|
a; // ERROR
|
||||||
|
|
||||||
|
target as string | boolean; // OK
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let target;
|
||||||
|
const out = match (x) {
|
||||||
|
1 => target = "foo",
|
||||||
|
2 => invariant(false),
|
||||||
|
};
|
||||||
|
|
||||||
|
target as string; // OK
|
||||||
|
}
|
||||||
|
{
|
||||||
|
declare const o: {prop: number};
|
||||||
|
const out = match (x) {
|
||||||
|
1 => o.prop = 1,
|
||||||
|
2 => o.prop = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
o.prop as 1 | 2; // OK
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const a = [];
|
||||||
|
const out = match (x) {
|
||||||
|
1 => a.push(1),
|
||||||
|
2 => a.push(2),
|
||||||
|
};
|
||||||
|
|
||||||
|
a as Array<number>; // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Natural inference hint
|
||||||
|
{
|
||||||
|
const out: 'a' | 'b' = match (x) {
|
||||||
|
1 => 'b', // OK
|
||||||
|
2 => 'xxx', // ERROR: 'xxx' is not a subtype of 'a' | 'b'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
declare const dict: {['a' | 'b']: number};
|
||||||
|
dict[match (x) {
|
||||||
|
1 => 'b', // OK
|
||||||
|
2 => 'xxx', // ERROR: 'xxx' is not a subtype of 'a' | 'b'
|
||||||
|
}];
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
runFormatTest(import.meta, ["flow"]);
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
// Annotation hint
|
||||||
|
type F = string => boolean;
|
||||||
|
{
|
||||||
|
declare const x: 'a';
|
||||||
|
|
||||||
|
const out: F = match (x) {
|
||||||
|
'a' => (y => true), // OK
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sibling before
|
||||||
|
{
|
||||||
|
declare const x: 'a' | 'b';
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
'a' => [1],
|
||||||
|
'b' => [], // Should be `Array<number>`
|
||||||
|
};
|
||||||
|
out as Array<number>; // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sibling after
|
||||||
|
{
|
||||||
|
declare const x: 'a' | 'b';
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
'a' => [], // Should be `Array<number>`
|
||||||
|
'b' => [1],
|
||||||
|
};
|
||||||
|
out as Array<number>; // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiple siblings, one valid
|
||||||
|
{
|
||||||
|
declare const x: 'a' | 'b' | 'c' | 'd';
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
'a' => 1,
|
||||||
|
'b' => {},
|
||||||
|
'c' => [1],
|
||||||
|
'd' => [], // Should be `Array<number>`
|
||||||
|
};
|
||||||
|
out as number | {} | Array<number>; // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiple siblings, multiple valid
|
||||||
|
{
|
||||||
|
declare const x: 'a' | 'b' | 'c';
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
'a' => [true],
|
||||||
|
'b' => [1],
|
||||||
|
'c' => [],
|
||||||
|
};
|
||||||
|
out as Array<boolean> | Array<number>; // OK
|
||||||
|
}
|
||||||
|
{
|
||||||
|
declare const x: 'a' | 'b' | 'c';
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
'a' => ((x: number) => 1),
|
||||||
|
'b' => ((x: string) => true),
|
||||||
|
'c' => (x => x as number), // OK
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cycles avoided
|
||||||
|
{
|
||||||
|
declare const x: 'a' | 'b';
|
||||||
|
|
||||||
|
const out: (x: number) => void = match (x) { // OK
|
||||||
|
'a' => ((x) => {}),
|
||||||
|
'b' => ((x) => {}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
declare const x: 'a' | 'b';
|
||||||
|
|
||||||
|
const out: Array<number> = match (x) { // OK
|
||||||
|
'a' => [],
|
||||||
|
'b' => [],
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,399 @@
|
|||||||
|
// Primitive value union
|
||||||
|
{
|
||||||
|
declare const x: 1 | -2 | 3n | 's' | false | null;
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
1 => 0,
|
||||||
|
-2 => 0,
|
||||||
|
3n => 0,
|
||||||
|
's' => 0,
|
||||||
|
false => 0,
|
||||||
|
null => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) { // ERROR: not all members checked
|
||||||
|
1 => 0,
|
||||||
|
false => 0,
|
||||||
|
3n => 0,
|
||||||
|
null => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identifier patterns
|
||||||
|
{
|
||||||
|
declare const x: 1 | 2;
|
||||||
|
|
||||||
|
declare const one: 1;
|
||||||
|
declare const two: 2;
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
one => 0,
|
||||||
|
two => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) { // ERROR: `2` not checked
|
||||||
|
one => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// `undefined`
|
||||||
|
{
|
||||||
|
declare const x: 1 | void;
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
1 => 0,
|
||||||
|
undefined => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) { // ERROR: `undefined` not checked
|
||||||
|
1 => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maybe types
|
||||||
|
{
|
||||||
|
declare const x: ?1;
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
1 => 0,
|
||||||
|
undefined => 0,
|
||||||
|
null => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) { // ERROR: `null` and `undefined` not checked
|
||||||
|
1 => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Member patterns
|
||||||
|
{
|
||||||
|
declare const x: 1 | 2;
|
||||||
|
|
||||||
|
declare const o: {
|
||||||
|
one: 1,
|
||||||
|
two: 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
o.one => 0,
|
||||||
|
o.two => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) { // ERROR: `2` not checked
|
||||||
|
o.one => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// `as` pattern refines using its pattern
|
||||||
|
{
|
||||||
|
declare const x: 1 | 2;
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
1 as a => a as 1, // OK
|
||||||
|
2 as a => a as 2, // OK
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
declare const x: {type: 'foo', value: 1}
|
||||||
|
| {type: 'bar', value: 2};
|
||||||
|
|
||||||
|
// Nested `as` pattern
|
||||||
|
const e1 = match (x) {
|
||||||
|
{type: 'foo' as a, const value} => (a as 'foo', value as 1), // OK
|
||||||
|
{type: 'bar' as a, const value} => (a as 'bar', value as 2), // OK
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top level binding and wildcard
|
||||||
|
{
|
||||||
|
declare const x: 1 | 2;
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
1 => 0,
|
||||||
|
const a => a as 2, // OK
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) {
|
||||||
|
1 => 0,
|
||||||
|
_ => 0, // OK
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-ident/member argument still works
|
||||||
|
{
|
||||||
|
declare const f: () => 1 | 2;
|
||||||
|
|
||||||
|
const e1 = match (f()) {
|
||||||
|
1 => 0,
|
||||||
|
2 => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (f()) { // ERROR: `2` not checked
|
||||||
|
1 => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or pattern
|
||||||
|
{
|
||||||
|
declare const x: 1 | 2 | 3;
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
1 | 2 | 3 => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) { // ERROR: `3` not checked
|
||||||
|
1 | 2 => true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patterns with guard could match or not match
|
||||||
|
{
|
||||||
|
declare const x: 1 | 2;
|
||||||
|
|
||||||
|
declare function f(): boolean;
|
||||||
|
|
||||||
|
const e1 = match (x) { // ERROR: `2` not checked
|
||||||
|
1 => 0,
|
||||||
|
2 if (f()) => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) {
|
||||||
|
1 => 0,
|
||||||
|
2 if (f()) => 0,
|
||||||
|
2 => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Property exists
|
||||||
|
{
|
||||||
|
declare const x: {foo: void, a: 0} | {bar: void, a: 1};
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
{foo: _, const a} => a as 0, // OK
|
||||||
|
{bar: _, const a} => a as 1, // OK
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
declare const x:
|
||||||
|
| {foo: void, a: 0}
|
||||||
|
| {bar: void, a: 1}
|
||||||
|
| {baz: void, a: 2}
|
||||||
|
| {zap: void, a: 3};
|
||||||
|
|
||||||
|
declare const u: void;
|
||||||
|
declare const o: {u: void};
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
{foo: u, const a} => a as 0, // OK
|
||||||
|
{bar: o.u, const a} => a as 1, // OK
|
||||||
|
{baz: undefined as v, const a} => a as 2, // OK
|
||||||
|
{zap: u, const a} => a as 3, // OK
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disjoint object union
|
||||||
|
{
|
||||||
|
declare const x: {type: 'foo', val: number}
|
||||||
|
| {type: 'bar', val: string}
|
||||||
|
| {type: 'baz', val: boolean};
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
{type: 'foo', val: const a} => a as number, // OK
|
||||||
|
{type: 'bar', val: const a} => a as string, // OK
|
||||||
|
{type: 'baz', val: const a} => a as boolean, // OK
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) { // ERROR: `type: 'baz'` not checked
|
||||||
|
{type: 'foo', val: const a} => a as number, // OK
|
||||||
|
{type: 'bar', val: const a} => a as string, // OK
|
||||||
|
};
|
||||||
|
|
||||||
|
// Using idents as pattern
|
||||||
|
declare const foo: 'foo';
|
||||||
|
declare const bar: 'bar';
|
||||||
|
declare const baz: 'baz';
|
||||||
|
const e3 = match (x) {
|
||||||
|
{type: foo, val: const a} => a as number, // OK
|
||||||
|
{type: bar, val: const a} => a as string, // OK
|
||||||
|
{type: baz, val: const a} => a as boolean, // OK
|
||||||
|
};
|
||||||
|
|
||||||
|
// Using members as pattern
|
||||||
|
declare const o: {
|
||||||
|
foo: 'foo',
|
||||||
|
bar: 'bar',
|
||||||
|
baz: 'baz',
|
||||||
|
};
|
||||||
|
const e4 = match (x) {
|
||||||
|
{type: o.foo, val: const a} => a as number, // OK
|
||||||
|
{type: o.bar, val: const a} => a as string, // OK
|
||||||
|
{type: o.baz, val: const a} => a as boolean, // OK
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disjoint object union with multiple pivot props
|
||||||
|
{
|
||||||
|
declare const x: {type: 'foo', val: number}
|
||||||
|
| {type: 'bar', n: 1, val: string}
|
||||||
|
| {type: 'bar', n: 2, val: boolean};
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
{type: 'foo', val: const a} => a as number, // OK
|
||||||
|
{type: 'bar', val: const a, ...} => a as string | boolean, // OK
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) {
|
||||||
|
{type: 'foo', val: const a} => a as number, // OK
|
||||||
|
{type: 'bar', n: 1, val: const a} => a as string, // OK
|
||||||
|
{type: 'bar', n: 2, val: const a} => a as boolean, // OK
|
||||||
|
};
|
||||||
|
|
||||||
|
const e3 = match (x) { // ERROR: `type: 'bar', n: 2` not checked
|
||||||
|
{type: 'foo', val: const a} => a as number, // OK
|
||||||
|
{type: 'bar', n: 1, val: const a} => a as string, // OK
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combo union of object with sentinel property and primitive value
|
||||||
|
{
|
||||||
|
declare const x: null | {type: 'bar', val: number};
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
{type: 'bar', val: const a} => a as number, // OK
|
||||||
|
null => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or pattern: objects
|
||||||
|
{
|
||||||
|
declare const x: {type: 'foo', val: number}
|
||||||
|
| {type: 'bar', val: string}
|
||||||
|
| {type: 'baz', val: boolean};
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
{type: 'foo', ...} | {type: 'bar', ...} | {type: 'baz', ...} => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) { // ERROR: `type: 'bar'` not checked
|
||||||
|
{type: 'foo', ...} | {type: 'baz', ...} => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disjoint tuple union
|
||||||
|
{
|
||||||
|
declare const x: ['foo', number]
|
||||||
|
| ['bar', string]
|
||||||
|
| ['baz', boolean];
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
['foo', const a] => a as number, // OK
|
||||||
|
['bar', const a] => a as string, // OK
|
||||||
|
['baz', const a] => a as boolean, // OK
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) { // ERROR: `'baz'` element not checked
|
||||||
|
['foo', const a] => a as number, // OK
|
||||||
|
['bar', const a] => a as string, // OK
|
||||||
|
};
|
||||||
|
|
||||||
|
// Using idents as pattern
|
||||||
|
declare const foo: 'foo';
|
||||||
|
declare const bar: 'bar';
|
||||||
|
declare const baz: 'baz';
|
||||||
|
const e3 = match (x) {
|
||||||
|
[foo, const a] => a as number, // OK
|
||||||
|
[bar, const a] => a as string, // OK
|
||||||
|
[baz, const a] => a as boolean, // OK
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combo union of tuples with sentinel property and primitive value
|
||||||
|
{
|
||||||
|
declare const x: null | ['bar', number] | ['foo', string];
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
['bar', const a] => a as number, // OK
|
||||||
|
['foo', const a] => a as string, // OK
|
||||||
|
null => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tuple length refinements
|
||||||
|
{
|
||||||
|
declare const x: [number]
|
||||||
|
| [string, string]
|
||||||
|
| [boolean, boolean, boolean];
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
[const a] => a as number, // OK
|
||||||
|
[const a, _] => a as string, // OK
|
||||||
|
[const a, _, _] => a as empty, // ERROR: `boolean` is not `empty`
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) {
|
||||||
|
[...] => 0, // OK: matches all
|
||||||
|
}
|
||||||
|
|
||||||
|
const e3 = match (x) {
|
||||||
|
[const a, _, ...] => a as string | boolean, // OK
|
||||||
|
[const a] => a as number, // OK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
declare const x: [number] | Array<string>;
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
[] => 0, // OK
|
||||||
|
[const a] => a as string, // ERROR: `number` is not `string`
|
||||||
|
[const a, _] => a as string, // OK
|
||||||
|
const d => d as Array<string>, // OK: tuple checked, but array could have other lengths
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) {
|
||||||
|
[...] => 0, // OK: matches all
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional tuple elements
|
||||||
|
{
|
||||||
|
declare const x: [a: 0, b?: 1, c?: 2];
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
[_, ...] => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) { // ERROR: does not match all possibilities
|
||||||
|
[_, _, ...] => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e3 = match (x) { // ERROR: does not match all possibilities
|
||||||
|
[_] => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e4 = match (x) { // ERROR: does not match all possibilities
|
||||||
|
[_, _, _] => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inexact tuple types
|
||||||
|
{
|
||||||
|
declare const x: [a: 0, ...];
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
[_, ...] => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) { // ERROR: does not match all elements
|
||||||
|
[_] => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exhaustive checking error points to definition
|
||||||
|
{
|
||||||
|
type T = {foo: 1} | {foo: 2};
|
||||||
|
declare const x: T;
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
{foo: 1} => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
// Match expressions only allow `const` bindings
|
||||||
|
{
|
||||||
|
declare const x: 0 | 1 | [2] | {a: 3, b: 4};
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
[...let a] => 0, // ERROR
|
||||||
|
{let a, ...let b} => 0, // ERROR
|
||||||
|
0 as let a => 0, // ERROR
|
||||||
|
let a => 0, // ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) {
|
||||||
|
[...var a] => 0, // ERROR
|
||||||
|
{var a, ...var b} => 0, // ERROR
|
||||||
|
0 as var a => 0, // ERROR
|
||||||
|
var a => 0, // ERROR
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid numeric property
|
||||||
|
{
|
||||||
|
declare const x: {1: true};
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
{1.1: _} => 0, // ERROR
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unary pattern on `0` banned
|
||||||
|
{
|
||||||
|
declare const x: 0;
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
-0 => true, // ERROR
|
||||||
|
+0 => true, // ERROR
|
||||||
|
0 => true, // OK
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unary `+` on bigint banned
|
||||||
|
{
|
||||||
|
declare const x: 1n;
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
+1n => true, // ERROR
|
||||||
|
1n => true, // OK
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duplicate object keys banned
|
||||||
|
{
|
||||||
|
declare const x: {foo: boolean};
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
{foo: true, foo: false} => 0, // ERROR
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) {
|
||||||
|
{foo: true, const foo} => 0, // ERROR
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e3 = match (x) {
|
||||||
|
{foo: true, 'foo': false} => 0, // ERROR
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duplicate binding names
|
||||||
|
{
|
||||||
|
declare const x: [boolean, boolean];
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
[const a, true as a] => 0, // ERROR
|
||||||
|
[const a, const a] => 0, // ERROR
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) {
|
||||||
|
[const a, true as const a] => 0, // ERROR
|
||||||
|
[const a, ...const a] => 0, // ERROR
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
declare const x: {a: boolean, b: boolean};
|
||||||
|
const e1 = match (x) {
|
||||||
|
{const a, b: true as a} => 0, // ERROR
|
||||||
|
{const a, ...const a} => 0, // ERROR
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bindings in 'or' patterns are not yet supported
|
||||||
|
{
|
||||||
|
declare const x: [boolean] | [string];
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
[true as a] | ['s'] => 0, // ERROR
|
||||||
|
[false as const a] | ['s'] => 0, // ERROR
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) {
|
||||||
|
[true as const a] | ['s'] => 0, // ERROR
|
||||||
|
['t'] | [...const a] => 0, // ERROR
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
declare const x: {a: boolean} | {a: string};
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
{a: true as a} | {a: 's'} => 0, // ERROR
|
||||||
|
{a: false as const a} | {a: 's'} => 0, // ERROR
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// As pattern on binding pattern
|
||||||
|
{
|
||||||
|
declare const x: [boolean];
|
||||||
|
|
||||||
|
const e1 = match (x) {
|
||||||
|
[const a as b] => 0, // ERROR
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const e2 = match (x) {
|
||||||
|
const a as const b => 0, // ERROR
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference before declaration
|
||||||
|
{
|
||||||
|
declare const x: [number, number];
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
[a, const a] => a, // ERROR: reference before declaration
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
declare const x: [number, {foo: number}];
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
[a.foo, const a] => a, // ERROR: reference before declaration
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference binding introduced in same pattern
|
||||||
|
{
|
||||||
|
declare const x: [number, number];
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
[const a, a] => a, // ERROR
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
declare const x: [{foo: number}, number];
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
[const a, a.foo] => a, // ERROR
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// // Invalid object property shorthand
|
||||||
|
// {
|
||||||
|
// declare const x: {foo: 1, bar: boolean};
|
||||||
|
|
||||||
|
// const out = match (x) {
|
||||||
|
// {foo} => 0, // ERROR
|
||||||
|
// {foo, bar: true} => 0, // ERROR
|
||||||
|
// _ => 0,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// BigInt property usage
|
||||||
|
{
|
||||||
|
declare const x: mixed;
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
{1n: 1, ...} => 0, // ERROR
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,197 @@
|
|||||||
|
// Top level binding with `const`
|
||||||
|
{
|
||||||
|
declare const x: number;
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
const a => a,
|
||||||
|
};
|
||||||
|
out as number; // OK
|
||||||
|
out as empty; // ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binding doesn't leak to outer scope
|
||||||
|
{
|
||||||
|
declare const x: number;
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
const a => a,
|
||||||
|
};
|
||||||
|
|
||||||
|
a; // ERROR: cannot resolve name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array pattern
|
||||||
|
{
|
||||||
|
declare const x: [number];
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
[const a] => a,
|
||||||
|
};
|
||||||
|
out as number; // OK
|
||||||
|
out as empty; // ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object pattern
|
||||||
|
{
|
||||||
|
declare const x: {foo: number};
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
{foo: const a} => a,
|
||||||
|
};
|
||||||
|
|
||||||
|
out as number; // OK
|
||||||
|
out as empty; // ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object shorthand pattern
|
||||||
|
{
|
||||||
|
declare const x: {foo: number};
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
{const foo} => foo,
|
||||||
|
};
|
||||||
|
|
||||||
|
out as number; // OK
|
||||||
|
out as empty; // ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nested patterns
|
||||||
|
{
|
||||||
|
declare const x: {foo: [{bar: number}]};
|
||||||
|
|
||||||
|
const out1 = match (x) {
|
||||||
|
{foo: [{bar: const a}]} => a,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
out1 as number; // OK
|
||||||
|
out1 as empty; // ERROR
|
||||||
|
|
||||||
|
const out2 = match (x) {
|
||||||
|
{foo: const a} => a[0].bar,
|
||||||
|
};
|
||||||
|
out2 as number; // OK
|
||||||
|
out2 as empty; // ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guards
|
||||||
|
{
|
||||||
|
declare const x: {foo: number};
|
||||||
|
declare const f: number => boolean;
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
{foo: const n} if (n === 0) => n, // OK
|
||||||
|
{foo: const n} if (f(n)) => n, // OK
|
||||||
|
{foo: const n} if (n as empty) => n, // ERROR
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// As pattern
|
||||||
|
{
|
||||||
|
declare const x: {foo: [number]};
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
{foo: [1] as n} => n as [number], // OK
|
||||||
|
{foo: [1 as n]} => n as number, // OK
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
declare const x: {foo: [number]};
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
{foo: [1] as const n} => n as [number], // OK
|
||||||
|
{foo: [1 as const n]} => n as number, // OK
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
declare const x: {foo: {bar: number}};
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
{foo: {bar: 1}} => 0, // OK
|
||||||
|
{foo: {bar: 2} as const a} => 0, // OK
|
||||||
|
{foo: {bar: 3 as const a}} => 0, // OK
|
||||||
|
{foo: {bar: const a}} => 0, // OK
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array rest
|
||||||
|
{
|
||||||
|
declare const x: [1, 2, 3];
|
||||||
|
|
||||||
|
const out1 = match (x) {
|
||||||
|
[1, 2, ...const xs] => xs as [3], // OK
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
const out2 = match (x) {
|
||||||
|
[1, ...const xs] => xs as [2, 3], // OK
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
const out3 = match (x) {
|
||||||
|
[...const xs] => xs as [1, 2, 3], // OK
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object rest
|
||||||
|
{
|
||||||
|
declare const x: {foo: 1, bar: 2, baz: 3};
|
||||||
|
|
||||||
|
const out1 = match (x) {
|
||||||
|
{foo: _, bar: _, ...const xs} => xs as {baz: 3}, // OK
|
||||||
|
};
|
||||||
|
const out2 = match (x) {
|
||||||
|
{bar: _, ...const xs} => xs as {foo: 1, baz: 3}, // OK
|
||||||
|
};
|
||||||
|
const out3 = match (x) {
|
||||||
|
{...const xs} => xs as {foo: 1, bar: 2, baz: 3}, // OK
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identifier, member, literal
|
||||||
|
{
|
||||||
|
declare const A: 3;
|
||||||
|
declare const O: {B: 2};
|
||||||
|
declare const x: number;
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
0 => 0,
|
||||||
|
-1 => 0,
|
||||||
|
+1 => 0,
|
||||||
|
A => 0,
|
||||||
|
O.B => 0,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or pattern
|
||||||
|
{
|
||||||
|
declare const x: number;
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
1 | 2 | 3 => 0,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array pattern applied to array literal
|
||||||
|
{
|
||||||
|
const x = [1, 'foo'] as const;
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
[_, const b] => b as string, // OK
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// BigInt member pattern
|
||||||
|
{
|
||||||
|
declare const x: string;
|
||||||
|
declare const O: {[bigint]: 'foo'};
|
||||||
|
|
||||||
|
const out = match (x) {
|
||||||
|
O[1n] => 0, // OK
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
declare const x: 1 | 2;
|
||||||
|
|
||||||
|
hook useHook() {}
|
||||||
|
|
||||||
|
component WithMatchStatement() {
|
||||||
|
match (x) {
|
||||||
|
1 => {
|
||||||
|
useHook(); // ERROR
|
||||||
|
}
|
||||||
|
2 => {}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
component WithMatchExpression() {
|
||||||
|
return match (x) {
|
||||||
|
1 => useHook(), // ERROR
|
||||||
|
2 => undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
match (x) {
|
||||||
|
1 => {
|
||||||
|
component NestedInMatch() {
|
||||||
|
useHook(); // OK
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
{
|
||||||
|
declare const x: empty;
|
||||||
|
match (x) {}; // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
declare const x: 1 | 2;
|
||||||
|
|
||||||
|
match (x) {
|
||||||
|
1 => {}
|
||||||
|
2 => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function f1() {
|
||||||
|
match (x) {
|
||||||
|
1 => {
|
||||||
|
throw 0;
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
throw 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
x; // ERROR: unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throws in guards
|
||||||
|
function f2() {
|
||||||
|
declare function invariant(boolean): empty;
|
||||||
|
|
||||||
|
match (x) {
|
||||||
|
1 => {}
|
||||||
|
2 if (invariant(false)) => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
x; // OK: not unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nested matches
|
||||||
|
{
|
||||||
|
match (x) {
|
||||||
|
1 => {}
|
||||||
|
const a => {
|
||||||
|
match (a) {
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Body makes refinements
|
||||||
|
{
|
||||||
|
let target;
|
||||||
|
match (x) {
|
||||||
|
1 => {
|
||||||
|
target = "foo";
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
target = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
target as string | boolean; // OK
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let target;
|
||||||
|
match (x) {
|
||||||
|
const a => {
|
||||||
|
target = "foo" as const;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a; // ERROR
|
||||||
|
|
||||||
|
target as "foo"; // OK
|
||||||
|
}
|
||||||
|
{
|
||||||
|
declare const x: [number] | number;
|
||||||
|
let target = null;
|
||||||
|
match (x) {
|
||||||
|
[const a] => {
|
||||||
|
target = "foo";
|
||||||
|
}
|
||||||
|
const a => {
|
||||||
|
target = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a; // ERROR
|
||||||
|
|
||||||
|
target as string | boolean; // OK
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let target;
|
||||||
|
match (x) {
|
||||||
|
1 => {
|
||||||
|
target = "foo";
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
throw 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
target as string; // OK
|
||||||
|
}
|
||||||
|
{
|
||||||
|
declare const o: {prop: number};
|
||||||
|
match (x) {
|
||||||
|
1 => {
|
||||||
|
o.prop = 1;
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
o.prop = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
o.prop as 1 | 2; // OK
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const a = [];
|
||||||
|
match (x) {
|
||||||
|
1 => {
|
||||||
|
a.push(1);
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
a.push(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a as Array<number>; // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abnormal exits functions
|
||||||
|
function t1(): boolean {
|
||||||
|
match (x) {
|
||||||
|
1 => {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function t2(): boolean {
|
||||||
|
match (x) {
|
||||||
|
1 => {
|
||||||
|
throw 0;
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abnormals in loops
|
||||||
|
{
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
match (i) {
|
||||||
|
0 => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
label: for (let i = 0; i < 2; i++) {
|
||||||
|
match (i) {
|
||||||
|
0 => {
|
||||||
|
break label;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // Invalid case body
|
||||||
|
// function t3() {
|
||||||
|
// match (x) {
|
||||||
|
// 1 => return 1; // ERROR
|
||||||
|
// 2 => throw false; // ERROR
|
||||||
|
// }
|
||||||
|
// }
|
||||||
@@ -0,0 +1,416 @@
|
|||||||
|
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||||
|
|
||||||
|
exports[`export.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["flow"]
|
||||||
|
printWidth: 80
|
||||||
|
| printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
export default match (a) {}
|
||||||
|
|
||||||
|
=====================================output=====================================
|
||||||
|
export default match (a) {
|
||||||
|
};
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`expression.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["flow"]
|
||||||
|
printWidth: 80
|
||||||
|
| printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
const e = match (a) {
|
||||||
|
1 => true,
|
||||||
|
'foo' => false,
|
||||||
|
2 => {obj: 'literal'},
|
||||||
|
};
|
||||||
|
|
||||||
|
=====================================output=====================================
|
||||||
|
const e = match (a) {
|
||||||
|
1 => true,
|
||||||
|
"foo" => false,
|
||||||
|
2 => { obj: "literal" },
|
||||||
|
};
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`expression-empty.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["flow"]
|
||||||
|
printWidth: 80
|
||||||
|
| printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
const e = match (a) {};
|
||||||
|
|
||||||
|
=====================================output=====================================
|
||||||
|
const e = match (a) {
|
||||||
|
};
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`expression-guards.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["flow"]
|
||||||
|
printWidth: 80
|
||||||
|
| printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
const e = match (a) {
|
||||||
|
1 if (b) => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
=====================================output=====================================
|
||||||
|
const e = match (a) {
|
||||||
|
1 if (b) => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`pattern-array.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["flow"]
|
||||||
|
printWidth: 80
|
||||||
|
| printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
const e = match (x) {
|
||||||
|
[10] => 1,
|
||||||
|
[const y, 1] => y,
|
||||||
|
[1, ...] => 1,
|
||||||
|
[1, 2, ...const rest] => rest,
|
||||||
|
[...let rest] => rest,
|
||||||
|
[...var rest] => rest,
|
||||||
|
[{nested: [1, const x]}] => x,
|
||||||
|
};
|
||||||
|
|
||||||
|
=====================================output=====================================
|
||||||
|
const e = match (x) {
|
||||||
|
[10] => 1,
|
||||||
|
[const y, 1] => y,
|
||||||
|
[1, ...] => 1,
|
||||||
|
[1, 2, ...const rest] => rest,
|
||||||
|
[...let rest] => rest,
|
||||||
|
[...var rest] => rest,
|
||||||
|
[{nested: [1, const x]}] => x,
|
||||||
|
};
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`pattern-core.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["flow"]
|
||||||
|
printWidth: 80
|
||||||
|
| printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
const e = match (x) {
|
||||||
|
"s" => 1,
|
||||||
|
true => 1,
|
||||||
|
null => 1,
|
||||||
|
3 => 1,
|
||||||
|
4n => 1,
|
||||||
|
+5 => 1,
|
||||||
|
-6 => 1,
|
||||||
|
+7n => 1,
|
||||||
|
-8n => 1,
|
||||||
|
y => 1,
|
||||||
|
const y => y,
|
||||||
|
let y => y,
|
||||||
|
var y => y,
|
||||||
|
('s') => 1,
|
||||||
|
_ => 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
=====================================output=====================================
|
||||||
|
const e = match (x) {
|
||||||
|
"s" => 1,
|
||||||
|
true => 1,
|
||||||
|
null => 1,
|
||||||
|
3 => 1,
|
||||||
|
4n => 1,
|
||||||
|
+5 => 1,
|
||||||
|
-6 => 1,
|
||||||
|
+7n => 1,
|
||||||
|
-8n => 1,
|
||||||
|
y => 1,
|
||||||
|
const y => y,
|
||||||
|
let y => y,
|
||||||
|
var y => y,
|
||||||
|
"s" => 1,
|
||||||
|
_ => 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`pattern-member.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["flow"]
|
||||||
|
printWidth: 80
|
||||||
|
| printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
const e = match (x) {
|
||||||
|
foo.bar => true,
|
||||||
|
foo[1] => true,
|
||||||
|
foo[1n] => true,
|
||||||
|
foo["bar"] => true,
|
||||||
|
foo.bar[1] => true,
|
||||||
|
foo[1].bar["baz"] => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
=====================================output=====================================
|
||||||
|
const e = match (x) {
|
||||||
|
foo.bar => true,
|
||||||
|
foo[1] => true,
|
||||||
|
foo[1n] => true,
|
||||||
|
foo["bar"] => true,
|
||||||
|
foo.bar[1] => true,
|
||||||
|
foo[1].bar["baz"] => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`pattern-object.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["flow"]
|
||||||
|
printWidth: 80
|
||||||
|
| printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
const e = match (x) {
|
||||||
|
{foo: 1, bar: 2} => 1,
|
||||||
|
{'foo': 1} => 1,
|
||||||
|
{111: true} => 1,
|
||||||
|
{foo: const y} => y,
|
||||||
|
{const x, let y, var z} => y,
|
||||||
|
{const x, ...const y} => y,
|
||||||
|
{const x, ...let y} => y,
|
||||||
|
{const x, ...} => x,
|
||||||
|
};
|
||||||
|
|
||||||
|
=====================================output=====================================
|
||||||
|
const e = match (x) {
|
||||||
|
{foo: 1, bar: 2} => 1,
|
||||||
|
{"foo": 1} => 1,
|
||||||
|
{111: true} => 1,
|
||||||
|
{foo: const y} => y,
|
||||||
|
{const x, let y, var z} => y,
|
||||||
|
{const x, ...const y} => y,
|
||||||
|
{const x, ...let y} => y,
|
||||||
|
{const x, ...} => x,
|
||||||
|
};
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`pattern-or-as.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["flow"]
|
||||||
|
printWidth: 80
|
||||||
|
| printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
const e = match (x) {
|
||||||
|
"s" | true | null => 1,
|
||||||
|
| "s"
|
||||||
|
| true
|
||||||
|
| null => 1,
|
||||||
|
{foo: 1 | 2} => 2,
|
||||||
|
{foo: | 1
|
||||||
|
| 2} => 2,
|
||||||
|
{foo: [1] as y} => y,
|
||||||
|
{foo: 1 | 2 | 3 as y} => y,
|
||||||
|
{foo: (1 | 2 | 3) as y} => y,
|
||||||
|
{foo: [1] as const y} => y,
|
||||||
|
};
|
||||||
|
|
||||||
|
=====================================output=====================================
|
||||||
|
const e = match (x) {
|
||||||
|
"s" | true | null => 1,
|
||||||
|
"s" | true | null => 1,
|
||||||
|
{foo: 1 | 2} => 2,
|
||||||
|
{foo: 1 | 2} => 2,
|
||||||
|
{foo: [1] as y} => y,
|
||||||
|
{foo: (1 | 2 | 3) as y} => y,
|
||||||
|
{foo: (1 | 2 | 3) as y} => y,
|
||||||
|
{foo: [1] as const y} => y,
|
||||||
|
};
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`regression.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["flow"]
|
||||||
|
printWidth: 80
|
||||||
|
| printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
type match = number;
|
||||||
|
{
|
||||||
|
const match = 1;
|
||||||
|
}
|
||||||
|
function match(match: match) {}
|
||||||
|
const a = match(1);
|
||||||
|
const b = match(1).f();
|
||||||
|
const c = match(1)
|
||||||
|
{
|
||||||
|
// block statement
|
||||||
|
}
|
||||||
|
const d = match(1) + 2;
|
||||||
|
const e = match(1)[2];
|
||||||
|
const f = match(1) ? 2 : 3;
|
||||||
|
const g = match(1) < 2;
|
||||||
|
const h = match(1) && 2;
|
||||||
|
const i = match();
|
||||||
|
const j = match(...b);
|
||||||
|
match(1);
|
||||||
|
match(1).f();
|
||||||
|
match(1)
|
||||||
|
{
|
||||||
|
// block statement
|
||||||
|
}
|
||||||
|
match(1) + 2;
|
||||||
|
match(1)[2];
|
||||||
|
match(1) ? 2 : 3;
|
||||||
|
match(1) < 2;
|
||||||
|
match(1) && 2;
|
||||||
|
match();
|
||||||
|
match(...b);
|
||||||
|
|
||||||
|
=====================================output=====================================
|
||||||
|
type match = number;
|
||||||
|
{
|
||||||
|
const match = 1;
|
||||||
|
}
|
||||||
|
function match(match: match) {}
|
||||||
|
const a = match(1);
|
||||||
|
const b = match(1).f();
|
||||||
|
const c = match(1);
|
||||||
|
{
|
||||||
|
// block statement
|
||||||
|
}
|
||||||
|
const d = match(1) + 2;
|
||||||
|
const e = match(1)[2];
|
||||||
|
const f = match(1) ? 2 : 3;
|
||||||
|
const g = match(1) < 2;
|
||||||
|
const h = match(1) && 2;
|
||||||
|
const i = match();
|
||||||
|
const j = match(...b);
|
||||||
|
match(1);
|
||||||
|
match(1).f();
|
||||||
|
match(1);
|
||||||
|
{
|
||||||
|
// block statement
|
||||||
|
}
|
||||||
|
match(1) + 2;
|
||||||
|
match(1)[2];
|
||||||
|
match(1) ? 2 : 3;
|
||||||
|
match(1) < 2;
|
||||||
|
match(1) && 2;
|
||||||
|
match();
|
||||||
|
match(...b);
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`statement.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["flow"]
|
||||||
|
printWidth: 80
|
||||||
|
| printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
match (a) {
|
||||||
|
1 => {
|
||||||
|
const x = 1;
|
||||||
|
f(x);
|
||||||
|
},
|
||||||
|
'foo' => {
|
||||||
|
// empty
|
||||||
|
},
|
||||||
|
2 => {
|
||||||
|
label: 'literal'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
=====================================output=====================================
|
||||||
|
match (a) {
|
||||||
|
1 => {
|
||||||
|
const x = 1;
|
||||||
|
f(x);
|
||||||
|
}
|
||||||
|
"foo" => {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
label: "literal";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`statement-empty.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["flow"]
|
||||||
|
printWidth: 80
|
||||||
|
| printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
match (a) {}
|
||||||
|
|
||||||
|
=====================================output=====================================
|
||||||
|
match (a) {
|
||||||
|
}
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`statement-guards.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["flow"]
|
||||||
|
printWidth: 80
|
||||||
|
| printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
match (a) {
|
||||||
|
1 if (b) => {
|
||||||
|
const x = 1;
|
||||||
|
},
|
||||||
|
'foo' if (f()) => {
|
||||||
|
const x = 2;
|
||||||
|
},
|
||||||
|
2 if (x < y) => {
|
||||||
|
const x = 3;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
=====================================output=====================================
|
||||||
|
match (a) {
|
||||||
|
1 if (b) => {
|
||||||
|
const x = 1;
|
||||||
|
}
|
||||||
|
"foo" if (f()) => {
|
||||||
|
const x = 2;
|
||||||
|
}
|
||||||
|
2 if (x < y) => {
|
||||||
|
const x = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`statement-sequence-arg.js format 1`] = `
|
||||||
|
====================================options=====================================
|
||||||
|
parsers: ["flow"]
|
||||||
|
printWidth: 80
|
||||||
|
| printWidth
|
||||||
|
=====================================input======================================
|
||||||
|
match (a, b) {}
|
||||||
|
|
||||||
|
=====================================output=====================================
|
||||||
|
match ((a, b)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
`;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export default match (a) {}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
const e = match (a) {};
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
const e = match (a) {
|
||||||
|
1 if (b) => true,
|
||||||
|
};
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const e = match (a) {
|
||||||
|
1 => true,
|
||||||
|
'foo' => false,
|
||||||
|
2 => {obj: 'literal'},
|
||||||
|
};
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// Tests taken from https://github.com/facebook/hermes/tree/83c8115/test/Parser/flow/match
|
||||||
|
runFormatTest(import.meta, ["flow"]);
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
const e = match (x) {
|
||||||
|
[10] => 1,
|
||||||
|
[const y, 1] => y,
|
||||||
|
[1, ...] => 1,
|
||||||
|
[1, 2, ...const rest] => rest,
|
||||||
|
[...let rest] => rest,
|
||||||
|
[...var rest] => rest,
|
||||||
|
[{nested: [1, const x]}] => x,
|
||||||
|
};
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
const e = match (x) {
|
||||||
|
"s" => 1,
|
||||||
|
true => 1,
|
||||||
|
null => 1,
|
||||||
|
3 => 1,
|
||||||
|
4n => 1,
|
||||||
|
+5 => 1,
|
||||||
|
-6 => 1,
|
||||||
|
+7n => 1,
|
||||||
|
-8n => 1,
|
||||||
|
y => 1,
|
||||||
|
const y => y,
|
||||||
|
let y => y,
|
||||||
|
var y => y,
|
||||||
|
('s') => 1,
|
||||||
|
_ => 1,
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
const e = match (x) {
|
||||||
|
foo.bar => true,
|
||||||
|
foo[1] => true,
|
||||||
|
foo[1n] => true,
|
||||||
|
foo["bar"] => true,
|
||||||
|
foo.bar[1] => true,
|
||||||
|
foo[1].bar["baz"] => true,
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
const e = match (x) {
|
||||||
|
{foo: 1, bar: 2} => 1,
|
||||||
|
{'foo': 1} => 1,
|
||||||
|
{111: true} => 1,
|
||||||
|
{foo: const y} => y,
|
||||||
|
{const x, let y, var z} => y,
|
||||||
|
{const x, ...const y} => y,
|
||||||
|
{const x, ...let y} => y,
|
||||||
|
{const x, ...} => x,
|
||||||
|
};
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
const e = match (x) {
|
||||||
|
"s" | true | null => 1,
|
||||||
|
| "s"
|
||||||
|
| true
|
||||||
|
| null => 1,
|
||||||
|
{foo: 1 | 2} => 2,
|
||||||
|
{foo: | 1
|
||||||
|
| 2} => 2,
|
||||||
|
{foo: [1] as y} => y,
|
||||||
|
{foo: 1 | 2 | 3 as y} => y,
|
||||||
|
{foo: (1 | 2 | 3) as y} => y,
|
||||||
|
{foo: [1] as const y} => y,
|
||||||
|
};
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
type match = number;
|
||||||
|
{
|
||||||
|
const match = 1;
|
||||||
|
}
|
||||||
|
function match(match: match) {}
|
||||||
|
const a = match(1);
|
||||||
|
const b = match(1).f();
|
||||||
|
const c = match(1)
|
||||||
|
{
|
||||||
|
// block statement
|
||||||
|
}
|
||||||
|
const d = match(1) + 2;
|
||||||
|
const e = match(1)[2];
|
||||||
|
const f = match(1) ? 2 : 3;
|
||||||
|
const g = match(1) < 2;
|
||||||
|
const h = match(1) && 2;
|
||||||
|
const i = match();
|
||||||
|
const j = match(...b);
|
||||||
|
match(1);
|
||||||
|
match(1).f();
|
||||||
|
match(1)
|
||||||
|
{
|
||||||
|
// block statement
|
||||||
|
}
|
||||||
|
match(1) + 2;
|
||||||
|
match(1)[2];
|
||||||
|
match(1) ? 2 : 3;
|
||||||
|
match(1) < 2;
|
||||||
|
match(1) && 2;
|
||||||
|
match();
|
||||||
|
match(...b);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
match (a) {}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
match (a) {
|
||||||
|
1 if (b) => {
|
||||||
|
const x = 1;
|
||||||
|
},
|
||||||
|
'foo' if (f()) => {
|
||||||
|
const x = 2;
|
||||||
|
},
|
||||||
|
2 if (x < y) => {
|
||||||
|
const x = 3;
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
match (a, b) {}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
match (a) {
|
||||||
|
1 => {
|
||||||
|
const x = 1;
|
||||||
|
f(x);
|
||||||
|
},
|
||||||
|
'foo' => {
|
||||||
|
// empty
|
||||||
|
},
|
||||||
|
2 => {
|
||||||
|
label: 'literal'
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -1,5 +1 @@
|
|||||||
runFormatTest(import.meta, ["flow"], {
|
runFormatTest(import.meta, ["flow"]);
|
||||||
errors: {
|
|
||||||
"babel-flow": ["const-type-params.js"],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||||
|
|
||||||
|
exports[`snippet: #0 [flow] format 1`] = `
|
||||||
|
"\`match\` argument must not be empty (1:7)
|
||||||
|
> 1 | match () {}
|
||||||
|
| ^^"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`snippet: #0 [hermes] format 1`] = `
|
||||||
|
"'match' argument must not be empty (1:6)
|
||||||
|
> 1 | match () {}
|
||||||
|
| ^
|
||||||
|
Cause: 'match' argument must not be empty (1:6)
|
||||||
|
match () {}
|
||||||
|
^~"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`snippet: #1 [flow] format 1`] = `
|
||||||
|
"\`match\` argument cannot contain spread elements (1:8)
|
||||||
|
> 1 | match (...b) {}
|
||||||
|
| ^^^^"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`snippet: #1 [hermes] format 1`] = `
|
||||||
|
"'match' argument cannot contain spread elements (1:7)
|
||||||
|
> 1 | match (...b) {}
|
||||||
|
| ^
|
||||||
|
Cause: 'match' argument cannot contain spread elements (1:7)
|
||||||
|
match (...b) {}
|
||||||
|
^~~~"
|
||||||
|
`;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
runFormatTest(
|
||||||
|
{
|
||||||
|
importMeta: import.meta,
|
||||||
|
snippets: [
|
||||||
|
// https://github.com/facebook/hermes/blob/83c811545b35dc2284ba27786314936e4c80ee6a/test/Parser/flow/match/statement-no-arg.js
|
||||||
|
"match () {}",
|
||||||
|
// https://github.com/facebook/hermes/blob/83c811545b35dc2284ba27786314936e4c80ee6a/test/Parser/flow/match/statement-spread-arg.js
|
||||||
|
"match (...b) {}",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
["flow", "hermes"],
|
||||||
|
);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||||
|
|
||||||
exports[`visitor keys estree 1`] = `
|
exports[`visitor keys estree 1`] = `
|
||||||
{
|
{
|
||||||
@@ -523,6 +523,63 @@ exports[`visitor keys estree 1`] = `
|
|||||||
"left",
|
"left",
|
||||||
"right",
|
"right",
|
||||||
],
|
],
|
||||||
|
"MatchArrayPattern": [
|
||||||
|
"elements",
|
||||||
|
"rest",
|
||||||
|
],
|
||||||
|
"MatchAsPattern": [
|
||||||
|
"pattern",
|
||||||
|
"target",
|
||||||
|
],
|
||||||
|
"MatchBindingPattern": [
|
||||||
|
"id",
|
||||||
|
],
|
||||||
|
"MatchExpression": [
|
||||||
|
"argument",
|
||||||
|
"cases",
|
||||||
|
],
|
||||||
|
"MatchExpressionCase": [
|
||||||
|
"body",
|
||||||
|
"guard",
|
||||||
|
"pattern",
|
||||||
|
],
|
||||||
|
"MatchIdentifierPattern": [
|
||||||
|
"id",
|
||||||
|
],
|
||||||
|
"MatchLiteralPattern": [
|
||||||
|
"literal",
|
||||||
|
],
|
||||||
|
"MatchMemberPattern": [
|
||||||
|
"base",
|
||||||
|
"property",
|
||||||
|
],
|
||||||
|
"MatchObjectPattern": [
|
||||||
|
"properties",
|
||||||
|
"rest",
|
||||||
|
],
|
||||||
|
"MatchObjectPatternProperty": [
|
||||||
|
"key",
|
||||||
|
"pattern",
|
||||||
|
],
|
||||||
|
"MatchOrPattern": [
|
||||||
|
"patterns",
|
||||||
|
],
|
||||||
|
"MatchRestPattern": [
|
||||||
|
"argument",
|
||||||
|
],
|
||||||
|
"MatchStatement": [
|
||||||
|
"argument",
|
||||||
|
"cases",
|
||||||
|
],
|
||||||
|
"MatchStatementCase": [
|
||||||
|
"body",
|
||||||
|
"guard",
|
||||||
|
"pattern",
|
||||||
|
],
|
||||||
|
"MatchUnaryPattern": [
|
||||||
|
"argument",
|
||||||
|
],
|
||||||
|
"MatchWildcardPattern": [],
|
||||||
"MemberExpression": [
|
"MemberExpression": [
|
||||||
"object",
|
"object",
|
||||||
"property",
|
"property",
|
||||||
|
|||||||
Reference in new issue
Block a user