Merge pull request #448 from lowdefy/fixes

General fixes
This commit is contained in:
Gervwyk 2021-02-18 14:11:47 +02:00 committed by GitHub
commit 89565c0a0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 191 additions and 251 deletions

View File

@ -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
--------------------------------`,

View File

@ -15,7 +15,8 @@
*/
function formatErrorMessage(error) {
return `--------- Schema Error ---------
return `
--------- Schema Error ---------
message: ${error.message}
path: ${error.dataPath}
--------------------------------`;

View File

@ -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
--------------------------------`);

View File

@ -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 () {

View File

@ -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')}".`
);

View 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;

View File

@ -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: [
{

View File

@ -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(

View File

@ -38,6 +38,8 @@ function getFromObject({
);
}
if (params.key === null) return null;
if (params.contextId) {
if (env === 'node') {
throw new Error(

View File

@ -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' } });

View File

@ -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 });

View 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."`
);
});

View File

@ -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({

View File

@ -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 []`);
});

View File

@ -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 []`);
});