UNPKG

@clean-js/api-gen

Version:

[docs](https://lulusir.github.io/clean-js/api-gen/usage) [中文文档](https://github.com/lulusir/clean-js-api-gen/blob/main/README-zh.md)

309 lines (300 loc) 10.2 kB
'use strict'; var dayjs = require('dayjs'); var fsExtra = require('fs-extra'); var _ = require('lodash'); var path = require('path'); var jiti = require('jiti'); class Config { url = ''; type = 'axios'; outDir = 'clean-js'; diff = true; loadRuntime() { const rootDir = process.cwd(); const require = jiti(rootDir, { interopDefault: true, esmResolve: true }); const runtimeConfig = require('./clean.config'); Object.assign(this, runtimeConfig); } getOutPath() { return path.join(process.cwd(), this.outDir); } getServicePath(serviceName = 'http') { return path.join(this.getOutPath(), `./${serviceName}.service.ts`); } getAstCachePath() { return path.join(this.getOutPath(), '.ast.cache.json'); } getLogPath() { return path.join(this.getOutPath(), './log'); } } const config = new Config(); class DiffAnalyzer { root; cache = null; log = { api: { data: [], addLen: 0, reduceLen: 0, }, pathParameter: { data: [], }, queryParameter: { data: [], }, bodyParameter: { data: [], }, responseParameter: { datas: [], }, }; constructor(root) { this.root = root; } readCache() { const dir = config.getAstCachePath(); if (fsExtra.existsSync(dir)) { const data = fsExtra.readJsonSync(dir); this.cache = data; } } writeCache() { const dir = config.getAstCachePath(); fsExtra.writeJsonSync(dir, this.root); } async visit() { this.readCache(); this.writeCache(); if (this.cache === null) { return; } await this.visitRootAST(this.root, this.cache); } async visitRootAST(node, cache) { this.apiDiff(node, cache); this.pathParamsDiff(node, cache); this.queryParamsDiff(node, cache); this.bodyParamsDiff(node, cache); this.responsesDiff(node, cache); if (this.hasDiff()) { this.writeLog(); } } apiDiff(node, cache) { const cacheApi = cache.requests.map((v) => { return `${v.method.toUpperCase()} ${v.url}`; }); const cacheApiMap = cacheApi.reduce((p, c) => { p[c] = p[c] ? p[c] + 1 : 1; return p; }, {}); const nodeApi = node.requests.map((v) => { return `${v.method.toUpperCase()} ${v.url}`; }); const nodeApiMap = nodeApi.reduce((p, c) => { p[c] = p[c] ? p[c] + 1 : 1; return p; }, {}); for (let i = 0; i < cacheApi.length; i++) { const a = cacheApi[i]; if (!nodeApiMap[a]) { this.log.api.reduceLen += 1; this.log.api.data.push('Reduce API ' + a); } } for (let i = 0; i < nodeApi.length; i++) { const a = nodeApi[i]; if (!cacheApiMap[a]) { this.log.api.addLen += 1; this.log.api.data.push('Add API ' + a); } } } pathParamsDiff(node, cache) { const cacheAPiMap = cache.requests.reduce((p, c) => { const k = c.method + c.url; p[k] = c; return p; }, {}); for (let i = 0; i < node.requests.length; i++) { const req = node.requests[i]; const k = req.method + req.url; const cacheReq = cacheAPiMap[k]; if (cacheReq) { const isEqual = _.isEqual(cacheReq.pathParams, req.pathParams); if (!isEqual) { function clean(p) { if (p) { const r = Object.entries(_.cloneDeep(p)).reduce((p, [k, v]) => { p[k] = v.schema; return p; }, {}); return r; } return p; } this.log.pathParameter.data.push(`Parameters Change in path ${req.method} ${req.url} ${JSON.stringify(clean(cacheReq.pathParams))} -> ${JSON.stringify(clean(req.pathParams))}`); } } } } queryParamsDiff(node, cache) { const cacheAPiMap = cache.requests.reduce((p, c) => { const k = c.method + c.url; p[k] = c; return p; }, {}); for (let i = 0; i < node.requests.length; i++) { const req = node.requests[i]; const k = req.method + req.url; const cacheReq = cacheAPiMap[k]; if (cacheReq) { const isEqual = _.isEqual(cacheReq.queryParams, req.queryParams); if (!isEqual) { function clean(p) { if (p) { const r = Object.entries(_.cloneDeep(p)).reduce((p, [k, v]) => { p[k] = v.schema; return p; }, {}); return r; } return p; } this.log.queryParameter.data.push(`Parameters Change in query ${req.method} ${req.url} ${JSON.stringify(clean(cacheReq.queryParams))} -> ${JSON.stringify(clean(req.queryParams))}`); } } } } bodyParamsDiff(node, cache) { const cacheAPiMap = cache.requests.reduce((p, c) => { const k = c.method + c.url; p[k] = c; return p; }, {}); for (let i = 0; i < node.requests.length; i++) { const req = node.requests[i]; const k = req.method + req.url; const cacheReq = cacheAPiMap[k]; if (cacheReq) { const isEqual = _.isEqual(cacheReq.bodyParams, req.bodyParams); if (!isEqual) { function clean(p) { if (p) { const r = Object.entries(_.cloneDeep(p)).reduce((p, [k, v]) => { p[k] = v.schema; return p; }, {}); return r; } return p; } this.log.bodyParameter.data.push(`Parameters Change in body ${req.method} ${req.url} ${JSON.stringify(clean(cacheReq.bodyParams))} -> ${JSON.stringify(clean(req.bodyParams))}`); } } } } responsesDiff(node, cache) { const cacheAPiMap = cache.requests.reduce((p, c) => { const k = c.method + c.url; p[k] = c; return p; }, {}); for (let i = 0; i < node.requests.length; i++) { const req = node.requests[i]; const k = req.method + req.url; const cacheReq = cacheAPiMap[k]; if (cacheReq) { const cacheRes200 = cacheReq.responses?.[0]; const nodeRes200 = req.responses?.[0]; const isEqual = _.isEqual(cacheRes200, nodeRes200); if (!isEqual) { this.log.responseParameter.datas.push([ `Parameters Change in response ${req.method} ${req.url} \n${JSON.stringify(cacheRes200, null, 2)}\n->\n${JSON.stringify(nodeRes200, null, 2)}`, ]); } } } } writeLog() { const dir = config.getLogPath(); const date = dayjs().format('YYYY-MM-DD HH:mm:ss'); const fileName = date + '.log'; const apiText = (() => { if (this.log.api.addLen > 0) { return `Added ${this.log.api.addLen} APIs`; } if (this.log.api.reduceLen > 0) { return `Reduce ${this.log.api.reduceLen} APIs`; } return ''; })(); const apiDiffText = (() => { if (this.log.api.data.length) { return this.log.api.data.join('\n'); } return ''; })(); const modifyText = (() => { const len = this.log.bodyParameter.data.length + this.log.pathParameter.data.length + this.log.queryParameter.data.length + this.log.responseParameter.datas.length; if (len > 0) { return `Modified ${len} APIs `; } return ''; })(); const pathText = (() => { return this.log.pathParameter.data.join('\n') || ''; })(); const queryText = (() => { return this.log.queryParameter.data.join('\n') || ''; })(); const bodyText = (() => { return this.log.bodyParameter.data.join('\n') || ''; })(); const responseText = (() => { return this.log.responseParameter.datas?.[0]?.join('\n') || ''; })(); let text = ` @clean-js/api-gen Date: ${date} Sum-up: ${apiText} ${modifyText} ${apiDiffText} ${pathText} ${queryText} ${bodyText} ${responseText} `; if (!fsExtra.existsSync(dir)) { fsExtra.mkdirsSync(dir); } fsExtra.writeFileSync(path.join(dir, fileName), text, 'utf-8'); } hasDiff() { if (this.log.api.addLen > 0) { return true; } if (this.log.api.reduceLen > 0) { return true; } const len = this.log.bodyParameter.data.length + this.log.pathParameter.data.length + this.log.queryParameter.data.length + this.log.responseParameter.datas.length; if (len > 0) { return true; } return false; } } process.on('message', (ast) => { console.log('Diff...'); const diff = new DiffAnalyzer(JSON.parse(ast)); diff.visit(); process.exit(); });