oak-domain/lib/compiler/routerBuilder.js

258 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildRouter = void 0;
const tslib_1 = require("tslib");
const path_1 = require("path");
const fs_extra_1 = require("fs-extra");
const assert_1 = tslib_1.__importDefault(require("assert"));
const ts = tslib_1.__importStar(require("typescript"));
const node_watch_1 = tslib_1.__importDefault(require("node-watch"));
const env_1 = require("./env");
const { factory } = ts;
const NameSpaceDescDict = {};
function checkPageDir(dir, relativePath, ns, type) {
let changed = false;
const { pages } = NameSpaceDescDict[ns];
const subdirs = [];
const files = (0, fs_extra_1.readdirSync)(dir);
files.forEach((file) => {
const filepath = (0, path_1.join)(dir, file);
const stat = (0, fs_extra_1.statSync)(filepath);
if (stat.isFile() &&
['web.tsx', 'web.pc.tsx', 'render.native.tsx', 'render.ios.tsx', 'render.android.tsx', 'index.xml'].includes(file)) {
if (!pages.hasOwnProperty(dir)) {
const indexJsonFile = (0, path_1.join)(dir, 'index.json');
let oakDisablePulldownRefresh = false;
if ((0, fs_extra_1.existsSync)(indexJsonFile)) {
const { enablePullDownRefresh = true, } = require(indexJsonFile);
oakDisablePulldownRefresh =
!enablePullDownRefresh;
}
pages[dir] = {
path: relativePath.replace(/\\/g, '/'),
oakDisablePulldownRefresh,
hasNative: ['render.native.tsx', 'render.ios.tsx', 'render.android.tsx'].includes(file),
hasWeb: ['web.tsx', 'web.pc.tsx'].includes(file),
hasWechatMp: file === 'index.xml',
};
changed = true;
}
else {
if (['render.native.tsx', 'render.ios.tsx', 'render.android.tsx'].includes(file) && type === 'native') {
if (pages[dir].hasNative === false) {
pages[dir].hasNative = true;
changed = true;
}
}
else if (['web.tsx', 'web.pc.tsx'].includes(file) && type === 'web') {
if (pages[dir].hasWeb === false) {
pages[dir].hasWeb = true;
changed = true;
}
}
else {
if (pages[dir].hasWechatMp === false && type === 'wechatMp') {
pages[dir].hasWechatMp = true;
}
}
}
}
else if (stat.isDirectory()) {
subdirs.push(file);
}
});
return {
subdirs,
changed,
};
}
function traverseNsDir(nsDir, ns, type) {
NameSpaceDescDict[ns] = {
pages: {}
};
const { pages } = NameSpaceDescDict[ns];
const traverse = (dir, relativePath) => {
const { subdirs } = checkPageDir(dir, relativePath, ns, type);
subdirs.forEach((subdir) => {
const dir2 = (0, path_1.join)(dir, subdir);
const relativePath2 = (0, path_1.join)(relativePath, subdir);
traverse(dir2, relativePath2);
});
};
traverse(nsDir, '');
}
function traversePageDir(projectDir, type) {
const pageDir = (0, path_1.join)(projectDir, 'src', 'pages');
const namespaces = (0, fs_extra_1.readdirSync)(pageDir);
namespaces.forEach((ns) => {
const nsDir = (0, path_1.join)(pageDir, ns);
const stat = (0, fs_extra_1.statSync)(nsDir);
if (stat.isDirectory()) {
traverseNsDir(nsDir, ns, type);
}
});
}
function makeWebAllRouters(namespaceDir, projectDir, routerFileDir) {
const nss = (0, fs_extra_1.readdirSync)(namespaceDir);
return factory.createArrayLiteralExpression(nss.map((ns) => {
(0, assert_1.default)(NameSpaceDescDict[ns], `${ns}在pages下没有对应的目录`);
const { pages } = NameSpaceDescDict[ns];
const nsIndexJsonFile = (0, path_1.join)(namespaceDir, ns, 'index.json');
let path2 = `/${ns}`;
let notFound2 = '', first2 = '';
let params2 = {};
if ((0, fs_extra_1.existsSync)(nsIndexJsonFile)) {
const { path, notFound, first, params } = require(nsIndexJsonFile);
if (path) {
path2 = path.replace(/\\/g, '/');
}
if (notFound) {
notFound2 = notFound.replace(/\\/g, '/');
}
if (first) {
first2 = first.replace(/\\/g, '/');
if (first2.startsWith('/')) {
first2 = first2.slice(1);
}
}
if (params) {
params2 = params;
}
}
let firstPage;
const children = Object.values(pages).filter((ele) => ele.hasWeb).map(({ path, oakDisablePulldownRefresh }) => {
let path2 = path;
if (params2[path]) {
// 如果有参数接在path后面
path2 += path2 ? `/:${params2[path]}` : `:${params2[path]}`;
}
const properties = [
factory.createPropertyAssignment('path', factory.createStringLiteral(path2)),
factory.createPropertyAssignment('namespace', factory.createStringLiteral(ns)),
factory.createPropertyAssignment('meta', factory.createObjectLiteralExpression([
factory.createPropertyAssignment('oakDisablePulldownRefresh', oakDisablePulldownRefresh ? factory.createTrue() : factory.createFalse())
])),
factory.createPropertyAssignment(factory.createIdentifier("Component"), factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("React"), factory.createIdentifier("lazy")), undefined, [factory.createArrowFunction(undefined, undefined, [], undefined, factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), factory.createCallExpression(factory.createIdentifier('import'), undefined, [
factory.createStringLiteral((0, path_1.relative)(routerFileDir, (0, path_1.join)(projectDir, 'src', 'pages', ns, path)).replace(/\\/g, '/'))
]))]))
];
if (first2 === path) {
const firstProperties = [...properties];
firstProperties.push(factory.createPropertyAssignment('isFirst', factory.createTrue()));
firstPage = factory.createObjectLiteralExpression(firstProperties, true);
}
return factory.createObjectLiteralExpression(properties, true);
});
if (firstPage) {
children.push(firstPage);
}
if (notFound2) {
children.push(factory.createObjectLiteralExpression([
factory.createPropertyAssignment('path', factory.createStringLiteral('*')),
factory.createPropertyAssignment('namespace', factory.createStringLiteral(path2)),
factory.createPropertyAssignment(factory.createIdentifier("Component"), factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("React"), factory.createIdentifier("lazy")), undefined, [factory.createArrowFunction(undefined, undefined, [], undefined, factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), factory.createCallExpression(factory.createIdentifier('import'), undefined, [
factory.createStringLiteral((0, path_1.relative)(routerFileDir, (0, path_1.join)(projectDir, 'src', 'pages', ns, notFound2)).replace(/\\/g, '/'))
]))]))
], true));
}
return factory.createObjectLiteralExpression([
factory.createPropertyAssignment('path', factory.createStringLiteral(path2)),
factory.createPropertyAssignment('namespace', factory.createStringLiteral(path2)),
factory.createPropertyAssignment(factory.createIdentifier("Component"), factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("React"), factory.createIdentifier("lazy")), undefined, [factory.createArrowFunction(undefined, undefined, [], undefined, factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), factory.createCallExpression(factory.createIdentifier('import'), undefined, [
factory.createStringLiteral((0, path_1.relative)(routerFileDir, (0, path_1.join)(namespaceDir, ns)).replace(/\\/g, '/'))
]))])),
factory.createPropertyAssignment('children', factory.createArrayLiteralExpression(children))
], true);
}), true);
}
function judgeUseOakRouterBuilder(statements) {
const stmt = statements[0];
return ts.isExpressionStatement(stmt) && ts.isStringLiteral(stmt.expression) && stmt.expression.text === 'use oak router builder';
}
function outputInWebAppDir(appDir) {
const routerFileName = (0, path_1.join)(appDir, 'routers', 'allRouters.ts');
const templateFileName = (0, path_1.join)(appDir, '../../..', 'node_modules', env_1.OAK_CLI_MODULE_NAME, 'templateFiles', 'allRouters.ts');
const program = ts.createProgram([templateFileName], {
removeComments: false,
});
const routerFile = program.getSourceFile(templateFileName);
(0, assert_1.default)(routerFile);
const namespaceDir = (0, path_1.join)(appDir, 'namespaces');
const { statements } = routerFile;
if (judgeUseOakRouterBuilder(statements)) {
statements.forEach((statement) => {
if (ts.isVariableStatement(statement)) {
const declaration = statement.declarationList.declarations.find(declaration => ts.isIdentifier(declaration.name) && declaration.name.text === 'allRouters');
if (declaration) {
Object.assign(declaration, {
initializer: makeWebAllRouters(namespaceDir, (0, path_1.join)(appDir, '../../..'), (0, path_1.dirname)(routerFileName))
});
}
}
});
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed, removeComments: false });
const result = printer.printNode(ts.EmitHint.Unspecified, routerFile, routerFile);
(0, fs_extra_1.writeFileSync)(routerFileName, result);
}
}
function outputInWebDir(dir) {
const srcAppDir = (0, path_1.join)(dir, 'src', 'app');
outputInWebAppDir(srcAppDir);
}
function watchDir(projectDir, startupDir, type) {
const srcPageDir = (0, path_1.join)(projectDir, 'src', 'pages');
console.log('watch dir ', srcPageDir);
if (startupDir.startsWith('web')) {
const srcAppDir = (0, path_1.join)(projectDir, startupDir, 'src', 'app');
const tryOutputAppDir = (ns) => {
const namespaceDir = (0, path_1.join)(srcAppDir, 'namespaces');
const namespaces = (0, fs_extra_1.readdirSync)(namespaceDir);
if (namespaces.includes(ns)) {
outputInWebAppDir(srcAppDir);
}
};
(0, node_watch_1.default)(srcPageDir, {
recursive: true,
filter: new RegExp('web\.tsx|web\.pc\.tsx|index\.xml|render\.(native|ios|android)\.tsx'),
}, (evt, filepath) => {
const dir = (0, path_1.dirname)(filepath);
const relativeDir = (0, path_1.relative)((0, path_1.join)(projectDir, 'src', 'pages'), filepath);
const ns = relativeDir.split('\\')[0];
const relativePath = (0, path_1.relative)(ns, (0, path_1.dirname)(relativeDir));
const { pages } = NameSpaceDescDict[ns];
if (evt === 'remove') {
if ((0, fs_extra_1.existsSync)(dir)) {
const { changed } = checkPageDir(dir, relativePath, ns, type);
if (changed) {
tryOutputAppDir(ns);
}
}
else {
delete pages[dir];
tryOutputAppDir(ns);
}
}
else {
const { changed } = checkPageDir(dir, relativePath, ns, type);
if (changed) {
tryOutputAppDir(ns);
}
}
});
}
}
function buildRouter(projectDir, startupDir, watch) {
const type = startupDir.startsWith('web') ? 'web' : (startupDir.startsWith('native') ? 'native' : 'wechatMp');
traversePageDir(projectDir, type);
const subDir = (0, fs_extra_1.readdirSync)(projectDir);
(0, assert_1.default)(subDir.includes(startupDir));
if (startupDir.startsWith('web')) {
outputInWebDir((0, path_1.join)(projectDir, startupDir));
}
// todo native
if (watch) {
watchDir(projectDir, startupDir, type);
}
}
exports.buildRouter = buildRouter;