mirror of
https://github.com/lowdefy/lowdefy.git
synced 2025-02-23 14:39:32 +08:00
commit
89565c0a0c
@ -82,7 +82,8 @@ test('invalid schema', async () => {
|
||||
expect(mockLogWarn.mock.calls).toEqual([
|
||||
['Schema not valid.'],
|
||||
[
|
||||
`--------- Schema Error ---------
|
||||
`
|
||||
--------- Schema Error ---------
|
||||
message: App "global" should be an object.
|
||||
path: /global
|
||||
--------------------------------`,
|
||||
@ -111,25 +112,29 @@ test('multiple schema errors', async () => {
|
||||
expect(mockLogWarn.mock.calls).toEqual([
|
||||
['Schema not valid.'],
|
||||
[
|
||||
`--------- Schema Error ---------
|
||||
`
|
||||
--------- Schema Error ---------
|
||||
message: Block should have required property "id".
|
||||
path: /pages/0
|
||||
--------------------------------`,
|
||||
],
|
||||
[
|
||||
`--------- Schema Error ---------
|
||||
`
|
||||
--------- Schema Error ---------
|
||||
message: Block should have required property "type".
|
||||
path: /pages/0
|
||||
--------------------------------`,
|
||||
],
|
||||
[
|
||||
`--------- Schema Error ---------
|
||||
`
|
||||
--------- Schema Error ---------
|
||||
message: Block "id" should be a string.
|
||||
path: /pages/1/id
|
||||
--------------------------------`,
|
||||
],
|
||||
[
|
||||
`--------- Schema Error ---------
|
||||
`
|
||||
--------- Schema Error ---------
|
||||
message: Block should have required property "type".
|
||||
path: /pages/1
|
||||
--------------------------------`,
|
||||
|
@ -15,7 +15,8 @@
|
||||
*/
|
||||
|
||||
function formatErrorMessage(error) {
|
||||
return `--------- Schema Error ---------
|
||||
return `
|
||||
--------- Schema Error ---------
|
||||
message: ${error.message}
|
||||
path: ${error.dataPath}
|
||||
--------------------------------`;
|
||||
|
@ -31,7 +31,8 @@ test('global incorrect type', async () => {
|
||||
data: 'global',
|
||||
};
|
||||
const res = formatErrorMessage(error, app);
|
||||
expect(res).toEqual(`--------- Schema Error ---------
|
||||
expect(res).toEqual(`
|
||||
--------- Schema Error ---------
|
||||
message: should be object
|
||||
path: /global
|
||||
--------------------------------`);
|
||||
@ -70,7 +71,8 @@ test('page id missing', async () => {
|
||||
},
|
||||
};
|
||||
const res = formatErrorMessage(error, app);
|
||||
expect(res).toEqual(`--------- Schema Error ---------
|
||||
expect(res).toEqual(`
|
||||
--------- Schema Error ---------
|
||||
message: should have required property 'id'
|
||||
path: /pages/0
|
||||
--------------------------------`);
|
||||
@ -99,7 +101,8 @@ test('page type missing', async () => {
|
||||
},
|
||||
};
|
||||
const res = formatErrorMessage(error, app);
|
||||
expect(res).toEqual(`--------- Schema Error ---------
|
||||
expect(res).toEqual(`
|
||||
--------- Schema Error ---------
|
||||
message: should have required property 'type'
|
||||
path: /pages/0
|
||||
--------------------------------`);
|
||||
@ -125,7 +128,8 @@ test('id incorrect type', async () => {
|
||||
data: 1,
|
||||
};
|
||||
const res = formatErrorMessage(error, app);
|
||||
expect(res).toEqual(`--------- Schema Error ---------
|
||||
expect(res).toEqual(`
|
||||
--------- Schema Error ---------
|
||||
message: should be string
|
||||
path: /pages/0/id
|
||||
--------------------------------`);
|
||||
|
@ -22,6 +22,7 @@ import getBuild from './getBuild';
|
||||
import getExpress from './getExpress';
|
||||
import getGraphQL from './getGraphQL';
|
||||
import prepare from './prepare';
|
||||
import versionWatcher from './versionWatcher';
|
||||
|
||||
async function initialBuild({ context }) {
|
||||
const build = await getBuild({ context });
|
||||
@ -46,6 +47,7 @@ async function dev({ context, options }) {
|
||||
|
||||
buildWatcher({ build, context, reloadFn });
|
||||
envWatcher({ context });
|
||||
versionWatcher({ context });
|
||||
|
||||
context.print.log('Starting Lowdefy development server.');
|
||||
expressApp.listen(expressApp.get('port'), function () {
|
||||
|
@ -23,7 +23,7 @@ async function prepare({ context, options }) {
|
||||
dotenv.config({ silent: true });
|
||||
// Setup
|
||||
if (!options.port) options.port = 3000;
|
||||
await startUp({ context, options });
|
||||
await startUp({ context, options, command: 'dev' });
|
||||
context.print.log(
|
||||
`Cleaning block meta cache at "${path.resolve(context.cacheDirectory, './meta')}".`
|
||||
);
|
||||
|
38
packages/cli/src/commands/dev/versionWatcher.js
Normal file
38
packages/cli/src/commands/dev/versionWatcher.js
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
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 chokidar from 'chokidar';
|
||||
import BatchChanges from '../../utils/BatchChanges';
|
||||
import getConfig from '../../utils/getConfig';
|
||||
|
||||
function versionWatcher({ context }) {
|
||||
const changeLowdefyFileCallback = async () => {
|
||||
const { lowdefyVersion } = await getConfig(context);
|
||||
if (lowdefyVersion !== context.lowdefyVersion) {
|
||||
context.print.warn('Lowdefy version changed. You should restart your development server.');
|
||||
process.exit();
|
||||
}
|
||||
};
|
||||
const changeLowdefyFileBatchChanges = new BatchChanges({
|
||||
fn: changeLowdefyFileCallback,
|
||||
context,
|
||||
});
|
||||
const lowdefyFileWatcher = chokidar.watch('./lowdefy.yaml', {
|
||||
persistent: true,
|
||||
});
|
||||
lowdefyFileWatcher.on('change', () => changeLowdefyFileBatchChanges.newChange());
|
||||
}
|
||||
|
||||
export default versionWatcher;
|
@ -2,6 +2,10 @@ const path = require('path');
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
const { dependencies, devDependencies } = require('./package.json');
|
||||
|
||||
const externals = [...Object.keys(dependencies), ...Object.keys(devDependencies)].filter(
|
||||
(name) => name !== 'saslprep'
|
||||
);
|
||||
|
||||
module.exports = {
|
||||
entry: './src/index.js',
|
||||
output: {
|
||||
@ -12,7 +16,7 @@ module.exports = {
|
||||
mode: 'production',
|
||||
target: 'node',
|
||||
node: false,
|
||||
externals: [...Object.keys(dependencies), ...Object.keys(devDependencies)],
|
||||
externals,
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
|
@ -25,6 +25,9 @@ function _get({ arrayIndices, env, location, params }) {
|
||||
)} at ${location}.`
|
||||
);
|
||||
}
|
||||
|
||||
if (params.from === null) return null;
|
||||
|
||||
if (!type.isObject(params.from) && !type.isArray(params.from)) {
|
||||
throw new Error(
|
||||
`Operator Error: _get.from is not an object or array. Received: ${JSON.stringify(
|
||||
|
@ -38,6 +38,8 @@ function getFromObject({
|
||||
);
|
||||
}
|
||||
|
||||
if (params.key === null) return null;
|
||||
|
||||
if (params.contextId) {
|
||||
if (env === 'node') {
|
||||
throw new Error(
|
||||
|
@ -406,6 +406,14 @@ describe('parse operators', () => {
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('parse _get operator', () => {
|
||||
const input = { _get: { key: 'key', from: { key: 'value' } } };
|
||||
const parser = new NodeParser({});
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toEqual('value');
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('parse _function operator', () => {
|
||||
const input = { _function: { state: { __state: 'key' }, args: { __args: true } } };
|
||||
const parser = new NodeParser({ state: { key: 'value' } });
|
||||
|
@ -447,6 +447,14 @@ describe('parse operators', () => {
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('parse _get operator', () => {
|
||||
const input = { _get: { key: 'key', from: { key: 'value' } } };
|
||||
const parser = new WebParser({ context, contexts });
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toEqual('value');
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('parse _function operator', () => {
|
||||
const input = { _function: { state: { __state: 'string' }, args: { __args: true } } };
|
||||
const parser = new WebParser({ context, contexts });
|
||||
|
89
packages/operators/test/common/get.test.js
Normal file
89
packages/operators/test/common/get.test.js
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
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 get from '../../src/common/get';
|
||||
import getFromObject from '../../src/getFromObject';
|
||||
|
||||
jest.mock('../../src/getFromObject');
|
||||
|
||||
test('_get calls getFromObject', () => {
|
||||
const input = {
|
||||
arrayIndices: [0],
|
||||
env: 'env',
|
||||
location: 'location',
|
||||
params: {
|
||||
from: { a: 1 },
|
||||
key: 'a',
|
||||
},
|
||||
};
|
||||
get(input);
|
||||
expect(getFromObject.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
arrayIndices: [0],
|
||||
env: 'env',
|
||||
location: 'location',
|
||||
object: { a: 1 },
|
||||
operator: '_get',
|
||||
params: {
|
||||
from: { a: 1 },
|
||||
key: 'a',
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
test('_get returns null if from is null', () => {
|
||||
const input = {
|
||||
arrayIndices: [0],
|
||||
env: 'env',
|
||||
location: 'location',
|
||||
params: {
|
||||
from: null,
|
||||
key: 'a',
|
||||
},
|
||||
};
|
||||
get(input);
|
||||
expect(get(input)).toBe(null);
|
||||
});
|
||||
|
||||
test('_get throws if params is not a object', () => {
|
||||
const input = {
|
||||
arrayIndices: [0],
|
||||
env: 'env',
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
};
|
||||
expect(() => get(input)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Operator Error: _get takes an object as params. Received: \\"params\\" at location."`
|
||||
);
|
||||
});
|
||||
|
||||
test('_get throws if from is not a object, array or null', () => {
|
||||
const input = {
|
||||
arrayIndices: [0],
|
||||
env: 'env',
|
||||
location: 'location',
|
||||
params: {
|
||||
from: 1,
|
||||
key: 'a',
|
||||
},
|
||||
};
|
||||
expect(() => get(input)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Operator Error: _get.from is not an object or array. Received: {\\"from\\":1,\\"key\\":\\"a\\"} at location."`
|
||||
);
|
||||
});
|
@ -117,6 +117,21 @@ test('get a field from an object, key as param, not found returns null', () => {
|
||||
expect(res).toEqual(null);
|
||||
});
|
||||
|
||||
test('If key is null, null is returned', () => {
|
||||
const params = { key: null };
|
||||
const res = getFromObject({
|
||||
params,
|
||||
object: defaultObject,
|
||||
context,
|
||||
contexts,
|
||||
arrayIndices: defaultArrayIndices,
|
||||
operator,
|
||||
location,
|
||||
env: 'node',
|
||||
});
|
||||
expect(res).toEqual(null);
|
||||
});
|
||||
|
||||
test('get an entire object, shorthand', () => {
|
||||
const params = true;
|
||||
const res = getFromObject({
|
||||
|
@ -1,101 +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 max-classes-per-file */
|
||||
import NodeParser from '../../src/nodeParser';
|
||||
|
||||
const object = {
|
||||
string: 'Some String',
|
||||
number: 42,
|
||||
arr: [{ a: 'a1' }, { a: 'a2' }],
|
||||
};
|
||||
const arr = [1, 2, 3];
|
||||
|
||||
test('_get in object', () => {
|
||||
const input = { a: { _get: { from: object, key: 'string' } } };
|
||||
const parser = new NodeParser();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toEqual({
|
||||
a: 'Some String',
|
||||
});
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
// test('_get replace key arrayIndices', () => {
|
||||
// const input = { a: { _get: { from: object, key: 'arr.$.a' } } };
|
||||
// const parser = new NodeParser({
|
||||
// arrayIndices: [1],
|
||||
// });
|
||||
// const res = parser.parse({ input, args, location: 'locationId' });
|
||||
// expect(res.output).toEqual({
|
||||
// a: 'a2',
|
||||
// });
|
||||
// expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
// });
|
||||
|
||||
test('_get on array', () => {
|
||||
const input = { a: { _get: { from: arr, key: '0' } } };
|
||||
const parser = new NodeParser();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toEqual({
|
||||
a: 1,
|
||||
});
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_get null', () => {
|
||||
const input = { _get: null };
|
||||
const parser = new NodeParser();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _get takes an object as params. Received: null at locationId.],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('_get from: int', () => {
|
||||
const input = { _get: { from: 1, key: 'a' } };
|
||||
const parser = new NodeParser();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(null);
|
||||
});
|
||||
|
||||
test('_get from: null', () => {
|
||||
const input = { _get: { from: null, key: 'a' } };
|
||||
const parser = new NodeParser();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(null);
|
||||
});
|
||||
|
||||
test('_get key: int', () => {
|
||||
const input = { _get: { from: [1, 2, 3], key: 1 } };
|
||||
const parser = new NodeParser();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(2);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_get replace key arrayIndices', () => {
|
||||
const input = { a: { _get: { from: object, key: 'arr.$.a' } } };
|
||||
const parser = new NodeParser({ arrayIndices: [1] });
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toEqual({
|
||||
a: 'a2',
|
||||
});
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
@ -1,138 +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 max-classes-per-file */
|
||||
import WebParser from '../../src/webParser';
|
||||
|
||||
const context = {
|
||||
config: {
|
||||
string: 'config',
|
||||
arr: [{ a: 'config1' }, { a: 'config2' }],
|
||||
},
|
||||
input: {
|
||||
string: 'input',
|
||||
arr: [{ a: 'input1' }, { a: 'input2' }],
|
||||
},
|
||||
lowdefyGlobal: {
|
||||
string: 'global',
|
||||
arr: [{ a: 'global1' }, { a: 'global2' }],
|
||||
},
|
||||
menus: [
|
||||
{
|
||||
menuId: 'default',
|
||||
},
|
||||
{
|
||||
menuId: 'm_1',
|
||||
},
|
||||
{
|
||||
menuId: 'm_2',
|
||||
},
|
||||
],
|
||||
mutations: {
|
||||
not_loaded: { loading: true, response: 'fail' },
|
||||
string: { loading: false, response: 'mutation String' },
|
||||
number: { loading: false, response: 500 },
|
||||
arr: { loading: false, response: [{ a: 'mutation a1' }, { a: 'mutation a2' }] },
|
||||
},
|
||||
requests: {
|
||||
not_loaded: { loading: true, response: 'fail' },
|
||||
string: { loading: false, response: 'request String' },
|
||||
number: { loading: false, response: 500 },
|
||||
arr: { loading: false, response: [{ a: 'request a1' }, { a: 'request a2' }] },
|
||||
},
|
||||
state: {
|
||||
string: 'state',
|
||||
arr: [{ a: 'state1' }, { a: 'state2' }],
|
||||
},
|
||||
urlQuery: {
|
||||
string: 'urlQuery',
|
||||
arr: [{ a: 'urlQuery1' }, { a: 'urlQuery2' }],
|
||||
},
|
||||
};
|
||||
|
||||
const contexts = {};
|
||||
|
||||
const arrayIndices = [1];
|
||||
const object = {
|
||||
string: 'Some String',
|
||||
number: 42,
|
||||
arr: [{ a: 'a1' }, { a: 'a2' }],
|
||||
};
|
||||
const arr = [1, 2, 3];
|
||||
|
||||
test('_get in object', () => {
|
||||
const input = { a: { _get: { from: object, key: 'string' } } };
|
||||
const parser = new WebParser({ context, contexts });
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual({
|
||||
a: 'Some String',
|
||||
});
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_get replace key arrayIndices', () => {
|
||||
const input = { a: { _get: { from: object, key: 'arr.$.a' } } };
|
||||
const parser = new WebParser({ context, contexts });
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual({
|
||||
a: 'a2',
|
||||
});
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_get on array', () => {
|
||||
const input = { a: { _get: { from: arr, key: '0' } } };
|
||||
const parser = new WebParser({ context, contexts });
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual({
|
||||
a: 1,
|
||||
});
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_get null', () => {
|
||||
const input = { _get: null };
|
||||
const parser = new WebParser({ context, contexts });
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toBe(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _get takes an object as params. Received: null at locationId.],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('_get from: int', () => {
|
||||
const input = { _get: { from: 1, key: 'a' } };
|
||||
const parser = new WebParser({ context, contexts });
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toBe(null);
|
||||
});
|
||||
|
||||
test('_get from: null', () => {
|
||||
const input = { _get: { from: null, key: 'a' } };
|
||||
const parser = new WebParser({ context, contexts });
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toBe(null);
|
||||
});
|
||||
|
||||
test('_get key: int', () => {
|
||||
const input = { _get: { from: [1, 2, 3], key: 1 } };
|
||||
const parser = new WebParser({ context, contexts });
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toBe(2);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
Loading…
Reference in New Issue
Block a user