Skip to content

Commit 6b49467

Browse files
authored
Merge pull request #4 from NodeFactoryIo/feature/update-param-comments
Feature/update param comments
2 parents 88d5f73 + 291555e commit 6b49467

File tree

10 files changed

+370
-151
lines changed

10 files changed

+370
-151
lines changed

src/index.es6

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

107
export function generateCommentsFromText(text, config = {}) {
11-
return generate(new Contract(text), config);
8+
return generate(new Contract(text), config);
129
}
1310

1411
export function generateCommentsFromFile(path, config = {}) {
15-
let contract = new ContractFile(path);
16-
generate(contract, config);
17-
contract.save();
12+
let contract = new ContractFile(path);
13+
generate(contract, config);
14+
contract.save();
1815
}
1916

2017
function generate(contract, config) {
21-
let ast = parser.parse(
22-
contract.getText(),
23-
{tolerant: true, loc: true, range: true}
24-
);
25-
const visitors = getVisitors(contract);
26-
parser.visit(ast, visitors);
27-
return contract.getText();
18+
let ast = parser.parse(
19+
contract.getText(),
20+
{tolerant: true, loc: true, range: true}
21+
);
22+
const contractComment = new ContractComment(contract);
23+
const visitors = getVisitors(contractComment);
24+
parser.visit(ast, visitors);
25+
return contract.getText();
2826
}
2927

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

0 commit comments

Comments
 (0)