π¦ PutoutScript
Among the maxims on Lord Naoshigeβs wall there was this one: βMatters ofβ great concern should be treated lightly.β Master lttei commented, βMatters of small concern should be treated seriously.β
(c) Yamamoto Tsunetomo "Hagakure"
π¦PutoutScript β JavaScript-compatible language which adds additional meaning to Identifiers
in AST-template. It is supported by all types of πPutout plugins (opens in a new tab).
Take a look at rule syntax (opens in a new tab) for more information.
βοΈ In the command line, patterns are specified with a flag --transform
.
Pattern matching
Pattern matching searches code for a given pattern. For example, the expression pattern say('hello π')
can match a full expression or be part of a subexpression:
loud(say('hello π'))
In the same way, the statement pattern return __
can match a top statement
in a function
or any nested statement
:
const when = () => {
if (isTime())
return 'now';
return 'laiter';
};
__
template value
The double low dush template value (__
) abstracts away Identifiers
, Expressions
and Literals
.
__args
template value
The __args
template value abstracts away a sequence of zero or more arguments.
Function calls
Use the __args
template value to search for function calls with arguments. For example, the pattern sey(__args)
finds calls regardless of its arguments.
say('hello π');
Method calls
The __args
template value can also be used to search for method calls. For example, the pattern __object.say(__args)
matches:
crocodile.say('hello π');
The __
template value can also be used for the function name. Indeed, In some cases, you may want to match any function definitions: regular functions, methods, but also arrow functions.
In that case you can use __
in place of the name of the function to match named or anonymous functions. For example, the pattern function __(__a) {}
will match any function with one parameter:
function say(a) {
return 'hello π';
}
const talk = function(a) {
return 'hello π';
};
Strings
The "__a"
template value can be used to search for strings containing any data. The pattern crocodile.say("__a")
matches:
crocodile.say('hello π');
This also works with constant propagation.
In languages where regular expressions use a special syntax (e.g., Javascript), the pattern /__a/
will match any regular expression construct:
const animalRegExp = /π|π¦/;
Binary operations
The __a
can match arguments to binary operations. The pattern const __a = __b + __c
matches:
const friends = 'π' + 'π¦';
Containers
The __array
and __object
template values can match container data structures like, arrays, objects.
The pattern const friends = __array
matches:
const friends = [
'π',
'π¦',
];
The pattern const animal = __object
matches:
const animal = {
'π': 'π¦',
};
Conditionals and loops
The __
can be used inside conditionals or loops. π¦ PutoutScript:
if (__a)
__b;
matches:
if (friends.includes('π'))
return `π friend of π¦`;
Template variables can match a conditional or loop body if the body statement information is re-used later. π¦ PutoutScript:
if (__a)
__body;
matches:
if (friends.includes('π¦'))
return `π¦ friend of π`;
Template variables
Template variables are an abstraction to match code when you donβt know the value or contents ahead of time, similar to capture groups in regular expressions. Template variables can be used to track values across a specific code scope. This includes variables, functions, arguments, classes, object methods, imports and more.
Template variables look like __a
, __b
, etc. They begin with a __
and can only contain one character.
Expression template variable
π¦ PutoutScript __a + __b
matches the following code examples:
'π' + 'πΌ';
Import template variable
Template variable __imports
can be used to match imports. For example, import __imports
matches:
import fs from 'fs/promises';
Reoccuring template variable
Re-using template variables shows their true power. Detect assignment of sum of duplicate nodes:
const __a = __b + __b;
Assignment of duplicate nodes sum detected:
const sum = 2 + 2;
Literal template variable
You can use "__a"
to match any string literal. This is similar to using __a
, but the content of the string is stored in the template variable __a
, which can then be used later.
Typed template variable
Same thing works with TypeScript
types, such pattern const __a: __b = __c
, finds:
const answer: number = 42;
Statements and expressions
JavaScript differentiate between expressions and statements. Expressions can appear inside if
conditions, in function
call arguments
, etc. Statements can not appear everywhere; they are sequence of operations (using ;
as a separator/terminator) or special control flow constructs (if
, while
, etc.):
- β
say()
is an expression - β
say();
is a statement
When you write the expression foo()
in a pattern, π¦PutoutScript
will visit every expression and sub-expression in your program and try to find a match.
Partial expressions
Partial expressions are not valid patterns. For example, the following is invalid:
'π' +
A complete expression is needed (like 'π' + __a
). Same with partial statements.
βοΈ Find what you needed in this doc? Create an issue (opens in a new tab) if you need any help π!