generate_js.py 11.7 KB
Newer Older
金凯强's avatar
金凯强 committed
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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
'''
一 、 注释添加
    目前视图函数名是’get_list‘, 'get_one', 'post_one', 'delete_one', 'delete_list'已经自动添加注释
    1、
        如果函数名在上述5个之中却未添加注释的原因可能有:
            视图函数名为delete_one, 使用的基类方法却是delete_list,需要规范,请自行修改
            等等
    2、
        如果视图函数名不在上述5个之中,请自行添加注释,请将注释写的尽量简练,暂时只取第一行注释
        未添加注释的模块打印在控制台

    3、
        同一个模块下视图函数名重复的也将输出在控制台,请自行修改

二 、
    1. 请将视图前缀统一写在视图类装饰器上,不要写在视图函数上
        例如:
            @api('/pb_workcenter')
            class Pb_workcenter(ApiController):

                @api('/')
                def get_list(self):
                    return Pb_workcenter_service().query_list(request.args)

                @api('/<int:id>/')
                def get_one(self, id):
                    return Pb_workcenter_service().query_one(id)
        而不是:
            @api('/')
            class Pb_workcenter(ApiController):

                @api('/pb_workcenter')
                    def get_list(self):
                        return Pb_workcenter_service().query_list(request.args)

                @api('/pb_workcenter/<int:id>/')
                def get_one(self, id):
                    return Pb_workcenter_service().query_one(id)
        否则会造成获取不到文件名,造成错误,不规范的模块输出在控制台

    2. 视图类装饰器上的视图前缀统一用下划线连接,而不是用斜线分割
        例如:
            @ApiSecurityFilter
            @api('/stock_sn/')
            class Stock_Sn(ApiController):
                pass
        而不是:
            @ApiSecurityFilter
            @api('/stock/sn/')
            class Stock_Sn(ApiController):
                pass

三 、
    未添加注释的控制台输入以***分隔
    视图函数名重复的以---分隔
    视图前缀不规范的以&&&分隔

'''


import shutil
import os
import re

from huansi_utils.webapi import ApiController
from flask_app import global_app
from huansi_utils.readme.generate_readme import GenerateReadMe


BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(os.path.dirname(__file__)))))

HEAD_TEMPLATE = '''import client from '@utils/sha256/myHttpClient'
// 模块 {module_name}
const mes_url = '/mesAPI'
const {module_name}_api = {{
'''

TAIL_TEMPLATE = '''}}
export default {module_name}_api
'''

WITH_PARAMS_TEMPLATE = '''  /**
   * {comments}
   */
  {module_name}__{view_name}({params}) {{
    const route_params = {{
      routerUrl: '{params}',
      data: {{
        {params}: {params}
      }}
    }}
    return client.{method}(
      `${{mes_url}}/{url}`,
      route_params
    )
  }},
'''

WITHOUT_PARAMS_TEMPLATE = '''  /**
   * {comments}
   */
  {module_name}__{view_name}(query_params = {{}}) {{
    return client.{method}(
      `${{mes_url}}/{url}`,
      {{}},
      query_params
    )
  }},
'''

POST_TEMPLATE = '''  /**
   * {comments}
   */
  {module_name}__{view_name}(body_params) {{
    return client.{method}(
      `${{mes_url}}/{url}`,
      {{}},
      {{}},
      body_params
    )
  }},
'''

API_TEMPLATE = '''function merge(...sources) {{
  return Object.assign({{}}, ...sources)
}}
const api = merge(
  {all_module_name}
  )
export default api
'''

DOT_TEMPLATE = '''  },
}
export default'''


REMOVE_DOT_TEMPLATE = '''  }
}
export default'''



class ReadMe(GenerateReadMe):

    def __init__(self):
        self.dir = os.path.join(os.path.join(BASE_DIR, r'HuanSi.GmtMES.WEB\src\components\api'), 'readme.txt')
        self.file = open(self.dir, 'w', encoding='utf-8')

    def get_comment(self, rule):
        '''
        获取模块说明
        '''
        comments = rule.__doc__
        if comments:
            comment, author = [comment.strip() for comment in comments.splitlines()[1:3]]
            if not author:
                author = '未添加负责人'
        else:
            comment = '未添加注释'
            author = '未添加负责人'
        return comment, author


