【babel】提取js函数注释

提取js函数注释

相关文章

提取js文件函数注释


一、函数定义语法

  • 函数声明(Function Declaration):使用 function 关键字定义的函数,例如:

    1
    2
    3
    function add(a, b) {
    return a + b;
    }
  • 函数表达式(Function Expression):将函数赋值给变量或对象属性的表达式,例如:

    1
    2
    3
    const add = function(a, b) {
    return a + b;
    };
  • 箭头函数表达式(Arrow Function Expression):使用箭头 => 定义的匿名函数,例如:

    1
    const add = (a, b) => a + b;
  • 导出函数表达式(Arrow Function Expression):使用export定义的函数,例如:

    1
    export const add = (a, b) => a + b;
  • 方法(Method):定义在对象上的函数,例如:

    1
    2
    3
    4
    function Person(name) {
    this.name = name;
    }
    const person = new Person('John');

二、函数声明语法 提取注释

FunctionDeclaration 节点表示的是通过 function 关键字直接声明的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;

const code = `
const a4 = {
// log1
a44: function(){}
}
const b4 = {
/**
* log2
*/
b44: function(){}
}
// log101
var x4 = { xx4 : 1}
`;

// 解析代码为抽象语法树(AST)
const ast = parser.parse(code);

// 存储函数注释的对象
let functionComments = {};

// 遍历 AST
traverse(ast, {
ObjectProperty(path) {
// 检查属性值是否为函数表达式或箭头函数表达式
if (
path.node.value.type === "FunctionExpression" ||
path.node.value.type === "ArrowFunctionExpression"
) {
// 获取前导注释
const leadingComments = path.node.leadingComments;
// 检查是否有前导注释
if (leadingComments && leadingComments.length > 0) {
// 将属性名和对应的注释添加到 functionComments 对象中
functionComments[path.node.key.name] = leadingComments.map((comment) =>
comment.value
// 清除注释中的星号和空白字符
.trim()
.replace(/\*[^*]*\*+/g, "")
.trim()
);
}
}
},
});

// 打印函数注释对象
console.log(functionComments);

输出

三、函数表达式语法 & 箭头函数表达式语法 提取注释

VariableDeclaration 节点表示的是通过 var、let 或 const 关键字声明的变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
const { parse } = require('@babel/parser');
const traverse = require("@babel/traverse").default;

const code = `
// log1
const a2 = function(){}
// log2
const b2 = () => {}
// log101
const x2 = 3
// log102
const xx2 = {}
`;

// 解析代码为抽象语法树(AST)
const ast = parse(code, {
sourceType: "module", // 将代码解析为 ES 模块化格式
});

// 存储函数注释的对象
let functionComments = {};

// 遍历 AST
traverse(ast, {
VariableDeclaration(path) {
// 检查声明是否为函数表达式 或者 箭头函数表达式
const isFunction =
path.node.declarations[0].init &&
(path.node.declarations[0].init.type === "FunctionExpression" ||
path.node.declarations[0].init.type === "ArrowFunctionExpression");
if (isFunction) {
// 获取前导注释
const leadingComments = path.node.leadingComments;
// 将函数名和对应的注释添加到 functionComments 对象中
functionComments[path.node.declarations[0].id.name] = leadingComments.map(
(comment) => comment.value.trim().replace(/\*[^*]*\*+/g, "").trim()
);
}
},
});

// 打印函数注释对象
console.log(functionComments);

输出

四、导出函数表达式语法 提取注释

ExportNamedDeclaration 节点表示的是通过 export 关键字导出的具名成员,例如导出函数、变量、类等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
const { parse } = require("@babel/parser");
const traverse = require("@babel/traverse").default;

const code = `
// log1
export function a3() {}
// log2
export const b3 = function() {}
// log3
export const c3 = () => {}
// log101
export const x3 = 4
// log102
export class xx3 {}
`;

// 解析代码为抽象语法树(AST)
const ast = parse(code, {
sourceType: "module", // 将代码解析为 ES 模块化格式
});

