对router的编译

This commit is contained in:
Wang Kejun 2022-09-09 10:55:05 +08:00
parent 01d94d0915
commit 21fcdca94c
1 changed files with 321 additions and 82 deletions

View File

@ -1,5 +1,5 @@
const fs = require('fs'); const fs = require('fs');
const { relative, join } = require('path'); const { relative, join, resolve } = require('path');
const t = require('@babel/types'); const t = require('@babel/types');
const assert = require('assert'); const assert = require('assert');
const AppPaths = require('../web/paths'); const AppPaths = require('../web/paths');
@ -10,95 +10,233 @@ module.exports = () => {
Program(path, state) { Program(path, state) {
const { cwd, filename } = state; const { cwd, filename } = state;
const rel = relative(cwd, filename).replace(/\\/g, '/'); const rel = relative(cwd, filename).replace(/\\/g, '/');
if (rel.endsWith(`/src/App.tsx`)) { // if (rel.endsWith(`/src/App.tsx`)) {
const appDir = rel.slice(0, rel.indexOf('/')); // const appDir = rel.slice(0, rel.indexOf('/'));
const { body } = path.node; // const { body } = path.node;
// 在Function App前面插入router的相关代码 // // 在Function App前面插入router的相关代码
const functionAppNode = body[body.length - 2]; // const functionAppNode = body[body.length - 2];
const routerDelarationNode = body[body.length - 3]; // const routerDelarationNode = body[body.length - 3];
assert( // assert(
t.isFunctionDeclaration(functionAppNode) && // t.isFunctionDeclaration(functionAppNode) &&
t.isIdentifier(functionAppNode.id) && // t.isIdentifier(functionAppNode.id) &&
functionAppNode.id.name === 'App' // functionAppNode.id.name === 'App'
); // );
assert( // assert(
t.isVariableDeclaration(routerDelarationNode) && // t.isVariableDeclaration(routerDelarationNode) &&
routerDelarationNode.kind === 'let' && // routerDelarationNode.kind === 'let' &&
t.isVariableDeclarator( // t.isVariableDeclarator(
routerDelarationNode.declarations[0] // routerDelarationNode.declarations[0]
) && // ) &&
t.isIdentifier( // t.isIdentifier(
routerDelarationNode.declarations[0].id // routerDelarationNode.declarations[0].id
) && // ) &&
routerDelarationNode.declarations[0].id.name === // routerDelarationNode.declarations[0].id.name ===
'routers' // 'routers'
); // );
const { pages } = require(join( // const { pages } = require(join(
cwd, // cwd,
appDir, // appDir,
'src', // 'src',
'app.json' // 'app.json'
)); // ));
const objs = pages.map((ele) => { // const objs = pages.map((ele) => {
const relPath = ele.replace(/\\/g, '/') // const relPath = ele.replace(/\\/g, '/')
.replace('@project', AppPaths.appRootSrc) // .replace('@project', AppPaths.appRootSrc)
.replace( // .replace(
'@oak-general-business', // '@oak-general-business',
AppPaths.oakGeneralBusinessAppPath // AppPaths.oakGeneralBusinessAppPath
); // );
const jsonFileExists = fs.existsSync(`${relPath}.json`); // const jsonFileExists = fs.existsSync(`${relPath}.json`);
const pagePath = ele.slice( // const pagePath = ele.slice(
ele.indexOf('pages/') + 6, // ele.indexOf('pages/') + 6,
ele.length - 6 // ele.length - 6
); // );
const params = [ // const params = [
t.objectProperty( // t.objectProperty(
t.identifier('path'), // t.identifier('path'),
t.stringLiteral(pagePath) // t.stringLiteral(pagePath)
), // ),
t.objectProperty( // t.objectProperty(
t.identifier('element'), // t.identifier('element'),
t.callExpression( // t.callExpression(
t.memberExpression( // t.memberExpression(
t.identifier('React'), // t.identifier('React'),
t.identifier('lazy') // t.identifier('lazy')
), // ),
[ // [
t.arrowFunctionExpression( // t.arrowFunctionExpression(
[], // [],
t.callExpression(t.import(), [ // t.callExpression(t.import(), [
t.stringLiteral(ele), // t.stringLiteral(ele),
]) // ])
), // ),
] // ]
) // )
), // ),
]; // ];
if (jsonFileExists) { // if (jsonFileExists) {
const { // const {
navigationBarTitleText, // navigationBarTitleText,
} = require(`${relPath}.json`); // } = require(`${relPath}.json`);
params.unshift( // params.unshift(
t.objectProperty( // t.objectProperty(
t.identifier('title'), // t.identifier('title'),
t.stringLiteral( // t.stringLiteral(
navigationBarTitleText || '' // navigationBarTitleText || ''
) // )
) // )
); // );
// }
// return t.objectExpression(params);
// });
// body.splice(
// body.length - 2,
// 0,
// t.expressionStatement(
// t.assignmentExpression(
// '=',
// t.identifier('routers'),
// t.arrayExpression(objs)
// )
// )
// );
// }
if (rel.endsWith(`/src/router/index.ts`)) {
const { body } = path.node;
const appDir = rel.slice(0, rel.indexOf('/'));
const allRouters = [];
const namespaces = {};
for (let node of body) {
if (
node &&
node.declarations &&
node.declarations[0] &&
node.declarations[0].id &&
node.declarations[0].id.name === 'namespaces'
) {
const init = node.declarations[0].init;
const properties = init && init.properties;
if (properties && properties.length > 0) {
for (let property of properties) {
namespaces[property.key.value] =
property.value.value;
}
}
} }
return t.objectExpression(params); else if (
}); node &&
node.declarations &&
node.declarations[0] &&
node.declarations[0].id &&
node.declarations[0].id.name === 'pages'
) {
const init = node.declarations[0].init;
const elements = init && init.elements;
for (let node2 of elements) {
const project = node2.elements[0].value;
const path = node2.elements[1].value;
const namespaceArr =
node2.elements[2] &&
node2.elements[2].elements &&
node2.elements[2].elements.map(
(ele) => ele.value
);
const disableAssemble = node2.elements[3] && node2.elements[3].value;
if (namespaceArr && namespaceArr.length > 0) {
for (let namespace of namespaceArr) {
const fIndex = allRouters.findIndex(
(ele) => !!ele.properties.find(property => property.value.value === namespace)
);
if (fIndex < 0) {
//找不到
let relPath = resolve(
filename
.replace(/\\/g, '/')
.slice(
0,
filename.lastIndexOf('/')
),
namespaces[namespace]
).replace(/\\/g, '/');
if (!relPath.endsWith('/index')) {
relPath = relPath + '/index';
}
const router = getNamespaceRouter(namespaces, namespace, relPath);
const children = [
getRouter(
project,
path,
namespace,
disableAssemble
),
];
router.properties.push(
t.objectProperty(
t.identifier('children'),
t.arrayExpression(children)
)
);
allRouters.push(router);
} else {
const router = getRouter(
project,
path,
namespace,
disableAssemble
);
const properties = allRouters[fIndex].properties;
if (properties && properties.length > 0) {
for (let property of properties) {
if (property.key.name === 'children') {
if (property.value.elements) {
property.value.elements.push(
router
);
}
else {
property.value =
t.arrayExpression(
[router]
);
}
}
}
}
}
}
} else {
const router = getRouter(
project,
path,
undefined,
disableAssemble
);
allRouters.push(router);
}
}
}
}
body.unshift(
t.importDeclaration(
[t.importDefaultSpecifier(t.identifier('React'))],
t.stringLiteral('react')
)
);
body.splice( body.splice(
body.length - 2, body.length - 1,
0, 0,
t.expressionStatement( t.expressionStatement(
t.assignmentExpression( t.assignmentExpression(
'=', '=',
t.identifier('routers'), t.identifier('allRouters'),
t.arrayExpression(objs) t.arrayExpression(allRouters)
) )
) )
); );
@ -107,3 +245,104 @@ module.exports = () => {
}, },
}; };
}; };
function getRouter(projectOrPath, path, namespace, disableAssemble) {
const filePath = disableAssemble ? projectOrPath : `${projectOrPath}/pages${path.startsWith('/') ? path : `/${path}`}/index`;
const relPath = filePath
.replace(/\\/g, '/')
.replace('@project', AppPaths.appRootSrc)
.replace('@oak-general-business', AppPaths.oakGeneralBusinessAppPath);
const jsonFileExists = fs.existsSync(`${relPath}.json`);
let meta = [];
if (jsonFileExists) {
const { navigationBarTitleText } = require(`${relPath}.json`);
meta = [
t.objectProperty(
t.identifier('title'),
t.stringLiteral(navigationBarTitleText || '')
),
];
}
const path2 =
namespace && path.startsWith('/')
? path.substring(path.indexOf('/') + 1)
: path;
const properties = [
t.objectProperty(t.identifier('path'), t.stringLiteral(path2)),
t.objectProperty(
t.identifier('Component'),
t.callExpression(
t.memberExpression(t.identifier('React'), t.identifier('lazy')),
[
t.arrowFunctionExpression(
[],
t.callExpression(t.import(), [
t.stringLiteral(filePath),
])
),
]
)
),
t.objectProperty(t.identifier('meta'), t.objectExpression(meta)),
];
if (namespace) {
properties.push(
t.objectProperty(
t.identifier('namespace'),
t.stringLiteral(namespace)
)
);
}
return t.objectExpression(properties);
}
function getNamespaceRouter(namespaces, namespace, relPath) {
const filePath = namespaces[namespace];
const jsonFileExists = fs.existsSync(`${relPath}.json`);
let meta = [];
if (jsonFileExists) {
const { navigationBarTitleText } = require(`${relPath}.json`);
meta = [
t.objectProperty(
t.identifier('title'),
t.stringLiteral(navigationBarTitleText || '')
),
];
}
const properties = [
t.objectProperty(t.identifier('path'), t.stringLiteral(namespace)),
t.objectProperty(
t.identifier('Component'),
filePath
? t.callExpression(
t.memberExpression(
t.identifier('React'),
t.identifier('lazy')
),
[
t.arrowFunctionExpression(
[],
t.callExpression(t.import(), [
t.stringLiteral(filePath),
])
),
]
)
: t.stringLiteral('undefined')
),
t.objectProperty(t.identifier('meta'), t.objectExpression(meta)),
];
if (namespace) {
properties.push(
t.objectProperty(
t.identifier('namespace'),
t.stringLiteral(namespace)
)
);
}
return t.objectExpression(properties);
}