aboutsummaryrefslogtreecommitdiff
path: root/data/plugins/language_js.lua
blob: 0b800bf93534223b49cf6efbd48fe32a750ad89a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
-- mod-version:3
local syntax = require "core.syntax"

-- Regex pattern explanation:
-- This will match / and will look ahead for something that looks like a regex.
--
-- (?!/) Don't match empty regexes.
--
-- (?>...) this is using an atomic group to minimize backtracking, as that'd
--         cause "Catastrophic Backtracking" in some cases.
--
-- [^\\[\/]++ will match anything that's isn't an escape, a start of character
--           class or an end of pattern, without backtracking (the second +).
--
-- \\. will match anything that's escaped.
--
-- \[(?:[^\\\]++]|\\.)*+\] will match character classes.
--
-- /[gmiyuvsd]*\s*[\n,;\)\]\}\.]) will match the end of pattern delimiter, optionally
--                                followed by pattern options, and anything that can
--                                be after a pattern.
--
-- Demo with some unit tests (click on the Unit Tests entry): https://regex101.com/r/Vx5L5V/1
-- Note that it has a couple of changes to make it work on that platform.
local regex_pattern = {
  [=[\/(?=(?!\/)(?:(?>[^\\[\/]++|\\.|\[(?:[^\\\]]++|\\.)*+\])*+)++\/[gmiyuvsd]*\s*(?:[\n,;\)\]\}\.]|\/[\/*]))()]=],
  "/()[gmiyuvsd]*", "\\"
}

-- For the moment let's not actually differentiate the insides of the regex,
-- as this will need new token types...
local inner_regex_syntax = {
  patterns = {
    { pattern = "%(()%?[:!=><]", type = { "string", "string" } },
    { pattern = "[.?+*%(%)|]", type = "string" },
    { pattern = "{%d*,?%d*}", type = "string" },
    { regex = { [=[\[()\^?]=], [=[(?:\]|(?=\n))()]=], "\\" },
      type = { "string", "string" },
      syntax = { -- Inside character class
        patterns = {
          { pattern = "\\\\", type = "string" },
          { pattern = "\\%]", type = "string" },
          { pattern = "[^%]\n]", type = "string" }
        },
        symbols = {}
      }
    },
    { regex = "\\/", type = "string" },
    { regex = "[^/\n]", type = "string" },
  },
  symbols = {}
}

syntax.add {
  name = "JavaScript",
  files = { "%.js$", "%.json$", "%.cson$", "%.mjs$", "%.cjs$" },
  comment = "//",
  block_comment = { "/*", "*/" },
  patterns = {
    -- Comments
    { pattern = "//.*",                      type = "comment"  },
    { pattern = { "/%*", "%*/" },            type = "comment"  },
    -- Strings
    { pattern = { '"', '"', '\\' },          type = "string"   },
    { pattern = { "'", "'", '\\' },          type = "string"   },
    { pattern = { "`", "`", '\\' },          type = "string"   },
    -- Numbers
    -- Use (?:\/(?!\/|\*))? to avoid that a regex can start after a number, while also allowing // and /* comments
    { regex = [[-?0[xXbBoO][\da-fA-F_]+n?()\s*()(?:\/(?!\/|\*))?]],
      type = {"number", "normal", "operator"}
    },
    { regex = [[-?\d+[0-9.eE_n]*()\s*()(?:\/(?!\/|\*))?]],
      type = {"number", "normal", "operator"}
    },
    { regex = [[-?\.?\d+()\s*()(?:\/(?!\/|\*))?]],
      type = {"number", "normal", "operator"}
    },
    -- Embedded html like that used on React
    { pattern = { "<%s*>", "<%s*/%s*>" },
      type = "operator", syntax = ".html"
    },
    { regex = "<\\s*/()\\s*()[\\w\\d\\-_]+()\\s*>",
      type = { "operator", "normal", "function", "operator" }
    },
    { regex = "<\\s*()[\\w\\d\\-_]+(?=.*/>)",
      type = { "operator", "function" }, syntax = ".html"
    },
    { regex = { "<\\s*()[\\w\\d\\-_]+()(?=.*>)", "</().*()>" },
      type = { "operator", "function", "operator" }, syntax = ".html"
    },
    { regex = { "^\\s*<\\s*()(?=[\\w\\d\\-_]\\s*.*)()", "</().*()>" },
      type = { "operator", "function", "operator" }, syntax = ".html"
    },
    -- Regex string
    { regex = regex_pattern, syntax = inner_regex_syntax, type = {"string", "string"}  },
    -- Operators
    { pattern = "[%+%-=/%*%^%%<>!~|&]",      type = "operator" },
    -- Functions
    { pattern = "[%a_][%w_]*%s*%f[(]",       type = "function" },
    { pattern = "[%a_][%w_]*",               type = "symbol"   },
  },
  symbols = {
    ["async"]      = "keyword",
    ["await"]      = "keyword",
    ["break"]      = "keyword",
    ["case"]       = "keyword",
    ["catch"]      = "keyword",
    ["class"]      = "keyword",
    ["const"]      = "keyword",
    ["continue"]   = "keyword",
    ["debugger"]   = "keyword",
    ["default"]    = "keyword",
    ["delete"]     = "keyword",
    ["do"]         = "keyword",
    ["else"]       = "keyword",
    ["export"]     = "keyword",
    ["extends"]    = "keyword",
    ["finally"]    = "keyword",
    ["for"]        = "keyword",
    ["from"]       = "keyword",
    ["function"]   = "keyword",
    ["get"]        = "keyword",
    ["if"]         = "keyword",
    ["import"]     = "keyword",
    ["in"]         = "keyword",
    ["of"]         = "keyword",
    ["instanceof"] = "keyword",
    ["let"]        = "keyword",
    ["new"]        = "keyword",
    ["return"]     = "keyword",
    ["set"]        = "keyword",
    ["static"]     = "keyword",
    ["super"]      = "keyword",
    ["switch"]     = "keyword",
    ["throw"]      = "keyword",
    ["try"]        = "keyword",
    ["typeof"]     = "keyword",
    ["var"]        = "keyword",
    ["void"]       = "keyword",
    ["while"]      = "keyword",
    ["with"]       = "keyword",
    ["yield"]      = "keyword",
    ["true"]       = "literal",
    ["false"]      = "literal",
    ["null"]       = "literal",
    ["undefined"]  = "literal",
    ["arguments"]  = "keyword2",
    ["Infinity"]   = "keyword2",
    ["NaN"]        = "keyword2",
    ["this"]       = "keyword2",
  },
}