Tree Sitter Types Builder

TreeSitter Types Builder is a transpiler for generating type definitions for a tree-sitter language definition file. This project was created out lost of personal reseach and interest into the language server protocal, and how tree-sitter is used to provide it’s features.

It primarily aims to solve a symptom of how the tree-sitter builds its node runtime, by converting the string’s of every possible value in a languages SyntaxNode.type to a corresponding string literal type representation.

What does this do?

  • Provides autocompletion for type’s of SyntaxNode’s that are not currently possible in the nodejs implementation by default.
  • Removes the unnecessarily wide type defintion’s provided by tree-sitter in node.
  • Creates an easily customizable design pattern for any union SyntaxNode type’s
  • Promotes a singular location to reference SyntaxNode type’s

Example

Using the command provided by this package, as a global executable, follows the behavior below.

tree-sitter-types-builder --wasm path/to/your.wasm --language your_language

Using bash as our language file, we will get the annotated typescript definitions as output.

// tree-sitter-types-builder --wasm tree-sitter-bash.wasm --language bash

/**
 * AUTO GENERATED FILE
 *     tree-sitter-types-builder
 */
export type BashNodeType =
  | "end"
  | "word"
  | "\n"
  | "for"
  | "select"
  | "in"
  | "(("
  | "))"
  | ";"
  | "while"
  | "until"
  | "do"
  | "done"
  | "if"
  | "then"
  | "fi"
  | "elif"
  | "else"
  | "case"
  | "esac"
  | "|"
  | ")"
  | ";;"
  | ";&"
  | ";;&"
  | "function"
  | "("
  | "{"
  | "}"
  | "|&"
  | "&&"
  | "||"
  | "!"
  | "["
  | "]"
  | "[["
  | "]]"
  | "declare"
  | "typeset"
  | "export"
  | "readonly"
  | "local"
  | "unset"
  | "unsetenv"
  | "=~"
  | "=="
  | "="
  | "+="
  | "<"
  | ">"
  | ">>"
  | "&>"
  | "&>>"
  | "<&"
  | ">&"
  | ">|"
  | "<<"
  | "<<-"
  | "<<<"
  | "!="
  | "+"
  | "-"
  | "-="
  | "<="
  | ">="
  | "?"
  | ":"
  | "++"
  | "--"
  | "$"
  | "_special_character"
  | '"'
  | "_string_content"
  | "raw_string"
  | "ansi_c_string"
  | "#"
  | "${"
  | "/"
  | ":?"
  | ":-"
  | "%"
  | "$("
  | "`"
  | "<("
  | ">("
  | "comment"
  | "variable_name"
  | "special_variable_name"
  | "test_operator"
  | "&"
  | "heredoc_start"
  | "_simple_heredoc_body"
  | "_heredoc_body_beginning"
  | "_heredoc_body_middle"
  | "_heredoc_body_end"
  | "file_descriptor"
  | "_empty_value"
  | "_concat"
  | "regex"
  | "program"
  | "_statements"
  | "_statements2"
  | "_terminated_statement"
  | "redirected_statement"
  | "for_statement"
  | "c_style_for_statement"
  | "while_statement"
  | "do_group"
  | "if_statement"
  | "elif_clause"
  | "else_clause"
  | "case_statement"
  | "case_item"
  | "function_definition"
  | "compound_statement"
  | "subshell"
  | "pipeline"
  | "list"
  | "negated_command"
  | "test_command"
  | "declaration_command"
  | "unset_command"
  | "command"
  | "command_name"
  | "variable_assignment"
  | "subscript"
  | "file_redirect"
  | "heredoc_redirect"
  | "heredoc_body"
  | "herestring_redirect"
  | "_expression"
  | "binary_expression"
  | "ternary_expression"
  | "unary_expression"
  | "postfix_expression"
  | "parenthesized_expression"
  | "concatenation"
  | "string"
  | "translated_string"
  | "array"
  | "simple_expansion"
  | "expansion"
  | "command_substitution"
  | "process_substitution"
  | "_statements_repeat1"
  | "redirected_statement_repeat1"
  | "for_statement_repeat1"
  | "if_statement_repeat1"
  | "case_statement_repeat1"
  | "case_item_repeat1"
  | "declaration_command_repeat1"
  | "unset_command_repeat1"
  | "command_repeat1"
  | "command_repeat2"
  | "heredoc_body_repeat1"
  | "_literal_repeat1"
  | "concatenation_repeat1"
  | "string_repeat1"
  | "expansion_repeat1";