// 存储函数注释的对象
let functionComments = {};

// 遍历 AST
traverse(ast, {
// 处理导出的函数声明和变量声明
ExportNamedDeclaration(path) {
const declaration = path.node.declaration;
if (declaration) {
// 检查声明类型是否为函数声明或函数表达式
if (declaration.type === "FunctionDeclaration" ||
(declaration.type === "VariableDeclaration" && declaration.declarations[0].init && (declaration.declarations[0].init.type === "FunctionExpression" || declaration.declarations[0].init.type === "ArrowFunctionExpression"))) {
// 获取前导注释
const leadingComments = path.node.leadingComments;
if (leadingComments && leadingComments.length > 0) {
// 确定函数名
const name = declaration.id ? declaration.id.name : declaration.declarations[0].id.name;
// 添加函数名及其对应的注释到 functionComments 对象中
functionComments[name] = leadingComments.map(comment => comment.value.trim().replace(/\*[^*]*\*+/g, "").trim());
}
}
}
},
});

// 打印函数注释对象
console.log(functionComments);

输出

五、方法属性函数语法 提取注释

ObjectProperty 表示对象字面量中的一个属性,包括属性名和属性值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;

const code = `
const _a4 = {
// log1
a4: function(){}
}
const _b4 = {
// log2
b4: () => {}
}
// log101
var x4 = { xx4 : 1}
`;

// 解析代码为抽象语法树(AST)
const ast = parser.parse(code);

// 存储函数注释的对象
let functionComments = {};

// 遍历 AST
traverse(ast, {
ObjectProperty(path) {
// 检查属性值是否为函数表达式或箭头函数表达式
if (
path.node.value.type === "FunctionExpression" ||
path.node.value.type === "ArrowFunctionExpression"
) {
// 获取前导注释
const leadingComments = path.node.leadingComments;
// 检查是否有前导注释
if (leadingComments && leadingComments.length > 0) {
// 将属性名和对应的注释添加到 functionComments 对象中
functionComments[path.node.key.name] = leadingComments.map((comment) =>
comment.value
// 清除注释中的星号和空白字符
.trim()
.replace(/\*[^*]*\*+/g, "")
.trim()
);
}
}
},
});

// 打印函数注释对象
console.log(functionComments);

输出

六、完整示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
const { parse } = require("@babel/parser");
const traverse = require("@babel/traverse").default;

const code = `
// log1
function a1() {}
// log1
const a2 = function(){}
// log2
const b2 = () => {}
// log101
const x2 = 3
// log102
const xx2 = {}
// log1
export function a3() {}
// log2
export const b3 = function() {}
// log3
export const c3 = () => {}
// log101
export const x3 = 4
// log102
export class xx3 {}
const _a4 = {
// log1
a4: function(){}
}
const _b4 = {
// log2
b4: () => {}
}
// log101
var x4 = { xx4 : 1}
`;

// 解析代码为抽象语法树(AST)
const ast = parse(code, {
sourceType: "module", // 将代码解析为 ES 模块化格式
});

// 存储函数注释的对象
let functionComments = {};

// 遍历 AST
traverse(ast, {
// 处理函数声明
FunctionDeclaration(path) {
processFunction(path.node.id.name, path.node.leadingComments);
},
// 处理变量声明
VariableDeclaration(path) {
const declaration = path.node.declarations[0];
if (declaration.init && isFunctionExpression(declaration.init.type)) {
processFunction(declaration.id.name, path.node.leadingComments);
}
},
// 处理导出的函数声明和变量声明
ExportNamedDeclaration(path) {
const declaration = path.node.declaration;
if (declaration) {
if (declaration.type === "FunctionDeclaration" ||
(declaration.type === "VariableDeclaration" && declaration.declarations[0].init && isFunctionExpression(declaration.declarations[0].init.type))) {
const name = declaration.id ? declaration.id.name : declaration.declarations[0].id.name;
processFunction(name, path.node.leadingComments);
}
}
},
// 处理对象属性中的函数
ObjectProperty(path) {
if (isFunctionExpression(path.node.value.type)) {
processFunction(path.node.key.name, path.node.leadingComments);
}
},
});

