UNPKG

@foxpage/foxpage-node-sdk

Version:

foxpage node sdk

490 lines (489 loc) 17.2 kB
"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;