Skip to content

Commit 39e1443

Browse files
committed
Updated to version 3.0.0
1 parent 63d5a1b commit 39e1443

File tree

6 files changed

+260
-79
lines changed

6 files changed

+260
-79
lines changed

README.md

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,34 @@
55
[![Downloads Stats][npm-downloads]][npm-url]
66

77
## What's it all about?
8-
SQL Highlight is a small package that highlights SQL queries. It can output to both the terminal with Unicode escape sequences, as well as to normal HTML
8+
SQL Highlight is a small package that highlights SQL queries. It can output to
9+
both the terminal with Unicode escape sequences, as well as to normal HTML. Oh,
10+
and there are no external dependencies 😉
911

1012
## Installation
1113

12-
Install via Yarn (recommended):
14+
Install via Yarn:
1315
```bash
14-
yarn add sql-highlight -D
16+
yarn add sql-highlight
1517
```
1618
Install via NPM:
1719
```bash
18-
npm install sql-highlight --save-dev
20+
npm install sql-highlight
1921
```
2022

2123
## Usage
22-
Note that we're using ES6 import statements here. Usage with `require` works just as well.
24+
> Note that we're using ES6 import statements here. Usage with `require` works
25+
> just as well.
2326
2427
**In its most basic form:**
25-
```javascript
26-
import Highlight from 'sql-highlight'
27-
const highlighter = new Highlight()
28+
```js
29+
import { highlight } from 'sql-highlight'
2830

29-
console.log(highlighter.highlight("SELECT `id`, `username` FROM `users` WHERE `email` = '[email protected]'"))
31+
const sqlString = "SELECT `id`, `username` FROM `users` WHERE `email` = '[email protected]'"
32+
33+
const highlighted = highlight(sqlString)
34+
35+
console.log(highlighted)
3036
```
3137

3238
**Output:**
@@ -35,13 +41,16 @@ console.log(highlighter.highlight("SELECT `id`, `username` FROM `users` WHERE `e
3541

3642
**HTML mode:**
3743

38-
```javascript
39-
import Highlight from 'sql-highlight'
40-
const highlighter = new Highlight({
44+
```js
45+
import { highlight } from 'sql-highlight'
46+
47+
const sqlString = "SELECT `id`, `username` FROM `users` WHERE `email` = '[email protected]'"
48+
49+
const highlighted = highlight(sqlString, {
4150
html: true
4251
})
4352