export namespace BashNodeType {
  export enum Keys {
    "end" = 0,
    "word" = 1,
    "\n" = 2,
    "for" = 3,
    "select" = 4,
    "in" = 5,
    "((" = 6,
    "))" = 7,
    ";" = 8,
    "while" = 9,
    "until" = 10,
    "do" = 11,
    "done" = 12,
    "if" = 13,
    "then" = 14,
    "fi" = 15,
    "elif" = 16,
    "else" = 17,
    "case" = 18,
    "esac" = 19,
    "|" = 20,
    ")" = 21,
    ";;" = 22,
    ";&" = 23,
    ";;&" = 24,
    "function" = 25,
    "(" = 26,
    "{" = 27,
    "}" = 28,
    "|&" = 29,
    "&&" = 30,
    "||" = 31,
    "!" = 32,
    "[" = 33,
    "]" = 34,
    "[[" = 35,
    "]]" = 36,
    "declare" = 37,
    "typeset" = 38,
    "export" = 39,
    "readonly" = 40,
    "local" = 41,
    "unset" = 42,
    "unsetenv" = 43,
    "=~" = 44,
    "==" = 45,
    "=" = 46,
    "+=" = 47,
    "<" = 48,
    ">" = 49,
    ">>" = 50,
    "&>" = 51,
    "&>>" = 52,
    "<&" = 53,
    ">&" = 54,
    ">|" = 55,
    "<<" = 56,
    "<<-" = 57,
    "<<<" = 58,
    "!=" = 59,
    "+" = 60,
    "-" = 61,
    "-=" = 62,
    "<=" = 63,
    ">=" = 64,
    "?" = 65,
    ":" = 66,
    "++" = 67,
    "--" = 68,
    "$" = 69,
    "_special_character" = 70,
    '"' = 71,
    "_string_content" = 72,
    "raw_string" = 73,
    "ansi_c_string" = 74,
    "#" = 75,
    "${" = 76,
    "/" = 77,
    ":?" = 78,
    ":-" = 79,
    "%" = 80,
    "$(" = 81,
    "`" = 82,
    "<(" = 83,
    ">(" = 84,
    "comment" = 85,
    "variable_name" = 86,
    "special_variable_name" = 87,
    "test_operator" = 88,
    "&" = 89,
    "heredoc_start" = 90,
    "_simple_heredoc_body" = 91,
    "_heredoc_body_beginning" = 92,
    "_heredoc_body_middle" = 93,
    "_heredoc_body_end" = 94,
    "file_descriptor" = 95,
    "_empty_value" = 96,
    "_concat" = 97,
    "regex" = 98,
    "program" = 99,
    "_statements" = 100,
    "_statements2" = 101,
    "_terminated_statement" = 102,
    "redirected_statement" = 103,
    "for_statement" = 104,
    "c_style_for_statement" = 105,
    "while_statement" = 106,
    "do_group" = 107,
    "if_statement" = 108,
    "elif_clause" = 109,
    "else_clause" = 110,
    "case_statement" = 111,
    "case_item" = 112,
    "function_definition" = 113,
    "compound_statement" = 114,
    "subshell" = 115,
    "pipeline" = 116,
    "list" = 117,
    "negated_command" = 118,
    "test_command" = 119,
    "declaration_command" = 120,
    "unset_command" = 121,
    "command" = 122,
    "command_name" = 123,
    "variable_assignment" = 124,
    "subscript" = 125,
    "file_redirect" = 126,
    "heredoc_redirect" = 127,
    "heredoc_body" = 128,
    "herestring_redirect" = 129,
    "_expression" = 130,
    "binary_expression" = 131,
    "ternary_expression" = 132,
    "unary_expression" = 133,
    "postfix_expression" = 134,
    "parenthesized_expression" = 135,
    "concatenation" = 136,
    "string" = 137,
    "translated_string" = 138,
    "array" = 139,
    "simple_expansion" = 140,
    "expansion" = 141,
    "command_substitution" = 142,
    "process_substitution" = 143,
    "_statements_repeat1" = 144,
    "redirected_statement_repeat1" = 145,
    "for_statement_repeat1" = 146,
    "if_statement_repeat1" = 147,
    "case_statement_repeat1" = 148,
    "case_item_repeat1" = 149,
    "declaration_command_repeat1" = 150,
    "unset_command_repeat1" = 151,
    "command_repeat1" = 152,
    "command_repeat2" = 153,
    "heredoc_body_repeat1" = 154,
    "_literal_repeat1" = 155,
    "concatenation_repeat1" = 156,
    "string_repeat1" = 157,
    "expansion_repeat1" = 158,
  }
  export function getKeys(): BashNodeType[] {
    return Object.keys(BashNodeType).map(
      x => BashNodeType[x]
    ) as BashNodeType[];
  }
  export function hasKeys(...keys: BashNodeType[]) {
    const allKeys = getKeys();

    return keys.every(k => allKeys.includes(k));
  }
}
export type BashFieldNameType =
  | "null"
  | "alternative"
  | "argument"
  | "body"
  | "condition"
  | "consequence"
  | "descriptor"
  | "destination"
  | "fallthrough"
  | "index"
  | "initializer"
  | "left"
  | "name"
  | "operator"
  | "redirect"
  | "right"
  | "termination"
  | "update"
  | "value";

export namespace BashFieldNameType {
  export enum Keys {
    "null" = 0,
    "alternative" = 1,
    "argument" = 2,
    "body" = 3,
    "condition" = 4,
    "consequence" = 5,
    "descriptor" = 6,
    "destination" = 7,
    "fallthrough" = 8,
    "index" = 9,
    "initializer" = 10,
    "left" = 11,
    "name" = 12,
    "operator" = 13,
    "redirect" = 14,
    "right" = 15,
    "termination" = 16,
    "update" = 17,
    "value" = 18,
  }
  export function getKeys(): BashFieldNameType[] {
    return Object.keys(BashFieldNameType).map(
      x => BashFieldNameType[x]
    ) as BashFieldNameType[];
  }
  export function hasKeys(...keys: BashFieldNameType[]) {
    const allKeys = getKeys();

    return keys.every(k => allKeys.includes(k));
  }
}

Thus, you can now use the types provided by tree-sitter in more reliable manor, by avoiding the use of strings to search through web-tree-sitter Objects. You also now have access to language tools through the tsserver lsp. This allows you to have completions on the BashNodeType, plus any other possible language feature (like seeing references, definitions, etc…).

Browse the GitHub repo for more info!

Join the Newsletter!