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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy