mirror of
https://github.com/lowdefy/lowdefy.git
synced 2025-01-24 13:45:07 +08:00
feat(build): add build pages function
This commit is contained in:
parent
ac216d4483
commit
01e892fad5
202
packages/build/src/build/buildPages.js
Normal file
202
packages/build/src/build/buildPages.js
Normal file
@ -0,0 +1,202 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
|
||||
/*
|
||||
Copyright 2020 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { set, type } from '@lowdefy/helpers';
|
||||
const blockTypes = {};
|
||||
|
||||
/* Page and block build steps
|
||||
|
||||
Pages:
|
||||
- set pageId = id
|
||||
- set id = `page:${page.id}`
|
||||
|
||||
Blocks:
|
||||
- set blockId = id
|
||||
- set id = `block:${pageId}:${block.id}` if not a page
|
||||
- set request ids
|
||||
- set mutation ids
|
||||
- set block meta
|
||||
- set blocks to areas.content
|
||||
*/
|
||||
|
||||
function buildRequests(block, context) {
|
||||
if (!type.isNone(block.requests)) {
|
||||
if (type.isArray(block.requests)) {
|
||||
block.requests.forEach((request) => {
|
||||
request.requestId = request.id;
|
||||
request.id = `request:${context.pageId}:${context.contextId}:${request.id}`;
|
||||
context.requests.push(request);
|
||||
});
|
||||
delete block.requests;
|
||||
} else {
|
||||
throw new Error(
|
||||
`Requests is not an array at ${block.blockId} on page ${
|
||||
context.pageId
|
||||
}. Received ${JSON.stringify(block.requests)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!type.isNone(block.mutations)) {
|
||||
if (type.isArray(block.mutations)) {
|
||||
block.mutations.forEach((mutation) => {
|
||||
mutation.mutationId = mutation.id;
|
||||
mutation.id = `mutation:${context.pageId}:${context.contextId}:${mutation.id}`;
|
||||
context.mutations.push(mutation);
|
||||
});
|
||||
delete block.mutations;
|
||||
} else {
|
||||
throw new Error(
|
||||
`Mutations is not an array at ${block.blockId} on page ${
|
||||
context.pageId
|
||||
}. Received ${JSON.stringify(block.mutations)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function checkPageIsContext(page, metaLoader) {
|
||||
if (type.isNone(page.type)) {
|
||||
throw new Error(`Page type is not defined at ${page.pageId}.`);
|
||||
}
|
||||
if (!type.isString(page.type)) {
|
||||
throw new Error(
|
||||
`Page type is not a string at ${page.pageId}. Received ${JSON.stringify(page.type)}`
|
||||
);
|
||||
}
|
||||
const meta = await metaLoader.load(page.type);
|
||||
if (!meta) {
|
||||
throw new Error(
|
||||
`Invalid block type at page ${page.pageId}. Received ${JSON.stringify(page.type)}`
|
||||
);
|
||||
}
|
||||
if (meta.category !== 'context') {
|
||||
throw new Error(
|
||||
`Page ${page.pageId} is not of category "context". Received ${JSON.stringify(page.type)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function setBlockMeta(block, context) {
|
||||
if (type.isNone(block.type)) {
|
||||
throw new Error(`Block type is not defined at ${block.blockId} on page ${context.pageId}.`);
|
||||
}
|
||||
if (!type.isString(block.type)) {
|
||||
throw new Error(
|
||||
`Block type is not a string at ${block.blockId} on page ${
|
||||
context.pageId
|
||||
}. Received ${JSON.stringify(block.type)}`
|
||||
);
|
||||
}
|
||||
const meta = await context.metaLoader.load(block.type);
|
||||
if (!meta) {
|
||||
throw new Error(
|
||||
`Invalid Block type at ${block.blockId} on page ${context.pageId}. Received ${JSON.stringify(
|
||||
block.type
|
||||
)}`
|
||||
);
|
||||
}
|
||||
const { category, loading, module, scope, url, valueType } = meta;
|
||||
block.meta = { category, loading, module, scope, url };
|
||||
if (category === 'input') {
|
||||
block.meta.valueType = valueType;
|
||||
}
|
||||
|
||||
if (category === 'list') {
|
||||
// include valueType to ensure block has value on init
|
||||
block.meta.valueType = 'array';
|
||||
}
|
||||
}
|
||||
|
||||
async function buildBlock(block, context) {
|
||||
if (!type.isObject(block)) {
|
||||
throw new Error(
|
||||
`Expected block to be an object on ${context.pageId}. Received ${JSON.stringify(block)}`
|
||||
);
|
||||
}
|
||||
if (type.isUndefined(block.id)) {
|
||||
throw new Error(`Block id missing at page ${context.pageId}`);
|
||||
}
|
||||
block.blockId = block.id;
|
||||
block.id = `block:${context.pageId}:${block.id}`;
|
||||
await setBlockMeta(block, context);
|
||||
if (block.meta.category === 'context') {
|
||||
context.requests = [];
|
||||
context.mutations = [];
|
||||
context.contextId = block.blockId;
|
||||
}
|
||||
buildRequests(block, context);
|
||||
if (block.meta.category === 'context') {
|
||||
block.requests = context.requests;
|
||||
block.mutations = context.mutations;
|
||||
}
|
||||
if (!type.isNone(block.blocks)) {
|
||||
if (type.isArray(block.blocks)) {
|
||||
set(block, 'areas.content.blocks', block.blocks);
|
||||
delete block.blocks;
|
||||
} else {
|
||||
throw new Error(
|
||||
`Blocks at ${block.blockId} on page ${
|
||||
context.pageId
|
||||
} is not an array. Received ${JSON.stringify(block.blocks)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
if (type.isObject(block.areas)) {
|
||||
let promises = [];
|
||||
Object.keys(block.areas).forEach((key) => {
|
||||
if (type.isArray(block.areas[key].blocks)) {
|
||||
const blockPromises = block.areas[key].blocks.map(async (blk) => {
|
||||
await buildBlock(blk, context);
|
||||
});
|
||||
promises = promises.concat(blockPromises);
|
||||
} else {
|
||||
throw new Error(
|
||||
`Expected blocks to be an array at ${block.blockId} in area ${key} on page ${
|
||||
context.pageId
|
||||
}. Received ${JSON.stringify(block.areas[key].blocks)}`
|
||||
);
|
||||
}
|
||||
});
|
||||
await Promise.all(promises);
|
||||
}
|
||||
}
|
||||
|
||||
async function buildPages({ components, context }) {
|
||||
const pages = type.isArray(components.pages) ? components.pages : [];
|
||||
const pageBuildPromises = pages.map(async (page, i) => {
|
||||
if (type.isUndefined(page.id)) {
|
||||
throw new Error(`Page id missing at page ${i}`);
|
||||
}
|
||||
page.pageId = page.id;
|
||||
|
||||
await checkPageIsContext(page, context.metaLoader);
|
||||
await buildBlock(page, {
|
||||
pageId: page.pageId,
|
||||
requests: [],
|
||||
mutations: [],
|
||||
metaLoader: context.metaLoader,
|
||||
});
|
||||
// set page.id since buildBlock sets id as well.
|
||||
page.id = `page:${page.pageId}`;
|
||||
});
|
||||
await Promise.all(pageBuildPromises);
|
||||
context.logger.debug('Built pages');
|
||||
return components;
|
||||
}
|
||||
|
||||
export default buildPages;
|
1490
packages/build/src/build/buildPages.test.js
Normal file
1490
packages/build/src/build/buildPages.test.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -17,13 +17,12 @@
|
||||
import buildRefs from './buildRefs';
|
||||
import testContext from '../test/testContext';
|
||||
|
||||
// TODO mock loader should throw if file not found
|
||||
const configLoaderMockImplementation = (files) => {
|
||||
const mockImp = (filePath) => {
|
||||
const file = files.find((file) => file.path === filePath);
|
||||
if (!file) {
|
||||
throw new Error(
|
||||
`Tried to read file with file path ${JSON.stringify(filePath)}, but file does not exist`
|
||||
`Tried to read file with file path ${JSON.stringify(filePath)}, but file does not exist.`
|
||||
);
|
||||
}
|
||||
return file.content;
|
||||
@ -49,7 +48,9 @@ test('buildRefs file not found', async () => {
|
||||
},
|
||||
];
|
||||
mockConfigLoader.mockImplementation(configLoaderMockImplementation(files));
|
||||
await expect(buildRefs({ context })).rejects.toThrow('File "doesNotExist" not found.');
|
||||
await expect(buildRefs({ context })).rejects.toThrow(
|
||||
'Tried to read file with file path "doesNotExist", but file does not exist.'
|
||||
);
|
||||
});
|
||||
|
||||
test('buildRefs', async () => {
|
||||
|
@ -29,10 +29,7 @@ const context = testContext({ logger });
|
||||
|
||||
beforeEach(() => {
|
||||
mockLogWarn.mockReset();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
mockLogWarn.mockReset();
|
||||
mockLogSuccess.mockReset();
|
||||
});
|
||||
|
||||
test('empty components', async () => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
function testContext({ logger = {}, configLoader, artifactSetter } = {}) {
|
||||
function testContext({ artifactSetter, configLoader, logger = {}, metaLoader } = {}) {
|
||||
const defaultLogger = {
|
||||
success: () => {},
|
||||
warn: () => {},
|
||||
@ -7,11 +7,14 @@ function testContext({ logger = {}, configLoader, artifactSetter } = {}) {
|
||||
};
|
||||
|
||||
const context = {
|
||||
artifactSetter: {
|
||||
set: () => [],
|
||||
},
|
||||
configLoader: {
|
||||
load: () => {},
|
||||
},
|
||||
artifactSetter: {
|
||||
set: () => [],
|
||||
metaLoader: {
|
||||
load: () => {},
|
||||
},
|
||||
};
|
||||
|
||||
@ -20,11 +23,14 @@ function testContext({ logger = {}, configLoader, artifactSetter } = {}) {
|
||||
...logger,
|
||||
};
|
||||
|
||||
if (artifactSetter) {
|
||||
context.artifactSetter = artifactSetter;
|
||||
}
|
||||
if (configLoader) {
|
||||
context.configLoader = configLoader;
|
||||
}
|
||||
if (artifactSetter) {
|
||||
context.artifactSetter = artifactSetter;
|
||||
if (metaLoader) {
|
||||
context.metaLoader = metaLoader;
|
||||
}
|
||||
|
||||
return context;
|
||||
|
Loading…
Reference in New Issue
Block a user