44-
document.body.innerHTML += highlighter.highlight("SELECT `id`, `username` FROM `users` WHERE `email` = '[email protected]'")
53+
document.body.innerHTML += highlighted
4554
```
4655

4756
**Output:**
@@ -59,7 +68,7 @@ document.body.innerHTML += highlighter.highlight("SELECT `id`, `username` FROM `
5968
```
6069

6170
## Options
62-
Options may be passed to the constructor while instantiating the `Highlighter` class.
71+
The following options may be passed to the `highlight` function.
6372

6473
| Option | Value | Default | Description |
6574
| --- | --- | --- | --- |
@@ -68,7 +77,7 @@ Options may be passed to the constructor while instantiating the `Highlighter` c
6877
| colors | `Object` | _See below_* | What color codes to use for Unicode rendering.
6978

7079
\* `colors` option default value
71-
```javascript
80+
```js
7281
{
7382
keyword: '\x1b[35m', // SQL reserved keywords
7483
function: '\x1b[31m', // Functions
@@ -96,8 +105,14 @@ Distributed under the MIT licence. See `LICENCE` for more information.
96105
https://github.com/scriptcoded
97106

98107
## Disclaimer
99-
This was initially a fork from https://github.com/pomahtuk/sequilize-highlight. The repo wasn't being
100-
updated, NPM wasn't serving the latest version and there was a severe memory leak. Though the latest version now exists on NPM, issues still persist. This repo serves to address those problems, as well as providing a cleaner interface that's not bound to Sequelize.
108+
This was initially a fork from https://github.com/pomahtuk/sequilize-highlight.
109+
The repo wasn't being updated, NPM wasn't serving the latest version and there
110+
was a severe memory leak. Though the latest version now exists on NPM, issues
111+
still persist. This repo serves to address those problems, as well as providing
112+
a cleaner interface that's not bound to Sequelize.
113+
114+
With version 3.0.0 the library was almost completely rewritten, which leaves
115+
very little similarity with the original repo.
101116

102117
[npm-image]: https://img.shields.io/npm/v/sql-highlight.svg
103118
[npm-url]: https://npmjs.org/package/sql-highlight

index.js

Lines changed: 68 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
'use strict'
22

3-
const defaultOptions = {
3+
const keywords = require('./keywords')
4+
5+
const DEFAULT_OPTIONS = {
46
html: false,
57
classPrefix: 'sql-hl-',
68
colors: {
@@ -12,75 +14,84 @@ const defaultOptions = {
1214
bracket: '\x1b[33m'
1315
}
1416
}
15-
const keywordsUpper = [
16-
'PRAGMA', 'CREATE', 'EXISTS', 'INTEGER', 'PRIMARY', 'letCHAR',
17-
'DATETIME', 'NULL', 'REFERENCES', 'AND', 'AS', 'ASC', 'INDEX_LIST',
18-
'BETWEEN', 'BY', 'CASE', 'CURRENT_DATE', 'CURRENT_TIME', 'DELETE',
19-
'DESC', 'DISTINCT', 'EACH', 'ELSE', 'ELSEIF', 'FALSE', 'FOR', 'FROM',
20-
'GROUP', 'HAVING', 'IF', 'IN', 'INSERT', 'INTERVAL', 'INTO', 'IS',
21-
'JOIN', 'KEY', 'KEYS', 'LEFT', 'LIKE', 'LIMIT', 'MATCH', 'NOT',
22-
'ON', 'OPTION', 'OR', 'ORDER', 'OUT', 'OUTER', 'REPLACE', 'TINYINT',
23-
'RIGHT', 'SELECT', 'SET', 'TABLE', 'THEN', 'TO', 'TRUE', 'UPDATE',
24-
'VALUES', 'WHEN', 'WHERE', 'UNSIGNED', 'CASCADE', 'UNIQUE', 'DEFAULT',
25-
'ENGINE', 'TEXT', 'auto_increment', 'SHOW', 'INDEX'
26-
]
27-
let keywordsLower = keywordsUpper.map(value => value.toLowerCase())
28-
const keywords = [].concat(keywordsUpper, keywordsLower)
29-
3017
const clearStyle = '\x1b[0m'
3118

32-
module.exports = class Highlighter {
33-
constructor (_options) {
34-
this.options = Object.assign({}, defaultOptions, _options)
19+
const SPLIT_CHARS = '(^|[^a-zA-Z_])'
3520

36-
this.unicodePattern = `{0}$1${clearStyle}`
37-
this.htmlPattern = `<span class="${this.options.classPrefix}{0}">$1</span>`
21+
const highlighters = [
22+
{
23+
name: 'keyword',
24+
regex: new RegExp(`${SPLIT_CHARS}(?:${keywords.join('|')})${SPLIT_CHARS}`, 'g')
25+
},
26+
{
27+
name: 'special',
28+
regex: /(=|%|\/|\*|-|,|;|:|\+|<|>)/g
29+
},
30+
{
31+
name: 'function',
32+
regex: /(\w*?)\(/g,
33+
trimEnd: 1
34+
},
35+
{
36+
name: 'number',
37+
regex: /(\d+)/g
38+
},
39+
{
40+
name: 'string',
41+
regex: /(['`].*?['`])/g
42+
},
43+
{
44+
name: 'bracket',
45+
regex: /([()])/g
3846
}
47+
]
3948

