11/**
2- * 向生成的组件类型文件中注入注释
2+ * 通过在其他脚本 import codeShift 方法,可以向生成的组件类型文件中增加 JSDoc
3+ * 通过npm scripts 触发,可在 src/types 下生成 props.json 文件
34 */
45import * as path from 'path'
6+ import { dirname } from 'path'
57import fse from 'fs-extra'
68import j from 'jscodeshift'
79import markdownit from 'markdown-it'
810import { fileURLToPath } from 'url'
9- import { dirname } from 'path'
1011
1112const __filename = fileURLToPath ( import . meta. url )
1213const __dirname = dirname ( __filename )
13- const dist = 'release/h5/dist'
14+
15+ const PROPS_JSON = process . env . PROPS_JSON
1416
1517/**
1618 * 通过 cofnig.json 获取所有组件的数据
1719 */
1820function readAllComponents ( ) {
1921 const config = JSON . parse ( fse . readFileSync ( path . join ( __dirname , '../src/config.json' ) ) . toString ( ) )
20- const components = config . nav . reduce ( function ( accumulator , currentValue ) {
22+ const components = config . nav . reduce ( function ( accumulator , currentValue ) {
2123 currentValue . packages . forEach ( ( pkg ) => {
22- if ( pkg . exclude || pkg . version !== '2.0.0' ) {
24+ if ( pkg . exclude ) {
2325 return
2426 }
2527 accumulator . push ( pkg )
@@ -52,7 +54,7 @@ function extractPropsTable(doc) {
5254 token . type == 'heading_open' &&
5355 token . tag == 'h3' &&
5456 sources [ index + 1 ] . type == 'inline' &&
55- sources [ index + 1 ] . content === 'Props '
57+ sources [ index + 1 ] . content . toLowerCase ( ) == 'props '
5658 ) {
5759 const componentName = sources [ index - 2 ] . content
5860 let startIndex = index + 3
@@ -99,95 +101,91 @@ function markdownTable2Json(table) {
99101 return rows
100102}
101103
102- function addComments ( dtsPath , propsTable , componentName ) {
103- const source = fse . readFileSync ( dtsPath ) . toString ( )
104-
105- function findInTable ( identifierName ) {
106- const [ info ] = propsTable . filter (
107- ( t ) => t [ 0 ] . replace ( / ' / g, '' ) === identifierName
108- )
109- return info
110- }
111-
112- const transform = ( file , api ) => {
113- const j = api . jscodeshift . withParser ( 'ts' )
114- return j ( file . source )
115- . find ( j . TSInterfaceDeclaration , {
116- id : {
117- name : componentName + 'Props' ,
118- type : 'Identifier' ,
119- } ,
120- } )
121- . forEach ( ( path ) => {
122- path . value ?. body ?. body ?. forEach ( ( item ) => {
123- if ( ! item . key ) return
124- const info = findInTable ( item . key . name )
125- if ( ! info ) return
126- item [ 'comments' ] = [
127- j . commentBlock ( `*\n* ${ info [ 1 ] } \n* @default ${ info [ 3 ] } \n` ) ,
128- ]
129- } )
130- } )
131- . toSource ( )
132- }
133- const result = transform ( { source } , { jscodeshift : j } )
134- if ( result ) {
135- fse . writeFileSync ( dtsPath , result )
136- }
137- }
138-
139- function getDtsPath ( key , outDir ) {
140- // Tabs.Tabpane -> tabpane
141- let name
142- if ( key === 'Tabs.Tabpane' ) {
143- name = 'tabpane'
144- } else {
145- name = key . toLowerCase ( ) . replace ( '.' , '' )
146- }
147- const file = path . join ( __dirname , `../${ outDir } /es/packages` , name , name + '.d.ts' )
148- return file
149- }
150-
151- function getComponentName ( key ) {
152- // Tabs.Tabpane -> tabpane
153- let name = key
154- if ( key === 'Tabs.Tabpane' ) {
155- name = 'TabPane'
156- }
157- return name . replace ( '.' , '' )
158- }
159-
160104/**
161105 * step 1: 从 config.json 中读取组件列表,迭代
162106 * step a: 读取组件的 doc.md 或 doc.taro.md
163107 * step b: 提取文档中的 Props 相关的表格,并转换为 JSON 数据
164108 * step c: 添加注释
165109 */
166- export function codeShift ( env ) {
110+ export function codeShift ( platform ) {
167111 const components = readAllComponents ( )
112+ const componentsProps = { }
168113 components . forEach ( ( component ) => {
169114 const { name } = component
170115 const componentDocumentPath = path . join (
171116 __dirname ,
172117 '../src/packages' ,
173118 name . toLowerCase ( ) ,
174- env === 'taro' ? 'doc.taro.md' : 'doc.md'
119+ platform === 'taro' ? 'doc.taro.md' : 'doc.md' ,
175120 )
176121 if ( fse . pathExistsSync ( componentDocumentPath ) ) {
177122 const tables = extractPropsTable (
178- readComponentDocument ( componentDocumentPath )
123+ readComponentDocument ( componentDocumentPath ) ,
179124 )
180125 Object . keys ( tables ) . forEach ( ( key ) => {
181- const dtsPath = getDtsPath ( key , env !== 'taro' ? dist : dist . replace ( 'h5' , env ) )
182- if ( fse . pathExistsSync ( dtsPath ) ) {
183- const table = markdownTable2Json ( tables [ key ] )
184- addComments ( dtsPath , table , getComponentName ( key ) )
185- } else {
186- console . warn ( name + ' dts file does not exist' )
187- }
126+ const table = markdownTable2Json ( tables [ key ] )
127+ componentsProps [ key . toLowerCase ( ) ] = table . reduce ( ( acc , [ key , desc , types , defaultValue ] ) => {
128+ acc [ key ] = {
129+ desc : desc ,
130+ types : types ,
131+ defaultValue : defaultValue ,
132+ }
133+ return acc
134+ } , { } )
188135 } )
189136 } else {
190137 // console.warn(name + ' document file does not exist')
191138 }
139+ if ( ! PROPS_JSON ) {
140+ if ( ! component . exportEmpty ) addJSDoc ( componentsProps , name , platform )
141+ }
192142 } )
143+ if ( PROPS_JSON ) {
144+ const jsonContent = JSON . stringify ( componentsProps , ' ' , 2 )
145+ fse . writeFileSync ( path . join ( __dirname , '../src/types' , `props.json` ) , jsonContent )
146+ }
193147}
148+
149+ function addJSDoc ( propsJson , componentName , platform ) {
150+ const transform = ( file , api ) => {
151+ const j = api . jscodeshift . withParser ( 'ts' )
152+ const ast = j ( file . source )
153+ function addComment ( item ) {
154+ if ( ! item . key ) return
155+ const description = propsJson [ componentName . toLowerCase ( ) ] [ item . key . name ]
156+ if ( ! description ) return
157+ item [ 'comments' ] = [
158+ j . commentBlock ( `*\n* ${ description [ 'desc' ] } \n` ) ,
159+ ]
160+ }
161+ ast
162+ . find ( j . TSTypeAliasDeclaration ) . forEach ( ( path ) => {
163+ const annotationTypes = path . value . typeAnnotation . types
164+ if ( ! annotationTypes ) return
165+ const typeLiteral = annotationTypes [ annotationTypes . length - 1 ]
166+ if ( ! typeLiteral . members ) return
167+ typeLiteral . members . forEach ( ( item ) => {
168+ addComment ( item )
169+ } )
170+ } )
171+ ast . find ( j . TSInterfaceDeclaration , {
172+ id : {
173+ name : `Base${ componentName } ` ,
174+ type : 'Identifier' ,
175+ } ,
176+ } )
177+ . forEach ( ( path ) => {
178+ path . value ?. body ?. body ?. forEach ( ( item ) => {
179+ addComment ( item )
180+ } )
181+ } )
182+
183+ return ast . toSource ( )
184+ }
185+ const baseType = path . join ( __dirname , `../release/${ platform || 'h5' } /dist/es/types/spec/${ componentName . toLowerCase ( ) } /base.d.ts` )
186+ const source = fse . readFileSync ( baseType , { encoding : 'utf8' } )
187+ const result = transform ( { source } , { jscodeshift : j } )
188+ fse . writeFileSync ( baseType , result )
189+ }
190+
191+ PROPS_JSON && codeShift ( 'h5' )
0 commit comments