prettier-plugin-sql-cst 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,7 +8,7 @@ this plugin formats SQL expressions differently depending on their length.
8
8
  A short SQL query will be formatted on a single line:
9
9
 
10
10
  ```sql
11
- SELECT a, b, c FROM tbl WHERE x > 10
11
+ SELECT a, b, c FROM tbl WHERE x > 10;
12
12
  ```
13
13
 
14
14
  A longer query, will get each clause printed on a separate line:
@@ -16,7 +16,7 @@ A longer query, will get each clause printed on a separate line:
16
16
  ```sql
17
17
  SELECT id, client.name, client.priority
18
18
  FROM client
19
- WHERE client.id IN (12, 18, 121)
19
+ WHERE client.id IN (12, 18, 121);
20
20
  ```
21
21
 
22
22
  An even longer one gets the contents of each clause indented:
@@ -37,9 +37,22 @@ WHERE
37
37
  AND order.status IN ('active', 'pending', 'processing')
38
38
  GROUP BY client.id
39
39
  ORDER BY client.name
40
- LIMIT 100
40
+ LIMIT 100;
41
41
  ```
42
42
 
43
+ ## Formatting philosophy
44
+
45
+ - Adapt formatting based on expression length.
46
+ - Stick to one style and avoid configuration options.
47
+ - Format embedded languages (like JSON data and JavaScript programs).
48
+ - When unsure, preserve existing syntax.
49
+
50
+ Currently this plugin preserves most of the syntax elements
51
+ and concentrates mainly on the layout of whitespace.
52
+ For example it does not add/remove paratheses.
53
+
54
+ See [STYLE_GUIDE][] for overview of the SQL formatting style used.
55
+
43
56
  ## Getting started
44
57
 
45
58
  Install it as any other Prettier plugin:
@@ -51,49 +64,58 @@ npm install --save-dev prettier prettier-plugin-sql-cst
51
64
  Then use it on SQL files though Prettier command line tool or Prettier extension
52
65
  for your editor of choice.
53
66
 
67
+ ## Choosing an SQL dialect
68
+
69
+ By default the plugin will determine SQL dialect based on file extension:
70
+
71
+ - `.sql` or `.sqlite` - SQLite
72
+ - `.bigquery` - BigQuery
73
+
74
+ You can override this behavior with a prettier configuration:
75
+
76
+ ```json
77
+ {
78
+ "overrides": [
79
+ {
80
+ "files": ["*.sql"],
81
+ "options": { "parser": "bigquery" }
82
+ }
83
+ ]
84
+ }
85
+ ```
86
+
87
+ The plugin provides the following parsers:
88
+
89
+ - `sqlite`
90
+ - `bigquery`
91
+
54
92
  ## Configuration
55
93
 
56
94
  The standard Prettier options [printWidth][], [tabWidth][], [useTabs][] apply.
57
95
  There are also some SQL-specific options:
58
96
 
59
- | API Option | Default | Description |
60
- | ---------------- | :--------: | ------------------------------------------------------ |
61
- | `sqlKeywordCase` | `preserve` | Converts SQL keywords to `upper` or `lower` case. |
62
- | `sqlAliasAs` | `preserve` | Uses AS keyword in aliases either `always` or `never`. |
97
+ | API Option | Default | Description |
98
+ | ---------------- | :-----: | ------------------------------------------------------------------------- |
99
+ | `sqlKeywordCase` | `upper` | Converts SQL keywords to `upper` or `lower` case, or `preserve` existing. |
63
100
 
64
101
  ## Limitations and development status
65
102
 
66
- Currently this plugin supports most of **SQLite** syntax.
67
- (It also supports some **BigQuery**, but only the syntax that's subset of SQLite.)
103
+ Currently this plugin supports the most common everyday **SQLite** and **BigQuery** syntax.
68
104
  Formatting of the following SQL statements is fully implemented:
69
105
 
70
106
  - SELECT
71
107
  - UPDATE
72
108
  - INSERT
73
109
  - DELETE
110
+ - TRUNCATE
74
111
  - CREATE / DROP / ALTER TABLE
75
112
  - CREATE / DROP VIEW
76
113
  - CREATE / DROP INDEX
77
114
 
78
- Unlike Prettier for JavaScript, this plugin currently preserves all the syntax elements.
79
- For example it does not add/remove paratheses or modify the case of keywords (by default).
80
- It only manipulates whitespace.
81
-
82
- This will likely change in the future, with the goal of being more opinionated.
83
- Some possibilities:
84
-
85
- - capitalize all keywords
86
- - ensure all alias definitions use the `AS` keyword.
87
- - ensure consistent use of quotes (e.g. always quote keywords)
88
- - eliminate redundant parenthesis.
89
-
90
- The exact formatting style is also very much still in flux.
91
- The overall goal is to have no options to configure different styles,
92
- but rather to develop one opinionated style of formatting SQL.
93
-
94
115
  [prettier]: https://prettier.io/
95
116
  [printWidth]: https://prettier.io/docs/en/options.html#print-width
96
117
  [tabWidth]: https://prettier.io/docs/en/options.html#tab-width
97
118
  [useTabs]: https://prettier.io/docs/en/options.html#tabs
98
119
  [sql-parser-cst]: https://github.com/nene/sql-parser-cst
99
120
  [wadler-prettier]: http://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf
121
+ [STYLE_GUIDE]: ./STYLE_GUIDE.md
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.embedJson = void 0;
15
+ var node_utils_1 = require("./node_utils");
16
+ var print_utils_1 = require("./print_utils");
17
+ var embedJson = function (path, print, textToDoc, options) {
18
+ var node = path.getValue();
19
+ var parent = path.getParentNode();
20
+ if ((0, node_utils_1.isStringLiteral)(node) && (0, node_utils_1.isJsonLiteral)(parent)) {
21
+ if (containsTripleQuote(node.value) ||
22
+ containsBackslash(node.value) ||
23
+ isRawString(node)) {
24
+ // Give up for now. Don't format JSON inside the string.
25
+ // Tackle these corner-case in the future.
26
+ return null;
27
+ }
28
+ var json = textToDoc(node.value, __assign(__assign({}, options), { parser: "json" }));
29
+ var inlineQuote = containsSingleQuote(node.value) ? "'''" : "'";
30
+ return [
31
+ (0, print_utils_1.ifBreak)("'''", inlineQuote),
32
+ (0, print_utils_1.indent)([print_utils_1.softline, (0, print_utils_1.stripTrailingHardline)(json)]),
33
+ print_utils_1.softline,
34
+ (0, print_utils_1.ifBreak)("'''", inlineQuote),
35
+ ];
36
+ }
37
+ return null;
38
+ };
39
+ exports.embedJson = embedJson;
40
+ var containsSingleQuote = function (json) { return /'/.test(json); };
41
+ var containsTripleQuote = function (json) { return /'''/.test(json); };
42
+ var containsBackslash = function (json) { return /\\/.test(json); };
43
+ var isRawString = function (node) { return /^R/i.test(node.text); };
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.printers = exports.parsers = exports.languages = exports.options = void 0;
4
4
  var sql_parser_cst_1 = require("sql-parser-cst");
5
5
  var printSql_1 = require("./printSql");
6
+ var embedJson_1 = require("./embedJson");
6
7
  var utils_1 = require("./utils");
7
8
  var transformCst_1 = require("./transform/transformCst");
8
9
  var options_1 = require("./options");
@@ -11,12 +12,12 @@ exports.languages = [
11
12
  {
12
13
  extensions: [".sql", ".sqlite"],
13
14
  name: "SQLite SQL",
14
- parsers: ["sql-parser-cst-sqlite"],
15
+ parsers: ["sqlite"],
15
16
  },
16
17
  {
17
18
  extensions: [".bigquery"],
18
19
  name: "BigQuery SQL",
19
- parsers: ["sql-parser-cst-bigquery"],
20
+ parsers: ["bigquery"],
20
21
  },
21
22
  ];
22
23
  var createParser = function (dialect) { return ({
@@ -26,19 +27,20 @@ var createParser = function (dialect) { return ({
26
27
  includeRange: true,
27
28
  includeComments: true,
28
29
  filename: options.filepath,
29
- }), options);
30
+ }), text);
30
31
  },
31
32
  astFormat: "sql-cst",
32
33
  locStart: function (node) { var _a; return (_a = node.range) === null || _a === void 0 ? void 0 : _a[0]; },
33
34
  locEnd: function (node) { var _a; return (_a = node.range) === null || _a === void 0 ? void 0 : _a[1]; },
34
35
  }); };
35
36
  exports.parsers = {
36
- "sql-parser-cst-sqlite": createParser("sqlite"),
37
- "sql-parser-cst-bigquery": createParser("bigquery"),
37
+ sqlite: createParser("sqlite"),
38
+ bigquery: createParser("bigquery"),
38
39
  };
39
40
  exports.printers = {
40
41
  "sql-cst": {
41
42
  print: printSql_1.printSql,
43
+ embed: embedJson_1.embedJson,
42
44
  printComment: function (path) {
43
45
  return path.getValue().text;
44
46
  },
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isKeyword = exports.isCreateTableStmt = exports.isFuncCall = exports.isValuesClause = void 0;
3
+ exports.isAsClause = exports.isArraySubscript = exports.isStringLiteral = exports.isJsonLiteral = exports.isEmpty = exports.isKeyword = exports.isCreateTableStmt = exports.isFuncCall = exports.isValuesClause = void 0;
4
4
  var utils_1 = require("./utils");
5
5
  var is = function (type) {
6
6
  return function (node) {
@@ -11,3 +11,8 @@ exports.isValuesClause = is("values_clause");
11
11
  exports.isFuncCall = is("func_call");
12
12
  exports.isCreateTableStmt = is("create_table_stmt");
13
13
  exports.isKeyword = is("keyword");
14
+ exports.isEmpty = is("empty");
15
+ exports.isJsonLiteral = is("json_literal");
16
+ exports.isStringLiteral = is("string_literal");
17
+ exports.isArraySubscript = is("array_subscript");
18
+ exports.isAsClause = is("as_clause");
package/dist/options.js CHANGED
@@ -6,7 +6,7 @@ exports.options = {
6
6
  type: "choice",
7
7
  category: "SQL",
8
8
  since: "0.1.0",
9
- default: "preserve",
9
+ default: "upper",
10
10
  description: "Enforces upper/lower case for SQL keywords",
11
11
  choices: [
12
12
  {
@@ -17,16 +17,4 @@ exports.options = {
17
17
  { value: "lower", description: "forces all keywords to lowercase" },
18
18
  ],
19
19
  },
20
- sqlAliasAs: {
21
- type: "choice",
22
- category: "SQL",
23
- since: "0.1.1",
24
- default: "preserve",
25
- description: "Enforce or forbid use of AS keyword in aliases",
26
- choices: [
27
- { value: "preserve", description: "keeps existing style" },
28
- { value: "always", description: "always includes AS keyword" },
29
- { value: "never", description: "never include AS keyword" },
30
- ],
31
- },
32
20
  };
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.containsNewline = exports.join = exports.lineSuffix = exports.group = exports.indent = exports.softline = exports.hardline = exports.line = void 0;
4
+ exports.containsNewline = exports.join = exports.stripTrailingHardline = exports.breakParent = exports.ifBreak = exports.lineSuffix = exports.group = exports.indent = exports.softline = exports.hardline = exports.line = void 0;
5
5
  var prettier_1 = require("prettier");
6
6
  var utils_1 = require("./utils");
7
- exports.line = (_a = prettier_1.doc.builders, _a.line), exports.hardline = _a.hardline, exports.softline = _a.softline, exports.indent = _a.indent, exports.group = _a.group, exports.lineSuffix = _a.lineSuffix;
7
+ exports.line = (_a = prettier_1.doc.builders, _a.line), exports.hardline = _a.hardline, exports.softline = _a.softline, exports.indent = _a.indent, exports.group = _a.group, exports.lineSuffix = _a.lineSuffix, exports.ifBreak = _a.ifBreak, exports.breakParent = _a.breakParent;
8
8
  var origJoin = prettier_1.doc.builders.join;
9
+ exports.stripTrailingHardline = prettier_1.doc.utils.stripTrailingHardline;
9
10
  /** Improved join() that also accepts a non-array docs parameter */
10
11
  var join = function (sep, docs) {
11
12
  return (0, utils_1.isArray)(docs) ? origJoin(sep, docs) : docs;
@@ -4,14 +4,33 @@ exports.alterTableMap = void 0;
4
4
  var print_utils_1 = require("../print_utils");
5
5
  exports.alterTableMap = {
6
6
  alter_table_stmt: function (print) { return [
7
- print.spaced(["alterTableKw", "table"]),
7
+ print.spaced(["alterTableKw", "ifExistsKw", "table"]),
8
8
  print_utils_1.hardline,
9
9
  print("actions"),
10
10
  ]; },
11
11
  alter_action_rename_table: function (print) { return print.spaced(["renameKw", "newName"]); },
12
12
  alter_action_rename_column: function (print) {
13
- return print.spaced(["renameKw", "oldName", "toKw", "newName"]);
13
+ return print.spaced(["renameKw", "ifExistsKw", "oldName", "toKw", "newName"]);
14
+ },
15
+ alter_action_add_column: function (print) {
16
+ return print.spaced(["addKw", "ifNotExistsKw", "column"]);
17
+ },
18
+ alter_action_drop_column: function (print) {
19
+ return print.spaced(["dropKw", "ifExistsKw", "column"]);
20
+ },
21
+ alter_action_set_options: function (print) { return print.spaced(["setKw", "options"]); },
22
+ alter_action_set_default_collate: function (print) {
23
+ return print.spaced(["setDefaultCollateKw", "collation"]);
24
+ },
25
+ alter_action_alter_column: function (print) { return [
26
+ print.spaced(["alterKw", "ifExistsKw", "column"]),
27
+ print_utils_1.hardline,
28
+ print("action"),
29
+ ]; },
30
+ alter_action_set_default: function (print) { return print.spaced(["setDefaultKw", "expr"]); },
31
+ alter_action_drop_default: function (print) { return print.spaced("dropDefaultKw"); },
32
+ alter_action_drop_not_null: function (print) { return print.spaced("dropNotNullKw"); },
33
+ alter_action_set_data_type: function (print) {
34
+ return print.spaced(["setDataTypeKw", "dataType"]);
14
35
  },
15
- alter_action_add_column: function (print) { return print.spaced(["addKw", "column"]); },
16
- alter_action_drop_column: function (print) { return print.spaced(["dropKw", "column"]); },
17
36
  };
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.bigqueryMap = void 0;
4
+ exports.bigqueryMap = {
5
+ bigquery_options: function (print) { return print(["optionsKw", "options"]); },
6
+ bigquery_option_default_collate: function (print) {
7
+ return print.spaced(["defaultCollateKw", "collation"]);
8
+ },
9
+ };
@@ -1,22 +1,58 @@
1
1
  "use strict";
2
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
3
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
4
+ if (ar || !(i in from)) {
5
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
6
+ ar[i] = from[i];
7
+ }
8
+ }
9
+ return to.concat(ar || Array.prototype.slice.call(from));
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
12
  exports.createTableMap = void 0;
13
+ var node_utils_1 = require("../node_utils");
4
14
  var print_utils_1 = require("../print_utils");
5
15
  exports.createTableMap = {
6
- create_table_stmt: function (print, node) { return [
7
- print.spaced([
8
- "createKw",
9
- "temporaryKw",
10
- "tableKw",
11
- "ifNotExistsKw",
12
- "name",
13
- "columns",
14
- "clauses",
15
- ]),
16
- node.options ? [" ", (0, print_utils_1.group)(print("options"))] : [],
17
- ]; },
16
+ create_table_stmt: function (print, node) {
17
+ var rest = [];
18
+ for (var _i = 2; _i < arguments.length; _i++) {
19
+ rest[_i - 2] = arguments[_i];
20
+ }
21
+ return [
22
+ print.spaced([
23
+ "createKw",
24
+ "orReplaceKw",
25
+ "temporaryKw",
26
+ "externalKw",
27
+ "snapshotKw",
28
+ "tableKw",
29
+ "ifNotExistsKw",
30
+ "name",
31
+ "columns",
32
+ ]),
33
+ printClauses.apply(void 0, __spreadArray([print, node], rest, false)),
34
+ node.options ? [print_utils_1.line, (0, print_utils_1.group)(print("options"))] : [],
35
+ ];
36
+ },
18
37
  column_definition: function (print) {
19
38
  return print.spaced(["name", "dataType", "constraints"]);
20
39
  },
21
40
  table_option: function (print) { return print.spaced(["name"]); },
41
+ create_table_like_clause: function (print) { return print.spaced(["likeKw", "name"]); },
42
+ create_table_copy_clause: function (print) { return print.spaced(["copyKw", "name"]); },
43
+ create_table_clone_clause: function (print) { return print.spaced(["cloneKw", "table"]); },
44
+ with_partition_columns_clause: function (print) {
45
+ return print.spaced(["withPartitionColumnsKw", "columns"]);
46
+ },
47
+ };
48
+ var printClauses = function (print, node) {
49
+ if (node.clauses.length === 1 && (0, node_utils_1.isAsClause)(node.clauses[0])) {
50
+ return [" ", print("clauses")];
51
+ }
52
+ else if (node.clauses.length > 0) {
53
+ return [print_utils_1.line, (0, print_utils_1.join)(print_utils_1.line, print("clauses"))];
54
+ }
55
+ else {
56
+ return [];
57
+ }
22
58
  };
@@ -1,15 +1,15 @@
1
1
  "use strict";
2
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
3
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
4
- if (ar || !(i in from)) {
5
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
6
- ar[i] = from[i];
7
- }
8
- }
9
- return to.concat(ar || Array.prototype.slice.call(from));
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.dataTypeMap = void 0;
4
+ var utils_1 = require("../utils");
13
5
  exports.dataTypeMap = {
14
- data_type: function (print) { return __spreadArray([print.spaced("nameKw")], print(["params"]), true); },
6
+ // print single-word types as `TYPE(10)` and multi-word types as `MY TYPE (10)`
7
+ data_type: function (print, node) {
8
+ return ((0, utils_1.isArray)(node.nameKw) ? print.spaced : print)(["nameKw", "params"]);
9
+ },
10
+ generic_type_params: function (print) { return ["<", print("params"), ">"]; },
11
+ array_type_param: function (print) { return print.spaced(["dataType", "constraints"]); },
12
+ struct_type_param: function (print) {
13
+ return print.spaced(["name", "dataType", "constraints"]);
14
+ },
15
15
  };
@@ -3,6 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.dropTableMap = void 0;
4
4
  exports.dropTableMap = {
5
5
  drop_table_stmt: function (print) {
6
- return print.spaced(["dropKw", "tableKw", "ifExistsKw", "tables"]);
6
+ return print.spaced([
7
+ "dropKw",
8
+ "externalKw",
9
+ "snapshotKw",
10
+ "tableKw",
11
+ "ifExistsKw",
12
+ "tables",
13
+ ]);
7
14
  },
8
15
  };
@@ -12,10 +12,25 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.exprMap = void 0;
13
13
  var print_utils_1 = require("../print_utils");
14
14
  var node_utils_1 = require("../node_utils");
15
+ var utils_1 = require("../utils");
15
16
  exports.exprMap = {
16
17
  list_expr: function (print, node, path) {
17
18
  var parent = path.getParentNode();
18
- return (0, print_utils_1.join)([",", (0, node_utils_1.isValuesClause)(parent) ? print_utils_1.hardline : print_utils_1.line], print("items").map(function (it) { return (0, print_utils_1.group)(it); }));
19
+ var children = print("items").map(function (it) { return (0, print_utils_1.group)(it); });
20
+ var lineType = (0, node_utils_1.isValuesClause)(parent) ? print_utils_1.hardline : print_utils_1.line;
21
+ // When last item is type:empty, we're dealing with a trailing comma.
22
+ // Don't add a space (or newline) after it.
23
+ // We still want to print it though, as it might have comments attached.
24
+ if ((0, node_utils_1.isEmpty)((0, utils_1.last)(node.items))) {
25
+ return [
26
+ (0, print_utils_1.join)([",", lineType], children.slice(0, -1)),
27
+ ",",
28
+ (0, utils_1.last)(children),
29
+ ];
30
+ }
31
+ else {
32
+ return (0, print_utils_1.join)([",", lineType], children);
33
+ }
19
34
  },
20
35
  paren_expr: function (print, node, path) {
21
36
  var parent = path.getParentNode();
@@ -28,7 +43,9 @@ exports.exprMap = {
28
43
  }
29
44
  return print.spaced(["left", "operator", "right"]);
30
45
  },
31
- prefix_op_expr: function (print) { return print.spaced(["operator", "expr"]); },
46
+ prefix_op_expr: function (print, node) {
47
+ return ((0, utils_1.isString)(node.operator) ? print : print.spaced)(["operator", "expr"]);
48
+ },
32
49
  postfix_op_expr: function (print) { return print.spaced(["expr", "operator"]); },
33
50
  between_expr: function (print) {
34
51
  return print.spaced(["left", "betweenKw", "begin", "andKw", "end"]);
@@ -43,8 +60,16 @@ exports.exprMap = {
43
60
  return print.spaced(["whenKw", "condition", "thenKw", "result"]);
44
61
  },
45
62
  case_else: function (print) { return print.spaced(["elseKw", "result"]); },
46
- member_expr: function (print) { return [print("object"), ".", print("property")]; },
63
+ member_expr: function (print, node) {
64
+ return (0, node_utils_1.isArraySubscript)(node.property)
65
+ ? print(["object", "property"])
66
+ : [print("object"), ".", print("property")];
67
+ },
47
68
  bigquery_quoted_member_expr: function (print) { return ["`", print("expr"), "`"]; },
69
+ array_subscript: function (print) {
70
+ return (0, print_utils_1.group)(["[", (0, print_utils_1.indent)([print_utils_1.softline, print("expr")]), print_utils_1.softline, "]"]);
71
+ },
72
+ array_subscript_specifier: function (print) { return print(["specifierKw", "args"]); },
48
73
  func_call: function (print) {
49
74
  var fnCall = print(["name", "args"]);
50
75
  var extras = print(["filter", "over"]);
@@ -61,10 +86,28 @@ exports.exprMap = {
61
86
  cast_expr: function (print) { return print(["castKw", "args"]); },
62
87
  cast_arg: function (print) { return print.spaced(["expr", "asKw", "dataType"]); },
63
88
  raise_expr: function (print) { return print(["raiseKw", "args"]); },
89
+ interval_expr: function (print) { return print.spaced(["intervalKw", "expr", "unit"]); },
90
+ interval_unit_range: function (print) {
91
+ return print.spaced(["fromUnitKw", "toKw", "toUnitKw"]);
92
+ },
93
+ array_expr: function (print) {
94
+ return (0, print_utils_1.group)(["[", (0, print_utils_1.indent)([print_utils_1.softline, print("expr")]), print_utils_1.softline, "]"]);
95
+ },
96
+ struct_expr: function (print) {
97
+ return (0, print_utils_1.group)(["(", (0, print_utils_1.indent)([print_utils_1.softline, print("expr")]), print_utils_1.softline, ")"]);
98
+ },
99
+ typed_expr: function (print) { return print(["dataType", "expr"]); },
64
100
  number_literal: function (print) { return print("text"); },
65
101
  boolean_literal: function (print) { return print("valueKw"); },
66
102
  string_literal: function (print) { return print("text"); },
67
103
  null_literal: function (print) { return print("nullKw"); },
104
+ numeric_literal: function (print) { return print.spaced(["numericKw", "string"]); },
105
+ bignumeric_literal: function (print) { return print.spaced(["bignumericKw", "string"]); },
106
+ date_literal: function (print) { return print.spaced(["dateKw", "string"]); },
107
+ time_literal: function (print) { return print.spaced(["timeKw", "string"]); },
108
+ datetime_literal: function (print) { return print.spaced(["datetimeKw", "string"]); },
109
+ timestamp_literal: function (print) { return print.spaced(["timestampKw", "string"]); },
110
+ json_literal: function (print) { return print.spaced(["jsonKw", "string"]); },
68
111
  identifier: function (print) { return print("text"); },
69
112
  };
70
113
  var isBooleanOp = function (_a) {
@@ -14,6 +14,7 @@ exports.insertMap = {
14
14
  return (0, print_utils_1.group)([print("valuesKw"), (0, print_utils_1.indent)([print_utils_1.hardline, print("values")])]);
15
15
  },
16
16
  or_alternate_action: function (print) { return print.spaced(["orKw", "actionKw"]); },
17
+ default: function (print) { return print("defaultKw"); },
17
18
  default_values: function (print) { return print.spaced("defaultValuesKw"); },
18
19
  upsert_clause: function (print) {
19
20
  return print.spaced(["onConflictKw", "columns", "where", "doKw", "action"]);
@@ -4,4 +4,7 @@ exports.procClauseMap = void 0;
4
4
  var print_utils_1 = require("../print_utils");
5
5
  exports.procClauseMap = {
6
6
  as_clause: function (print) { return [print("asKw"), (0, print_utils_1.indent)([print_utils_1.hardline, print("expr")])]; },
7
+ with_connection_clause: function (print) {
8
+ return print.spaced(["withConnectionKw", "connection"]);
9
+ },
7
10
  };
@@ -3,19 +3,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.programMap = void 0;
4
4
  var print_utils_1 = require("../print_utils");
5
5
  exports.programMap = {
6
- program: function (print, node, path) { return path.map(printLineWith(print), "statements"); },
6
+ program: function (print, node) {
7
+ return print("statements").map(function (doc, i) {
8
+ return printStatement(doc, i, node.statements);
9
+ });
10
+ },
7
11
  };
8
- var printLineWith = function (print) {
9
- return function (childPath, i, all) {
10
- var node = childPath.getValue();
11
- if (i === 0) {
12
- return print(childPath);
13
- }
14
- else if (i < all.length - 1 || node.type !== "empty") {
15
- return [";", print_utils_1.hardline, print_utils_1.hardline, print(childPath)];
16
- }
17
- else {
18
- return [";", print(childPath)];
19
- }
20
- };
12
+ var printStatement = function (doc, i, statements) {
13
+ var node = statements[i];
14
+ if (i === 0) {
15
+ return doc;
16
+ }
17
+ else if (node.type !== "empty") {
18
+ return [";", print_utils_1.hardline, print_utils_1.hardline, doc];
19
+ }
20
+ else {
21
+ return [";", print_utils_1.hardline, doc];
22
+ }
21
23
  };
@@ -22,10 +22,11 @@ exports.selectMap = {
22
22
  " ",
23
23
  print.spaced(["asKw", "materializedKw", "expr"]),
24
24
  ]; },
25
- select_clause: function (print) {
25
+ select_clause: function (print, node, path, opts) {
26
26
  return (0, print_utils_1.group)([
27
- print.spaced(["selectKw", "distinctKw"]),
27
+ print.spaced(["selectKw", "distinctKw", "asStructOrValueKw"]),
28
28
  (0, print_utils_1.indent)([print_utils_1.line, print("columns")]),
29
+ (0, print_utils_1.containsNewline)(node, opts) ? print_utils_1.breakParent : [],
29
30
  ]);
30
31
  },
31
32
  except_columns: function (print) { return print.spaced(["expr", "exceptKw", "columns"]); },
@@ -57,6 +58,39 @@ exports.selectMap = {
57
58
  join_using_specification: function (print) { return (0, print_utils_1.group)(print.spaced(["usingKw", "expr"])); },
58
59
  indexed_table: function (print) { return print.spaced(["table", "indexedByKw", "index"]); },
59
60
  not_indexed_table: function (print) { return print.spaced(["table", "notIndexedKw"]); },
61
+ unnest_expr: function (print) { return print(["unnestKw", "expr"]); },
62
+ unnest_with_offset_expr: function (print) { return print.spaced(["unnest", "withOffsetKw"]); },
63
+ pivot_expr: function (print) { return [print("left"), print_utils_1.hardline, print(["pivotKw", "args"])]; },
64
+ pivot_for_in: function (print) {
65
+ return (0, print_utils_1.group)((0, print_utils_1.join)(print_utils_1.line, [
66
+ (0, print_utils_1.group)(print("aggregations")),
67
+ print.spaced(["forKw", "inputColumn"]),
68
+ print.spaced(["inKw", "pivotColumns"]),
69
+ ]));
70
+ },
71
+ unpivot_expr: function (print, node) { return [
72
+ print("left"),
73
+ print_utils_1.hardline,
74
+ (node.nullHandlingKw ? print.spaced : print)([
75
+ "unpivotKw",
76
+ "nullHandlingKw",
77
+ "args",
78
+ ]),
79
+ ]; },
80
+ unpivot_for_in: function (print) {
81
+ return (0, print_utils_1.group)((0, print_utils_1.join)(print_utils_1.line, [
82
+ print("valuesColumn"),
83
+ print.spaced(["forKw", "nameColumn"]),
84
+ print.spaced(["inKw", "unpivotColumns"]),
85
+ ]));
86
+ },
87
+ tablesample_expr: function (print) {
88
+ return (0, print_utils_1.group)([print("left"), print_utils_1.line, print.spaced(["tablesampleKw", "args"])]);
89
+ },
90
+ tablesample_percent: function (print) { return print.spaced(["percent", "percentKw"]); },
91
+ for_system_time_as_of_expr: function (print) {
92
+ return (0, print_utils_1.group)([print("left"), print_utils_1.line, print.spaced(["forSystemTimeAsOfKw", "expr"])]);
93
+ },
60
94
  where_clause: function (print) {
61
95
  return (0, print_utils_1.group)([print("whereKw"), (0, print_utils_1.indent)([print_utils_1.line, print("expr")])]);
62
96
  },
@@ -66,15 +100,22 @@ exports.selectMap = {
66
100
  group_by_clause: function (print) {
67
101
  return (0, print_utils_1.group)([print.spaced("groupByKw"), (0, print_utils_1.indent)([print_utils_1.line, print("columns")])]);
68
102
  },
103
+ group_by_rollup: function (print) { return print(["rollupKw", "columns"]); },
69
104
  partition_by_clause: function (print) {
70
105
  return (0, print_utils_1.group)([
71
106
  print.spaced("partitionByKw"),
72
107
  (0, print_utils_1.indent)([print_utils_1.line, print("specifications")]),
73
108
  ]);
74
109
  },
110
+ cluster_by_clause: function (print) {
111
+ return (0, print_utils_1.group)([print.spaced("clusterByKw"), (0, print_utils_1.indent)([print_utils_1.line, print("columns")])]);
112
+ },
75
113
  having_clause: function (print) {
76
114
  return (0, print_utils_1.group)([print("havingKw"), (0, print_utils_1.indent)([print_utils_1.line, print("expr")])]);
77
115
  },
116
+ qualify_clause: function (print) {
117
+ return (0, print_utils_1.group)([print("qualifyKw"), (0, print_utils_1.indent)([print_utils_1.line, print("expr")])]);
118
+ },
78
119
  returning_clause: function (print) {
79
120
  return (0, print_utils_1.group)([print("returningKw"), (0, print_utils_1.indent)([print_utils_1.line, print("columns")])]);
80
121
  },
@@ -15,6 +15,7 @@ exports.transformMap = void 0;
15
15
  var alias_1 = require("./alias");
16
16
  var alter_table_1 = require("./alter_table");
17
17
  var base_1 = require("./base");
18
+ var bigquery_1 = require("./bigquery");
18
19
  var constraint_1 = require("./constraint");
19
20
  var create_table_1 = require("./create_table");
20
21
  var data_type_1 = require("./data_type");
@@ -27,6 +28,7 @@ var insert_1 = require("./insert");
27
28
  var proc_clause_1 = require("./proc_clause");
28
29
  var program_1 = require("./program");
29
30
  var select_1 = require("./select");
31
+ var truncate_1 = require("./truncate");
30
32
  var update_1 = require("./update");
31
33
  var view_1 = require("./view");
32
- exports.transformMap = __assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign({}, alias_1.aliasMap), alter_table_1.alterTableMap), base_1.baseMap), constraint_1.constraintMap), create_table_1.createTableMap), data_type_1.dataTypeMap), delete_1.deleteMap), drop_table_1.dropTableMap), expr_1.exprMap), frame_1.frameMap), index_1.indexMap), insert_1.insertMap), proc_clause_1.procClauseMap), program_1.programMap), select_1.selectMap), update_1.updateMap), view_1.viewMap);
34
+ exports.transformMap = __assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign({}, alias_1.aliasMap), alter_table_1.alterTableMap), base_1.baseMap), bigquery_1.bigqueryMap), constraint_1.constraintMap), create_table_1.createTableMap), data_type_1.dataTypeMap), delete_1.deleteMap), drop_table_1.dropTableMap), expr_1.exprMap), frame_1.frameMap), index_1.indexMap), insert_1.insertMap), proc_clause_1.procClauseMap), program_1.programMap), select_1.selectMap), truncate_1.truncateMap), update_1.updateMap), view_1.viewMap);
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.truncateMap = void 0;
4
+ exports.truncateMap = {
5
+ truncate_stmt: function (print) { return print.spaced(["truncateTableKw", "table"]); },
6
+ };
@@ -3,19 +3,25 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.viewMap = void 0;
4
4
  var print_utils_1 = require("../print_utils");
5
5
  exports.viewMap = {
6
- create_view_stmt: function (print) { return [
7
- print.spaced([
8
- "createKw",
9
- "temporaryKw",
10
- "viewKw",
11
- "ifNotExistsKw",
12
- "name",
13
- "columns",
14
- "asKw",
15
- ]),
16
- (0, print_utils_1.indent)([print_utils_1.hardline, (0, print_utils_1.group)(print("expr"))]),
17
- ]; },
6
+ create_view_stmt: function (print, node) {
7
+ var hasOnlyAsClause = node.clauses.length === 1;
8
+ var hasManyClauses = node.clauses.length > 1;
9
+ return [
10
+ print.spaced([
11
+ "createKw",
12
+ "orReplaceKw",
13
+ "temporaryKw",
14
+ "materializedKw",
15
+ "viewKw",
16
+ "ifNotExistsKw",
17
+ "name",
18
+ "columns",
19
+ ]),
20
+ hasOnlyAsClause ? [" ", print("clauses")] : [],
21
+ hasManyClauses ? [print_utils_1.hardline, (0, print_utils_1.join)(print_utils_1.hardline, print("clauses"))] : [],
22
+ ];
23
+ },
18
24
  drop_view_stmt: function (print) {
19
- return print.spaced(["dropKw", "viewKw", "ifExistsKw", "views"]);
25
+ return print.spaced(["dropKw", "materializedKw", "viewKw", "ifExistsKw", "views"]);
20
26
  },
21
27
  };
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addFinalSemicolon = void 0;
4
+ var node_utils_1 = require("../node_utils");
5
+ var utils_1 = require("../utils");
6
+ var addFinalSemicolon = function (program, originalText) {
7
+ if (!(0, node_utils_1.isEmpty)((0, utils_1.last)(program.statements))) {
8
+ var end = originalText.length;
9
+ program.statements.push({ type: "empty", range: [end, end] });
10
+ }
11
+ return program;
12
+ };
13
+ exports.addFinalSemicolon = addFinalSemicolon;
@@ -1,36 +1,12 @@
1
1
  "use strict";
2
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
3
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
4
- if (ar || !(i in from)) {
5
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
6
- ar[i] = from[i];
7
- }
8
- }
9
- return to.concat(ar || Array.prototype.slice.call(from));
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.processAliasAs = void 0;
13
4
  var sql_parser_cst_1 = require("sql-parser-cst");
14
- var processAliasAs = function (cst, options) {
5
+ // Adds AS keyword to aliases if none exists
6
+ var processAliasAs = function (cst) {
15
7
  var mutateAliases = (0, sql_parser_cst_1.cstVisitor)({
16
8
  alias: function (node) {
17
- var _a, _b;
18
- switch (options.sqlAliasAs) {
19
- case "preserve":
20
- // do nothing
21
- break;
22
- case "always":
23
- // Add AS keyword if none exists
24
- node.asKw = node.asKw || { type: "keyword", name: "AS", text: "AS" };
25
- break;
26
- case "never":
27
- // Remove AS keyword and ensure comments attached to it don't get lost
28
- if (node.asKw && (((_a = node.leading) === null || _a === void 0 ? void 0 : _a.length) || ((_b = node.trailing) === null || _b === void 0 ? void 0 : _b.length))) {
29
- var comments = __spreadArray(__spreadArray([], (node.leading || []), true), (node.trailing || []), true);
30
- node.alias.leading = __spreadArray(__spreadArray([], comments, true), (node.alias.leading || []), true);
31
- }
32
- node.asKw = undefined;
33
- }
9
+ node.asKw = node.asKw || { type: "keyword", name: "AS", text: "AS" };
34
10
  },
35
11
  });
36
12
  mutateAliases(cst);
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stripTrailingCommas = void 0;
4
+ var sql_parser_cst_1 = require("sql-parser-cst");
5
+ var node_utils_1 = require("../node_utils");
6
+ var utils_1 = require("../utils");
7
+ // Removes trailing comma from SELECT clauses
8
+ var stripTrailingCommas = function (cst) {
9
+ // Trailing comma is represented as an empty element at the end of column list
10
+ var removeLastEmptyColumn = (0, sql_parser_cst_1.cstVisitor)({
11
+ select_clause: function (node) {
12
+ if ((0, node_utils_1.isEmpty)((0, utils_1.last)(node.columns.items))) {
13
+ node.columns.items = node.columns.items.slice(0, -1);
14
+ }
15
+ },
16
+ });
17
+ removeLastEmptyColumn(cst);
18
+ return cst;
19
+ };
20
+ exports.stripTrailingCommas = stripTrailingCommas;
@@ -3,5 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.transformCst = void 0;
4
4
  var comments_1 = require("./comments");
5
5
  var aliasAs_1 = require("./aliasAs");
6
- var transformCst = function (cst, options) { return (0, comments_1.moveCommentsToRoot)((0, aliasAs_1.processAliasAs)(cst, options)); };
6
+ var stripTrailingCommas_1 = require("./stripTrailingCommas");
7
+ var addFinalSemicolon_1 = require("./addFinalSemicolon");
8
+ // Note that we first perform moveCommentsToRoot transform,
9
+ // so we don't need to worry about comments interfering with other transforms
10
+ var transformCst = function (cst, originalText) {
11
+ return (0, addFinalSemicolon_1.addFinalSemicolon)((0, stripTrailingCommas_1.stripTrailingCommas)((0, aliasAs_1.processAliasAs)((0, comments_1.moveCommentsToRoot)(cst))), originalText);
12
+ };
7
13
  exports.transformCst = transformCst;
package/dist/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.arrayWrap = exports.isNode = exports.isEmptyArray = exports.isArray = exports.isObject = exports.isString = exports.isDefined = void 0;
3
+ exports.last = exports.arrayWrap = exports.isNode = exports.isEmptyArray = exports.isArray = exports.isObject = exports.isString = exports.isDefined = void 0;
4
4
  var isDefined = function (value) {
5
5
  return value !== undefined;
6
6
  };
@@ -26,3 +26,5 @@ var isCommentType = function (type) {
26
26
  };
27
27
  var arrayWrap = function (x) { return ((0, exports.isArray)(x) ? x : [x]); };
28
28
  exports.arrayWrap = arrayWrap;
29
+ var last = function (arr) { return arr[arr.length - 1]; };
30
+ exports.last = last;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prettier-plugin-sql-cst",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Prettier plugin for SQL",
5
5
  "author": "Rene Saarsoo <nene@triin.net>",
6
6
  "license": "GPL-3.0-or-later",
@@ -29,7 +29,7 @@
29
29
  ],
30
30
  "dependencies": {
31
31
  "prettier": "^2.8.2",
32
- "sql-parser-cst": "^0.11.0"
32
+ "sql-parser-cst": "^0.12.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/jest": "^29.2.5",