Merge pull request #990 from lowdefy/build-create-plugin-imports

Build create plugin imports
This commit is contained in:
Gerrie van Wyk 2021-11-25 10:40:36 +02:00 committed by GitHub
commit ae93232123
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 306 additions and 170 deletions

1
.pnp.cjs generated
View File

@ -5370,7 +5370,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@swc/core", "npm:1.2.107"],
["@swc/jest", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:0.2.5"],
["ajv", "npm:8.6.3"],
["axios", "npm:0.23.0"],
["jest", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:27.3.1"],
["js-yaml", "npm:4.1.0"],
["json5", "npm:2.2.0"],

View File

@ -46,7 +46,6 @@
"@lowdefy/node-utils": "4.0.0-alpha.0",
"@lowdefy/nunjucks": "4.0.0-alpha.0",
"ajv": "8.6.3",
"axios": "0.23.0",
"js-yaml": "4.1.0",
"json5": "2.2.0",
"uuid": "8.3.2"

View File

@ -42,11 +42,11 @@ async function buildConnections({ components, context }) {
}". Received ${JSON.stringify(connection.type)}.`
);
}
context.counters.connectionTypes.increment(connection.type);
context.typeCounters.connections.increment(connection.type);
connection.connectionId = connection.id;
connection.id = `connection:${connection.id}`;
countOperators(connection.properties || {}, {
counter: context.counters.serverOperatorTypes,
counter: context.typeCounters.operators.server,
});
});
}

View File

