Web Inspector: Formatter: Pretty Print HTML resources (including inline <script>...
[WebKit-https.git] / Source / WebInspectorUI / Tools / JSFormatter / JSFormatterDebug.js
1 JSFormatterDebug = class JSFormatterDebug
2 {
3     constructor(sourceText, sourceType)
4     {
5         let tree = esprima.parse(sourceText, {attachComment: true, range: true, tokens: true, sourceType});
6         let walker = new ESTreeWalker(this._before.bind(this), this._after.bind(this));
7
8         this._statistics = {
9             nodeTypes: {},
10             tokenTypes: {},
11         };
12
13         this._nextCommentId = 1;
14
15         this._lines = [];
16         this._tokens = tree.tokens;
17         this._tokensLength = this._tokens.length;
18         this._tokenIndex = 0;
19         this._debugHeader();
20         walker.walk(tree);
21         this._debugAfterProgramNode(tree);
22         this._debugFooter();
23     }
24
25     // Public
26
27     get debugText()
28     {
29         return this._lines.join("\n");
30     }
31
32     // Private
33
34     _pad(str, width)
35     {
36         let result = str;
37         for (let toPad = width - result.length; toPad > 0; --toPad)
38             result += " ";
39         return result;
40     }
41
42     _debugHeader()
43     {
44         let nodeString = this._pad("Node Type", 25);
45         let tokenTypeString = this._pad("Token Type", 20);
46         let tokenValueString = "Token Value";
47         this._lines.push(nodeString + " " + tokenTypeString + " " + tokenValueString);
48         this._lines.push("-".repeat(25) + " " + "-".repeat(20) + " " + "-".repeat(20));
49     }
50
51     _debugFooter()
52     {
53         this._lines.push("");
54         this._lines.push(this._pad("Node Type", 25) + " Frequency");
55         this._lines.push("-".repeat(25) + " " + "-".repeat(15));
56         let groups = [];
57         for (let key of Object.keys(this._statistics.nodeTypes))
58             groups.push([key, this._statistics.nodeTypes[key]]);
59         groups.sort((a, b) => b[1] - a[1]);
60         for (let [nodeType, frequency] of groups)
61             this._lines.push(this._pad(nodeType, 25) + " " + frequency);
62
63         this._lines.push("");
64         this._lines.push(this._pad("Token Type", 20) + " Frequency");
65         this._lines.push("-".repeat(20) + " " + "-".repeat(15));
66         groups = [];
67         for (let key of Object.keys(this._statistics.tokenTypes))
68             groups.push([key, this._statistics.tokenTypes[key]]);
69         groups.sort((a, b) => b[1] - a[1]);
70         for (let [tokenType, frequency] of groups)
71             this._lines.push(this._pad(tokenType, 20) + " " + frequency);
72     }
73
74     _debug(node, token)
75     {
76         let nodeString = this._pad(node.type, 25);
77         let tokenTypeString = this._pad(token.type, 20);
78         let tokenValueString = token.value;
79         this._lines.push(nodeString + " " + tokenTypeString + " " + tokenValueString);
80
81         if (!this._statistics.nodeTypes[node.type])
82             this._statistics.nodeTypes[node.type] = 0;
83         if (!this._statistics.tokenTypes[token.type])
84             this._statistics.tokenTypes[token.type] = 0;
85         this._statistics.nodeTypes[node.type]++;
86         this._statistics.tokenTypes[token.type]++;
87     }
88
89     _debugComments(comments, trailing)
90     {
91         for (let comment of comments) {
92             if (!comment.__id)
93                 comment.__id = this._nextCommentId++;
94             let nodeString = this._pad(`** ${trailing ? "T " :"L "}Comment (${comment.__id})`, 25);
95             let commentTypeString = this._pad(comment.type, 20);
96             let commentValueString = comment.value;
97             this._lines.push(nodeString + " " + commentTypeString + " " + commentValueString);
98         }
99     }
100
101     _debugAfterProgramNode(programNode)
102     {
103         if (programNode.body.length) {
104             let lastNode = programNode.body[programNode.body.length - 1];
105             if (lastNode.trailingComments)
106                 this._debugComments(lastNode.trailingComments, true);
107         } else {
108             if (programNode.leadingComments)
109                 this._debugComments(programNode.leadingComments);
110             if (programNode.trailingComments)
111                 this._debugComments(programNode.trailingComments, true);
112         }
113     }
114
115     _before(node)
116     {
117         if (!node.parent)
118             return;
119
120         while (this._tokenIndex < this._tokensLength && this._tokens[this._tokenIndex].range[0] < node.range[0]) {
121             let token = this._tokens[this._tokenIndex++];
122             this._debug(node.parent, token);
123         }
124
125         if (node.leadingComments)
126             this._debugComments(node.leadingComments);
127     }
128
129     _after(node)
130     {
131         while (this._tokenIndex < this._tokensLength && this._tokens[this._tokenIndex].range[0] < node.range[1]) {
132             let token = this._tokens[this._tokenIndex++];
133             this._debug(node, token);
134         }
135
136         if (node.trailingComments)
137             this._debugComments(node.trailingComments, true);
138     }
139 }