Description
Description
Manipulating and querying ASTs is inherently a complex problem. Often, we need to perform consecutive checks for children's properties, including their type and value. This leads to repetitive, not-so-readable code. Here's an example of such code:
if (ASTUtils.isVariableDeclarator(parent)) {
const init = parent.init;
let type: ProviderType | undefined;
if (init?.type === AST_NODE_TYPES.ObjectExpression) {
const properties = init.properties;
for (const property of properties) {
if (property.type === AST_NODE_TYPES.Property) {
type = providerTypeOfProperty(property);
}
}
}
return type;
}
And here's how this could be replaced with TS-Pattern
return match(node)
.with(
{
parent: {
init: {
type: AST_NODE_TYPES.ObjectExpression,
properties: P.select(),
},
type: P.when(ASTUtils.isVariableDeclarator),
},
},
(properties) => {
for (const property of properties) {
if (property.type === AST_NODE_TYPES.Property) {
const type = providerTypeOfProperty(property);
if (type) {
return type;
}
}
}
}
)
.otherwise(() => undefined);
This second approach is more declarative and makes it easier to grasp the expected node structure. Moreover, we can select parts of the matched node with the P.select()
function and make use of it in the following callback function.
Acceptance Criteria
Initially, it would suffice to implement a match(node)
function that accepts two additional methods:
with(structure, callback | value)
- matches with given object structure, and returns either the value or the callback's returned value
when(function, callback | value)
- matches with the given matching function, and returns either the value or the callback's returned value