Skip to content

Commit a4f2724

Browse files
committed
Implement for handling generating comments for edited contracts with comments
1 parent fed3dda commit a4f2724

File tree

3 files changed

+211
-153
lines changed

3 files changed

+211
-153
lines changed

src/index.es6

Lines changed: 2 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import parser from 'solidity-parser-antlr';
22
import { ContractFile } from './lib/contract/contract-file';
33
import { Contract } from './lib/contract/contract';
4-
import CommentsGenerator from './lib/generators/comments-generator';
54
import ContractParts from './lib/contract-parts.es6';
6-
import { pad } from './lib/utils/string-utils';
7-
8-
const generator = new CommentsGenerator();
5+
import {insertComment} from "./lib/contract/contract-comment";
96

107
export function generateCommentsFromText(text, config = {}) {
118
return generate(new Contract(text), config);
@@ -37,75 +34,4 @@ function getVisitors(contract) {
3734
}
3835
}
3936
return visitors;
40-
}
41-
42-
function isTab(originalLineAt) {
43-
return originalLineAt.startsWith('\t');
44-
}
45-
46-
function hasComment(contract, line) {
47-
let counter = 1;
48-
while (true) {
49-
counter++;
50-
let lineText = contract.getOriginalLineAt(line - counter);
51-
if (lineText === undefined) return false;
52-
lineText = lineText.trim();
53-
if (lineText.startsWith('*') || lineText.startsWith('//')) return true;
54-
if (!lineText.replace(/\s/g, '').length) continue;
55-
return false;
56-
}
57-
}
58-
59-
function updateComment(contract, commentLines, line) {
60-
if (hasComment(contract,line)) {
61-
62-
let newCommentsParams = [];
63-
let newCommentsMap = commentLines.reduce(function(map, obj) {
64-
let key = obj.match(/\/\/\/ @([a-zA-Z]*)\b/g)[0];
65-
if(key === "/// @param") {
66-
newCommentsParams.push(obj);
67-
} else map[key] = obj;
68-
return map;
69-
}, {});
70-
71-
let oldCommentsParams = [];
72-
let oldCommentsMap = {};
73-
let oldCommentPosition = line - 2;
74-
while (true) {
75-
let comment = contract.getLineAt(oldCommentPosition);
76-
if(comment.startsWith('/// @param')) {
77-
oldCommentsParams.push(comment)
78-
} else if(comment.startsWith('//')) {
79-
oldCommentsMap[comment.match(/\/\/\/ @([a-zA-Z]*)\b/g)[0]] = comment
80-
} else break;
81-
}
82-
83-
return true;
84-
}
85-
// let offsetCounter = commentLines.length + 1;
86-
// for(let l of commentLines) {
87-
// let currentLine = line - offsetCounter;
88-
// let currentComment = contract.getLineAt(currentLine).trim();
89-
// if (currentComment.startsWith('/// @param') && l.trim().startsWith('/// @param')) {
90-
// contract.removeLine(currentLine);
91-
// contract.insertLinesBefore(l.split(), currentLine);
92-
// }
93-
// offsetCounter--;
94-
// }
95-
// return true;
96-
// }
97-
return false;
98-
}
99-
100-
function insertComment(contract, node) {
101-
let comment = generator.generate(node);
102-
if (!comment) return;
103-
let commentLines = comment.split('\n');
104-
if (updateComment(contract, commentLines, node.loc.start.line)) return;
105-
commentLines = pad(
106-
node.loc.start.column,
107-
commentLines,
108-
isTab(contract.getOriginalLineAt(node.loc.start.line - 1))
109-
);
110-
contract.insertLinesBefore(commentLines, node.loc.start.line - 1);
111-
}
37+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import {pad} from "../utils/string-utils";
2+
import CommentsGenerator from "../generators/comments-generator";
3+
4+
const generator = new CommentsGenerator();
5+
6+
export function insertComment(contract, node) {
7+
let comment = generator.generate(node);
8+
if (!comment) return;
9+
let commentLines = comment.split('\n');
10+
if (updateComment(contract, commentLines, node.loc)) return;
11+
commentLines = pad(
12+
node.loc.start.column,
13+
commentLines,
14+
isTab(contract.getOriginalLineAt(node.loc.start.line - 1))
15+
);
16+
contract.insertLinesBefore(commentLines, node.loc.start.line - 1);
17+
}
18+
19+
function updateComment(contract, commentLines, location) {
20+
let line = location.start.line;
21+
if (hasComment(contract, line)) {
22+
// extract old comments
23+
let oldCommentsParams = [];
24+
let oldCommentsMap = {};
25+
let oldCommentPosition = line - 2;
26+
while (true) {
27+
let comment = contract.getLineAt(oldCommentPosition).trim();
28+
if (comment.startsWith('/// @param')) {
29+
oldCommentsParams.push({line: oldCommentPosition, value: comment})
30+
} else if (comment.startsWith('//')) {
31+
oldCommentsMap[comment.match(/\/\/\/ @([a-zA-Z]*)\b/g)[0]] = comment
32+
} else if (!comment.startsWith('function')) {
33+
break;
34+
}
35+
oldCommentPosition--;
36+
}
37+
// check if old comment is generated comment
38+
if (isEmptyObject(oldCommentsMap)) {
39+
return true;
40+
}
41+
// extract new comments
42+
let newCommentsParams = [];
43+
let newCommentsMap = commentLines.reduce(function (map, obj) {
44+
let key = obj.match(/\/\/\/ @([a-zA-Z]*)\b/g)[0];
45+
if (key === "/// @param") {
46+
newCommentsParams.push(obj);
47+
} else map[key] = obj;
48+
return map;
49+
}, {});
50+
51+
if (newCommentsParams.length) {
52+
for (let k in oldCommentsMap) {
53+
if (!k in newCommentsMap) {
54+
return true;
55+
}
56+
}
57+
let firstCommentLine = oldCommentsParams
58+
.reduce((min, b) => Math.min(min, b.line), oldCommentsParams[0].line);
59+
// remove old params comments and save additional information about params
60+
let savedComments = {};
61+
for (let oldComment of oldCommentsParams) {
62+
contract.removeLine(firstCommentLine);
63+
// save old right part of comment
64+
let c = oldComment.value.toString().trim().split(' ');
65+
if (c.length > 3) {
66+
savedComments[c[2]] = c.slice(3).join(' ');
67+
}
68+
}
69+
// insert new params comments
70+
newCommentsParams = pad(
71+
location.start.column,
72+
newCommentsParams,
73+
isTab(contract.getOriginalLineAt(location.start.line - 1))
74+
);
75+
for (let c of newCommentsParams.reverse()) {
76+
let newComment = c;
77+
let oldCommentParamName = c.trim().split(' ')[2];
78+
let savedComment = savedComments[oldCommentParamName];
79+
if (typeof savedComment !== "undefined") {
80+
newComment = newComment + " " + savedComment;
81+
}
82+
contract.insertLinesBeforeWithoutCalculatingAndAddingOffset(newComment.split(), firstCommentLine);
83+
84+
}
85+
contract.addOffset(firstCommentLine, newCommentsParams.length - oldCommentsParams.length);
86+
return true;
87+
}
88+
return true;
89+
}
90+
return false;
91+
}
92+
93+
function hasComment(contract, line) {
94+
let counter = 1;
95+
while (true) {
96+
counter++;
97+
let lineText = contract.getOriginalLineAt(line - counter);
98+
if (lineText.trim().startsWith('function')) {
99+
lineText = contract.getOriginalLineAt(line - counter - 1);
100+
}
101+
if (lineText === undefined) return false;
102+
lineText = lineText.trim();
103+
if (lineText.startsWith('*') || lineText.startsWith('//')) return true;
104+
if (!lineText.replace(/\s/g, '').length) continue;
105+
return false;
106+
}
107+
}
108+
109+
function isEmptyObject(obj) {
110+
for (let name in obj) {
111+
return false;
112+
}
113+
return true;
114+
}
115+
116+
function isTab(originalLineAt) {
117+
return originalLineAt.startsWith('\t');
118+
}

