Browse Source
* support Access-Control-Allow-Headers * add magic code * add magic code * add magic!!!! code * try auto publish * new plugin * update script * use fetch-blocks package * add env * add fetch-blocks package * fix ci error * fix lint error * delete extra comments * use https://ant-design-pro.netlify.compull/4622/head
committed by
GitHub
15 changed files with 42 additions and 636 deletions
@ -0,0 +1 @@ |
|||
test.preview.pro.ant.design |
|||
@ -1,130 +0,0 @@ |
|||
const path = require('path'); |
|||
const fs = require('fs'); |
|||
const fetch = require('node-fetch'); |
|||
const exec = require('child_process').exec; |
|||
const getNewRouteCode = require('./repalceRouter'); |
|||
const router = require('./router.config'); |
|||
const chalk = require('chalk'); |
|||
const insertCode = require('./insertCode'); |
|||
|
|||
const fetchGithubFiles = async () => { |
|||
const ignoreFile = ['_scripts']; |
|||
const data = await fetch(`https://api.github.com/repos/ant-design/pro-blocks/git/trees/master`); |
|||
if (data.status !== 200) { |
|||
return; |
|||
} |
|||
const { tree } = await data.json(); |
|||
const files = tree.filter(file => file.type === 'tree' && !ignoreFile.includes(file.path)); |
|||
return Promise.resolve(files); |
|||
}; |
|||
|
|||
const relativePath = path.join(__dirname, '../config/config.ts'); |
|||
|
|||
const findAllInstallRouter = router => { |
|||
let routers = []; |
|||
router.forEach(item => { |
|||
if (item.component && item.path) { |
|||
if (item.path !== '/user' || item.path !== '/') { |
|||
routers.push({ |
|||
...item, |
|||
routes: !!item.routes, |
|||
}); |
|||
} |
|||
} |
|||
if (item.routes) { |
|||
routers = routers.concat(findAllInstallRouter(item.routes)); |
|||
} |
|||
}); |
|||
return routers; |
|||
}; |
|||
|
|||
const filterParentRouter = (router, layout) => { |
|||
return [...router] |
|||
.map(item => { |
|||
if (!item.path && item.component === '404') { |
|||
return item; |
|||
} |
|||
if (item.routes && (!router.component || layout)) { |
|||
return { ...item, routes: filterParentRouter(item.routes, false) }; |
|||
} |
|||
if (item.redirect) { |
|||
return item; |
|||
} |
|||
return null; |
|||
}) |
|||
.filter(item => item); |
|||
}; |
|||
const firstUpperCase = pathString => { |
|||
return pathString |
|||
.replace('.', '') |
|||
.split(/\/|\-/) |
|||
.map(s => s.toLowerCase().replace(/( |^)[a-z]/g, L => L.toUpperCase())) |
|||
.filter(s => s) |
|||
.join(''); |
|||
}; |
|||
|
|||
const execCmd = shell => { |
|||
return new Promise((resolve, reject) => { |
|||
exec(shell, { encoding: 'utf8' }, (error, statusbar) => { |
|||
if (error) { |
|||
console.log(error); |
|||
return reject(error); |
|||
} |
|||
console.log(statusbar); |
|||
resolve(); |
|||
}); |
|||
}); |
|||
}; |
|||
|
|||
// replace router config
|
|||
const parentRouter = filterParentRouter(router, true); |
|||
const { routesPath, code } = getNewRouteCode(relativePath, parentRouter); |
|||
// write ParentRouter
|
|||
fs.writeFileSync(routesPath, code); |
|||
|
|||
const installBlock = async () => { |
|||
let gitFiles = await fetchGithubFiles(); |
|||
const installRouters = findAllInstallRouter(router); |
|||
const installBlockIteration = async i => { |
|||
const item = installRouters[i]; |
|||
|
|||
if (!item || !item.path) { |
|||
return Promise.resolve(); |
|||
} |
|||
const gitPath = firstUpperCase(item.path); |
|||
// 如果这个区块在 git 上存在
|
|||
if (gitFiles.find(file => file.path === gitPath)) { |
|||
console.log('install ' + chalk.green(item.name) + ' to: ' + chalk.yellow(item.path)); |
|||
gitFiles = gitFiles.filter(file => file.path !== gitPath); |
|||
const skipModifyRouter = item.routes ? '--skip-modify-routes' : ''; |
|||
const cmd = `umi block add https://github.com/ant-design/pro-blocks/tree/master/${gitPath} --path=${item.path} ${skipModifyRouter}`; |
|||
try { |
|||
await execCmd(cmd); |
|||
console.log(`install ${chalk.hex('#1890ff')(item.name)} success`); |
|||
} catch (error) { |
|||
console.error(error); |
|||
} |
|||
} |
|||
return installBlockIteration(i + 1); |
|||
}; |
|||
// 安装路由中设置的区块
|
|||
await installBlockIteration(0); |
|||
|
|||
const installGitFile = async i => { |
|||
const item = gitFiles[i]; |
|||
if (!item || !item.path) { |
|||
return Promise.resolve(); |
|||
} |
|||
console.log('install ' + chalk.green(item.path)); |
|||
const cmd = `umi block add https://github.com/ant-design/pro-blocks/tree/master/${item.path}`; |
|||
await execCmd(cmd); |
|||
return installBlockIteration(1); |
|||
}; |
|||
|
|||
// 安装 router 中没有的剩余区块.
|
|||
installGitFile(0); |
|||
}; |
|||
installBlock().then(() => { |
|||
// 插入 pro 需要的演示代码
|
|||
insertCode(); |
|||
}); |
|||
@ -1,161 +0,0 @@ |
|||
const parser = require('@babel/parser'); |
|||
const traverse = require('@babel/traverse'); |
|||
const generate = require('@babel/generator'); |
|||
const t = require('@babel/types'); |
|||
const fs = require('fs'); |
|||
const path = require('path'); |
|||
const prettier = require('prettier'); |
|||
const chalk = require('chalk'); |
|||
|
|||
const parseCode = code => { |
|||
return parser.parse(code, { |
|||
sourceType: 'module', |
|||
plugins: ['typescript', 'jsx'], |
|||
}).program.body[0]; |
|||
}; |
|||
|
|||
/** |
|||
* 生成代码 |
|||
* @param {*} ast |
|||
*/ |
|||
function generateCode(ast) { |
|||
const newCode = generate.default(ast, {}).code; |
|||
return prettier.format(newCode, { |
|||
// format same as ant-design-pro
|
|||
singleQuote: true, |
|||
trailingComma: 'es5', |
|||
printWidth: 100, |
|||
parser: 'typescript', |
|||
}); |
|||
} |
|||
|
|||
const SettingCodeString = ` |
|||
<SettingDrawer |
|||
settings={settings} |
|||
onSettingChange={config => |
|||
dispatch({ |
|||
type: 'settings/changeSetting', |
|||
payload: config, |
|||
}) |
|||
} |
|||
/> |
|||
`;
|
|||
|
|||
const mapAst = (configPath, callBack) => { |
|||
const ast = parser.parse(fs.readFileSync(configPath, 'utf-8'), { |
|||
sourceType: 'module', |
|||
plugins: ['typescript', 'jsx'], |
|||
}); |
|||
// 查询当前配置文件是否导出 routes 属性
|
|||
traverse.default(ast, { |
|||
Program({ node }) { |
|||
const { body } = node; |
|||
callBack(body); |
|||
}, |
|||
}); |
|||
return generateCode(ast); |
|||
}; |
|||
|
|||
const insertBasicLayout = configPath => { |
|||
return mapAst(configPath, body => { |
|||
const index = body.findIndex(item => { |
|||
return item.type !== 'ImportDeclaration'; |
|||
}); |
|||
|
|||
body.forEach(item => { |
|||
// 从包中导出 SettingDrawer
|
|||
if (item.type === 'ImportDeclaration') { |
|||
if (item.source.value === '@ant-design/pro-layout') { |
|||
item.specifiers.push(parseCode(`SettingDrawer`).expression); |
|||
} |
|||
} |
|||
if (item.type === 'VariableDeclaration') { |
|||
const { |
|||
id, |
|||
init: { body }, |
|||
} = item.declarations[0]; |
|||
// 给 BasicLayout 中插入 button 和 设置抽屉
|
|||
if (id.name === `BasicLayout`) { |
|||
body.body.forEach(node => { |
|||
if (node.type === 'ReturnStatement') { |
|||
const JSXFragment = parseCode(`<></>`).expression; |
|||
JSXFragment.children.push({ ...node.argument }); |
|||
JSXFragment.children.push(parseCode(SettingCodeString).expression); |
|||
node.argument = JSXFragment; |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
}); |
|||
}); |
|||
}; |
|||
|
|||
const insertBlankLayout = configPath => { |
|||
return mapAst(configPath, body => { |
|||
const index = body.findIndex(item => { |
|||
return item.type !== 'ImportDeclaration'; |
|||
}); |
|||
// 从组件中导入 CopyBlock
|
|||
body.splice( |
|||
index, |
|||
0, |
|||
parseCode(`import CopyBlock from '@/components/CopyBlock';
|
|||
`),
|
|||
); |
|||
body.forEach(item => { |
|||
if (item.type === 'VariableDeclaration') { |
|||
const { id, init } = item.declarations[0]; |
|||
// 给 BasicLayout 中插入 button 和 设置抽屉
|
|||
if (id.name === `Layout`) { |
|||
const JSXFragment = parseCode(`<></>`).expression; |
|||
JSXFragment.children.push({ ...init.body }); |
|||
JSXFragment.children.push(parseCode(` <CopyBlock id={Date.now()}/>`).expression); |
|||
init.body = JSXFragment; |
|||
} |
|||
} |
|||
}); |
|||
}); |
|||
}; |
|||
|
|||
const insertRightContent = configPath => { |
|||
return mapAst(configPath, body => { |
|||
const index = body.findIndex(item => { |
|||
return item.type !== 'ImportDeclaration'; |
|||
}); |
|||
// 从组件中导入 CopyBlock
|
|||
body.splice(index, 0, parseCode(`import NoticeIconView from './NoticeIconView';`)); |
|||
|
|||
body.forEach(item => { |
|||
if (item.type === 'VariableDeclaration') { |
|||
const classBody = item.declarations[0].init.body; |
|||
classBody.body.forEach(node => { |
|||
if (node.type === 'ReturnStatement') { |
|||
const index = node.argument.children.findIndex(item => { |
|||
if (item.type === 'JSXElement') { |
|||
if (item.openingElement.name.name === 'Avatar') { |
|||
return true; |
|||
} |
|||
} |
|||
}); |
|||
node.argument.children.splice(index, 1, parseCode(`<Avatar menu />`).expression); |
|||
node.argument.children.splice(index, 0, parseCode(`<NoticeIconView />`).expression); |
|||
} |
|||
}); |
|||
} |
|||
}); |
|||
}); |
|||
}; |
|||
|
|||
module.exports = () => { |
|||
const basicLayoutPath = path.join(__dirname, '../src/layouts/BasicLayout.tsx'); |
|||
fs.writeFileSync(basicLayoutPath, insertBasicLayout(basicLayoutPath)); |
|||
console.log(`insert ${chalk.hex('#1890ff')('BasicLayout')} success`); |
|||
|
|||
const rightContentPath = path.join(__dirname, '../src/components/GlobalHeader/RightContent.tsx'); |
|||
fs.writeFileSync(rightContentPath, insertRightContent(rightContentPath)); |
|||
console.log(`insert ${chalk.hex('#1890ff')('RightContent')} success`); |
|||
|
|||
const blankLayoutPath = path.join(__dirname, '../src/layouts/BlankLayout.tsx'); |
|||
fs.writeFileSync(blankLayoutPath, insertBlankLayout(blankLayoutPath)); |
|||
console.log(`insert ${chalk.hex('#1890ff')('blankLayoutPath')} success`); |
|||
}; |
|||
@ -1,77 +0,0 @@ |
|||
const parser = require('@babel/parser'); |
|||
const traverse = require('@babel/traverse'); |
|||
const generate = require('@babel/generator'); |
|||
const t = require('@babel/types'); |
|||
const fs = require('fs'); |
|||
const prettier = require('prettier'); |
|||
|
|||
const getNewRouteCode = (configPath, newRoute) => { |
|||
const ast = parser.parse(fs.readFileSync(configPath, 'utf-8'), { |
|||
sourceType: 'module', |
|||
plugins: ['typescript'], |
|||
}); |
|||
let routesNode = null; |
|||
const importModules = []; |
|||
// 查询当前配置文件是否导出 routes 属性
|
|||
traverse.default(ast, { |
|||
Program({ node }) { |
|||
// find import
|
|||
const { body } = node; |
|||
body.forEach(item => { |
|||
if (t.isImportDeclaration(item)) { |
|||
const { specifiers } = item; |
|||
const defaultEpecifier = specifiers.find(s => { |
|||
return t.isImportDefaultSpecifier(s) && t.isIdentifier(s.local); |
|||
}); |
|||
if (defaultEpecifier && t.isStringLiteral(item.source)) { |
|||
importModules.push({ |
|||
identifierName: defaultEpecifier.local.name, |
|||
modulePath: item.source.value, |
|||
}); |
|||
} |
|||
} |
|||
}); |
|||
}, |
|||
ObjectExpression({ node, parent }) { |
|||
// find routes on object, like { routes: [] }
|
|||
if (t.isArrayExpression(parent)) { |
|||
// children routes
|
|||
return; |
|||
} |
|||
const { properties } = node; |
|||
properties.forEach(p => { |
|||
const { key, value } = p; |
|||
if (t.isObjectProperty(p) && t.isIdentifier(key) && key.name === 'routes') { |
|||
if (value) { |
|||
// find json file program expression
|
|||
(p.value = parser.parse(JSON.stringify(newRoute)).program.body[0].expression), |
|||
(routesNode = value); |
|||
} |
|||
} |
|||
}); |
|||
}, |
|||
}); |
|||
if (routesNode) { |
|||
const code = generateCode(ast); |
|||
return { code, routesPath: configPath }; |
|||
} else { |
|||
throw new Error('route array config not found.'); |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* 生成代码 |
|||
* @param {*} ast |
|||
*/ |
|||
function generateCode(ast) { |
|||
const newCode = generate.default(ast, {}).code; |
|||
return prettier.format(newCode, { |
|||
// format same as ant-design-pro
|
|||
singleQuote: true, |
|||
trailingComma: 'es5', |
|||
printWidth: 100, |
|||
parser: 'typescript', |
|||
}); |
|||
} |
|||
|
|||
module.exports = getNewRouteCode; |
|||
@ -1,236 +0,0 @@ |
|||
module.exports = [ |
|||
{ |
|||
path: '/', |
|||
component: '../layouts/BlankLayout', |
|||
routes: [ |
|||
// user
|
|||
{ |
|||
path: '/user', |
|||
component: '../layouts/UserLayout', |
|||
routes: [ |
|||
{ path: '/user/login', name: 'login', component: './User/Login' }, |
|||
{ path: '/user/register', name: 'register', component: './User/Register' }, |
|||
{ |
|||
path: '/user/register-result', |
|||
name: 'register.result', |
|||
component: './User/RegisterResult', |
|||
}, |
|||
{ path: '/user', redirect: '/user/login' }, |
|||
{ |
|||
component: '404', |
|||
}, |
|||
], |
|||
}, |
|||
// app
|
|||
{ |
|||
path: '/', |
|||
component: '../layouts/BasicLayout', |
|||
Routes: ['src/pages/Authorized'], |
|||
authority: ['admin', 'user'], |
|||
routes: [ |
|||
// dashboard
|
|||
{ |
|||
path: '/dashboard', |
|||
name: 'dashboard', |
|||
icon: 'dashboard', |
|||
routes: [ |
|||
{ |
|||
path: '/dashboard/analysis', |
|||
name: 'analysis', |
|||
component: './Dashboard/Analysis', |
|||
}, |
|||
{ |
|||
path: '/dashboard/monitor', |
|||
name: 'monitor', |
|||
component: './Dashboard/Monitor', |
|||
}, |
|||
{ |
|||
path: '/dashboard/workplace', |
|||
name: 'workplace', |
|||
component: './Dashboard/Workplace', |
|||
}, |
|||
], |
|||
}, |
|||
// forms
|
|||
{ |
|||
path: '/form', |
|||
icon: 'form', |
|||
name: 'form', |
|||
routes: [ |
|||
{ |
|||
path: '/form/basic-form', |
|||
name: 'basicform', |
|||
component: './Form/BasicForm', |
|||
}, |
|||
{ |
|||
path: '/form/step-form', |
|||
name: 'stepform', |
|||
component: './Form/StepForm', |
|||
}, |
|||
{ |
|||
path: '/form/advanced-form', |
|||
name: 'advancedform', |
|||
authority: ['admin'], |
|||
component: './Form/AdvancedForm', |
|||
}, |
|||
], |
|||
}, |
|||
// list
|
|||
{ |
|||
path: '/list', |
|||
icon: 'table', |
|||
name: 'list', |
|||
routes: [ |
|||
{ |
|||
path: '/list/table-list', |
|||
name: 'searchtable', |
|||
component: './list/Tablelist', |
|||
}, |
|||
{ |
|||
path: '/list/basic-list', |
|||
name: 'basiclist', |
|||
component: './list/Basiclist', |
|||
}, |
|||
{ |
|||
path: '/list/card-list', |
|||
name: 'cardlist', |
|||
component: './list/Cardlist', |
|||
}, |
|||
{ |
|||
path: '/list/search', |
|||
name: 'search-list', |
|||
component: './list/search', |
|||
routes: [ |
|||
{ |
|||
path: '/list/search/articles', |
|||
name: 'articles', |
|||
component: './list/Articles', |
|||
}, |
|||
{ |
|||
path: '/list/search/projects', |
|||
name: 'projects', |
|||
component: './list/Projects', |
|||
}, |
|||
{ |
|||
path: '/list/search/applications', |
|||
name: 'applications', |
|||
component: './list/Applications', |
|||
}, |
|||
{ |
|||
path: '/list/search', |
|||
redirect: '/list/search/articles', |
|||
}, |
|||
], |
|||
}, |
|||
], |
|||
}, |
|||
{ |
|||
path: '/profile', |
|||
name: 'profile', |
|||
icon: 'profile', |
|||
routes: [ |
|||
// profile
|
|||
{ |
|||
path: '/profile/basic', |
|||
name: 'basic', |
|||
component: './Profile/BasicProfile', |
|||
}, |
|||
{ |
|||
path: '/profile/basic/:id', |
|||
hideInMenu: true, |
|||
component: './Profile/BasicProfile', |
|||
}, |
|||
{ |
|||
path: '/profile/advanced', |
|||
name: 'advanced', |
|||
authority: ['admin'], |
|||
component: './Profile/AdvancedProfile', |
|||
}, |
|||
], |
|||
}, |
|||
{ |
|||
name: 'result', |
|||
icon: 'check-circle-o', |
|||
path: '/result', |
|||
routes: [ |
|||
// result
|
|||
{ |
|||
path: '/result/success', |
|||
name: 'success', |
|||
component: './Result/Success', |
|||
}, |
|||
{ path: '/result/fail', name: 'fail', component: './Result/Error' }, |
|||
], |
|||
}, |
|||
{ |
|||
name: 'exception', |
|||
icon: 'warning', |
|||
path: '/exception', |
|||
routes: [ |
|||
// exception
|
|||
{ |
|||
path: '/exception/403', |
|||
name: 'not-permission', |
|||
component: './Exception/403', |
|||
}, |
|||
{ |
|||
path: '/exception/404', |
|||
name: 'not-find', |
|||
component: './Exception/404', |
|||
}, |
|||
{ |
|||
path: '/exception/500', |
|||
name: 'server-error', |
|||
component: './Exception/500', |
|||
}, |
|||
], |
|||
}, |
|||
{ |
|||
name: 'account', |
|||
icon: 'user', |
|||
path: '/account', |
|||
routes: [ |
|||
{ |
|||
path: '/account/center', |
|||
name: 'center', |
|||
component: './Account/Center/Center', |
|||
}, |
|||
{ |
|||
path: '/account/settings', |
|||
name: 'settings', |
|||
component: './Account/Settings/Info', |
|||
}, |
|||
], |
|||
}, |
|||
// editor
|
|||
{ |
|||
name: 'editor', |
|||
icon: 'highlight', |
|||
path: '/editor', |
|||
routes: [ |
|||
{ |
|||
path: '/editor/flow', |
|||
name: 'flow', |
|||
component: './Editor/GGEditor/Flow', |
|||
}, |
|||
{ |
|||
path: '/editor/mind', |
|||
name: 'mind', |
|||
component: './Editor/GGEditor/Mind', |
|||
}, |
|||
{ |
|||
path: '/editor/koni', |
|||
name: 'koni', |
|||
component: './Editor/GGEditor/Koni', |
|||
}, |
|||
], |
|||
}, |
|||
{ path: '/', redirect: '/dashboard/analysis', authority: ['admin', 'user'] }, |
|||
{ |
|||
component: '404', |
|||
}, |
|||
], |
|||
}, |
|||
], |
|||
}, |
|||
]; |
|||
Loading…
Reference in new issue