diff --git a/Libraries/NativeComponent/NativeComponentRegistry.js b/Libraries/NativeComponent/NativeComponentRegistry.js index cc8986ae694d63..1c3205981b8c23 100644 --- a/Libraries/NativeComponent/NativeComponentRegistry.js +++ b/Libraries/NativeComponent/NativeComponentRegistry.js @@ -68,33 +68,30 @@ export function get( : createViewConfig(viewConfigProvider()); if (verify) { + const nativeViewConfig = native + ? viewConfig + : getNativeComponentAttributes(name); + const staticViewConfig = native + ? createViewConfig(viewConfigProvider()) + : viewConfig; + if (strict) { - const results = native - ? StaticViewConfigValidator.validate( - name, - viewConfig, - createViewConfig(viewConfigProvider()), - ) - : StaticViewConfigValidator.validate( + const validationOutput = StaticViewConfigValidator.validate( + name, + nativeViewConfig, + staticViewConfig, + ); + + if (validationOutput.type === 'invalid') { + console.error( + StaticViewConfigValidator.stringifyValidationResult( name, - getNativeComponentAttributes(name), - viewConfig, - ); - if (results != null) { - console.error(results); - } - } else { - if (native) { - verifyComponentAttributeEquivalence( - viewConfig, - createViewConfig(viewConfigProvider()), - ); - } else { - verifyComponentAttributeEquivalence( - getNativeComponentAttributes(name), - viewConfig, + validationOutput, + ), ); } + } else { + verifyComponentAttributeEquivalence(nativeViewConfig, staticViewConfig); } } diff --git a/Libraries/NativeComponent/StaticViewConfigValidator.js b/Libraries/NativeComponent/StaticViewConfigValidator.js index 8eadb748b90059..6aa70649a5b61c 100644 --- a/Libraries/NativeComponent/StaticViewConfigValidator.js +++ b/Libraries/NativeComponent/StaticViewConfigValidator.js @@ -10,9 +10,31 @@ import {type ViewConfig} from '../Renderer/shims/ReactNativeTypes'; -type Difference = { - path: $ReadOnlyArray, - type: 'missing' | 'unequal' | 'unexpected', +type Difference = + | { + type: 'missing', + path: Array, + nativeValue: mixed, + } + | { + type: 'unequal', + path: Array, + nativeValue: mixed, + staticValue: mixed, + } + | { + type: 'unexpected', + path: Array, + staticValue: mixed, + }; + +type ValidationResult = ValidResult | InvalidResult; +type ValidResult = { + type: 'valid', +}; +type InvalidResult = { + type: 'invalid', + differences: Array, }; /** @@ -23,7 +45,7 @@ export function validate( name: string, nativeViewConfig: ViewConfig, staticViewConfig: ViewConfig, -): ?string { +): ValidationResult { const differences = []; accumulateDifferences( differences, @@ -41,13 +63,27 @@ export function validate( validAttributes: staticViewConfig.validAttributes, }, ); + if (differences.length === 0) { - return null; + return {type: 'valid'}; } + + return { + type: 'invalid', + differences, + }; +} + +export function stringifyValidationResult( + name: string, + validationResult: InvalidResult, +): string { + const {differences} = validationResult; return [ `StaticViewConfigValidator: Invalid static view config for '${name}'.`, '', - ...differences.map(({path, type}) => { + ...differences.map(difference => { + const {type, path} = difference; switch (type) { case 'missing': return `- '${path.join('.')}' is missing.`; @@ -71,7 +107,11 @@ function accumulateDifferences( const nativeValue = nativeObject[nativeKey]; if (!staticObject.hasOwnProperty(nativeKey)) { - differences.push({path: [...path, nativeKey], type: 'missing'}); + differences.push({ + path: [...path, nativeKey], + type: 'missing', + nativeValue, + }); continue; } @@ -94,13 +134,22 @@ function accumulateDifferences( } if (nativeValue !== staticValue) { - differences.push({path: [...path, nativeKey], type: 'unequal'}); + differences.push({ + path: [...path, nativeKey], + type: 'unequal', + nativeValue, + staticValue, + }); } } for (const staticKey in staticObject) { if (!nativeObject.hasOwnProperty(staticKey)) { - differences.push({path: [...path, staticKey], type: 'unexpected'}); + differences.push({ + path: [...path, staticKey], + type: 'unexpected', + staticValue: staticObject[staticKey], + }); } } } diff --git a/Libraries/NativeComponent/__tests__/StaticViewConfigValidator-test.js b/Libraries/NativeComponent/__tests__/StaticViewConfigValidator-test.js index 05c6a5dd2757b5..1c13325405a61c 100644 --- a/Libraries/NativeComponent/__tests__/StaticViewConfigValidator-test.js +++ b/Libraries/NativeComponent/__tests__/StaticViewConfigValidator-test.js @@ -74,13 +74,13 @@ test('passes for identical configs', () => { }, }; - expect( - StaticViewConfigValidator.validate( - name, - nativeViewConfig, - staticViewConfig, - ), - ).toBe(null); + const validationResult = StaticViewConfigValidator.validate( + name, + nativeViewConfig, + staticViewConfig, + ); + + expect(validationResult.type).toBe('valid'); }); test('fails for mismatched names', () => { @@ -98,13 +98,10 @@ test('fails for mismatched names', () => { }, }; - expect( - StaticViewConfigValidator.validate( - name, - nativeViewConfig, - staticViewConfig, - ), - ).toBe( + expectSVCToNotMatchNVC( + name, + nativeViewConfig, + staticViewConfig, ` StaticViewConfigValidator: Invalid static view config for 'RCTView'. @@ -130,13 +127,10 @@ test('fails for unequal attributes', () => { }, }; - expect( - StaticViewConfigValidator.validate( - name, - nativeViewConfig, - staticViewConfig, - ), - ).toBe( + expectSVCToNotMatchNVC( + name, + nativeViewConfig, + staticViewConfig, ` StaticViewConfigValidator: Invalid static view config for 'RCTView'. @@ -165,13 +159,10 @@ test('fails for missing attributes', () => { }, }; - expect( - StaticViewConfigValidator.validate( - name, - nativeViewConfig, - staticViewConfig, - ), - ).toBe( + expectSVCToNotMatchNVC( + name, + nativeViewConfig, + staticViewConfig, ` StaticViewConfigValidator: Invalid static view config for 'RCTView'. @@ -203,13 +194,10 @@ test('fails for unexpected attributes', () => { }, }; - expect( - StaticViewConfigValidator.validate( - name, - nativeViewConfig, - staticViewConfig, - ), - ).toBe( + expectSVCToNotMatchNVC( + name, + nativeViewConfig, + staticViewConfig, ` StaticViewConfigValidator: Invalid static view config for 'RCTView'. @@ -220,3 +208,26 @@ StaticViewConfigValidator: Invalid static view config for 'RCTView'. `.trimStart(), ); }); + +function expectSVCToNotMatchNVC( + name, + nativeViewConfig, + staticViewConfig, + message, +) { + const validationResult = StaticViewConfigValidator.validate( + name, + nativeViewConfig, + staticViewConfig, + ); + + expect(validationResult.type).toBe('invalid'); + if (validationResult.type === 'invalid') { + expect( + StaticViewConfigValidator.stringifyValidationResult( + name, + validationResult, + ), + ).toBe(message); + } +}