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
2 changed files with 102 additions and 92 deletions

View File

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

View File

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