refactor: mutate config in normalizeConfig and handleLocalBackend fns (#4846)

This commit is contained in:
Vladislav Shkodin 2021-02-07 18:11:30 +02:00 committed by GitHub
parent 319a5381eb
commit 3924cfbce5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 102 additions and 92 deletions

View File

@ -10,7 +10,7 @@ import {
jest.spyOn(console, 'log').mockImplementation(() => {});
jest.spyOn(console, 'warn').mockImplementation(() => {});
jest.mock('coreSrc/backend', () => {
jest.mock('../../backend', () => {
return {
resolveBackend: jest.fn(() => ({ isGitBackend: jest.fn(() => true) })),
};
@ -452,8 +452,8 @@ describe('config', () => {
test('should convert camel case to snake case', () => {
expect(
applyDefaults(
normalizeConfig(
fromJS({
fromJS(
normalizeConfig({
collections: [
{
sortableFields: ['title'],
@ -922,7 +922,7 @@ describe('config', () => {
window.location = { hostname: 'localhost' };
global.fetch = jest.fn().mockRejectedValue(new Error());
const config = fromJS({ local_backend: true, backend: { name: 'github' } });
const config = { local_backend: true, backend: { name: 'github' } };
const actual = await handleLocalBackend(config);
expect(actual).toEqual(config);

View File

@ -2,17 +2,32 @@ import yaml from 'yaml';
import { Map, fromJS } from 'immutable';
import deepmerge from 'deepmerge';
import { trimStart, trim, get, isPlainObject, isEmpty } from 'lodash';
import * as publishModes from 'Constants/publishModes';
import { validateConfig } from 'Constants/configSchema';
import { SIMPLE as SIMPLE_PUBLISH_MODE } from '../constants/publishModes';
import { validateConfig } from '../constants/configSchema';
import { selectDefaultSortableFields, traverseFields } from '../reducers/collections';
import { getIntegrations, selectIntegration } from '../reducers/integrations';
import { resolveBackend } from 'coreSrc/backend';
import { resolveBackend } from '../backend';
import { I18N, I18N_FIELD, I18N_STRUCTURE } from '../lib/i18n';
export const CONFIG_REQUEST = 'CONFIG_REQUEST';
export const CONFIG_SUCCESS = 'CONFIG_SUCCESS';
export const CONFIG_FAILURE = 'CONFIG_FAILURE';
const traverseFieldsJS = (fields, updater) => {
return fields.map(field => {
let newField = updater(field);
if (newField.fields) {
newField = { ...newField, fields: traverseFieldsJS(newField.fields, updater) };
} else if (newField.field) {
newField = { ...newField, field: traverseFieldsJS([newField.field], updater)[0] };
} else if (newField.types) {
newField = { ...newField, types: traverseFieldsJS(newField.types, updater) };
}
return newField;
});
};
const getConfigUrl = () => {
const validTypes = { 'text/yaml': 'yaml', 'application/x-yaml': 'yaml' };
const configLinkEl = document.querySelector('link[rel="cms-config-url"]');
@ -32,31 +47,30 @@ const setDefaultPublicFolder = map => {
return map;
};
const setSnakeCaseConfig = field => {
// Mapping between existing camelCase and its snake_case counterpart
const widgetKeyMap = {
dateFormat: 'date_format',
timeFormat: 'time_format',
pickerUtc: 'picker_utc',
editorComponents: 'editor_components',
valueType: 'value_type',
valueField: 'value_field',
searchFields: 'search_fields',
displayFields: 'display_fields',
optionsLength: 'options_length',
};
// Mapping between existing camelCase and its snake_case counterpart
const WIDGET_KEY_MAP = {
dateFormat: 'date_format',
timeFormat: 'time_format',
pickerUtc: 'picker_utc',
editorComponents: 'editor_components',
valueType: 'value_type',
valueField: 'value_field',
searchFields: 'search_fields',
displayFields: 'display_fields',
optionsLength: 'options_length',
};
Object.entries(widgetKeyMap).forEach(([camel, snake]) => {
if (field.has(camel)) {
field = field.set(snake, field.get(camel));
console.warn(
`Field ${field.get(
'name',
)} is using a deprecated configuration '${camel}'. Please use '${snake}'`,
);
}
const setSnakeCaseConfig = field => {
const deprecatedKeys = Object.keys(WIDGET_KEY_MAP).filter(camel => camel in field);
const snakeValues = deprecatedKeys.map(camel => {
const snake = WIDGET_KEY_MAP[camel];
console.warn(
`Field ${field.name} is using a deprecated configuration '${camel}'. Please use '${snake}'`,
);
return { [snake]: field[camel] };
});
return field;
return Object.assign({}, field, ...snakeValues);
};
const setI18nField = field => {
@ -141,7 +155,7 @@ const setViewPatternsDefaults = (key, collection) => {
};
const defaults = {
publish_mode: publishModes.SIMPLE,
publish_mode: SIMPLE_PUBLISH_MODE,
};
const hasIntegration = (config, collection) => {
@ -151,45 +165,38 @@ const hasIntegration = (config, collection) => {
};
export function normalizeConfig(config) {
return Map(config).withMutations(map => {
map.set(
'collections',
map.get('collections').map(collection => {
const folder = collection.get('folder');
if (folder) {
collection = collection.set(
'fields',
traverseFields(collection.get('fields'), setSnakeCaseConfig),
);
}
const { collections = [] } = config;
const files = collection.get('files');
if (files) {
collection = collection.set(
'files',
files.map(file => {
file = file.set('fields', traverseFields(file.get('fields'), setSnakeCaseConfig));
return file;
}),
);
}
const normalizedCollections = collections.map(collection => {
const { fields, files } = collection;
if (collection.has('sortableFields')) {
collection = collection
.set('sortable_fields', collection.get('sortableFields'))
.delete('sortableFields');
let normalizedCollection = collection;
if (fields) {
const normalizedFields = traverseFieldsJS(fields, setSnakeCaseConfig);
normalizedCollection = { ...normalizedCollection, fields: normalizedFields };
}
console.warn(
`Collection ${collection.get(
'name',
)} is using a deprecated configuration 'sortableFields'. Please use 'sortable_fields'`,
);
}
if (files) {
const normalizedFiles = files.map(file => {
const normalizedFileFields = traverseFieldsJS(file.fields, setSnakeCaseConfig);
return { ...file, fields: normalizedFileFields };
});
normalizedCollection = { ...normalizedCollection, files: normalizedFiles };
}
return collection;
}),
);
if (normalizedCollection.sortableFields) {
const { sortableFields, ...rest } = normalizedCollection;
normalizedCollection = { ...rest, sortable_fields: sortableFields };
console.warn(
`Collection ${collection.name} is using a deprecated configuration 'sortableFields'. Please use 'sortable_fields'`,
);
}
return normalizedCollection;
});
return { ...config, collections: normalizedCollections };
}
export function applyDefaults(config) {
@ -383,36 +390,38 @@ export async function detectProxyServer(localBackend) {
return {};
}
export async function handleLocalBackend(originalConfig) {
if (!originalConfig.local_backend) {
return originalConfig;
const getPublishMode = (config, publishModes, backendType) => {
if (config.publish_mode && publishModes && !publishModes.includes(config.publish_mode)) {
const newPublishMode = publishModes[0];
console.log(
`'${config.publish_mode}' is not supported by '${backendType}' backend, switching to '${newPublishMode}'`,
);
return newPublishMode;
}
const { proxyUrl, publish_modes, type } = await detectProxyServer(originalConfig.local_backend);
return config.publish_mode;
};
export const handleLocalBackend = async config => {
if (!config.local_backend) {
return config;
}
const { proxyUrl, publish_modes: publishModes, type: backendType } = await detectProxyServer(
config.local_backend,
);
if (!proxyUrl) {
return originalConfig;
return config;
}
let mergedConfig = deepmerge(originalConfig, {
backend: { name: 'proxy', proxy_url: proxyUrl },
});
if (
mergedConfig.publish_mode &&
publish_modes &&
!publish_modes.includes(mergedConfig.publish_mode)
) {
const newPublishMode = publish_modes[0];
mergedConfig = deepmerge(mergedConfig, {
publish_mode: newPublishMode,
});
console.log(
`'${mergedConfig.publish_mode}' is not supported by '${type}' backend, switching to '${newPublishMode}'`,
);
}
return mergedConfig;
}
const publishMode = getPublishMode(config, publishModes, backendType);
return {
...config,
...(publishMode && { publish_mode: publishMode }),
backend: { ...config.backend, name: 'proxy', proxy_url: proxyUrl },
};
};
export function loadConfig(manualConfig = {}, onLoad) {
if (window.CMS_CONFIG) {
@ -430,13 +439,14 @@ export function loadConfig(manualConfig = {}, onLoad) {
: await getConfigYaml(configUrl, hasManualConfig);
// Merge manual config into the config.yml one
let mergedConfig = deepmerge(configYaml, manualConfig);
const mergedConfig = deepmerge(configYaml, manualConfig);
validateConfig(mergedConfig);
mergedConfig = await handleLocalBackend(mergedConfig);
const withLocalBackend = await handleLocalBackend(mergedConfig);
const normalizedConfig = normalizeConfig(withLocalBackend);
const config = applyDefaults(normalizeConfig(fromJS(mergedConfig)));
const config = applyDefaults(fromJS(normalizedConfig));
dispatch(configLoaded(config));