@foxpage/foxpage-node-sdk
Version:
foxpage node sdk
490 lines (489 loc) • 17.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.renderTask = exports.parseTask = exports.mockTask = exports.mergeTask = exports.fetchBlockTask = exports.blockTask = exports.fetchDSLTask = exports.pageTask = exports.fileTask = exports.initRelationsTask = exports.routerTask = exports.accessControlTask = exports.contextTask = exports.appTask = void 0;
const foxpage_core_1 = require("@foxpage/foxpage-core");
const foxpage_manager_1 = require("@foxpage/foxpage-manager");
const foxpage_shared_1 = require("@foxpage/foxpage-shared");
const common_1 = require("../common");
const context_1 = require("../context");
const errors_1 = require("../errors");
const render_1 = require("../render");
const main_1 = require("./../manager/main");
const locale_1 = require("./locale");
const module_1 = require("./module");
const route_1 = require("./route");
/**
* get user request application task
* @param pathname user request pathname
* @returns Application | null |undefined
*/
const appTask = (pathname) => {
return (0, foxpage_manager_1.getApplicationByPath)(pathname);
};
exports.appTask = appTask;
/**
* init render context
* @param app application
* @param opt contain ctx dependency data
* @returns Context
*/
const contextTask = async (app, opt) => {
const startTime = new Date().getTime();
const ctx = await (0, context_1.createContext)(app, opt);
// init env: debug,preview,...
(0, common_1.initEnv)(ctx);
const { afterContextCreate } = ctx.hooks || {};
if (typeof afterContextCreate === 'function') {
await afterContextCreate(ctx);
}
// default locale setting
const { locale } = app.configs;
if (locale) {
ctx.locale = locale;
}
ctx.performance.start = startTime;
return ctx;
};
exports.contextTask = contextTask;
/**
* access control task
* @param app application
* @param request request
*/
const accessControlTask = async (app, ctx, opt = {}) => {
const { accessControl } = app.configs.security || {};
const { enable = true } = accessControl || {};
if (!enable) {
return true;
}
let result = false;
const ticket = (0, common_1.getTicket)(ctx);
if (ticket) {
const _contentId = opt.contentId || (0, common_1.getPageId)(ctx) || '';
const _fileId = opt.fileId || '';
result = await app.securityManager.ticketCheck(ticket, { contentId: _contentId, fileId: _fileId });
}
return result;
};
exports.accessControlTask = accessControlTask;
/**
* router task: get the matched content
* @param url user request url
* @param app current application
* @returns Promise<FPRouter | undefined>
*/
const routerTask = async (app, ctx) => {
var _a, _b;
if (!ctx.URL) {
return null;
}
try {
const routeCost = ctx.performanceLogger('routerTime');
// get pageId from querystring
// for preview mode
// if pageId is set, then return the pageId content
// else, get the route by pathname
if (ctx.isPreviewMode) {
const { pageid } = (((_a = ctx.request) === null || _a === void 0 ? void 0 : _a.query) || {});
if (pageid) {
return { id: pageid };
}
}
const { searchParams } = ctx.URL;
const pathnameStr = (0, route_1.getPathname)(app.slug, ctx);
if (!pathnameStr) {
return null;
}
// sys default routers
const route = app.routeManager.getRoute(pathnameStr);
if (route) {
return route;
}
let searchStr = searchParams.toString();
if (ctx.locale) {
searchStr = searchStr ? `${searchStr}&locale=${ctx.locale}` : `locale=${ctx.locale}`;
}
// pathname
let _pathname = pathnameStr.toLowerCase();
if (!pathnameStr.endsWith('.html') && !pathnameStr.endsWith('/')) {
_pathname = `${_pathname}/`;
}
// get content by tags
const tags = searchStr ? foxpage_shared_1.tag.generateTagByQuerystring(searchStr) : [];
const file = await app.fileManager.getFileByPathname(_pathname);
let result = await app.tagManager.matchTag(tags, {
pathname: _pathname,
fileId: (file === null || file === void 0 ? void 0 : file.id) || '',
withContentInfo: !ctx.isPreviewMode,
});
// hook: afterRouteMatch
const { afterRouteMatch } = ctx.hooks || {};
if (typeof afterRouteMatch === 'function') {
const { fileId } = await afterRouteMatch(ctx);
if (fileId) {
result = await app.tagManager.matchTag(tags, {
fileId,
withContentInfo: !ctx.isPreviewMode,
});
}
}
routeCost();
return result;
}
catch (e) {
(_b = ctx.logger) === null || _b === void 0 ? void 0 : _b.warn(`get route failed: ${e.message}`);
return null;
}
};
exports.routerTask = routerTask;
/**
* init relation task for create content instance by relation
* @param relations relations
* @param ctx context
*/
const initRelationsTask = (relations, ctx) => {
return (0, foxpage_shared_1.initCtxRelations)(relations, ctx);
};
exports.initRelationsTask = initRelationsTask;
/**
* file task
* get file & set to context
* @param fileId
* @param app
* @param ctx
*/
const fileTask = async (fileId, app, ctx) => {
const file = await app.fileManager.getFileById(fileId);
ctx.file = file || undefined;
};
exports.fileTask = fileTask;
/**
* get page task
* @param pageId pageId
* @param app current application
* @returns Promise<Application|null|undefined>
*/
const pageTask = async (pageId, app, ctx) => {
let _pageId = pageId;
let page = null;
const getDSLCost = ctx.performanceLogger('getDSLTime');
const { beforeDSLFetch, afterDSLFetch } = ctx.hooks || {};
if (typeof beforeDSLFetch === 'function') {
const result = await beforeDSLFetch(ctx);
if (result.pageId) {
_pageId = result.pageId;
}
}
// get page dsl with mode
if (ctx.isPreviewMode) {
(0, locale_1.initPreviewLocale)(ctx);
const previewVersion = (0, common_1.getPreviewVersion)(ctx);
const contents = previewVersion
? [await app.pageManager.getPreviewPages(_pageId, previewVersion, ctx.locale)]
: await app.pageManager.getDraftPages([_pageId], ctx.locale);
if (contents) {
const { content, relations } = contents[0];
page = content;
if (page) {
const contentInstances = (0, exports.initRelationsTask)(Object.assign(Object.assign({}, relations), { pages: [page] }), ctx);
const pageInstance = contentInstances.pages ? contentInstances.pages[0] : null;
if (pageInstance) {
ctx.updateOriginPage(pageInstance);
}
}
}
// set preview time
ctx._foxpage_preview_time = (0, common_1.getFoxpagePreviewTime)(ctx);
ctx.mockConditions = (0, common_1.getMockConditions)(ctx);
}
else {
page = (await app.pageManager.getPage(_pageId)) || null;
}
if (page) {
page.locale = ctx.locale;
}
// with merge
page = await (0, exports.mergeTask)(page, app, ctx);
if (typeof afterDSLFetch === 'function') {
page = await afterDSLFetch(ctx, page);
}
// module render
if (page && ctx.isModuleViewMode) {
page = (0, module_1.formatePageWithModules)(page, ctx);
}
// create instance by page content
// update context
if (page) {
page = new foxpage_manager_1.PageInstance(page);
if (page) {
if (ctx.isPreviewMode) {
ctx.updateOriginPage(page);
}
else {
await (0, context_1.updateContext)(ctx, { app, content: page });
}
}
}
// with mock
if (ctx.isMock) {
const mockedContent = await (0, exports.mockTask)(page, app, ctx);
if (mockedContent) {
page = new foxpage_manager_1.PageInstance(mockedContent);
}
}
if (page) {
ctx.updatePage(page);
// get file
if (page.fileId) {
await (0, exports.fileTask)(page.fileId, app, ctx);
}
}
getDSLCost();
return page;
};
exports.pageTask = pageTask;
exports.fetchDSLTask = exports.pageTask;
const blockTask = async (blockId, app, ctx) => {
let _blockId = blockId;
let block = null;
const getDSLCost = ctx.performanceLogger('getDSLTime');
const { beforeDSLFetch, afterDSLFetch } = ctx.hooks || {};
if (typeof beforeDSLFetch === 'function') {
const result = await beforeDSLFetch(ctx);
if (result.contentId) {
_blockId = result.contentId;
}
}
// get block dsl with mode
if (ctx.isPreviewMode) {
const previewVersion = (0, common_1.getPreviewVersion)(ctx);
const contents = previewVersion
? [await app.blockManager.getPreviewBlocks(_blockId, previewVersion)]
: await app.blockManager.getDraftBlocks([_blockId]);
if (contents) {
const { content, relations } = contents[0];
block = content;
if (block) {
const contentInstances = (0, exports.initRelationsTask)(Object.assign(Object.assign({}, relations), { blocks: [block] }), ctx);
const blockInstance = contentInstances.blocks ? contentInstances.blocks[0] : null;
if (blockInstance) {
ctx.updateOriginPage(blockInstance);
}
}
}
// set preview time
ctx._foxpage_preview_time = (0, common_1.getFoxpagePreviewTime)(ctx);
}
else {
block = (await app.blockManager.getBlock(_blockId)) || null;
}
// // with merge
// block = await mergeTask(block, app, ctx);
if (typeof afterDSLFetch === 'function') {
block = await afterDSLFetch(ctx, block);
}
// create instance by block content
// update context
if (block) {
block = new foxpage_manager_1.BlockInstance(block);
if (block) {
if (ctx.isPreviewMode) {
ctx.updateOriginPage(block);
}
else {
await (0, context_1.updateContext)(ctx, { app, content: block });
}
}
}
// with mock
if (ctx.isMock) {
const mockedBlock = await (0, exports.mockTask)(block, app, ctx);
if (mockedBlock) {
block = new foxpage_manager_1.BlockInstance(mockedBlock);
}
}
if (block) {
ctx.updatePage(block);
// get file
if (block.fileId) {
await (0, exports.fileTask)(block.fileId, app, ctx);
}
}
getDSLCost();
return block;
};
exports.blockTask = blockTask;
exports.fetchBlockTask = exports.blockTask;
/**
* content merge task
* only support page content
* @param content base content
* @param app application
* @param ctx Context
* @returns merged content
*/
const mergeTask = async (content, app, ctx) => {
var _a;
if (!content) {
return null;
}
const { extendId } = content.extension || {};
if (extendId) {
const base = await app.pageManager.getPage(extendId);
if (base) {
ctx.updateOriginByKey('extendPage', base);
const relations = await app.getContentRelationInfo(base, { isBase: true });
if (relations) {
// update base content relations
Object.keys(relations).forEach(key => {
const keyStr = key;
if (relations[keyStr]) {
// @ts-ignore
ctx.updateOriginByKey(keyStr, (relations[keyStr] || []).concat(ctx.origin[keyStr] || []));
}
});
}
const merged = foxpage_core_1.merger.merge(base, content, {
strategy: foxpage_core_1.merger.MergeStrategy.COMBINE_BY_EXTEND,
});
return merged;
}
(_a = ctx.logger) === null || _a === void 0 ? void 0 : _a.error(`The base content is invalid @${extendId}`);
return null;
}
return content;
};
exports.mergeTask = mergeTask;
/**
* pre mock task
* @param content content
* @param ctx context
*/
const preMockTask = (content, ctx) => {
var _a, _b, _c;
const { mockId, extendId } = content.extension || {};
const mockIds = [];
// get content mock
if (mockId) {
const exist = (_a = ctx.getOrigin('mocks')) === null || _a === void 0 ? void 0 : _a.findIndex(item => item.id === mockId);
if ((!exist && exist !== 0) || exist === -1) {
mockIds.push(mockId);
}
}
// get extend content mock
if (extendId) {
const extendPage = ctx.getOrigin('extendPage');
if (extendId === (extendPage === null || extendPage === void 0 ? void 0 : extendPage.id) && !!((_b = extendPage.extension) === null || _b === void 0 ? void 0 : _b.mockId)) {
mockIds.push((_c = extendPage.extension) === null || _c === void 0 ? void 0 : _c.mockId);
}
}
// get templates mocks
const templates = ctx.getOrigin('templates');
if (templates && templates.length > 0) {
templates.forEach(item => {
var _a;
const mockId = (_a = item.extension) === null || _a === void 0 ? void 0 : _a.mockId;
if (mockId) {
mockIds.push(mockId);
}
});
}
return mockIds;
};
/**
* mock task
* @param content content
* @param app application
* @param ctx context
* @returns new content with mock
*/
const mockTask = async (content, app, ctx) => {
if (content) {
const mocks = ctx.getOrigin('mocks') || [];
const mockIds = preMockTask(content, ctx);
if (mockIds.length > 0) {
const list = ctx.isPreviewMode
? await app.mockManager.getDraftMocks(mockIds)
: await app.mockManager.getMocks(mockIds);
list.forEach(item => {
const { content, relations = {} } = item;
if (content) {
(0, exports.initRelationsTask)(Object.assign({}, relations), ctx);
mocks.push(content);
}
});
}
const { content: mockedContent, templates } = foxpage_core_1.mocker.withMock(mocks, ctx);
if (mockedContent) {
// get new relations via content
const pageRelationInfo = await (0, main_1.getRelations)(mockedContent, app);
// get new relations via template
const templateRelationInfos = await (0, main_1.getRelationsBatch)(templates, app);
pageRelationInfo.templates = templates;
// final relations
const _pageRelations = (0, foxpage_shared_1.relationsMerge)({
variables: ctx.getOrigin('variables'),
conditions: ctx.getOrigin('conditions'),
functions: ctx.getOrigin('functions'),
}, pageRelationInfo);
const relationInfo = (0, foxpage_shared_1.relationsMerge)(templateRelationInfos, _pageRelations);
if (relationInfo) {
// // mock variables
// const variables = mocker.mockVariable(relationInfo.variables, mocks, ctx);
ctx.updateOrigin(Object.assign(Object.assign({}, relationInfo), { mocks }));
}
return mockedContent;
}
}
};
exports.mockTask = mockTask;
/**
* parse content task
* @param content content
* @param ctx Context
* @returns ParsedDSL
*/
const parseTask = async (content, ctx) => {
const { beforeDSLParse, afterDSLParse } = ctx.hooks || {};
const parseCost = ctx.performanceLogger('parseTime');
if (typeof beforeDSLParse === 'function') {
await beforeDSLParse(ctx);
}
let parsed = await foxpage_core_1.parser.parse(content, ctx);
if (typeof afterDSLParse === 'function') {
parsed = (await afterDSLParse(ctx)) || parsed;
}
parseCost();
return parsed;
};
exports.parseTask = parseTask;
/**
* render task
* @param parsed parsed content schemas
* @param ctx render context
* @returns html string
*/
const renderTask = async (parsed, ctx) => {
try {
const renderCost = ctx.performanceLogger('renderTime');
const opt = {
useStructureVersion: ctx.isPreviewMode,
};
const html = ctx.isModuleViewMode
? await (0, render_1.renderModuleToHTML)(parsed.schemas, ctx, opt)
: await (0, render_1.renderToHTML)(parsed.schemas, ctx, opt);
renderCost();
return html;
}
catch (e) {
const { onRenderError } = ctx.hooks || {};
if (typeof onRenderError === 'function') {
await onRenderError(ctx, e);
}
else {
// throw e;
throw new errors_1.RenderPageError(e, parsed);
}
}
};
exports.renderTask = renderTask;