Skip to content

Commit e83b933

Browse files
committed
feat: implementing basic functions
0 parents  commit e83b933

16 files changed

+2364
-0
lines changed

.eslintignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules/
2+
dist/
3+
*.js

.eslintrc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"root": true,
3+
"parser": "@typescript-eslint/parser",
4+
"plugins": [
5+
"@typescript-eslint"
6+
],
7+
"extends": [
8+
"eslint:recommended",
9+
"plugin:@typescript-eslint/eslint-recommended",
10+
"plugin:@typescript-eslint/recommended"
11+
],
12+
"rules": {
13+
"no-explicit-any": 0,
14+
"no-non-null-assertion": 0,
15+
"no-useless-escape": 0
16+
}
17+
}

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
node_modules
2+
coverage
3+
.nyc_output
4+
.DS_Store
5+
*.log
6+
.vscode
7+
dist

package.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "coderfly",
3+
"version": "1.0.0",
4+
"main": "index.js",
5+
"license": "MIT",
6+
"type": "module",
7+
"scripts": {
8+
"build": "rm -rf dist/ && tsc && find ./dist -type f|xargs dos2unix",
9+
"lint": "eslint . --ext .ts",
10+
"lint:fix": "eslint . --ext .ts --fix"
11+
},
12+
"devDependencies": {
13+
"@types/n-readlines": "^1.0.3",
14+
"@types/node": "^17.0.22",
15+
"@typescript-eslint/eslint-plugin": "^5.19.0",
16+
"@typescript-eslint/parser": "^5.19.0",
17+
"eslint": "^8.13.0",
18+
"typescript": "^4.6.3"
19+
},
20+
"dependencies": {
21+
"@babel/parser": "^7.17.8",
22+
"@types/lodash-es": "^4.17.6",
23+
"enhanced-resolve": "^5.9.2",
24+
"execa": "^6.1.0",
25+
"lodash-es": "^4.17.21",
26+
"n-readlines": "^1.0.1",
27+
"parse-git-diff": "^0.0.6",
28+
"recast": "^0.20.5",
29+
"vue-template-compiler": "^2.6.14"
30+
}
31+
}

src/const.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const ALLOW_EXT = ['.vue', '.js', '.ts'];
2+
export const UN_KNOWN = 'unknown';
3+
export const IS_TOP_SCOPE = '[is_top_scope]';
4+
5+
export const MUSTACHE_TAG_REG = /\{\{((?:.|\n)+?)\}\}/g;
6+
7+
export const TEXT_NODE_TYPES = [2, 3];

