prettier-plugin-bq 1.0.0-beta.1 → 1.0.0-beta.3
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 +58 -0
- package/dist/index.d.ts +51 -1
- package/dist/index.js +7 -8
- package/dist/index.js.map +1 -1
- package/dist/printer.js +137 -31
- package/dist/printer.js.map +1 -1
- package/package.json +4 -3
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# prettier-plugin-bq
|
|
2
|
+
|
|
3
|
+
`prettier-plugin-bq` is a [prettier](https://prettier.io/) plugin for **GoogleSQL**, which is a dialect of BigQuery.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- support [pipe syntax](https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax)
|
|
8
|
+
- support [procedural language](https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language) (a.k.a BigQuery Scripting)
|
|
9
|
+
- try to handle jinja templates (though not perfect)
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
npm install --save-dev prettier prettier-plugin-bq
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
You can format `.sql` and `.bq` file by the following command.
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
npx prettier --write ./xxx.sql --plugin=prettier-plugin-bq
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If you want to omit `--plugin=prettier-plugin-bq`, add the plugin to your `.prettierrc`.
|
|
26
|
+
|
|
27
|
+
```jsonc
|
|
28
|
+
// .prettierrc
|
|
29
|
+
{
|
|
30
|
+
"plugins": ["prettier-plugin-bq"]
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
For more information, please read the prettier document.
|
|
35
|
+
|
|
36
|
+
## Configuration
|
|
37
|
+
|
|
38
|
+
`prettier-plugin-bq` supports the options below.
|
|
39
|
+
|
|
40
|
+
| API Option | CLI Option | Default | Description |
|
|
41
|
+
| ------------------------ | ---------------------------- | ------- | -------------------------------------------------------------------------------------------------------------- |
|
|
42
|
+
| indentCte | indent-cte | true | Indent CTEs in with clause. |
|
|
43
|
+
| printBlankLineAfterCte | print-blank-line-after-cte | false | Print blank line after CTE in with clause. |
|
|
44
|
+
| printKeywordsInUpperCase | print-keywords-in-upper-case | true | Print keywords, built-in functions and pseudo columns (e.g. `_PARTITIONDATE`, `_PARTITIONTIME`) in upper case. |
|
|
45
|
+
|
|
46
|
+
> [!NOTE]
|
|
47
|
+
>
|
|
48
|
+
> `printPseudoColumnsInUpperCase` was merged into printKeywordsInUpperCase.
|
|
49
|
+
|
|
50
|
+
## Coding style
|
|
51
|
+
|
|
52
|
+
This plugin doesn't follow any famous style guides,
|
|
53
|
+
because none of them account for GoogleSQL's latest syntax (such as pipe syntax).
|
|
54
|
+
|
|
55
|
+
## Feedback
|
|
56
|
+
|
|
57
|
+
I'm not ready to accept pull requests, but your feedback is always welcome.
|
|
58
|
+
If you find any bugs, please feel free to create an issue.
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,51 @@
|
|
|
1
|
-
|
|
1
|
+
declare const languages: {
|
|
2
|
+
extensions: string[];
|
|
3
|
+
name: string;
|
|
4
|
+
parsers: string[];
|
|
5
|
+
}[];
|
|
6
|
+
declare const parsers: {
|
|
7
|
+
"sql-parse": {
|
|
8
|
+
parse: (text: string) => import("bq2cst").UnknownNode[];
|
|
9
|
+
astFormat: string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
declare const printers: {
|
|
13
|
+
"sql-ast": {
|
|
14
|
+
print: (path: import("prettier").AstPath, options: {
|
|
15
|
+
[x: string]: unknown;
|
|
16
|
+
}, print: (path: import("prettier").AstPath) => import("prettier").Doc) => import("prettier").Doc;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
declare const options: {
|
|
20
|
+
formatMultilineComment: {
|
|
21
|
+
type: string;
|
|
22
|
+
category: string;
|
|
23
|
+
default: boolean;
|
|
24
|
+
description: string;
|
|
25
|
+
};
|
|
26
|
+
indentCte: {
|
|
27
|
+
type: string;
|
|
28
|
+
category: string;
|
|
29
|
+
default: boolean;
|
|
30
|
+
description: string;
|
|
31
|
+
};
|
|
32
|
+
printBlankLineAfterCte: {
|
|
33
|
+
type: string;
|
|
34
|
+
category: string;
|
|
35
|
+
default: boolean;
|
|
36
|
+
description: string;
|
|
37
|
+
};
|
|
38
|
+
printKeywordsInUpperCase: {
|
|
39
|
+
type: string;
|
|
40
|
+
category: string;
|
|
41
|
+
default: boolean;
|
|
42
|
+
description: string;
|
|
43
|
+
};
|
|
44
|
+
printPseudoColumnsInUpperCase: {
|
|
45
|
+
type: string;
|
|
46
|
+
category: string;
|
|
47
|
+
default: boolean;
|
|
48
|
+
description: string;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
export { languages, parsers, printers, options };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.options = exports.printers = exports.parsers = exports.languages = void 0;
|
|
3
4
|
const bq2cst_1 = require("bq2cst");
|
|
4
5
|
const printer_1 = require("./printer");
|
|
5
6
|
const languages = [
|
|
@@ -9,17 +10,20 @@ const languages = [
|
|
|
9
10
|
parsers: ["sql-parse"],
|
|
10
11
|
},
|
|
11
12
|
];
|
|
13
|
+
exports.languages = languages;
|
|
12
14
|
const parsers = {
|
|
13
15
|
"sql-parse": {
|
|
14
16
|
parse: (text) => (0, bq2cst_1.parse)(text),
|
|
15
17
|
astFormat: "sql-ast",
|
|
16
18
|
},
|
|
17
19
|
};
|
|
20
|
+
exports.parsers = parsers;
|
|
18
21
|
const printers = {
|
|
19
22
|
"sql-ast": {
|
|
20
23
|
print: printer_1.printSQL,
|
|
21
24
|
},
|
|
22
25
|
};
|
|
26
|
+
exports.printers = printers;
|
|
23
27
|
const CATEGORY_BQ = "BQ";
|
|
24
28
|
const options = {
|
|
25
29
|
formatMultilineComment: {
|
|
@@ -44,19 +48,14 @@ const options = {
|
|
|
44
48
|
type: "boolean",
|
|
45
49
|
category: CATEGORY_BQ,
|
|
46
50
|
default: true,
|
|
47
|
-
description: "Print
|
|
51
|
+
description: "Print keywords, built-in functions and pseudo columns in upper case.",
|
|
48
52
|
},
|
|
49
53
|
printPseudoColumnsInUpperCase: {
|
|
50
54
|
type: "boolean",
|
|
51
55
|
category: CATEGORY_BQ,
|
|
52
56
|
default: true,
|
|
53
|
-
description: "
|
|
57
|
+
description: "Deprecated: This option was merged into printKeywordsInUpperCase.",
|
|
54
58
|
},
|
|
55
59
|
};
|
|
56
|
-
|
|
57
|
-
languages,
|
|
58
|
-
parsers,
|
|
59
|
-
printers,
|
|
60
|
-
options,
|
|
61
|
-
};
|
|
60
|
+
exports.options = options;
|
|
62
61
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mCAA+B;AAC/B,uCAAqC;AAErC,MAAM,SAAS,GAAG;IAChB;QACE,UAAU,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC;QAC3B,IAAI,EAAE,KAAK;QACX,OAAO,EAAE,CAAC,WAAW,CAAC;KACvB;CACF,CAAC;AAoDO,8BAAS;AAlDlB,MAAM,OAAO,GAAG;IACd,WAAW,EAAE;QACX,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAA,cAAK,EAAC,IAAI,CAAC;QACpC,SAAS,EAAE,SAAS;KACrB;CACF,CAAC;AA6CkB,0BAAO;AA3C3B,MAAM,QAAQ,GAAG;IACf,SAAS,EAAE;QACT,KAAK,EAAE,kBAAQ;KAChB;CACF,CAAC;AAuC2B,4BAAQ;AArCrC,MAAM,WAAW,GAAG,IAAI,CAAC;AAEzB,MAAM,OAAO,GAAG;IACd,sBAAsB,EAAE;QACtB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,WAAW;QACrB,OAAO,EAAE,KAAK;QACd,WAAW,EAAE,2BAA2B;KACzC;IACD,SAAS,EAAE;QACT,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,WAAW;QACrB,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,4BAA4B;KAC1C;IACD,sBAAsB,EAAE;QACtB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,WAAW;QACrB,OAAO,EAAE,KAAK;QACd,WAAW,EAAE,4CAA4C;KAC1D;IACD,wBAAwB,EAAE;QACxB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,WAAW;QACrB,OAAO,EAAE,IAAI;QACb,WAAW,EACT,sEAAsE;KACzE;IACD,6BAA6B,EAAE;QAC7B,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,WAAW;QACrB,OAAO,EAAE,IAAI;QACb,WAAW,EACT,mEAAmE;KACtE;CACF,CAAC;AAEqC,0BAAO"}
|
package/dist/printer.js
CHANGED
|
@@ -207,7 +207,7 @@ class Printer {
|
|
|
207
207
|
else if (!this.node.notGlobal && this.includedIn(keywords_1.reservedKeywords)) {
|
|
208
208
|
literal = literal.toUpperCase();
|
|
209
209
|
}
|
|
210
|
-
else if (this.options.
|
|
210
|
+
else if (this.options.printKeywordsInUpperCase &&
|
|
211
211
|
(literal.match(/^_PARTITION/i) ||
|
|
212
212
|
literal.match(/^_TABLE_/i) ||
|
|
213
213
|
literal.match(/^_FILE_/i) ||
|
|
@@ -355,40 +355,57 @@ const getFirstNode = (node, includeComment = false) => {
|
|
|
355
355
|
}
|
|
356
356
|
return res;
|
|
357
357
|
};
|
|
358
|
+
const getLastNode = (node, includeComment = false) => {
|
|
359
|
+
const candidates = [];
|
|
360
|
+
for (const [k, v] of Object.entries(node.children)) {
|
|
361
|
+
if (["leading_comments", "trailing_comments"].includes(k) &&
|
|
362
|
+
!includeComment) {
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
if ((0, exports.isNodeChild)(v)) {
|
|
366
|
+
candidates.push(getLastNode(v.Node, includeComment));
|
|
367
|
+
}
|
|
368
|
+
else if ((0, exports.isNodeVecChild)(v)) {
|
|
369
|
+
// NOTE maybe you don't have to check 2nd, 3rd, or latter node
|
|
370
|
+
v.NodeVec.forEach((x) => candidates.push(getLastNode(x, includeComment)));
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
let res = node;
|
|
374
|
+
for (const c of candidates) {
|
|
375
|
+
if (!c.token) {
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
if (!res.token) {
|
|
379
|
+
res = c;
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
if (res.token.line < c.token.line ||
|
|
383
|
+
(c.token.line === res.token.line && res.token.column < c.token.column)) {
|
|
384
|
+
res = c;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return res;
|
|
388
|
+
};
|
|
358
389
|
const printSQL = (path, options, print) => {
|
|
359
390
|
const node = path.node;
|
|
360
391
|
if (Array.isArray(node)) {
|
|
361
392
|
for (let i = 0; i < node.length - 1; i++) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const last_comments = comments[len - 1];
|
|
373
|
-
endLine = last_comments.token.line;
|
|
374
|
-
const endLiteral = last_comments.token.literal;
|
|
375
|
-
const newLines = endLiteral.match(/\n/g);
|
|
376
|
-
if (newLines) {
|
|
377
|
-
endLine += newLines.length;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
// start of statement
|
|
381
|
-
const startNode = getFirstNode(node[i + 1], true);
|
|
382
|
-
let startLine;
|
|
383
|
-
if (startNode.token) {
|
|
384
|
-
startLine = startNode.token.line;
|
|
385
|
-
}
|
|
386
|
-
else {
|
|
387
|
-
// EOF
|
|
388
|
-
startLine = endLine + 1;
|
|
389
|
-
}
|
|
390
|
-
node[i].emptyLines = startLine - endLine - 1; // >= -1
|
|
393
|
+
if ("semicolon" in node[i].children ||
|
|
394
|
+
node[i].node_type === "StandAloneExpr") {
|
|
395
|
+
const endNode = getLastNode(node[i], true);
|
|
396
|
+
if (!endNode.token)
|
|
397
|
+
continue;
|
|
398
|
+
const endLine = endNode.token.line;
|
|
399
|
+
const startNode = getFirstNode(node[i + 1], true);
|
|
400
|
+
let startLine;
|
|
401
|
+
if (startNode.token) {
|
|
402
|
+
startLine = startNode.token.line;
|
|
391
403
|
}
|
|
404
|
+
else {
|
|
405
|
+
// EOF
|
|
406
|
+
startLine = endLine + 1;
|
|
407
|
+
}
|
|
408
|
+
node[i].emptyLines = startLine - endLine - 1; // >= -1
|
|
392
409
|
}
|
|
393
410
|
}
|
|
394
411
|
return path.map(print);
|
|
@@ -632,6 +649,8 @@ const printSQL = (path, options, print) => {
|
|
|
632
649
|
return printSetStatement(path, options, print, node);
|
|
633
650
|
case "SingleTokenStatement":
|
|
634
651
|
return printSingleTokenStatement(path, options, print, node);
|
|
652
|
+
case "StandAloneExpr":
|
|
653
|
+
return printStandAloneExpr(path, options, print, node);
|
|
635
654
|
case "StringLiteral":
|
|
636
655
|
return printStringLiteral(path, options, print, node);
|
|
637
656
|
case "StructLiteral":
|
|
@@ -644,8 +663,14 @@ const printSQL = (path, options, print) => {
|
|
|
644
663
|
return printTableSamplePipeOperator(path, options, print, node);
|
|
645
664
|
case "TableSampleRatio":
|
|
646
665
|
return printTableSampleRatio(path, options, print, node);
|
|
647
|
-
case "
|
|
666
|
+
case "TemplateExpr":
|
|
648
667
|
return printIdentifier(path, options, print, node);
|
|
668
|
+
case "TemplateExprContinue":
|
|
669
|
+
return printTemplateExprContinue(path, options, print, node);
|
|
670
|
+
case "TemplateExprEnd":
|
|
671
|
+
return printTemplateExprEnd(path, options, print, node);
|
|
672
|
+
case "TemplateExprStart":
|
|
673
|
+
return printTemplateExprStart(path, options, print, node);
|
|
649
674
|
case "TransactionStatement":
|
|
650
675
|
return printTransactionStatement(path, options, print, node);
|
|
651
676
|
case "TrainingDataCustomHolidayClause":
|
|
@@ -4525,6 +4550,14 @@ const printSingleTokenStatement = (path, options, print, node) => {
|
|
|
4525
4550
|
p.newLine(),
|
|
4526
4551
|
];
|
|
4527
4552
|
};
|
|
4553
|
+
const printStandAloneExpr = (path, options, print, node) => {
|
|
4554
|
+
const p = new Printer(path, options, print, node);
|
|
4555
|
+
const docs = {
|
|
4556
|
+
self: "", // eslint-disable-line unicorn/no-unused-properties
|
|
4557
|
+
expr: p.child("expr"),
|
|
4558
|
+
};
|
|
4559
|
+
return [docs.expr, p.newLine()];
|
|
4560
|
+
};
|
|
4528
4561
|
const printStringLiteral = (path, options, print, node) => {
|
|
4529
4562
|
const p = new Printer(path, options, print, node);
|
|
4530
4563
|
const docs = {
|
|
@@ -4649,6 +4682,79 @@ const printTableSampleRatio = (path, options, print, node) => {
|
|
|
4649
4682
|
docs.rparen,
|
|
4650
4683
|
];
|
|
4651
4684
|
};
|
|
4685
|
+
const printTemplateExprContinue = (path, options, print, node) => {
|
|
4686
|
+
const p = new Printer(path, options, print, node);
|
|
4687
|
+
p.setNotRoot("exprs");
|
|
4688
|
+
p.setGroupRecommended("exprs");
|
|
4689
|
+
const docs = {
|
|
4690
|
+
leading_comments: printLeadingComments(path, options, print, node),
|
|
4691
|
+
self: p.self("asItIs"),
|
|
4692
|
+
trailing_comments: printTrailingComments(path, options, print, node),
|
|
4693
|
+
exprs: p.child("exprs", (x) => [line, x]),
|
|
4694
|
+
};
|
|
4695
|
+
return [
|
|
4696
|
+
docs.leading_comments,
|
|
4697
|
+
docs.self,
|
|
4698
|
+
docs.trailing_comments,
|
|
4699
|
+
indent(docs.exprs),
|
|
4700
|
+
];
|
|
4701
|
+
};
|
|
4702
|
+
const printTemplateExprEnd = (path, options, print, node) => {
|
|
4703
|
+
const p = new Printer(path, options, print, node);
|
|
4704
|
+
const docs = {
|
|
4705
|
+
leading_comments: printLeadingComments(path, options, print, node),
|
|
4706
|
+
self: p.self("asItIs"),
|
|
4707
|
+
trailing_comments: printTrailingComments(path, options, print, node),
|
|
4708
|
+
};
|
|
4709
|
+
return [docs.leading_comments, docs.self, docs.trailing_comments];
|
|
4710
|
+
};
|
|
4711
|
+
const printTemplateExprStart = (path, options, print, node) => {
|
|
4712
|
+
const p = new Printer(path, options, print, node);
|
|
4713
|
+
p.setNotRoot("exprs");
|
|
4714
|
+
p.setGroupRecommended("exprs");
|
|
4715
|
+
const docs = {
|
|
4716
|
+
leading_comments: printLeadingComments(path, options, print, node),
|
|
4717
|
+
self: p.self("asItIs"),
|
|
4718
|
+
trailing_comments: printTrailingComments(path, options, print, node),
|
|
4719
|
+
exprs: p.child("exprs", (x) => [line, x]),
|
|
4720
|
+
continues: p.child("continues", (x) => [line, x]),
|
|
4721
|
+
end: p.child("end"),
|
|
4722
|
+
as: "", // eslint-disable-line unicorn/no-unused-properties
|
|
4723
|
+
alias: printAlias(path, options, print, node),
|
|
4724
|
+
order: printOrder(path, options, print, node),
|
|
4725
|
+
null_order: "", // eslint-disable-line unicorn/no-unused-properties
|
|
4726
|
+
// do not use printComma here
|
|
4727
|
+
// additional trailing comma may break your code
|
|
4728
|
+
comma: p.child("comma", undefined, "all"),
|
|
4729
|
+
with_offset: p.child("with_offset", undefined, "all"),
|
|
4730
|
+
pivot: printPivotOrUnpivotOperator(path, options, print, node),
|
|
4731
|
+
unpivot: "", // eslint-disable-line unicorn/no-unused-properties
|
|
4732
|
+
match_recognize: p.child("match_recognize", undefined, "all"),
|
|
4733
|
+
};
|
|
4734
|
+
return [
|
|
4735
|
+
docs.leading_comments,
|
|
4736
|
+
group([
|
|
4737
|
+
docs.self,
|
|
4738
|
+
indent(docs.exprs),
|
|
4739
|
+
docs.continues,
|
|
4740
|
+
0 < p.children.exprs.NodeVec.length ||
|
|
4741
|
+
0 < p.children.continues.NodeVec.length
|
|
4742
|
+
? line
|
|
4743
|
+
: "",
|
|
4744
|
+
docs.end,
|
|
4745
|
+
docs.trailing_comments,
|
|
4746
|
+
docs.alias,
|
|
4747
|
+
docs.order,
|
|
4748
|
+
docs.pivot,
|
|
4749
|
+
docs.comma,
|
|
4750
|
+
p.has("match_recognize") ? " " : "",
|
|
4751
|
+
docs.match_recognize,
|
|
4752
|
+
p.has("with_offset") ? " " : "",
|
|
4753
|
+
docs.with_offset,
|
|
4754
|
+
]),
|
|
4755
|
+
p.newLine(),
|
|
4756
|
+
];
|
|
4757
|
+
};
|
|
4652
4758
|
const printTransactionStatement = (path, options, print, node) => {
|
|
4653
4759
|
const p = new Printer(path, options, print, node);
|
|
4654
4760
|
const docs = {
|