-
-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathindex.js
More file actions
83 lines (67 loc) · 2.02 KB
/
index.js
File metadata and controls
83 lines (67 loc) · 2.02 KB
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
'use strict'
const keywords = require('./keywords')
const escapeHtml = require('./escapeHtml')
const DEFAULT_OPTIONS = {
html: false,
htmlEscaper: escapeHtml,
classPrefix: 'sql-hl-',
colors: {
keyword: '\x1b[35m',
function: '\x1b[31m',
number: '\x1b[32m',
string: '\x1b[32m',
identifier: '\x1b[0m',
special: '\x1b[33m',
bracket: '\x1b[33m',
comment: '\x1b[2m\x1b[90m',
clear: '\x1b[0m'
}
}
const highlighters = [
/\b(?<number>\d+(?:\.\d+)?)\b/,
// Note: Repeating string escapes like 'sql''server' will also work as they are just repeating strings
/(?<string>'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*")/,
/(?<comment>--[^\n\r]*|#[^\n\r]*|\/\*(?:[^*]|\*(?!\/))*\*\/)/,
// Future improvement: Comments should be allowed between the function name and the opening parenthesis
/\b(?<function>\w+)(?=\s*\()/,
/(?<bracket>[()])/,
/(?<special>!=|[=%*/\-+,;:<>.])/,
/(?<identifier>\b\w+\b|`(?:[^`\\]|\\.)*`)/,
/(?<whitespace>\s+)/,
/(?<unknown>\.+?)/
]
// Regex of the shape /(?<token1>...)|(?<token2>...)|.../g
const tokenizer = new RegExp(
[
'\\b(?<keyword>' + keywords.join('|') + ')\\b',
...highlighters.map(regex => regex.source)
].join('|'),
'gis'
)
function getSegments (sqlString) {
const segments = Array.from(sqlString.matchAll(tokenizer), match => ({
name: Object.keys(match.groups).find(key => match.groups[key]),
content: match[0]
}))
return segments
}
function highlight (sqlString, options) {
options = Object.assign({}, DEFAULT_OPTIONS, options)
return getSegments(sqlString)
.map(({ name, content }) => {
if (options.html) {
const escapedContent = options.htmlEscaper(content)
return name === 'whitespace' ? escapedContent : `<span class="${options.classPrefix}${name}">${escapedContent}</span>`
}
if (options.colors[name]) {
return options.colors[name] + content + options.colors.clear
}
return content
})
.join('')
}
module.exports = {
getSegments,
highlight,
DEFAULT_OPTIONS
}