Skip to content

Commit

Permalink
gogocode
Browse files Browse the repository at this point in the history
  • Loading branch information
tedjmzhang committed May 31, 2024
1 parent 479353c commit ba8c831
Show file tree
Hide file tree
Showing 7 changed files with 492 additions and 7 deletions.
349 changes: 342 additions & 7 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@metalsmith/permalinks": "^3.0.1",
"chalk": "^5.3.0",
"commander": "^12.1.0",
"gogocode": "^1.0.55",
"handlebars": "^4.7.8",
"inquirer": "^8.2.6",
"metalsmith": "^2.6.3",
Expand Down
65 changes: 65 additions & 0 deletions src/frontend/library/gogocode/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const $ = require('gogocode');
let path = require('path');
let fs = require('fs')

let filePath = path.resolve(__dirname, './test.js');
let str = fs.readFileSync(filePath, { encoding: 'utf-8' });
const ast = $(str);
const test1 = ast.find('const $_$variable = $_$value');
let test1Match = test1.match

// const code = test1.generate();
// ast.replace('function log(){}', `let log = 12;`);
// let code2 = ast.generate();
// console.log(code2)

let test2 = ast.find('function log($$$param){$$$statement}')
let test2match = test2.match;

let ddd = ast.replace('function log($$$param){$$$statement}', 'function testLog($$$params){$$$statement}')
let replacedValue = ast.generate();
fs.writeFileSync('output.js', replacedValue)


test1.each(item => {
let variable = item.match.variable[0].value;
let value = item.match.value[0].value;
console.log('variable value', variable, value)
})

const res = ast.find('const dict = { $$$0 }');
const kvs = res.match['$$$0'];
kvs.map((kv) => `${kv.key.name}:${kv.value.value}`);
// a:1,b:2,c:f



const console1 = ast.find('function testLog($_$0) {}')
let console2 = console1.find('console.log($_$0)');

// 找到 reactClass 定义的语句
const reactClass = ast.find('class $_$0 extends React.Component {}');

// 找到 jsx 里面带有 onClick 属性的标签
const onClick = reactClass.find('<$_$0 onClick={$_$1}></$_$0>');

// 创建一个数组用来收集 onClick 对应的 hanlder 的名称
const clickFnNames = [];

// 有可能找到很多个带有 onClick 的标签,我们这里用 each 去处理每一条
onClick.each((e) => {
// 用 match[1][0] 来找到 $_$1 匹配到的第一个 onClick 属性对应的 handler 节点
// 取 value 即为节点名
// handlerName = 'this.handleClick'
const handlerName = e.match[1][0].value;
clickFnNames.push(handlerName);
});

// 替换原有的 constructor,但利用 $$$ 保留原有的参数和语句,只是在最后补上 bind 语句即可
reactClass.replace(
'constructor($$$0) { $$$1 }',
`constructor($$$0) {
$$$1;
${clickFnNames.map((name) => `${name} = ${name}.bind(this)`).join(';')}
}`,
);
14 changes: 14 additions & 0 deletions src/frontend/library/gogocode/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# gogocode

> 解析源码字符串为ast,然后对其操作
let ast = gogocode(string) // 生成gogoCode的ast实例

## 实例方法: 全部返回的都是gogocode实例,只不过他们的match不一样而已,返回值是一个对象,但是有each方法,返回匹配的多个值,直接调用match只会返回匹配的第一个值(改值是一个对象,对象的key是$_$name里面的name)
- find: 匹配某格式文本,并且将其命名,ast.find('const $_$key = $_$value'), 可以使用.match或者(.each(item,index => item.match)index为1是表示第一个)获取第一个匹配的,如果有多个匹配,只能.each(item => item.match)

- replaceBy: find之后直接替换

-- replace: 找到并替换 ast.replace('const a = $_$value', 'const b = $_$value')



17 changes: 17 additions & 0 deletions src/frontend/library/gogocode/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
function testLog(a,b,cs){console.log(a, b, c);}

function alert(a) {
alert(a);
}


// 以下每一种都能被匹配到
const a1 = 123;
const a2 = "b";
const a3 = () => 1;

const dict = {
a: 1,
b: 2,
c: 'f',
};
43 changes: 43 additions & 0 deletions src/frontend/library/gogocode/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
function log(a, b, c) {
console.log(a, b, c);
}

function alert(a) {
alert(a);
}


// 以下每一种都能被匹配到
const a1 = 123;
const a2 = "b";
const a3 = () => 1;

const dict = {
a: 1,
b: 2,
c: 'f',
};

class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isToggleOn: true };

// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
}

handleClick() {
this.setState((prevState) => ({
isToggleOn: !prevState.isToggleOn,
}));
}

render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
10 changes: 10 additions & 0 deletions src/frontend/node/tmskit.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ run
dev:
使用chokdir库监听每一个modules下面的文件,然后复制文件到sinan/dist下面

钩子:
beforeNpmInstall
afterFirstCompile
updateFile
beforePreview
beforeUpload

关于埋点:
埋点是在钩子afterFirstCompile里面执行的,使用gogocode将文件解析成ast,然后将wxml的bind等代码提取到js或者ts的tmsReportEvent里面




Expand Down

0 comments on commit ba8c831

Please sign in to comment.