Skip to content

Commit

Permalink
Refactor: Make StaticViewConfigValidator.validate() output objects
Browse files Browse the repository at this point in the history
Summary:
## Changes
- StaticViewConfigValidator.validate() now outputs a ValidationOutput object, that contains a Array<Differences>, if invalid
- The Difference type now contains the nativeValue and the staticValue. This makes the validate() function more useful in reconciling ViewConfigs.
- Nothing should change in NativeComponentRegistry.

Changelog: [Internal]

Reviewed By: yungsters

Differential Revision: D32139973

fbshipit-source-id: a9556fa370d2c14f9e5d0540b44824cd61773958
  • Loading branch information
RSNara authored and facebook-github-bot committed Nov 9, 2021
1 parent 36612a8 commit 73b243a
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 67 deletions.
43 changes: 20 additions & 23 deletions Libraries/NativeComponent/NativeComponentRegistry.js
Expand Up @@ -68,33 +68,30 @@ export function get<Config>(
: 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);
}
}

Expand Down
67 changes: 58 additions & 9 deletions Libraries/NativeComponent/StaticViewConfigValidator.js
Expand Up @@ -10,9 +10,31 @@

import {type ViewConfig} from '../Renderer/shims/ReactNativeTypes';

type Difference = {
path: $ReadOnlyArray<string>,
type: 'missing' | 'unequal' | 'unexpected',
type Difference =
| {
type: 'missing',
path: Array<string>,
nativeValue: mixed,
}
| {
type: 'unequal',
path: Array<string>,
nativeValue: mixed,
staticValue: mixed,
}
| {
type: 'unexpected',
path: Array<string>,
staticValue: mixed,
};

type ValidationResult = ValidResult | InvalidResult;
type ValidResult = {
type: 'valid',
};
type InvalidResult = {
type: 'invalid',
differences: Array<Difference>,
};

/**
Expand All @@ -23,7 +45,7 @@ export function validate(
name: string,
nativeViewConfig: ViewConfig,
staticViewConfig: ViewConfig,
): ?string {
): ValidationResult {
const differences = [];
accumulateDifferences(
differences,
Expand All @@ -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.`;
Expand All @@ -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;
}

Expand All @@ -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],
});
}
}
}
Expand Down
Expand Up @@ -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', () => {
Expand All @@ -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'.
Expand All @@ -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'.
Expand Down Expand Up @@ -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'.
Expand Down Expand Up @@ -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'.
Expand All @@ -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);
}
}

0 comments on commit 73b243a

Please sign in to comment.