diff --git a/src/modify.js b/src/modify.js index b20a4ab8..da2981e9 100644 --- a/src/modify.js +++ b/src/modify.js @@ -1,6 +1,9 @@ import get from 'lodash/get'; import mergeWith from 'lodash/mergeWith'; +const WARNING_TYPES = { + CHANGE_FIELD_NOT_FOUND: 'CHANGE_FIELD_NOT_FOUND', +}; /** * * @param {*} path @@ -26,6 +29,7 @@ function standardizeAttrs(attrs) { function rewriteFields(schema, fieldsConfig) { if (!fieldsConfig) return null; + const warnings = []; const fieldsToModify = Object.entries(fieldsConfig); @@ -33,7 +37,13 @@ function rewriteFields(schema, fieldsConfig) { const fieldPath = shortToFullPath(shortPath); if (!get(schema.properties, fieldPath)) { - return; // Ignore field non existent in original schema. + // Do not override/edit a field that already exists. + // That's the job of config.fields method. + warnings.push({ + type: WARNING_TYPES.CHANGE_FIELD_NOT_FOUND, + message: `Changing field "${shortPath}" was ignored because it does not exist.`, + }); + return; } const fieldAttrs = get(schema.properties, fieldPath); @@ -49,13 +59,17 @@ function rewriteFields(schema, fieldsConfig) { ); if (fieldChanges.properties) { - rewriteFields(get(schema.properties, fieldPath), fieldChanges.properties); + const result = rewriteFields(get(schema.properties, fieldPath), fieldChanges.properties); + warnings.push(result.warnings); } }); + + return { warnings: warnings.flat() }; } function rewriteAllFields(schema, configCallback, context) { if (!configCallback) return null; + const parentName = context?.parent; Object.entries(schema.properties).forEach(([fieldName, fieldAttrs]) => { @@ -80,12 +94,9 @@ function rewriteAllFields(schema, configCallback, context) { export function modify(originalSchema, config) { const schema = JSON.parse(JSON.stringify(originalSchema)); - let warnings = []; // To be implemented in next PRs. - - // All these functions mutate "schema", - // that's why we create a copy above - rewriteFields(schema, config.fields); + // All these functions mutate "schema" that's why we create a copy above + const resultRewrite = rewriteFields(schema, config.fields); rewriteAllFields(schema, config.allFields); if (!config.muteWarningTip) { @@ -94,8 +105,10 @@ export function modify(originalSchema, config) { ); } + const allWarnings = [resultRewrite?.warnings].filter(Boolean).flat(); + return { schema, - warnings: warnings.length > 0 ? warnings : null, + warnings: allWarnings.length > 0 ? allWarnings : null, }; } diff --git a/src/tests/modify.test.js b/src/tests/modify.test.js index 81e0d399..316e8c39 100644 --- a/src/tests/modify.test.js +++ b/src/tests/modify.test.js @@ -208,6 +208,44 @@ describe('modify() - basic mutations', () => { }); }); + it('replace fields that dont exist gets ignored', () => { + // IMPORTANT NOTE on this behavior: + // Context: At Remote we have a lot of global customization that run equally across multiple different JSON Schemas. + // With this, we avoid applying customizations to non-existing fields. (aka create fields) + // That's why we have the "create" config, specific to create new fields. + const result = modify(schemaPet, { + fields: { + unknown_field: { + title: 'This field does not exist in the original schema', + }, + 'nested.field': { + title: 'Nop', + }, + pet_name: { + title: 'New pet title', + }, + }, + }); + + expect(result.schema.properties.unknown_field).toBeUndefined(); + expect(result.schema.properties.nested).toBeUndefined(); + expect(result.schema.properties.pet_name).toEqual({ + ...schemaPet.properties.pet_name, + title: 'New pet title', + }); + + expect(result.warnings).toEqual([ + { + type: 'CHANGE_FIELD_NOT_FOUND', + message: 'Changing field "unknown_field" was ignored because it does not exist.', + }, + { + type: 'CHANGE_FIELD_NOT_FOUND', + message: 'Changing field "nested.field" was ignored because it does not exist.', + }, + ]); + }); + it('replace all fields', () => { const result = modify(schemaPet, { allFields: (fieldName, fieldAttrs) => {