Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 55de594

Browse files
committed
Replace "default" token with "whitespace" and "identifier" tokens, with fallback to "unknown" token.
Also, change backticked identifiers like `foo` to be classified as "identifier" rather than "string". This allows for identifiers to be styled independently from strings and whitespace. It also simplifies getSegments() from 30 lines down to 5, by removing the special-case code for the "default" token. Fixes #147.
1 parent 4a3aa67 commit 55de594

File tree

3 files changed

+85
-111
lines changed

3 files changed

+85
-111
lines changed

README.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,13 @@ document.body.innerHTML += highlighted
5959
**Output:**
6060
```html
6161
<span class="sql-hl-keyword">SELECT</span>
62-
<span class="sql-hl-string">`id`</span>
62+
<span class="sql-hl-identifier">`id`</span>
6363
<span class="sql-hl-special">,</span>
64-
<span class="sql-hl-string">`username`</span>
64+
<span class="sql-hl-identifier">`username`</span>
6565
<span class="sql-hl-keyword">FROM</span>
66-
<span class="sql-hl-string">`users`</span>
66+
<span class="sql-hl-identifier">`users`</span>
6767
<span class="sql-hl-keyword">WHERE</span>
68-
<span class="sql-hl-string">`email`</span>
68+
<span class="sql-hl-identifier">`email`</span>
6969
<span class="sql-hl-special">=</span>
7070
<span class="sql-hl-string">'[email protected]'</span>
7171
```
@@ -112,22 +112,22 @@ console.log(segments)
112112
```js
113113
[
114114
{ name: 'keyword', content: 'SELECT' },
115-
{ name: 'default', content: ' ' },
116-
{ name: 'string', content: '`id`' },
115+
{ name: 'whitespace', content: ' ' },
116+
{ name: 'identifier', content: '`id`' },
117117
{ name: 'special', content: ',' },
118-
{ name: 'default', content: ' ' },
119-
{ name: 'string', content: '`username`' },
120-
{ name: 'default', content: ' ' },
118+
{ name: 'whitespace', content: ' ' },
119+
{ name: 'identifier', content: '`username`' },
120+
{ name: 'whitespace', content: ' ' },
121121
{ name: 'keyword', content: 'FROM' },
122-
{ name: 'default', content: ' ' },
123-
{ name: 'string', content: '`users`' },
124-
{ name: 'default', content: ' ' },
122+
{ name: 'whitespace', content: ' ' },
123+
{ name: 'identifier', content: '`users`' },
124+
{ name: 'whitespace', content: ' ' },
125125
{ name: 'keyword', content: 'WHERE' },
126-
{ name: 'default', content: ' ' },
127-
{ name: 'string', content: '`email`' },
128-
{ name: 'default', content: ' ' },
126+
{ name: 'whitespace', content: ' ' },
127+
{ name: 'identifier', content: '`email`' },
128+
{ name: 'whitespace', content: ' ' },
129129
{ name: 'special', content: '=' },
130-
{ name: 'default', content: ' ' },
130+
{ name: 'whitespace', content: ' ' },
131131
{ name: 'string', content: "'[email protected]'" }
132132
]
133133
```

lib/index.js

Lines changed: 23 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,11 @@ const DEFAULT_OPTIONS = {
1919
}
2020
}
2121

22-
const DEFAULT_KEYWORD = 'default'
23-
2422
const highlighters = [
2523
/\b(?<number>\d+(?:\.\d+)?)\b/,
2624

2725
// Note: Repeating string escapes like 'sql''server' will also work as they are just repeating strings
28-
/(?<string>'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*`)/,
26+
/(?<string>'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*")/,
2927

3028
/(?<comment>--[^\n\r]*|#[^\n\r]*|\/\*(?:[^*]|\*(?!\/))*\*\/)/,
3129

@@ -34,54 +32,29 @@ const highlighters = [
3432

3533
/(?<bracket>[()])/,
3634

37-
/(?<special>!=|[=%*/\-+,;:<>])/
38-
]
35+
/(?<special>!=|[=%*/\-+,;:<>.])/,
3936

40-
function getRegexString (regex) {
41-
const str = regex.toString()
42-
return str.replace(/^\/|\/\w*$/g, '')
43-
}
37+
/(?<identifier>\b\w+\b|`(?:[^`\\]|\\.)*`)/,
38+
39+
/(?<whitespace>\s+)/,
40+
41+
/(?<unknown>\.+?)/
42+
]
4443

45-
// Regex of the shape /(.*?)|((?<token1>...)|(?<token2>...)|...|$)/y
44+
// Regex of the shape /(?<token1>...)|(?<token2>...)|.../g
4645
const tokenizer = new RegExp(
47-
'(.*?)(' +
48-
'\\b(?<keyword>' + keywords.join('|') + ')\\b|' +
49-
highlighters.map(getRegexString).join('|') +
50-
'|$)', // $ needed to to match "default" till the end of string
51-
'isy'
46+
[
47+
'\\b(?<keyword>' + keywords.join('|') + ')\\b',
48+
...highlighters.map(regex => regex.source)
49+
].join('|'),
50+
'gis'
5251
)
5352

5453
function getSegments (sqlString) {
55-
const segments = []
56-
let match
57-
58-
// Reset the starting position
59-
tokenizer.lastIndex = 0
60-
61-
// This is probably the one time when an assignment inside a condition makes sense
62-
// eslint-disable-next-line no-cond-assign
63-
while (match = tokenizer.exec(sqlString)) {
64-
if (match[1]) {
65-
segments.push({
66-
name: DEFAULT_KEYWORD,
67-
content: match[1]
68-
})
69-
}
70-
71-
if (match[2]) {
72-
const name = Object.keys(match.groups).find(key => match.groups[key])
73-
segments.push({
74-
name,
75-
content: match.groups[name]
76-
})
77-
}
78-
79-
// Stop at the end of string
80-
if (match.index + match[0].length >= sqlString.length) {
81-
break
82-
}
83-
}
84-
54+
const segments = Array.from(sqlString.matchAll(tokenizer), match => ({
55+
name: Object.keys(match.groups).find(key => match.groups[key]),
56+
content: match[0]
57+
}))
8558
return segments
8659
}
8760

@@ -90,14 +63,14 @@ function highlight (sqlString, options) {
9063

9164
return getSegments(sqlString)
9265
.map(({ name, content }) => {
93-
if (name === DEFAULT_KEYWORD) {
94-
return content
95-
}
9666
if (options.html) {
9767
const escapedContent = options.htmlEscaper(content)
98-
return `<span class="${options.classPrefix}${name}">${escapedContent}</span>`
68+
return name === 'whitespace' ? escapedContent : `<span class="${options.classPrefix}${name}">${escapedContent}</span>`
69+
}
70+
if (options.colors[name]) {
71+
return options.colors[name] + content + options.colors.clear
9972
}
100-
return options.colors[name] + content + options.colors.clear
73+
return content
10174
})
10275
.join('')
10376
}

0 commit comments

Comments
 (0)