@@ -24,124 +24,222 @@ function formatClassName(className) {
2424 return parts . join ( '_' ) ;
2525}
2626
27- const lines = content . split ( '\n' ) ;
28- const results = [ ] ;
29- let currentClass = null ;
30-
31- for ( let i = 0 ; i < lines . length ; i ++ ) {
32- const line = lines [ i ] . trim ( ) ;
33-
34- // 捕获 class 声明
35- if ( line . startsWith ( 'declare class ' ) ) {
36- const match = line . match ( / d e c l a r e \s + c l a s s \s + ( \w + ) / ) ;
27+ // === 读取已有 EDA_Codes.js 用于增量合并 ===
28+ let existingMap = new Map ( ) ;
29+ if ( fs . existsSync ( outputPath ) ) {
30+ try {
31+ const existingContent = fs . readFileSync ( outputPath , 'utf8' ) ;
32+ const match = existingContent . match ( / e d c o d e \s * = \s * ( \[ .* ?\] ) ; / s) ;
3733 if ( match ) {
38- currentClass = match [ 1 ] ;
39- continue ;
34+ const arrStr = match [ 1 ] ;
35+ const parsed = new Function ( 'return ' + arrStr ) ( ) ;
36+ for ( const item of parsed ) {
37+ if ( item && typeof item . methodPath === 'string' ) {
38+ existingMap . set ( item . methodPath , item ) ;
39+ }
40+ }
4041 }
42+ } catch ( e ) {
43+ console . warn ( '无法解析已有的 EDA_Codes.js,将重新生成全部内容。' , e . message ) ;
44+ existingMap = new Map ( ) ;
4145 }
46+ }
4247
43- // 离开当前 class
44- if ( currentClass && line === '}' ) {
45- currentClass = null ;
46- continue ;
47- }
48+ // === 解析逻辑:提取类型描述 + 成员 ===
49+ const newResults = [ ] ;
50+ const lines = content . split ( '\n' ) ;
4851
49- if ( ! currentClass ) continue ;
52+ // 第一步:用正则提取所有 /** ... */ declare (class|interface) 块的主描述
53+ const fullContent = content ;
54+ const typeBlockRegex = / \/ \* \* ( [ \s \S ] * ?) \* \/ / g;
55+ let typeMatch ;
56+ while ( ( typeMatch = typeBlockRegex . exec ( fullContent ) ) !== null ) {
57+ const commentStart = typeMatch . index ;
58+ const commentEnd = typeMatch . index + typeMatch [ 0 ] . length ;
59+ const afterComment = fullContent . slice ( commentEnd ) . trimStart ( ) ;
60+
61+ // 检查紧接着是否是 declare class/interface(允许 export 和空格)
62+ const declareMatch = afterComment . match ( / ^ ( \s * (?: e x p o r t \s + ) ? d e c l a r e \s + ( c l a s s | i n t e r f a c e ) \s + ( \w + ) ) / ) ;
63+ if ( declareMatch ) {
64+ const typeName = declareMatch [ 3 ] ;
65+ const commentText = typeMatch [ 1 ] ;
66+
67+ // 提取主描述(第一段非 @ 的行)
68+ let mainDesc = '' ;
69+ const commentLines = commentText . split ( '\n' ) ;
70+ for ( const line of commentLines ) {
71+ const trimmed = line . trim ( ) ;
72+ if ( trimmed . startsWith ( '*' ) && ! trimmed . startsWith ( '* @' ) ) {
73+ const text = trimmed . replace ( / ^ \* \s * / , '' ) . trim ( ) ;
74+ if ( text && ! mainDesc ) {
75+ mainDesc = text ;
76+ break ;
77+ }
78+ }
79+ }
5080
51- // 跳过被排除的成员
52- if ( line . startsWith ( '/* Excluded from this release type:' ) ) {
53- continue ;
81+ if ( mainDesc ) {
82+ const formattedName = formatClassName ( typeName ) ;
83+ const typePath = `eda.${ formattedName } ` ;
84+ newResults . push ( {
85+ methodPath : typePath ,
86+ description : mainDesc . replace ( / \r / g, '' ) ,
87+ parameters : [ ] ,
88+ } ) ;
89+ }
5490 }
91+ }
5592
56- // 只处理标准 JSDoc 注释块(以 /** 开始)
57- if ( line === '/**' ) {
58- let description = '' ;
59- const params = [ ] ;
60- let returnsDesc = '' ; // ← 新增:用于存储返回值描述
61- let j = i + 1 ;
93+ // 第二步:遍历所有 declare class/interface,提取内部成员(属性/方法)
94+ for ( let i = 0 ; i < lines . length ; i ++ ) {
95+ let line = lines [ i ] . trim ( ) ;
96+ if ( line === '' || line . startsWith ( '//' ) ) continue ;
6297
63- // 解析整个注释块直到 */
64- while ( j < lines . length ) {
65- const l = lines [ j ] . trim ( ) ;
66- if ( l === '*/' ) {
67- break ;
68- }
98+ // 匹配 declare 或 export declare
99+ const declMatch = line . match ( / ^ (?: e x p o r t \s + ) ? d e c l a r e \s + ( c l a s s | i n t e r f a c e ) \s + ( \w + ) / ) ;
100+ if ( declMatch ) {
101+ const typeName = declMatch [ 2 ] ;
102+ const formattedName = formatClassName ( typeName ) ;
103+ const typePath = `eda. ${ formattedName } ` ;
69104
70- // 提取主描述:第一个非 @ 标签的 * 行
71- if ( l . startsWith ( '*' ) && ! l . startsWith ( '* @' ) ) {
72- const text = l . slice ( 1 ) . trim ( ) ;
73- if ( text && ! description ) {
74- description = text ;
75- }
105+ // 解析内部结构
106+ let j = i + 1 ;
107+ let depth = 1 ;
108+ let localPendingComment = null ;
109+
110+ while ( j < lines . length && depth > 0 ) {
111+ const innerLineRaw = lines [ j ] ;
112+ const innerLine = innerLineRaw . trim ( ) ;
113+
114+ if ( innerLine . endsWith ( '{' ) ) {
115+ depth ++ ;
116+ } else if ( innerLine === '}' ) {
117+ depth -- ;
118+ if ( depth === 0 ) break ;
76119 }
77120
78- // 提取 @param 行:* @param name - description
79- const paramMatch = l . match ( / ^ \* \s * @ p a r a m \s + ( [ a - z A - Z _ $ ] [ \w $ ] * ) \s * - \s * ( .+ ) $ / ) ;
80- if ( paramMatch ) {
81- let desc = paramMatch [ 2 ] . trim ( ) ;
82- desc = desc . replace ( / ' / g, "\\'" ) . replace ( / \r / g, '' ) ;
83- params . push ( {
84- name : paramMatch [ 1 ] ,
85- description : desc ,
86- } ) ;
121+ // 跳过排除标记
122+ if ( innerLine . startsWith ( '/* Excluded from this release type:' ) ) {
123+ localPendingComment = null ;
124+ j ++ ;
125+ continue ;
87126 }
88127
89- // 提取 @returns 或 @return(支持两种写法)
90- const returnMatch = l . match ( / ^ \* \s * @ (?: r e t u r n s ? | r e t u r n ) \s + ( .+ ) $ / ) ;
91- if ( returnMatch && ! returnsDesc ) {
92- returnsDesc = returnMatch [ 1 ] . trim ( ) . replace ( / ' / g, "\\'" ) . replace ( / \r / g, '' ) ;
128+ // 单行 JSDoc 注释(用于属性)
129+ if ( innerLine . startsWith ( '/**' ) && innerLine . endsWith ( '*/' ) ) {
130+ localPendingComment = innerLine . slice ( 3 , - 2 ) . trim ( ) . replace ( / \r / g, '' ) ;
131+ j ++ ;
132+ continue ;
93133 }
94134
95- j ++ ;
96- }
135+ // 多行 JSDoc 注释(用于方法)
136+ if ( innerLine === '/**' ) {
137+ let desc = '' ;
138+ let params = [ ] ;
139+ let returnsDesc = '' ;
140+ let k = j + 1 ;
141+ while ( k < lines . length ) {
142+ const l = lines [ k ] . trim ( ) ;
143+ if ( l === '*/' ) break ;
144+ if ( l . startsWith ( '*' ) && ! l . startsWith ( '* @' ) ) {
145+ const text = l . slice ( 1 ) . trim ( ) ;
146+ if ( text && ! desc ) desc = text ;
147+ }
148+ const paramMatch = l . match ( / ^ \* \s * @ p a r a m \s + ( [ a - z A - Z _ $ ] [ \w $ ] * ) \s * - \s * ( .+ ) $ / ) ;
149+ if ( paramMatch ) {
150+ params . push ( {
151+ name : paramMatch [ 1 ] ,
152+ description : paramMatch [ 2 ] . trim ( ) . replace ( / \r / g, '' )
153+ } ) ;
154+ }
155+ const returnMatch = l . match ( / ^ \* \s * @ (?: r e t u r n s ? | r e t u r n ) \s + ( .+ ) $ / ) ;
156+ if ( returnMatch && ! returnsDesc ) {
157+ returnsDesc = returnMatch [ 1 ] . trim ( ) . replace ( / \r / g, '' ) ;
158+ }
159+ k ++ ;
160+ }
97161
98- // 方法定义应在 */ 的下一行
99- const methodLineIndex = j + 1 ;
100- if ( methodLineIndex < lines . length ) {
101- const methodLine = lines [ methodLineIndex ] ;
102- const methodMatch = methodLine . match ( / ^ \s * (?: a s y n c \s + ) ? ( \w + ) \s * \( / ) ;
103- if ( methodMatch ) {
104- const methodName = methodMatch [ 1 ] ;
105- const classNameLower = formatClassName ( currentClass ) ;
106- const item = {
107- methodPath : `eda.${ classNameLower } .${ methodName } ` ,
108- description : description . replace ( / ' / g, "\\'" ) ,
109- parameters : params ,
110- } ;
111- if ( returnsDesc !== '' ) {
112- item . returns = returnsDesc ;
162+ // 方法应在 */ 下一行
163+ const methodLineIndex = k + 1 ;
164+ if ( methodLineIndex < lines . length ) {
165+ const methodLine = lines [ methodLineIndex ] ;
166+ const methodMatch = methodLine . match ( / ^ \s * (?: a s y n c \s + ) ? ( \w + ) \s * \( / ) ;
167+ if ( methodMatch ) {
168+ const methodName = methodMatch [ 1 ] ;
169+ const item = {
170+ methodPath : `${ typePath } .${ methodName } ` ,
171+ description : desc ,
172+ parameters : params ,
173+ } ;
174+ if ( returnsDesc ) item . returns = returnsDesc ;
175+ newResults . push ( item ) ;
176+ j = methodLineIndex ;
177+ }
113178 }
114- results . push ( item ) ;
179+ j = k ;
180+ localPendingComment = null ;
181+ j ++ ;
182+ continue ;
183+ }
115184
116- // 跳过已处理的方法行
117- i = methodLineIndex ;
185+ // 属性解析(id: string 等)
186+ if ( innerLine . includes ( ':' ) && ! innerLine . includes ( '(' ) && / ^ [ a - z A - Z _ $ ] / . test ( innerLine ) ) {
187+ const propMatch = innerLine . match ( / ^ ( \w + ) ( \? ? ) \s * : / ) ;
188+ if ( propMatch ) {
189+ const propName = propMatch [ 1 ] ;
190+ newResults . push ( {
191+ methodPath : `${ typePath } .${ propName } ` ,
192+ description : localPendingComment || '' ,
193+ parameters : [ ] ,
194+ } ) ;
195+ }
196+ localPendingComment = null ;
197+ } else {
198+ localPendingComment = null ;
118199 }
200+
201+ j ++ ;
119202 }
120203
121- // 跳过整个注释块
122- i = j ;
123- continue ;
204+ i = j - 1 ; // for 循环会 i++
124205 }
125206}
126207
127- // 构建输出字符串
128- let outputStr = 'edcode = [\n' ;
129- results . forEach ( item => {
130- outputStr += '\t{\n' ;
131- outputStr += `\t\t'methodPath': '${ item . methodPath } ',\n` ;
132- outputStr += `\t\t'description': '${ item . description } ',\n` ;
208+ // === 增量合并:新条目 + 未被覆盖的旧条目 ===
209+ const newMap = new Map ( ) ;
210+ for ( const item of newResults ) {
211+ newMap . set ( item . methodPath , item ) ;
212+ }
213+
214+ const merged = [
215+ ...newResults ,
216+ ...Array . from ( existingMap . entries ( ) )
217+ . filter ( ( [ key ] ) => ! newMap . has ( key ) )
218+ . map ( ( [ , item ] ) => item )
219+ ] ;
220+
221+ merged . sort ( ( a , b ) => a . methodPath . localeCompare ( b . methodPath ) ) ;
222+
223+ // === 安全输出:使用 JSON.stringify 避免语法错误 ===
224+ const outputObject = merged . map ( item => {
225+ const obj = {
226+ methodPath : item . methodPath ,
227+ description : item . description ,
228+ parameters : ( item . parameters || [ ] ) . map ( p => ( {
229+ name : p . name ,
230+ description : p . description
231+ } ) )
232+ } ;
133233 if ( item . hasOwnProperty ( 'returns' ) ) {
134- outputStr += `\t\t'returns': ' ${ item . returns } ',\n` ;
234+ obj . returns = item . returns ;
135235 }
136- outputStr += '\t\t\'parameters\': [\n' ;
137- item . parameters . forEach ( param => {
138- outputStr += `\t\t\t{ 'name': '${ param . name } ', 'description': '${ param . description } ' },\n` ;
139- } ) ;
140- outputStr += '\t\t],\n' ;
141- outputStr += '\t},\n' ;
236+ return obj ;
142237} ) ;
143- outputStr += '];\n' ;
238+
239+ const jsonString = JSON . stringify ( outputObject , null , '\t' ) ;
240+ const outputStr = 'edcode = ' + jsonString + ';\n' ;
144241
145242fs . writeFileSync ( outputPath , outputStr , 'utf8' ) ;
146243
147- console . log ( `成功生成 ${ results . length } 个方法条目到 ${ outputPath } ` ) ;
244+ console . log ( `生成 ${ newResults . length } 个新条目` ) ;
245+ console . log ( `共 ${ merged . length } 项` ) ;
0 commit comments