src/impact.ts

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
import { TEXT_NODE_TYPES } from './const.js';
2+
import {
3+
FileInfoTree,
4+
FuncCallSearchResult,
5+
NameAndPath,
6+
ImpactReason,
7+
TemplateImpact,
8+
TemplateKeyInfo,
9+
TemplateImpactResult
10+
} from './type';
11+
import { handleCircularPath } from './utils/handle_circular_path.js';
12+
13+
function getImpacts (treeData: FileInfoTree, funcInfo: ImpactReason) {
14+
let templateImpact = [] as TemplateImpactResult[];
15+
16+
// function entrance
17+
const main = {
18+
name: funcInfo.name,
19+
file: funcInfo.filePath,
20+
};
21+
22+
let callList = [funcInfo] as ImpactReason[];
23+
const impactReport = [];
24+
25+
while (callList.length) {
26+
const curFuncInfo = callList.shift();
27+
28+
if (!curFuncInfo) {
29+
continue;
30+
}
31+
32+
const { theyCallYou } = findWhoCallMe(treeData, curFuncInfo, templateImpact);
33+
const [ isCircular, miniPath ] = handleCircularPath(curFuncInfo.paths);
34+
35+
if (!theyCallYou.length) { // the end of function call stack
36+
impactReport.push({
37+
callPaths: curFuncInfo.paths,
38+
templateImpact
39+
});
40+
templateImpact = [];
41+
} else if (isCircular) { // function calls are looped,stop here
42+
impactReport.push({
43+
callPaths: miniPath,
44+
templateImpact,
45+
});
46+
callList = [];
47+
templateImpact = [];
48+
} else { // keep finding
49+
callList.push(...theyCallYou);
50+
}
51+
52+
}
53+
54+
return {
55+
main,
56+
impactReport
57+
};
58+
}
59+
60+
// find a function called by which function
61+
function findWhoCallMe (treeData: FileInfoTree, funcInfo: ImpactReason, reportInfo=[] as TemplateImpactResult[]) {
62+
const theyCallYou = [] as FuncCallSearchResult[];
63+
64+
const curFilePath = funcInfo.filePath;
65+
const funcName = funcInfo.name;
66+
const curPaths = funcInfo.paths;
67+
68+
// these found functions are used to find the impact of template
69+
// TODO: there is a bug: a same dom node will be found and push to the array twice
70+
const templateImpactSearchFunc: NameAndPath = {
71+
[funcName]: curFilePath
72+
};
73+
74+
// because the mixin function is mixed into each file,it wil be found multiple times
75+
// so we need a set
76+
const set = new Set();
77+
78+
for (const fileInfo in treeData) {
79+
const allFuncsInfo = treeData[fileInfo].allFuncsInfo;
80+
const templateKeyInfo = treeData[fileInfo].templateKeyInfo;
81+
82+
if (!Object.keys(allFuncsInfo).length) continue;
83+
84+
// find the caller in current file
85+
Object.values(allFuncsInfo).forEach(func => {
86+
if (func.calledFnList.includes(funcName) &&
87+
func.calledFnFrom[funcName].filePath === curFilePath &&
88+
!set.has(`${func.name}-${func.filePath}`)
89+
) {
90+
set.add(`${func.name}-${func.filePath}`);
91+
92+
// collect call paths
93+
const paths = [...curPaths];
94+
paths.push([func.name, func.filePath, func.position]);
95+
96+
theyCallYou.push({
97+
filePath: func.filePath,
98+
name: func.name,
99+
paths,
100+
});
101+
102+
templateImpactSearchFunc[func.name] = func.filePath;
103+
}
104+
});
105+
106+
// find if the function in the paths is used in the template
107+
if (templateKeyInfo && templateKeyInfo.length) {
108+
const domInfo = getTemplateImpact(templateKeyInfo, templateImpactSearchFunc);
109+
domInfo.length && reportInfo.push({
110+
filePath: treeData[fileInfo].file,
111+
domInfo
112+
});
113+
}
114+
115+
}
116+
117+
return {
118+
theyCallYou,
119+
reportInfo,
120+
};
121+
122+
}
123+
124+
function getTemplateImpact (templateKeyInfo: TemplateKeyInfo[], templateImpactSearchFunc: NameAndPath) {
125+
const res = [] as TemplateImpact[];
126+
127+
const funcNameArr = Object.keys(templateImpactSearchFunc);
128+
129+
if (!funcNameArr.length) {
130+
return res;
131+
}
132+
133+
for (const templateInfo of templateKeyInfo) {
134+
dfsTemplateInfo(funcNameArr, templateInfo, [], res);
135+
}
136+
137+
return res;
138+
}
139+
140+
function dfsTemplateInfo (funcNameArr: string[], templateInfo: TemplateKeyInfo, pathList: string[], collect: TemplateImpact[]) {
141+
const { tag='[blank]', children, type } = templateInfo;
142+
143+
if (tag !== '[blank]') {
144+
pathList.push(tag);
145+
}
146+
const curPath = pathList.join('->');
147+
148+
if (type === 1) {
149+
const { vIf, events, vBinds, classBinding } = templateInfo;
150+
151+
vIf?.forEach(item => {
152+
if (funcNameArr.includes(item)) {
153+
collect.push({
154+
curPath,
155+
nodeInfo: {
156+
type: 'if',
157+
tag,
158+
funcName: item,
159+
meta: 'if',
160+
}
161+
})
162+
}
163+
});
164+
165+
events?.forEach(eventInfo => {
166+
Object.keys(eventInfo).forEach(eventName => {
167+
if (funcNameArr.includes(eventInfo[eventName])) {
168+
collect.push({
169+
curPath,
170+
nodeInfo: {
171+
type: 'event',
172+
tag,
173+
funcName: eventInfo[eventName],
174+
meta: eventName,
175+
}
176+
});
177+
}
178+
});
179+
});
180+
181+
vBinds?.forEach(bindInfo => {
182+
const bindFunc = Object.values(bindInfo)[0];
183+
const bindName = Object.keys(bindInfo)[0];
184+
185+
if (funcNameArr.includes(bindFunc)) {
186+
collect.push({
187+
curPath,
188+
nodeInfo: {
189+
type: 'bind',
190+
tag,
191+
funcName: bindFunc,
192+
meta: bindName,
193+
}
194+
});
195+
}
196+
});
197+
198+
if (classBinding?.length) {
199+
for (const item of classBinding) {
200+
funcNameArr.includes(item) &&
201+
collect.push({
202+
curPath,
203+
nodeInfo: {
204+
type: 'classBinding',
205+
tag,
206+
funcName: item,
207+
meta: 'class',
208+
}
209+
});
210+
}
211+
}
212+
}
213+
214+
if (TEXT_NODE_TYPES.includes(type)) {
215+
if (templateInfo.text) {
216+
for (const item of templateInfo.text) {
217+
funcNameArr.includes(item) &&
218+
collect.push({
219+
curPath,
220+
nodeInfo: {
221+
type: 'text',
222+
tag,
223+
funcName: item,
224+
}
225+
});
226+
}
227+
}
228+
}
229+
230+
children.forEach(info => {
231+
dfsTemplateInfo(funcNameArr, info, pathList, collect);
232+
});
233+
}
234+
235+
export {
236+
getImpacts,
237+
findWhoCallMe,
238+
};

src/index.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { diff } from './utils/function_change/index.js';
2+
import { getAllFiles, getFuncTree } from './utils/handle_file_utils.js';
3+
import { getImpacts, findWhoCallMe } from './impact.js';
4+
import { getTemplateInfo } from './utils/parse_template_ast.js';
5+
6+
export {
7+
getAllFiles,
8+
getFuncTree,
9+
getTemplateInfo,
10+
getImpacts,
11+
findWhoCallMe,
12+
diff,
13+
};

0 commit comments

Comments
 (0)