class GenerateJS:

    def __init__(self):
        self.dirname = os.path.join(os.path.join(BASE_DIR, r'HuanSi.GmtMES.WEB\src\components'), 'api')
        self.filename_list = []
        if os.path.exists(self.dirname):
            shutil.rmtree(self.dirname)
        os.mkdir(self.dirname)


    def get_route_rule(self):
        '''
        获取所有的路由规则
        '''
        with global_app.test_request_context():
            rules = ApiController()._ApiController__rules.items()
            rules = filter(lambda d: not d[0].__name__.startswith('Test'), rules)
            return rules


    def get_comments(self, klass, view_name):
        func = getattr(klass, view_name)
        comments = func.__doc__
        if comments:
            comment = comments.splitlines()[1].strip()
        else:
            print('{:<80}***  {}方法未添加注释'.format(str(klass).strip('<class> '), view_name))
            comment = '{}模块的{}方法未添加注释'.format(str(klass).strip('<class> '), view_name)
        return comment


    def get_method(self, view_name):
        '''
        获取请求方法
        '''
        if view_name.startswith('get') or view_name.startswith('query'):
            return 'get'
        elif view_name.startswith('post'):
            return 'post'
        elif view_name.startswith('delete'):
            return 'delete'


    def get_url(self, url):
        '''
        获取url
        '''
        return ''.join(url.split('<')[:-1])


    def get_params(self, url):
        '''
        获取问号参数
        '''
        pattern = re.compile(r':(.*?)>')
        return re.search(pattern, url).group(1)


    def get_module_name(self, rule, klass):
        '''
        获取模块名
        '''
        module_name = list(rule.keys())[0].split('/')[1]
        if not module_name:
            print('{:<80}&&&  模块未添加路由前缀'.format(str(klass).strip('<class> ')))
        return module_name


    def write_header(self, module_name):
        '''
        写入头文件
        '''
        self.filename_list.append(module_name)
        self.temp_filename = os.path.join(self.dirname, module_name + '_temp' + '.js')
        self.temp_file = open(self.temp_filename, 'a+', encoding='utf-8')
        self.temp_file.write(HEAD_TEMPLATE.format(module_name=module_name))


    def write_tail(self, module_name):
        '''
        写入尾文件
        '''
        self.temp_file.write(TAIL_TEMPLATE.format(module_name=module_name))
        self.remove_dot(module_name)
        self.temp_file.close()
        os.remove(self.temp_filename)


    def remove_dot(self, module_name):
        '''
        去除掉最后一个方法结尾的逗号
        '''
        self.temp_file.flush()
        self.temp_file.seek(0)
        pattern = re.compile(DOT_TEMPLATE)
        data = re.sub(pattern, REMOVE_DOT_TEMPLATE, self.temp_file.read())
        self.file = open(os.path.join(self.dirname, module_name + '.js'), 'w', encoding='utf8')
        self.file.write(data)
        self.file.close()


    def write_readme(self):
        '''
        readme文件也写入到js目录下
        :return:
        '''
        readme = ReadMe()
        readme.run()


    def genarate_file(self, module_name, url, view_name, method, klass, params=None):
        '''
        写入接口函数
        '''
        if method == 'post':
            template = POST_TEMPLATE
            if view_name == 'post_one':
                comments = '增加或更新资源'
            else:
                comments = self.get_comments(klass, view_name)
        elif method == 'delete' and view_name != 'delete_one':
            template = POST_TEMPLATE
            if view_name == 'delete_list':
                comments = '批量删除资源'
            else:
                comments = self.get_comments(klass, view_name)
        elif params:
            template = WITH_PARAMS_TEMPLATE
            if method == 'get':
                if view_name == 'get_one':
                    comments = '根据{}获取单个资源'.format(params)
                elif view_name == 'get_list':
                    comments = '根据{}获取资源列表'.format(params)
                else:
                    comments = self.get_comments(klass, view_name)
            elif method == 'delete':
                if view_name == 'delete_one':
                    comments = '根据{}删除资源'.format(params)
                else:
                    comments = self.get_comments(klass, view_name)
            else:
                comments = self.get_comments(klass, view_name)
        else:
            template = WITHOUT_PARAMS_TEMPLATE
            if method == 'get':
                if view_name == 'get_list':
                    comments = '获取全部资源列表'
                elif view_name == 'get_one':
                    comments = '获取单个资源列表'
                else:
                    comments = self.get_comments(klass, view_name)
            else:
                comments = self.get_comments(klass, view_name)
        self.temp_file.write("%s" % template.format(module_name=module_name,
                                             url=url,
                                             view_name=view_name,
                                             method=method,
                                             params=params,
                                             comments=comments))


    def write_api(self):
        '''
        写入api主文件
        :return:
        '''
        filename = os.path.join(self.dirname, 'api.js')
        with open(filename, 'a', encoding='utf-8') as f:
            for module_name in self.filename_list:
                f.write("import {0} from './{0}'\n".format(module_name))
            f.write(API_TEMPLATE.format(all_module_name=',\n  '.join(self.filename_list)))


    def handle_rule(self, rule, module_name, klass):
        '''
        处理路由规则,写入文件
        '''
        view_list = []
        self.write_header(module_name)
        for key, value in rule.items():
            route_address = key.split('/', maxsplit=1)[-1].lstrip('/')
            if ':' in route_address:
                url = self.get_url(route_address)
                params = self.get_params(route_address)
                for view_name in value:
                    if view_name not in view_list:
                        view_list.append(view_name)
                        method = self.get_method(view_name)
                        self.genarate_file(module_name, url, view_name, method, klass, params)
                    else:
                        print('{:<80}---  模块{}方法名重复'.format(str(klass).strip('<class> '), view_name))
            else:
                for view_name in value:
                    if view_name not in view_list:
                        view_list.append(view_name)
                        method = self.get_method(view_name)
                        self.genarate_file(module_name, route_address, view_name, method, klass)
                    else:
                        print('{:<80}---  模块{}方法名重复'.format(str(klass).strip('<class> '), view_name))
        self.write_tail(module_name)


    def run(self):
        '''
        主函数
        '''
        rules = self.get_route_rule()
        for rule in rules:
            klass = rule[0]
            module_name = self.get_module_name(rule[1], klass)
            self.handle_rule(rule[1], module_name, klass)
        self.write_api()
        self.write_readme()


if __name__ == '__main__':
    generateJS = GenerateJS()
    generateJS.run()