-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathprintSql.ts
87 lines (75 loc) · 2.39 KB
/
printSql.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import { Node } from "sql-parser-cst";
import { AstPath, Doc } from "prettier";
import { OldPrintFn, PrintableKey, PrintFn } from "./PrintFn";
import { arrayWrap, isArray, isDefined, isEmptyArray, isString } from "./utils";
import { transformMap } from "./syntax/transformMap";
import { NodeByType, ToDocFn } from "./CstToDocMap";
import { AllPrettierOptions } from "./options";
import { join } from "./print_utils";
export function printSql(
path: AstPath<Node>,
options: AllPrettierOptions,
oldPrint: OldPrintFn,
): Doc {
return printNode(path, options, createPrintFn(path, oldPrint));
}
let cachedPrintFn: PrintFn<Node>;
let cachedPath: AstPath<Node>;
function createPrintFn(
path: AstPath<Node>,
oldPrint: OldPrintFn,
): PrintFn<Node> {
// The path parameter will reference the same AstPath instance
// during the whole printing cycle.
// So we can keep using the same print function as long as
// the path stays the same.
if (cachedPath === path) {
return cachedPrintFn;
}
cachedPath = path;
cachedPrintFn = ((selector): Doc => {
if (isArray(selector)) {
const node = path.getValue();
return selector.filter((sel) => isDefined(node[sel])).map(oldPrint);
} else {
return oldPrint(selector);
}
}) as PrintFn<Node>;
cachedPrintFn.spaced = (
selector: PrintableKey<Node> | PrintableKey<Node>[],
): Doc[] => {
const node = path.getValue();
const docs = arrayWrap(selector)
.filter((sel) => isDefined(node[sel]))
.map((sel) => [sel, oldPrint(sel)] as [PrintableKey<Node>, Doc])
// skip empty arrays
.filter(([sel, doc]) => !isEmptyArray(doc))
// only join with spaces when input to print was Node[]
.map(([sel, doc]) => (isArray(node[sel]) ? join(" ", doc) : doc));
return docs.length > 0 ? [join(" ", docs)] : [];
};
return cachedPrintFn;
}
function printNode(
path: AstPath<Node>,
options: AllPrettierOptions,
print: PrintFn<Node>,
): Doc {
const node = path.getValue();
if (isArray(node)) {
return path.map(print as OldPrintFn);
}
if (isString(node)) {
return node;
}
if (!node?.type) {
throw new Error(`No type field on node: ${JSON.stringify(node)}`);
}
const fn = transformMap[node.type] as ToDocFn<
NodeByType<(typeof node)["type"], Node>
>;
if (!fn) {
throw new Error(`Unexpected node type: ${node.type}`);
}
return fn(print, node, path, options);
}