Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SQL and JSON language support #23

Merged
merged 5 commits into from
Jun 14, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@ HTML (including [Handlebars](http://handlebarsjs.com/)),
CSS (including [Sass](http://sass-lang.com/) and [LESS](http://lesscss.org/))
and JavaScript in Atom.

Atom Package: https://atom.io/packages/atom-beautify

## Language Support

- JavaScript
- JavaScript and JSON
- HTML, including
- [Handlebars](http://handlebarsjs.com/)
- XML is supported as an *experimental feature*.
- XML
- CSS, including
- [Sass](http://sass-lang.com/)
- [LESS](http://lesscss.org/)
- SQL, special thanks to [pretty-data](https://github.com/vkiryukhin/pretty-data)

## Usage

Expand Down Expand Up @@ -89,6 +92,12 @@ See [examples/nested-jsbeautifyrc/.jsbeautifyrc](https://github.com/donaldpipowi
"preserve_newlines": true,
"max_preserve_newlines": 2,
"jslint_happy": true
},
"sql": {
"indent_size": 4,
"indent_char": " ",
"indent_level": 0,
"indent_with_tabs": false
}
}
```
Expand Down
6 changes: 6 additions & 0 deletions examples/nested-jsbeautifyrc/.jsbeautifyrc
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,11 @@
"preserve_newlines": true,
"max_preserve_newlines": 2,
"jslint_happy": true
},
"sql": {
"indent_size": 4,
"indent_char": " ",
"indent_level": 0,
"indent_with_tabs": false
}
}
1 change: 1 addition & 0 deletions examples/nested-jsbeautifyrc/test.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SELECT ca.proj_id AS proj_id, ca.ca_name AS proj_name, ca.ca_date_start AS proj_start, ca.ca_date_end AS proj_end,(SELECT COUNT(*) FROM rotations r WHERE r.proj_id = proj_id AND r.r_status = 'R' GROUP BY r.proj_id) r_count, (SELECT count(*) FROM rotations r WHERE r.proj_id = proj_id AND r.channel_id = 24 ) r_rtb_count FROM projs ca, clients c, proj_auth caa WHERE ca.client_id = 12345 AND ca.client_id = c.client_id AND ca_type = 'zzz' AND c.agency_id = 0 AND ca.client_id = NVL( caa.client_id, ca.client_id ) AND proj_id = NVL( caa.proj_id, proj_id ) AND caa.contact_id = 7890
9 changes: 9 additions & 0 deletions examples/simple-jsbeautifyrc/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"indent_size": 2,
"indent_char": " ", // test
"indent_level": 0,
"indent_with_tabs": false, /* test */
"preserve_newlines": true,
"max_preserve_newlines": 2, /* test *
"jslint_happy": true
}
1 change: 1 addition & 0 deletions examples/simple-jsbeautifyrc/test.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SELECT ca.proj_id AS proj_id, ca.ca_name AS proj_name, ca.ca_date_start AS proj_start, ca.ca_date_end AS proj_end,(SELECT COUNT(*) FROM rotations r WHERE r.proj_id = proj_id AND r.r_status = 'R' GROUP BY r.proj_id) r_count, (SELECT count(*) FROM rotations r WHERE r.proj_id = proj_id AND r.channel_id = 24 ) r_rtb_count FROM projs ca, clients c, proj_auth caa WHERE ca.client_id = 12345 AND ca.client_id = c.client_id AND ca_type = 'zzz' AND c.agency_id = 0 AND ca.client_id = NVL( caa.client_id, ca.client_id ) AND proj_id = NVL( caa.proj_id, proj_id ) AND caa.contact_id = 7890
18 changes: 13 additions & 5 deletions lib/atom-beautify.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
var beautifyJS = require('js-beautify');
var beautifyHTML = require('js-beautify').html;
var beautifyCSS = require('js-beautify').css;
var beautifySQL = require('./sql-beautify');
var fs = require('fs');
var path = require('path');
var nopt = require('nopt');
Expand Down Expand Up @@ -82,7 +83,7 @@ function setCursors(editor, posArray) {
}

function verifyExists(fullPath) {
return fs.existsSync(fullPath) ? fullPath : null;
return fs.existsSync(fullPath) ? fullPath : null;
}

// Storage for memoized results from find file
Expand Down Expand Up @@ -154,7 +155,7 @@ function beautify() {

var text;
var editor = atom.workspace.getActiveEditor();
var isSelection = !! editor.getSelectedText();
var isSelection = !!editor.getSelectedText();
var softTabs = editor.softTabs;
var tabLength = editor.getTabLength();

Expand All @@ -181,6 +182,7 @@ function beautify() {
encoding: 'utf8'
})));
} catch (e) {
console.log('Failed parsing config JSON at '+configPath);
externalOptions = {};
}
} else {
Expand Down Expand Up @@ -208,7 +210,7 @@ function beautify() {
function getOptions(selection, allOptions) {

// Reduce all options into correctly merged options.
var options = _.reduce(allOptions, function(result, currOptions) {
var options = _.reduce(allOptions, function (result, currOptions) {

var containsNested = false;
var collectedConfig = {};
Expand All @@ -224,7 +226,7 @@ function beautify() {

// Create a flat object of config options if nested format was used
if (!containsNested) {
collectedConfig = currOptions;
_.merge(collectedConfig, currOptions);
} else {
// Merge with selected options
// where `selection` could be `html`, `js`, 'css', etc
Expand All @@ -235,7 +237,6 @@ function beautify() {

}, {});


// TODO: Clean.
// There is a bug in nopt
// See https://github.com/npm/nopt/issues/38#issuecomment-45971505
Expand All @@ -247,6 +248,9 @@ function beautify() {
}

switch (editor.getGrammar().name) {
case 'JSON':
// Treat JSON as JavaScript, because it will support comments.
// And Glavin001 has tested JSON beauifying with beautifyJS.
case 'JavaScript':
text = beautifyJS(text, getOptions('js', allOptions));
break;
Expand All @@ -263,6 +267,10 @@ function beautify() {
case 'CSS':
text = beautifyCSS(text, getOptions('css', allOptions));
break;
case 'SQL (Rails)':
case 'SQL':
text = beautifySQL(text, getOptions('sql', allOptions));
break;
default:
return;
}
Expand Down
144 changes: 144 additions & 0 deletions lib/sql-beautify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/**
Original SQL Beautifier Source code from https://github.com/vkiryukhin/pretty-data
*/
'use strict';

module.exports = function (text, options) {

function SQL() {
var self = this;

self.step = ' '; // 2 spaces
self.shift = ['\n']; // array of shifts
var maxdeep = 100, // nesting level
ix = 0;

// initialize array with shifts //
for (ix = 0; ix < maxdeep; ix++) {
self.shift.push(self.shift[ix] + self.step);
}
}

function isSubquery(str, parenthesisLevel) {
return parenthesisLevel - (str.replace(/\(/g, '').length - str.replace(/\)/g, '').length);
}

function splitSql(str, tab) {

return str.replace(/\s{1,}/g, ' ')

.replace(/ AND /ig, '~::~' + tab + tab + 'AND ')
.replace(/ BETWEEN /ig, '~::~' + tab + 'BETWEEN ')
.replace(/ CASE /ig, '~::~' + tab + 'CASE ')
.replace(/ ELSE /ig, '~::~' + tab + 'ELSE ')
.replace(/ END /ig, '~::~' + tab + 'END ')
.replace(/ FROM /ig, '~::~FROM ')
.replace(/ GROUP\s{1,}BY/ig, '~::~GROUP BY ')
.replace(/ HAVING /ig, '~::~HAVING ')
//.replace(/ IN /ig,'~::~'+tab+'IN ')
.replace(/ IN /ig, ' IN ')
.replace(/ JOIN /ig, '~::~JOIN ')
.replace(/ CROSS~::~{1,}JOIN /ig, '~::~CROSS JOIN ')
.replace(/ INNER~::~{1,}JOIN /ig, '~::~INNER JOIN ')
.replace(/ LEFT~::~{1,}JOIN /ig, '~::~LEFT JOIN ')
.replace(/ RIGHT~::~{1,}JOIN /ig, '~::~RIGHT JOIN ')
.replace(/ ON /ig, '~::~' + tab + 'ON ')
.replace(/ OR /ig, '~::~' + tab + tab + 'OR ')
.replace(/ ORDER\s{1,}BY/ig, '~::~ORDER BY ')
.replace(/ OVER /ig, '~::~' + tab + 'OVER ')
.replace(/\(\s{0,}SELECT /ig, '~::~(SELECT ')
.replace(/\)\s{0,}SELECT /ig, ')~::~SELECT ')
.replace(/ THEN /ig, ' THEN~::~' + tab + '')
.replace(/ UNION /ig, '~::~UNION~::~')
.replace(/ USING /ig, '~::~USING ')
.replace(/ WHEN /ig, '~::~' + tab + 'WHEN ')
.replace(/ WHERE /ig, '~::~WHERE ')
.replace(/ WITH /ig, '~::~WITH ')
//.replace(/\,\s{0,}\(/ig,',~::~( ')
//.replace(/\,/ig,',~::~'+tab+tab+'')
.replace(/ ALL /ig, ' ALL ')
.replace(/ AS /ig, ' AS ')
.replace(/ ASC /ig, ' ASC ')
.replace(/ DESC /ig, ' DESC ')
.replace(/ DISTINCT /ig, ' DISTINCT ')
.replace(/ EXISTS /ig, ' EXISTS ')
.replace(/ NOT /ig, ' NOT ')
.replace(/ NULL /ig, ' NULL ')
.replace(/ LIKE /ig, ' LIKE ')
.replace(/\s{0,}SELECT /ig, 'SELECT ')
.replace(/~::~{1,}/g, '~::~')
.split('~::~');
}

SQL.prototype.beautify = function (text, options) {

/* jshint camelcase: false */
// Apply options
// options.indent_size = Indentation size [4]
// options.indent_char = Indentation character [" "]
this.step = new Array(options.indent_size).join(options.indent_char);
// Initial indentation level [0]
if (options.indent_level) {
// Not supported.
}
// Indent with tabs, overrides indent_size and indent_char
if (!!options.indent_with_tabs) {
this.step = '\t';
}

var arByQuote = text.replace(/\s{1,}/g, ' ')
.replace(/\'/ig, '~::~\'')
.split('~::~'),
len = arByQuote.length,
ar = [],
deep = 0,
tab = this.step,
inComment = true,
inQuote = false,
parenthesisLevel = 0,
str = '',
ix = 0;

for (ix = 0; ix < len; ix++) {

if (ix % 2) {
ar = ar.concat(arByQuote[ix]);
} else {
ar = ar.concat(splitSql(arByQuote[ix], tab));
}
}

len = ar.length;
for (ix = 0; ix < len; ix++) {

parenthesisLevel = isSubquery(ar[ix], parenthesisLevel);

if (/\s{0,}\s{0,}SELECT\s{0,}/.exec(ar[ix])) {
ar[ix] = ar[ix].replace(/\,/g, ',\n' + tab + tab + '');
}

if (/\s{0,}\(\s{0,}SELECT\s{0,}/.exec(ar[ix])) {
deep++;
str += this.shift[deep] + ar[ix];
} else
if (/\'/.exec(ar[ix])) {
if (parenthesisLevel < 1 && deep) {
deep--;
}
str += ar[ix];
} else {
str += this.shift[deep] + ar[ix];
if (parenthesisLevel < 1 && deep) {
deep--;
}
}
}

str = str.replace(/^\n{1,}/, '').replace(/\n{1,}/g, '\n');
return str;

};

return new SQL().beautify(text, options);

};