/**
* 处理函数的注释
* @param {string} name 函数名
* @param {object[]} leadingComments 前导注释节点数组
*/
function processFunction(name, leadingComments) {
if (leadingComments && leadingComments.length > 0) {
functionComments[name] = leadingComments
.map((comment) =>
comment.value
.trim()
.split("\n")
.map((line) => line.trim().replace(/^\*+\s*/, ""))
.filter(Boolean)
)
.flat();
}
}

/**
* 检查节点类型是否为函数表达式或箭头函数表达式
* @param {string} type 节点类型
* @returns {boolean} 是否为函数表达式或箭头函数表达式
*/
function isFunctionExpression(type) {
return type === "FunctionExpression" || type === "ArrowFunctionExpression";
}

// 打印函数注释对象
console.log(functionComments);

输出

七、常见问题

不同日志写法是否兼容,例如单行日志,多行日志,多个单行日志,多个多行日志,混合日志

答案:兼容,请看示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
const { parse } = require("@babel/parser");
const traverse = require("@babel/traverse").default;

const code = `
// log1
function a0() {}
// log2
// log3
function b0() {}
/**
* log4
*/
function c0() {}
/**
* log5
* log6
*/
function d0() {}
/**
* log7
*/
/**
* log8
* log9
*/
function e0() {}
// log10
/**
* log11
* log12
*/
function f0() {}
`;

// 解析代码为抽象语法树(AST)
const ast = parse(code, {
sourceType: "module", // 将代码解析为 ES 模块化格式
});

// 存储函数注释的对象
let functionComments = {};

// 遍历 AST
traverse(ast, {
// 处理函数声明
FunctionDeclaration(path) {
processFunction(path.node.id.name, path.node.leadingComments);
},
// 处理变量声明
VariableDeclaration(path) {
const declaration = path.node.declarations[0];
if (declaration.init && isFunctionExpression(declaration.init.type)) {
processFunction(declaration.id.name, path.node.leadingComments);
}
},
// 处理导出的函数声明和变量声明
ExportNamedDeclaration(path) {
const declaration = path.node.declaration;
if (declaration) {
if (
declaration.type === "FunctionDeclaration" ||
(declaration.type === "VariableDeclaration" &&
declaration.declarations[0].init &&
isFunctionExpression(declaration.declarations[0].init.type))
) {
const name = declaration.id
? declaration.id.name
: declaration.declarations[0].id.name;
processFunction(name, path.node.leadingComments);
}
}
},
// 处理对象属性中的函数
ObjectProperty(path) {
if (isFunctionExpression(path.node.value.type)) {
processFunction(path.node.key.name, path.node.leadingComments);
}
},
});

/**
* 处理函数的注释
* @param {string} name 函数名
* @param {object[]} leadingComments 前导注释节点数组
*/
function processFunction(name, leadingComments) {
if (leadingComments && leadingComments.length > 0) {
functionComments[name] = leadingComments
.map((comment) =>
comment.value
.trim()
.split("\n")
.map((line) => line.trim().replace(/^\*+\s*/, ""))
.filter(Boolean)
)
.flat();
}
}


/**
* 检查节点类型是否为函数表达式或箭头函数表达式
* @param {string} type 节点类型
* @returns {boolean} 是否为函数表达式或箭头函数表达式
*/
function isFunctionExpression(type) {
return type === "FunctionExpression" || type === "ArrowFunctionExpression";
}

// 打印函数注释对象
console.log(functionComments);

输出


喜欢这篇文章?打赏一下支持一下作者吧!
【babel】提取js函数注释
https://www.cccccl.com/20240115/babel/提取js文件函数注释/
作者
Jeffrey
发布于
2024年1月15日
许可协议