; Types
; Javascript
; Variables
;-----------
(identifier) @variable

; Properties
;-----------
(property_identifier) @variable.member

(shorthand_property_identifier) @variable.member

(private_property_identifier) @variable.member

(object_pattern
  (shorthand_property_identifier_pattern) @variable)

(object_pattern
  (object_assignment_pattern
    (shorthand_property_identifier_pattern) @variable))

; Special identifiers
;--------------------
((identifier) @type
  (#match? @type "^[A-Z]"))

((identifier) @constant
  (#match? @constant "^_*[A-Z][A-Z0-9_]*$"))

((shorthand_property_identifier) @constant
  (#match? @constant "^_*[A-Z][A-Z0-9_]*$"))

((identifier) @variable.builtin
  (#any-of? @variable.builtin "arguments" "module" "console" "window" "document"))

((identifier) @type.builtin
  (#any-of? @type.builtin
    "Object" "Function" "Boolean" "Symbol" "Number" "Math" "Date" "String" "RegExp" "Map" "Set"
    "WeakMap" "WeakSet" "Promise" "Array" "Int8Array" "Uint8Array" "Uint8ClampedArray" "Int16Array"
    "Uint16Array" "Int32Array" "Uint32Array" "Float32Array" "Float64Array" "ArrayBuffer" "DataView"
    "Error" "EvalError" "InternalError" "RangeError" "ReferenceError" "SyntaxError" "TypeError"
    "URIError"))

(statement_identifier) @label

; Function and method definitions
;--------------------------------
(function_expression
  name: (identifier) @function)

(function_declaration
  name: (identifier) @function)

(generator_function
  name: (identifier) @function)

(generator_function_declaration
  name: (identifier) @function)

(method_definition
  name: [
    (property_identifier)
    (private_property_identifier)
  ] @function.method)

(method_definition
  name: (property_identifier) @constructor
  (#eq? @constructor "constructor"))

(pair
  key: (property_identifier) @function.method
  value: (function_expression))

(pair
  key: (property_identifier) @function.method
  value: (arrow_function))

(assignment_expression
  left: (member_expression
    property: (property_identifier) @function.method)
  right: (arrow_function))

(assignment_expression
  left: (member_expression
    property: (property_identifier) @function.method)
  right: (function_expression))

(variable_declarator
  name: (identifier) @function
  value: (arrow_function))

(variable_declarator
  name: (identifier) @function
  value: (function_expression))

(assignment_expression
  left: (identifier) @function
  right: (arrow_function))

(assignment_expression
  left: (identifier) @function
  right: (function_expression))

; Function and method calls
;--------------------------
(call_expression
  function: (identifier) @function.call)

(call_expression
  function: (member_expression
    property: [
      (property_identifier)
      (private_property_identifier)
    ] @function.method.call))

(call_expression
  function: (await_expression
    (identifier) @function.call))

(call_expression
  function: (await_expression
    (member_expression
      property: [
        (property_identifier)
        (private_property_identifier)
      ] @function.method.call)))

; Builtins
;---------
((identifier) @module.builtin
  (#eq? @module.builtin "Intl"))

((identifier) @function.builtin
  (#any-of? @function.builtin
    "eval" "isFinite" "isNaN" "parseFloat" "parseInt" "decodeURI" "decodeURIComponent" "encodeURI"
    "encodeURIComponent" "require"))

; Constructor
;------------
(new_expression
  constructor: (identifier) @constructor)

; Decorators
;----------
(decorator
  "@" @attribute
  (identifier) @attribute)

(decorator
  "@" @attribute
  (call_expression
    (identifier) @attribute))

(decorator
  "@" @attribute
  (member_expression
    (property_identifier) @attribute))

(decorator
  "@" @attribute
  (call_expression
    (member_expression
      (property_identifier) @attribute)))

; Literals
;---------
[
  (this)
  (super)
] @variable.builtin

((identifier) @variable.builtin
  (#eq? @variable.builtin "self"))

[
  (true)
  (false)
] @boolean

[
  (null)
  (undefined)
] @constant.builtin

[
  (comment)
  (html_comment)
] @comment @spell

((comment) @comment.documentation
  (#match? @comment.documentation "^/[*][*][^*].*[*]/$"))

(hash_bang_line) @keyword.directive

((string_fragment) @keyword.directive
  (#eq? @keyword.directive "use strict"))

(string) @string

(template_string) @string

(escape_sequence) @string.escape

(regex_pattern) @string.regexp

(regex_flags) @character.special

(regex
  "/" @punctuation.bracket) ; Regex delimiters

(number) @number

((identifier) @number
  (#any-of? @number "NaN" "Infinity"))

; Punctuation
;------------
[
  ";"
  "."
  ","
  ":"
] @punctuation.delimiter

[
  "--"
  "-"
  "-="
  "&&"
  "+"
  "++"
  "+="
  "&="
  "/="
  "**="
  "<<="
  "<"
  "<="
  "<<"
  "="
  "=="
  "==="
  "!="
  "!=="
  "=>"
  ">"
  ">="
  ">>"
  "||"
  "%"
  "%="
  "*"
  "**"
  ">>>"
  "&"
  "|"
  "^"
  "??"
  "*="
  ">>="
  ">>>="
  "^="
  "|="
  "&&="
  "||="
  "??="
  "..."
] @operator

(binary_expression
  "/" @operator)

(ternary_expression
  [
    "?"
    ":"
  ] @keyword.conditional.ternary)

(unary_expression
  [
    "!"
    "~"
    "-"
    "+"
  ] @operator)

(unary_expression
  [
    "delete"
    "void"
  ] @keyword.operator)

[
  "("
  ")"
  "["
  "]"
  "{"
  "}"
] @punctuation.bracket

(template_substitution
  [
    "${"
    "}"
  ] @punctuation.special) @none

; Imports
;----------
(namespace_import
  "*" @character.special
  (identifier) @module)

(namespace_export
  "*" @character.special
  (identifier) @module)

(export_statement
  "*" @character.special)

; Keywords
;----------
[
  "if"
  "else"
  "switch"
  "case"
] @keyword.conditional

[
  "import"
  "from"
  "as"
  "export"
] @keyword.import

[
  "for"
  "of"
  "do"
  "while"
  "continue"
] @keyword.repeat

[
  "break"
  "const"
  "debugger"
  "extends"
  "get"
  "let"
  "set"
  "static"
  "target"
  "var"
  "with"
] @keyword

"class" @keyword.type

[
  "async"
  "await"
] @keyword.coroutine

[
  "return"
  "yield"
] @keyword.return

"function" @keyword.function

[
  "new"
  "delete"
  "in"
  "instanceof"
  "typeof"
] @keyword.operator

[
  "throw"
  "try"
  "catch"
  "finally"
] @keyword.exception

(export_statement
  "default" @keyword)

(switch_default
  "default" @keyword.conditional)

"require" @keyword.import

(import_require_clause
  source: (string) @string.special.url)

[
  "declare"
  "implements"
  "type"
  "override"
  "module"
  "asserts"
  "infer"
  "is"
  "using"
] @keyword

[
  "namespace"
  "interface"
  "enum"
] @keyword.type

[
  "keyof"
  "satisfies"
] @keyword.operator

(as_expression
  "as" @keyword.operator)

(mapped_type_clause
  "as" @keyword.operator)

[
  "abstract"
  "private"
  "protected"
  "public"
  "readonly"
] @keyword.modifier

; types
(type_identifier) @type

(predefined_type) @type.builtin

(import_statement
  "type"
  (import_clause
    (named_imports
      (import_specifier
        name: (identifier) @type))))

(template_literal_type) @string

(non_null_expression
  "!" @operator)

; punctuation
(type_arguments
  [
    "<"
    ">"
  ] @punctuation.bracket)

(type_parameters
  [
    "<"
    ">"
  ] @punctuation.bracket)

(object_type
  [
    "{|"
    "|}"
  ] @punctuation.bracket)

(union_type
  "|" @punctuation.delimiter)

(intersection_type
  "&" @punctuation.delimiter)

(type_annotation
  ":" @punctuation.delimiter)

(type_predicate_annotation
  ":" @punctuation.delimiter)

(index_signature
  ":" @punctuation.delimiter)

(omitting_type_annotation
  "-?:" @punctuation.delimiter)

(adding_type_annotation
  "+?:" @punctuation.delimiter)

(opting_type_annotation
  "?:" @punctuation.delimiter)

"?." @punctuation.delimiter

(abstract_method_signature
  "?" @punctuation.special)

(method_signature
  "?" @punctuation.special)

(method_definition
  "?" @punctuation.special)

(property_signature
  "?" @punctuation.special)

(optional_parameter
  "?" @punctuation.special)

(optional_type
  "?" @punctuation.special)

(public_field_definition
  [
    "?"
    "!"
  ] @punctuation.special)

(flow_maybe_type
  "?" @punctuation.special)

(template_type
  [
    "${"
    "}"
  ] @punctuation.special)

(conditional_type
  [
    "?"
    ":"
  ] @keyword.conditional.ternary)

; Parameters
(required_parameter
  pattern: (identifier) @variable.parameter)

(optional_parameter
  pattern: (identifier) @variable.parameter)

(required_parameter
  (rest_pattern
    (identifier) @variable.parameter))

; ({ a }) => null
(required_parameter
  (object_pattern
    (shorthand_property_identifier_pattern) @variable.parameter))

; ({ a = b }) => null
(required_parameter
  (object_pattern
    (object_assignment_pattern
      (shorthand_property_identifier_pattern) @variable.parameter)))

; ({ a: b }) => null
(required_parameter
  (object_pattern
    (pair_pattern
      value: (identifier) @variable.parameter)))

; ([ a ]) => null
(required_parameter
  (array_pattern
    (identifier) @variable.parameter))

; a => null
(arrow_function
  parameter: (identifier) @variable.parameter)

; global declaration
(ambient_declaration
  "global" @module)

; function signatures
(ambient_declaration
  (function_signature
    name: (identifier) @function))

; method signatures
(method_signature
  name: (_) @function.method)

(abstract_method_signature
  name: (property_identifier) @function.method)

; property signatures
(property_signature
  name: (property_identifier) @function.method
  type: (type_annotation
    [
      (union_type
        (parenthesized_type
          (function_type)))
      (function_type)
    ]))
(jsx_element
  open_tag: (jsx_opening_element
    [
      "<"
      ">"
    ] @tag.delimiter))

(jsx_element
  close_tag: (jsx_closing_element
    [
      "</"
      ">"
    ] @tag.delimiter))

(jsx_self_closing_element
  [
    "<"
    "/>"
  ] @tag.delimiter)

(jsx_attribute
  (property_identifier) @tag.attribute)

(jsx_opening_element
  name: (identifier) @tag.builtin)

(jsx_closing_element
  name: (identifier) @tag.builtin)

(jsx_self_closing_element
  name: (identifier) @tag.builtin)

(jsx_opening_element
  ((identifier) @tag
    (#match? @tag "^[A-Z]")))

; Handle the dot operator effectively - <My.Component>
(jsx_opening_element
  (member_expression
    (identifier) @tag.builtin
    (property_identifier) @tag))

(jsx_closing_element
  ((identifier) @tag
    (#match? @tag "^[A-Z]")))

; Handle the dot operator effectively - </My.Component>
(jsx_closing_element
  (member_expression
    (identifier) @tag.builtin
    (property_identifier) @tag))

(jsx_self_closing_element
  ((identifier) @tag
    (#match? @tag "^[A-Z]")))

; Handle the dot operator effectively - <My.Component />
(jsx_self_closing_element
  (member_expression
    (identifier) @tag.builtin
    (property_identifier) @tag))

(html_character_reference) @tag

(jsx_text) @none @spell

(html_character_reference) @character.special

((jsx_element
  (jsx_opening_element
    name: (identifier) @_tag)
  (jsx_text) @markup.heading)
  (#eq? @_tag "title"))

((jsx_element
  (jsx_opening_element
    name: (identifier) @_tag)
  (jsx_text) @markup.heading.1)
  (#eq? @_tag "h1"))

((jsx_element
  (jsx_opening_element
    name: (identifier) @_tag)
  (jsx_text) @markup.heading.2)
  (#eq? @_tag "h2"))

((jsx_element
  (jsx_opening_element
    name: (identifier) @_tag)
  (jsx_text) @markup.heading.3)
  (#eq? @_tag "h3"))

((jsx_element
  (jsx_opening_element
    name: (identifier) @_tag)
  (jsx_text) @markup.heading.4)
  (#eq? @_tag "h4"))

((jsx_element
  (jsx_opening_element
    name: (identifier) @_tag)
  (jsx_text) @markup.heading.5)
  (#eq? @_tag "h5"))

((jsx_element
  (jsx_opening_element
    name: (identifier) @_tag)
  (jsx_text) @markup.heading.6)
  (#eq? @_tag "h6"))

((jsx_element
  (jsx_opening_element
    name: (identifier) @_tag)
  (jsx_text) @markup.strong)
  (#any-of? @_tag "strong" "b"))

((jsx_element
  (jsx_opening_element
    name: (identifier) @_tag)
  (jsx_text) @markup.italic)
  (#any-of? @_tag "em" "i"))

((jsx_element
  (jsx_opening_element
    name: (identifier) @_tag)
  (jsx_text) @markup.strikethrough)
  (#any-of? @_tag "s" "del"))

((jsx_element
  (jsx_opening_element
    name: (identifier) @_tag)
  (jsx_text) @markup.underline)
  (#eq? @_tag "u"))

((jsx_element
  (jsx_opening_element
    name: (identifier) @_tag)
  (jsx_text) @markup.raw)
  (#any-of? @_tag "code" "kbd"))

((jsx_element
  (jsx_opening_element
    name: (identifier) @_tag)
  (jsx_text) @markup.link.label)
  (#eq? @_tag "a"))

((jsx_attribute
  (property_identifier) @_attr
  (string
    (string_fragment) @string.special.url))
  (#any-of? @_attr "href" "src"))