40-
highlight (text) {
41-
let newText = text
49+
function highlight (sqlString, options) {
50+
options = Object.assign({}, DEFAULT_OPTIONS, options)
51+
52+
const matches = []
4253

43-
let rules = {
44-
special: /(=|%|\/|\*|-|,|;|:|\+|<|>)/g,
45-
function: {
46-
match: /(\w*?)\(/g,
47-
pattern: '{0}('
48-
},
49-
number: /(\d+)/g,
50-
string: /(['`].*?['`])/g,
51-
bracket: /([()])/g
54+
for (const hl of highlighters) {
55+
let match
56+
57+
while (match = hl.regex.exec(sqlString)) {
58+
matches.push({
59+
name: hl.name,
60+
start: match.index,
61+
length: (hl.trimEnd ? match[0].substr(0, match[0].length - hl.trimEnd) : match[0]).length
62+
})
5263
}
64+
}
5365

54-
for (let key in rules) {
55-
let rule = rules[key]
56-
let match = rule
57-
let pattern = '{0}'
66+
const sortedMatches = matches.slice().sort((a, b) => a.start - b.start)
5867

59-
if (typeof rule === 'function') {
60-
match = rule.match
61-
pattern = rule.pattern
62-
}
68+
let highlighted = ''
6369

64-
let replacer
70+
for (let i = 0; i < sortedMatches.length; i++) {
71+
const match = sortedMatches[i]
72+
const nextMatch = sortedMatches[i + 1]
6573

66-
if (!this.options.html) {
67-
replacer = this.unicodePattern.replace('{0}', this.options.colors[key])
68-
} else {
69-
replacer = this.htmlPattern.replace('{0}', key)
70-
}
71-
newText = newText.replace(match, pattern.replace('{0}', replacer))
72-
}
74+
const stringMatch = sqlString.substr(match.start, match.length)
7375

74-
let replacer = !this.options.html
75-
? this.unicodePattern.replace('{0}', this.options.colors.keyword)
76-
: this.htmlPattern.replace('{0}', 'keyword')
77-
78-
// Keywords
79-
for (let i = 0; i < keywords.length; i++) {
80-
let regEx = new RegExp(`\\b(${keywords[i]})\\b`, 'g')
81-
newText = newText.replace(regEx, replacer)
76+
if (options.html) {
77+
highlighted += `<span class="${options.classPrefix}${match.name}">`
78+
highlighted += stringMatch
79+
highlighted += '</span>'
80+
} else {
81+
highlighted += options.colors[match.name]
82+
highlighted += stringMatch
83+
highlighted += clearStyle
8284
}
8385

84-
return newText
86+
87+
if (nextMatch) {
88+
highlighted += sqlString.substr(match.start + match.length, nextMatch.start - (match.start + match.length))
89+
}
8590
}
91+
92+
return highlighted
93+
}
94+
95+
module.exports = {
96+
highlight
8697
}

keywords.js

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
const KEYWORDS = [
2+
'ADD',
3+
'ADD CONSTRAINT',
4+
'ALTER',
5+
'ALTER COLUMN',
6+
'ALTER TABLE',
7+
'ALL',
8+
'AND',
9+
'ANY',
10+
'AS',
11+
'ASC',
12+
'BACKUP DATABASE',
13+
'BETWEEN',
14+
'CASE',
15+
'CHECK',
16+
'COLUMN',
17+
'CONSTRAINT',
18+
'CREATE',
19+
'CREATE DATABASE',
20+
'CREATE INDEX',
21+
'CREATE OR REPLACE VIEW',
22+
'CREATE TABLE',
23+
'CREATE PROCEDURE',
24+
'CREATE UNIQUE INDEX',
25+
'CREATE VIEW',
26+
'DATABASE',
27+
'DEFAULT',
28+
'DELETE',
29+
'DESC',
30+
'DISTINCT',
31+
'DROP',
32+
'DROP COLUMN',
33+
'DROP CONSTRAINT',
34+
'DROP DATABASE',
35+
'DROP DEFAULT',
36+
'DROP INDEX',
37+
'DROP TABLE',
38+
'DROP VIEW',
39+
'EXEC',
40+
'EXISTS',
41+
'FOREIGN KEY',
42+
'FROM',
43+
'FULL OUTER JOIN',
44+
'GROUP BY',
45+
'HAVING',
46+
'IN',
47+
'INDEX',
48+
'INNER JOIN',
49+
'INSERT INTO',
50+
'INSERT INTO SELECT',
51+
'IS NULL',
52+
'IS NOT NULL',
53+
'JOIN',
54+
'LEFT JOIN',
55+
'LIKE',
56+
'LIMIT',
57+
'NOT',
58+
'NOT NULL',
59+
'OR',
60+
'ORDER BY',
61+
'OUTER JOIN',
62+
'PRIMARY KEY',
63+
'PROCEDURE',
64+
'RIGHT JOIN',
65+
'ROWNUM',
66+
'SELECT',
67+
'SELECT DISTINCT',
68+
'SELECT INTO',
69+
'SELECT TOP',
70+
'SET',
71+
'TABLE',
72+
'TOP',
73+
'TRUNCATE TABLE',
74+
'UNION',
75+
'UNION ALL',
76+
'UNIQUE',
77+
'UPDATE',
78+
'VALUES',
79+
'VIEW',
80+
'WHERE',
81+
'PRAGMA',
82+
'INTEGER',
83+
'PRIMARY',
84+
'letCHAR',
85+
'DATETIME',
86+
'NULL',
87+
'REFERENCES',
88+
'INDEX_LIST',
89+
'BY',
90+
'CURRENT_DATE',
91+
'CURRENT_TIME',
92+
'EACH',
93+
'ELSE',
94+
'ELSEIF',
95+
'FALSE',
96+
'FOR',
97+
'GROUP',
98+
'IF',
99+
'INSERT',
100+
'INTERVAL',
101+
'INTO',
102+
'IS',
103+
'KEY',
104+
'KEYS',
105+
'LEFT',
106+
'MATCH',
107+
'ON',
108+
'OPTION',
109+
'ORDER',
110+
'OUT',
111+
'OUTER',
112+
'REPLACE',
113+
'TINYINT',
114+
'RIGHT',
115+
'THEN',
116+
'TO',
117+
'TRUE',
118+
'WHEN',
119+
'UNSIGNED',
120+
'CASCADE',
121+
'ENGINE',
122+
'TEXT',
123+
'AUTO_INCREMENT',
124+
'SHOW'
125+
]
126+
127+
module.exports = [
128+
...KEYWORDS,
129+
...KEYWORDS.map((keyword) => keyword.toLowerCase())
130+
]

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sql-highlight",
3-
"version": "2.1.2",
3+
"version": "3.0.0",
44
"description": "A simple and lightweight syntax highlighting library for SQL",
55
"main": "index.js",
66
"repository": {

0 commit comments

Comments
 (0)