@react-native/compatibility-check
Version:
Check a React Native app's boundary between JS and Native for incompatibilities
315 lines (313 loc) • 9.61 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.formatDiffSet = formatDiffSet;
exports.formatErrorMessage = formatErrorMessage;
exports.formatErrorStore = formatErrorStore;
exports.formatNativeSpecErrorStore = formatNativeSpecErrorStore;
var _Utils = require("@react-native/codegen/src/generators/Utils");
function indentedLineStart(indent) {
return "\n" + " ".repeat(indent);
}
function formatErrorMessage(error, indent = 0) {
switch (error.type) {
case "PropertyComparisonError":
const propertyPreviousError = error.previousError;
const formattedProperties = error.mismatchedProperties.map(
(individualPropertyError) =>
indentedLineStart(indent + 1) +
"-- " +
individualPropertyError.property +
(individualPropertyError.fault
? ": " +
formatErrorMessage(individualPropertyError.fault, indent + 2)
: ""),
);
return (
(propertyPreviousError != null
? formatErrorMessage(propertyPreviousError, indent) +
indentedLineStart(indent + 1)
: "") +
error.message +
formattedProperties.join("")
);
case "PositionalComparisonError":
const formattedPositionalChanges = error.erroneousItems.map(
([index, type]) =>
indentedLineStart(indent + 1) +
"-- position " +
index +
" " +
formatTypeAnnotation(type),
);
return error.message + formattedPositionalChanges.join("");
case "TypeAnnotationComparisonError":
case "TypeInformationComparisonError":
const previousError = error.previousError;
return (
error.message +
indentedLineStart(indent + 1) +
"--new: " +
formatTypeAnnotation(error.newerAnnotation) +
indentedLineStart(indent + 1) +
"--old: " +
formatTypeAnnotation(error.olderAnnotation) +
(previousError != null
? indentedLineStart(indent + 1) +
"" +
formatErrorMessage(previousError, indent + 2)
: "")
);
case "MemberComparisonError":
const formattedMembers = error.mismatchedMembers.map(
(individualMemberError) =>
indentedLineStart(indent + 1) +
"-- Member " +
individualMemberError.member +
(individualMemberError.fault
? ": " + formatErrorMessage(individualMemberError.fault, indent + 2)
: ""),
);
return error.message + formattedMembers.join("");
default:
error.type;
return "";
}
}
function formatTypeAnnotation(annotation) {
switch (annotation.type) {
case "AnyTypeAnnotation":
return "any";
case "ArrayTypeAnnotation":
return "Array<" + formatTypeAnnotation(annotation.elementType) + ">";
case "BooleanTypeAnnotation":
return "boolean";
case "EnumDeclaration": {
let shortHandType = "";
switch (annotation.memberType) {
case "StringTypeAnnotation":
shortHandType = "string";
break;
case "NumberTypeAnnotation":
shortHandType = "number";
break;
default:
annotation.memberType;
throw new Error("Unexpected enum memberType");
}
return `Enum<${shortHandType}>` + "";
}
case "EnumDeclarationWithMembers": {
let shortHandType = "";
switch (annotation.memberType) {
case "StringTypeAnnotation":
shortHandType = "string";
break;
case "NumberTypeAnnotation":
shortHandType = "number";
break;
default:
annotation.memberType;
throw new Error("Unexptected enum memberType");
}
return (
`Enum<${shortHandType}> {` +
annotation.members
.map(
(member) =>
`${member.name} = ${formatTypeAnnotation(member.value)}`,
)
.join(", ") +
"}"
);
}
case "FunctionTypeAnnotation":
return (
"(" +
annotation.params
.map(
(param) =>
param.name +
(param.optional ? "?" : "") +
": " +
formatTypeAnnotation(param.typeAnnotation),
)
.join(", ") +
")" +
"=>" +
formatTypeAnnotation(annotation.returnTypeAnnotation)
);
case "NullableTypeAnnotation":
return "?" + formatTypeAnnotation(annotation.typeAnnotation);
case "NumberTypeAnnotation":
return "number";
case "DoubleTypeAnnotation":
return "double";
case "FloatTypeAnnotation":
return "float";
case "Int32TypeAnnotation":
return "int";
case "NumberLiteralTypeAnnotation":
return annotation.value.toString();
case "BooleanLiteralTypeAnnotation":
return annotation.value.toString();
case "ObjectTypeAnnotation":
return (
"{" +
annotation.properties
.map(
(property) =>
property.name +
(property.optional ? "?" : "") +
": " +
formatTypeAnnotation(property.typeAnnotation),
)
.join(", ") +
"}"
);
case "StringLiteralTypeAnnotation":
return parseInt(annotation.value, 10).toString() === annotation.value ||
annotation.value.includes(" ")
? `'${annotation.value}'`
: annotation.value;
case "UnionTypeAnnotation":
let validUnionType;
try {
validUnionType = (0, _Utils.parseValidUnionType)(annotation);
} catch (_e) {
return "Union<mixed>";
}
switch (validUnionType) {
case "boolean":
if (
annotation.types.every(
({ type }) => type === "BooleanLiteralTypeAnnotation",
)
) {
return (
"(" +
annotation.types
.map((boolLit) => formatTypeAnnotation(boolLit))
.join(" | ") +
")"
);
}
return `Union<boolean>`;
case "number":
if (
annotation.types.every(
({ type }) => type === "NumberLiteralTypeAnnotation",
)
) {
return (
"(" +
annotation.types
.map((numLit) => formatTypeAnnotation(numLit))
.join(" | ") +
")"
);
}
return `Union<number>`;
case "object":
return `Union<Object>`;
case "string":
if (
annotation.types.every(
({ type }) => type === "StringLiteralTypeAnnotation",
)
) {
return (
"(" +
annotation.types
.map((stringLit) => formatTypeAnnotation(stringLit))
.join(" | ") +
")"
);
}
return `Union<string>`;
default:
throw new Error(`Unsupported union member type`);
}
case "StringTypeAnnotation":
return "string";
case "PromiseTypeAnnotation":
return "Promise<" + formatTypeAnnotation(annotation.elementType) + ">";
case "EventEmitterTypeAnnotation":
return (
"EventEmitter<" + formatTypeAnnotation(annotation.typeAnnotation) + ">"
);
case "TypeAliasTypeAnnotation":
case "ReservedTypeAnnotation":
return annotation.name;
case "VoidTypeAnnotation":
return "void";
case "MixedTypeAnnotation":
return "mixed";
case "GenericObjectTypeAnnotation":
if (annotation.dictionaryValueType) {
return `{[string]: ${formatTypeAnnotation(annotation.dictionaryValueType)}`;
}
return "Object";
default:
annotation.type;
return JSON.stringify(annotation);
}
}
function formatErrorStore(errorStore) {
return {
message:
errorStore.typeName +
": " +
formatErrorMessage(errorStore.errorInformation),
errorCode: errorStore.errorCode,
};
}
function formatNativeSpecErrorStore(specError) {
if (specError.errorInformation) {
return [
{
message:
specError.nativeSpecName +
": " +
formatErrorMessage(specError.errorInformation),
errorCode: specError.errorCode,
},
];
}
if (specError.changeInformation?.incompatibleChanges != null) {
return Array.from(specError.changeInformation.incompatibleChanges).map(
(errorStore) => formatErrorStore(errorStore),
);
}
return [];
}
function formatDiffSet(summary) {
const summaryStatus = summary.status;
if (summaryStatus === "ok" || summaryStatus === "patchable") {
return summary;
}
const hasteModules = Object.keys(summary.incompatibilityReport);
const incompatibles = summary.incompatibilityReport;
const formattedIncompatibilities = {};
hasteModules.forEach((hasteModule) => {
const incompat = incompatibles[hasteModule];
const formattedIncompat = {
framework: incompat.framework,
};
if (incompat.incompatibleSpecs) {
formattedIncompat.incompatibleSpecs = incompat.incompatibleSpecs.reduce(
(formattedModuleErrors, specErrorStore) =>
formattedModuleErrors.concat(
formatNativeSpecErrorStore(specErrorStore),
),
[],
);
}
formattedIncompatibilities[hasteModule] = formattedIncompat;
});
return {
status: summaryStatus,
incompatibilityReport: formattedIncompatibilities,
};
}