src/lib/contract/contract.es6

Lines changed: 91 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,96 @@
11
export class Contract {
22

3-
constructor(text) {
4-
if (Array.isArray(text)) {
5-
this.lines = text;
6-
} else {
7-
this.lines = text.split('\n');
8-
}
9-
this.pos = 0;
10-
this.offsets = {};
11-
}
12-
13-
reset() {
14-
this.pos = 0;
15-
}
16-
17-
getLineCount() {
18-
return this.lines.length;
19-
}
20-
21-
getPosition() {
22-
return this.pos;
23-
}
24-
25-
setPosition(pos) {
26-
this.pos = pos;
27-
}
28-
29-
getNextLine() {
30-
if (this.pos >= this.lines.length) {
31-
return null;
32-
}
33-
return this.lines[this.pos++];
34-
}
35-
36-
removeLine(pos) {
37-
this.lines.splice(pos, 1);
38-
}
39-
40-
removeLines(positions) {
41-
positions.forEach((pos) => this.removeLine(pos));
42-
}
43-
44-
insertLinesBefore(lines, line) {
45-
line += this.offset(line);
46-
this.addOffset(line, lines.length);
47-
this.lines.splice(line, 0, ...lines);
48-
}
49-
50-
insertTextBefore(text, line) {
51-
let lines = text.split('\n');
52-
this.insertLinesBefore(lines, line);
53-
}
54-
55-
getText() {
56-
return this.lines.join('\n');
57-
}
58-
59-
getLineAt(pos) {
60-
return this.lines[pos];
61-
}
62-
63-
getOriginalLineAt(pos) {
64-
return this.lines[pos + this.offset(pos)];
65-
}
66-
67-
addOffset(line, offset) {
68-
this.offsets[line] = offset;
69-
}
70-
71-
offset(line) {
72-
let offsetAmount = 0;
73-
for (let offset in this.offsets) {
74-
if (this.offsets.hasOwnProperty(offset)) {
75-
if (line >= offset) {
76-
offsetAmount += this.offsets[offset];
3+
constructor(text) {
4+
if (Array.isArray(text)) {
5+
this.lines = text;
6+
} else {
7+
this.lines = text.split('\n');
778
}
78-
}
9+
this.pos = 0;
10+
this.offsets = {};
11+
}
12+
13+
reset() {
14+
this.pos = 0;
15+
}
16+
17+
getLineCount() {
18+
return this.lines.length;
19+
}
20+
21+
getPosition() {
22+
return this.pos;
23+
}
24+
25+
setPosition(pos) {
26+
this.pos = pos;
27+
}
28+
29+
getNextLine() {
30+
if (this.pos >= this.lines.length) {
31+
return null;
32+
}
33+
return this.lines[this.pos++];
34+
}
35+
36+
removeLine(pos) {
37+
this.lines.splice(pos, 1);
38+
}
39+
40+
removeLines(positions) {
41+
positions.forEach((pos) => this.removeLine(pos));
42+
}
43+
44+
calculateLine(line) {
45+
let currentOffset = this.offset(line);
46+
line += this.offset(line + currentOffset);
47+
return line;
48+
}
49+
50+
insertLinesBeforeWithoutCalculatingAndAddingOffset(lines, line) {
51+
this.lines.splice(line, 0, ...lines);
52+
}
53+
54+
insertLinesBeforeWithoutAddingOffset(lines, line) {
55+
this.insertLinesBeforeWithoutCalculatingAndAddingOffset(lines, line);
56+
}
57+
58+
insertLinesBefore(lines, line) {
59+
let offsetLine = this.calculateLine(line);
60+
this.insertLinesBeforeWithoutAddingOffset(lines, offsetLine);
61+
this.addOffset(offsetLine, lines.length);
62+
}
63+
64+
insertTextBefore(text, line) {
65+
let lines = text.split('\n');
66+
this.insertLinesBefore(lines, line);
67+
}
68+
69+
getText() {
70+
return this.lines.join('\n');
71+
}
72+
73+
getLineAt(pos) {
74+
return this.lines[pos];
75+
}
76+
77+
getOriginalLineAt(pos) {
78+
return this.lines[pos + this.offset(pos)];
79+
}
80+
81+
addOffset(line, offset) {
82+
this.offsets[line] = offset;
83+
}
84+
85+
offset(line) {
86+
let offsetAmount = 0;
87+
for (let offset in this.offsets) {
88+
if (this.offsets.hasOwnProperty(offset)) {
89+
if (line >= offset) {
90+
offsetAmount += this.offsets[offset];
91+
}
92+
}
93+
}
94+
return offsetAmount;
7995
}
80-
return offsetAmount;
81-
}
8296
}

0 commit comments

Comments
 (0)