@ -17,7 +17,7 @@
import { type } from '@lowdefy/helpers';
import createCheckDuplicateId from '../../../utils/createCheckDuplicateId.js';
function checkAction(action, { blockId, checkDuplicateActionId, counters, eventId, pageId }) {
function checkAction(action, { blockId, checkDuplicateActionId, eventId, pageId, typeCounters }) {
if (type.isUndefined(action.id)) {
throw new Error(
`Action id missing on event "${eventId}" on block "${blockId}" on page "${pageId}".`
@ -45,7 +45,7 @@ function checkAction(action, { blockId, checkDuplicateActionId, counters, eventI
)}.`
);
}
counters.actionTypes.increment(action.type);
typeCounters.actions.increment(action.type);
}
function buildEvents(block, pageContext) {
@ -81,7 +81,7 @@ function buildEvents(block, pageContext) {
checkAction(action, {
eventId: key,
blockId: block.blockId,
counters: pageContext.counters,
typeCounters: pageContext.typeCounters,
pageId: pageContext.pageId,
checkDuplicateActionId,
})
@ -90,7 +90,7 @@ function buildEvents(block, pageContext) {
checkAction(action, {
eventId: key,
blockId: block.blockId,
counters: pageContext.counters,
typeCounters: pageContext.typeCounters,
pageId: pageContext.pageId,
checkDuplicateActionId,
})

View File

@ -17,7 +17,7 @@
import { type } from '@lowdefy/helpers';
function buildRequest(request, pageContext) {
const { auth, counters, pageId, checkDuplicateRequestId } = pageContext;
const { auth, checkDuplicateRequestId, pageId, typeCounters } = pageContext;
if (type.isUndefined(request.id)) {
throw new Error(`Request id missing at page "${pageId}".`);
}
@ -40,7 +40,7 @@ function buildRequest(request, pageContext) {
}" at page "${pageId}". Received ${JSON.stringify(request.type)}.`
);
}
counters.requestTypes.increment(request.type);
typeCounters.requests.increment(request.type);
if (type.isUndefined(request.payload)) request.payload = {};

View File

@ -16,14 +16,16 @@
import countOperators from '../../../utils/countOperators.js';
function countBlockOperators(block, pageContext) {
function countBlockOperators(block, { typeCounters }) {
// eslint-disable-next-line no-unused-vars
const { requests, blocks, areas, ...webBlock } = block;
countOperators(webBlock, { counter: pageContext.counters.clientOperatorTypes });
countOperators(webBlock, { counter: typeCounters.operators.client });
(requests || []).forEach((request) => {
countOperators(request.payload || {}, { counter: pageContext.counters.clientOperatorTypes });
countOperators(request.properties || {}, { counter: pageContext.counters.serverOperatorTypes });
countOperators(request.payload || {}, { counter: typeCounters.operators.client });
countOperators(request.properties || {}, {
counter: typeCounters.operators.server,
});
});
}

View File

@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
import { get } from '@lowdefy/helpers';
import buildPages from '../buildPages.js';
import testContext from '../../../test/testContext.js';

View File

@ -16,7 +16,7 @@
import { type } from '@lowdefy/helpers';
function validateBlock(block, { pageId, counters }) {
function validateBlock(block, { pageId, typeCounters }) {
if (!type.isObject(block)) {
throw new Error(
`Expected block to be an object on page "${pageId}". Received ${JSON.stringify(block)}.`
@ -40,7 +40,7 @@ function validateBlock(block, { pageId, counters }) {
)}.`
);
}
counters.blockTypes.increment(block.type);
typeCounters.blocks.increment(block.type);
if (!type.isNone(block.requests)) {
if (!type.isArray(block.requests)) {
throw new Error(

View File

@ -36,14 +36,14 @@ async function buildPage({ page, index, context, checkDuplicatePageId }) {
const operators = new Set();
await buildBlock(page, {
auth: page.auth,
counters: context.counters,
operators,
pageId: page.pageId,
requests,
blockIdCounter: createCounter(),
checkDuplicateRequestId: createCheckDuplicateId({
message: 'Duplicate requestId "{{ id }}" on page "{{ pageId }}".',
}),
operators,
pageId: page.pageId,
requests,
typeCounters: context.typeCounters,
});
// set page.id since buildBlock sets id as well.
page.id = `page:${page.pageId}`;

View File

@ -0,0 +1,95 @@
/*
Copyright 2020-2021 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.
*/
function buildTypeClass({ counter, definitions, store, typeClass }) {
const counts = counter.getCounts();
Object.keys(counts).forEach((typeName) => {
if (!definitions[typeName]) {
throw new Error(`${typeClass} type "${typeName}" was used but is not defined.`);
}
store[typeName] = {
package: definitions[typeName].package,
version: definitions[typeName].version,
count: counts[typeName],
};
});
}
function buildTypes({ components, context }) {
const { typeCounters } = context;
components.types = {
actions: {},
blocks: {},
connections: {},
requests: {},
operators: {
client: {},
server: {},
},
};
// buildTypeClass({
// counter: typeCounters.actions,
// definitions: context.types.actions,
// store: components.types.actions,
// typeClass: 'Action',
// });
buildTypeClass({
counter: typeCounters.blocks,
definitions: context.types.blocks,
store: components.types.blocks,
typeClass: 'Block',
});
buildTypeClass({
counter: typeCounters.connections,
definitions: context.types.connections,
store: components.types.connections,
typeClass: 'Connection',
});
buildTypeClass({
counter: typeCounters.requests,
definitions: context.types.requests,
store: components.types.requests,
typeClass: 'Request',
});
// buildTypeClass({
// counter: typeCounters.operators.client,
// definitions: context.types.operators.client,
// store: components.types.operators.client,
// typeClass: 'Operator',
// });
// buildTypeClass({
// counter: typeCounters.operators.server,
// definitions: context.types.operators.server,
// store: components.types.operators.server,
// typeClass: 'Operator',
// });
// TODO: Handle styles
const blocksPackages = new Set();
Object.values(components.types.blocks).forEach((typeDef) => {
blocksPackages.add(typeDef.package);
});
components.styles = context.types.styles.filter((style) => blocksPackages.has(style.package));
}
export default buildTypes;

View File

@ -0,0 +1,41 @@
/*
Copyright 2020-2021 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 { nunjucksFunction } from '@lowdefy/nunjucks';
const template = `{%- for block in blocks -%}
import { {{ block.type }} } from '{{ block.package }}/blocks';
{% endfor -%}
export default {
{%- for block in blocks -%}
{{ block.type }},
{% endfor -%}
};
`;
async function writeBlockImports({ components, context }) {
const templateFn = nunjucksFunction(template);
const blocks = Object.keys(components.types.blocks).map((type) => ({
type,
...components.types.blocks[type],
}));
await context.writeBuildArtifact({
filePath: 'plugins/blocks.js',
content: templateFn({ blocks }),
});
}
export default writeBlockImports;

View File

@ -0,0 +1,41 @@
/*
Copyright 2020-2021 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 { nunjucksFunction } from '@lowdefy/nunjucks';
const template = `{%- for connection in connections -%}
import { {{ connection.type }} } from '{{ connection.package }}/connections';
{% endfor -%}
export default {
{%- for connection in connections -%}
{{ connection.type }},
{% endfor -%}
};
`;
async function writeConnectionImports({ components, context }) {
const templateFn = nunjucksFunction(template);
const connections = Object.keys(components.types.connections).map((type) => ({
type,
...components.types.connections[type],
}));
await context.writeBuildArtifact({
filePath: 'plugins/connections.js',
content: templateFn({ connections }),
});
}
export default writeConnectionImports;

View File

@ -14,19 +14,10 @@
limitations under the License.
*/
async function writeTypes({ context }) {
const types = {
actions: context.counters.actionTypes.getCounts(),
blocks: context.counters.blockTypes.getCounts(),
connections: context.counters.connectionTypes.getCounts(),
requests: context.counters.requestTypes.getCounts(),
clientOperators: context.counters.clientOperatorTypes.getCounts(),
serverOperators: context.counters.serverOperatorTypes.getCounts(),
};
async function writeTypes({ components, context }) {
await context.writeBuildArtifact({
filePath: 'types.json',
content: JSON.stringify(types, null, 2),
content: JSON.stringify(components.types, null, 2),
});
}

View File

@ -16,6 +16,8 @@
limitations under the License.
*/
import { readFile } from '@lowdefy/node-utils';
import createCounter from './utils/createCounter.js';
import createReadConfigFile from './utils/files/readConfigFile.js';
import createWriteBuildArtifact from './utils/files/writeBuildArtifact.js';
@ -26,11 +28,14 @@ import buildConnections from './build/buildConnections.js';
import buildMenu from './build/buildMenu.js';
import buildPages from './build/buildPages/buildPages.js';
import buildRefs from './build/buildRefs/buildRefs.js';
import buildTypes from './build/buildTypes.js';
import cleanBuildDirectory from './build/cleanBuildDirectory.js';
import testSchema from './build/testSchema.js';
import validateApp from './build/validateApp.js';
import validateConfig from './build/validateConfig.js';
import writeApp from './build/writeApp.js';
import writeBlockImports from './build/writePluginImports/writeBlockImports.js';
import writeConnectionImports from './build/writePluginImports/writeConnectionImports.js';
import writeConfig from './build/writeConfig.js';
import writeConnections from './build/writeConnections.js';
import writeGlobal from './build/writeGlobal.js';
@ -39,32 +44,42 @@ import writePages from './build/writePages.js';
import writeRequests from './build/writeRequests.js';
import writeTypes from './build/writeTypes.js';
function createContext(options) {
async function createContext(options) {
const { blocksServerUrl, buildDirectory, cacheDirectory, configDirectory, logger, refResolver } =
options;
const defaultTypes = JSON.parse(
await readFile(new URL('./defaultTypes.json', import.meta.url).pathname)
);
// TODO: resolve custom plugin types
const context = {
blocksServerUrl,
buildDirectory,
cacheDirectory,
configDirectory,
counters: {
actionTypes: createCounter(),
blockTypes: createCounter(),
connectionTypes: createCounter(),
requestTypes: createCounter(),
clientOperatorTypes: createCounter(),
serverOperatorTypes: createCounter(),
typeCounters: {
actions: createCounter(),
blocks: createCounter(),
connections: createCounter(),
requests: createCounter(),
operators: {
client: createCounter(),
server: createCounter(),
},
},
logger,
readConfigFile: createReadConfigFile({ configDirectory }),
refResolver,
types: defaultTypes,
writeBuildArtifact: createWriteBuildArtifact({ buildDirectory }),
};
return context;
}
async function build(options) {
const context = createContext(options);
const context = await createContext(options);
try {
let components = await buildRefs({ context });
await testSchema({ components, context });
@ -75,6 +90,7 @@ async function build(options) {
await buildConnections({ components, context });
await buildPages({ components, context });
await buildMenu({ components, context });
await buildTypes({ components, context });
await cleanBuildDirectory({ context });
await writeApp({ components, context });
await writeConnections({ components, context });
@ -83,7 +99,12 @@ async function build(options) {
await writeConfig({ components, context });
await writeGlobal({ components, context });
await writeMenus({ components, context });
await writeTypes({ context });
await writeTypes({ components, context });
await writeBlockImports({ components, context });
await writeConnectionImports({ components, context });
// TODO: write style file
// TODO: write icons file
// TODO: add plugins to package.json
} catch (error) {
context.logger.error(error);
throw error;

View File

@ -21,12 +21,24 @@ import { readFile, writeFile } from '@lowdefy/node-utils';
const defaultPackages = ['@lowdefy/blocks-basic', '@lowdefy/connection-axios-http'];
function createTypeDefinitions({ typeNames, store, packageName, version }) {
if (type.isArray(typeNames)) {
typeNames.forEach((typeName) => {
store[typeName] = {
package: packageName,
version,
};
});
}
}
async function generateDefaultTypes() {
const packageFile = JSON.parse(await readFile(path.resolve(process.cwd(), './package.json')));
const defaultTypes = {
actions: {},
blocks: {},
connections: {},
requests: {},
operators: {
client: {},
server: {},
@ -36,48 +48,51 @@ async function generateDefaultTypes() {
await Promise.all(
defaultPackages.map(async (packageName) => {
const { default: types } = await import(`${packageName}/types.js`);
if (type.isArray(types.actions)) {
types.actions.forEach((typeName) => {
defaultTypes.actions[typeName] = {
package: packageName,
version: packageFile.devDependencies[packageName],
};
});
}
if (type.isArray(types.blocks)) {
types.blocks.forEach((typeName) => {
defaultTypes.blocks[typeName] = {
package: packageName,
version: packageFile.devDependencies[packageName],
};
});
}
if (type.isObject(types.connections)) {
Object.keys(types.connections).forEach((typeName) => {
defaultTypes.connections[typeName] = {
package: packageName,
version: packageFile.devDependencies[packageName],
requests: types.connections[typeName].requests,
};
});
}
if (type.isObject(types.operators) && type.isArray(types.operators.client)) {
types.operators.client.forEach((typeName) => {
defaultTypes.operators.client[typeName] = {
package: packageName,
version: packageFile.devDependencies[packageName],
};
});
}
if (type.isObject(types.operators) && type.isArray(types.operators.server)) {
types.operators.server.forEach((typeName) => {
defaultTypes.operators.server[typeName] = {
package: packageName,
version: packageFile.devDependencies[packageName],
};
});
}
const { default: types } = await import(`${packageName}/types`);
const version = packageFile.devDependencies[packageName];
createTypeDefinitions({
typeNames: types.actions,
store: defaultTypes.actions,
packageName,
version,
});
createTypeDefinitions({
typeNames: types.blocks,
store: defaultTypes.blocks,
packageName,
version,
});
createTypeDefinitions({
typeNames: types.connections,
store: defaultTypes.connections,
packageName,
version,
});
createTypeDefinitions({
typeNames: types.requests,
store: defaultTypes.requests,
packageName,
version,
});
createTypeDefinitions({
typeNames: type.isObject(types.operators) ? types.operators.client : [],
store: defaultTypes.operators.client,
packageName,
version,
});
createTypeDefinitions({
typeNames: type.isObject(types.operators) ? types.operators.server : [],
store: defaultTypes.operators.server,
packageName,
version,
});
if (type.isArray(types.styles)) {
types.styles.forEach((pathName) => {
defaultTypes.styles.push({

View File

@ -28,13 +28,15 @@ function testContext({ writeBuildArtifact, configDirectory, readConfigFile, logg
const context = {
id: 'test',
configDirectory: configDirectory || '',
counters: {
actionTypes: createCounter(),
blockTypes: createCounter(),
connectionTypes: createCounter(),
requestTypes: createCounter(),
clientOperatorTypes: createCounter(),
serverOperatorTypes: createCounter(),
typeCounters: {
actions: createCounter(),
blocks: createCounter(),
connections: createCounter(),
requests: createCounter(),
operators: {
client: createCounter(),
server: createCounter(),
},
},
writeBuildArtifact: writeBuildArtifact || (() => {}),
readConfigFile: readConfigFile || (() => {}),

View File

@ -27,8 +27,8 @@
},
"type": "module",
"exports": {
"./blocks.js": "./dist/blocks.js",
"./types.js": "./dist/types.js"
"./blocks": "./dist/blocks.js",
"./types": "./dist/types.js"
},
"files": [
"dist/*"

View File

@ -16,4 +16,5 @@
export default {
blocks: ['Anchor', 'Box', 'DangerousHtml', 'Html', 'Icon', 'Img', 'List', 'Span'],
styles: ['style.less'],
};

View File

@ -27,8 +27,8 @@
},
"type": "module",
"exports": {
"./connections.js": "./dist/connections.js",
"./types.js": "./dist/types.js"
"./connections": "./dist/connections.js",
"./types": "./dist/types.js"
},
"files": [
"dist/*"

View File

@ -15,9 +15,6 @@
*/
export default {
connections: {
AxiosHttp: {
requests: ['AxiosHttp'],
},
},
connections: ['AxiosHttp'],
requests: ['AxiosHttp'],
};

View File

@ -17,7 +17,7 @@
import React from 'react';
import callRequest from '../utils/callRequest.js';
import blockComponents from '../plugins/blocks.js';
import blockComponents from '../../.lowdefy/build/plugins/blocks.js';
import components from './components.js';
const LowdefyContext = ({ children }) => {

View File

@ -15,7 +15,7 @@
*/
import { callRequest, createApiContext } from '@lowdefy/api';
import connections from '../../../../plugins/connections.js';
import connections from '../../../../../.lowdefy/build/plugins/connections.js';
export default async function handler(req, res) {
try {

View File

@ -1,29 +0,0 @@
/*
Copyright 2020-2021 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.
*/
/* eslint-disable import/no-duplicates */
import { Anchor } from '@lowdefy/blocks-basic/blocks.js';
import { Box } from '@lowdefy/blocks-basic/blocks.js';
import { Html } from '@lowdefy/blocks-basic/blocks.js';
import { Icon } from '@lowdefy/blocks-basic/blocks.js';
export default {
Anchor,
Box,
Html,
Icon,
};

View File

@ -1,17 +0,0 @@
/*
Copyright 2020-2021 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.
*/
// ------------- GENERATED AT BUILD -------------

View File

@ -1,21 +0,0 @@
/*
Copyright 2020-2021 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 { AxiosHttp } from '@lowdefy/connection-axios-http/connections.js';
export default {
AxiosHttp,
};

View File

@ -3614,7 +3614,6 @@ __metadata:
"@swc/core": 1.2.107
"@swc/jest": 0.2.5
ajv: 8.6.3
axios: 0.23.0
jest: 27.3.1
js-yaml: 4.1.0
json5: 2.2.0