GAQ is the library to query ast.Node
children like JavaScript querySelector
or querySelectorAll
.
go get github.com/tamayika/gaq/pkg/gaq
Please refer pkg/gaq/example_test.go
go get github.com/tamayika/gaq
or there are binaries for various os at Releases.
You can see help with --help
flag.
$ gaq --help
gaq is the cli tool to query ast node.
Typical usage is
cat <go file path> | gaq <Query>
cat <go file path> | gaq -m replace <Query> <Replace command>
Please see details at https://github.com/tamayika/gaq
Usage:
gaq <Query> [flags]
Flags:
-f, --format string Output format, 'text' or 'pos'. Default is 'text' (default "text")
-h, --help help for gaq
-m, --mode string Execution mode, 'filter' or 'replace'. Default is 'filter' (default "filter")
--version version for gaq
Default mode is filter
.
For example, File > Ident
query filters package name in main.go
$ cat main.go | gaq "File > Ident"
main
You can replace matched node text by replace
mode.
For example, below command exports functions except main
function.
$ cat main.go | gaq -m replace "FuncDecl > Ident:not([Name='main'])" -- sed -e "s/^\(.\)/\U\1/"
In replace
mode, below sequence is executed for each matched node
- command is spawned
- gaq passes node text as stdin
- wait command exit
- replace node text by command output
You can use any tool which gets input from stdin and puts result to stdout, sed
, awk
, tr
etc.
Heavily inspired by CSS Selector.
Query:
Selector [',' Selector]
Selector:
SimpleSelector [Combinator SimpleSelector]
SimpleSelector:
[[NodeName] [Attribute] [Pseudo]]!
Attribute:
'[' Field [ AttributeOperator Value ] ']'
Pseudo:
':' Name [ '(' Expression ')' ]
Full used example
File > Ident[Name*='test']:first-child, File > Ident[Name*='test']:last-child
Here, NodeName is one of node type of ast.
For example, if you want to find *ast.StructType
, NodeName is StructType
.
You can also specify *
as any node type.
If you don't know NodeName, VSCode extension vscode-go-ast-explorer will help you to find it out.
Combinator | Name | Meaning |
---|---|---|
+ | Adjacent sibling combinator | The second node directly follows the first, and both share the same parent. |
~ | General sibling combinator | The second node follows the first (though not necessarily immediately), and both share the same parent. |
> | Child combinator | Selects nodes that are direct children of the first node. |
(whitespace) | Descendant combinator | Selects nodes that are descendants of the first node. |
Syntax | Meaning |
---|---|
[f] |
Represents Node with an field name of f. |
[f=value] |
Represents Node with an field name of f whose value is exactly value. |
[f~=value] |
Represents Node with an field name of f whose value is a whitespace-separated list of words, one of which is exactly value. |
[f|=value] |
Represents Node with an field name of f whose value can be exactly value or can begin with value immediately followed by a hyphen, - . |
[f^=value] |
Represents Node with an field name of f whose value is prefixed (preceded) by value. |
[f$=value] |
Represents Node with an field name of f whose value is suffixed (followed) by value. |
[f*=value] |
Represents Node with an field name of f whose value contains at least one occurrence of value within the string. |
Syntax | Meaning |
---|---|
:empty |
Represents nodes that has no children. ast.CommentGroup and ast.Comment are ignored. |
:first-child |
Represents the first node among a group of sibling nodes. |
:first-of-type |
Represents the first node of its type among a group of sibling nodes. |
:has(Query) |
Represents a node if any of the selectors passed as parameters, match at least one node. |
:is(Query) |
Represents nodes that can be selected by one of the selectors in that list |
:last-child |
Represents the last node among a group of sibling nodes. |
:last-of-type |
Represents the last node of its type among a group of sibling nodes. |
:not(Query) |
Represents nodes that do not match a list of selectors. |
:root |
Represents the root node. When gaq.Parse(source string) is used, the root node is *ast.File . When gaq.ParseNode(n ast.Node) is used, the root node is n . |