@definitelytyped/dts-critic
Version:
Checks a new .d.ts against the Javascript source and tells you what problems it has
619 lines (616 loc) • 27.5 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultErrors = exports.ErrorKind = void 0;
exports.dtsCritic = dtsCritic;
exports.findDtsName = findDtsName;
exports.checkSource = checkSource;
exports.dtToNpmName = dtToNpmName;
exports.parseExportErrorKind = parseExportErrorKind;
const yargs = require("yargs");
const headerParser = require("@definitelytyped/header-parser");
const fs = require("fs");
const path = require("path");
const typescript_1 = __importDefault(require("typescript"));
var ErrorKind;
(function (ErrorKind) {
/** Declaration needs to use `export =` to match the JavaScript module's behavior. */
ErrorKind["NeedsExportEquals"] = "NeedsExportEquals";
/** Declaration has a default export, but JavaScript module does not have a default export. */
ErrorKind["NoDefaultExport"] = "NoDefaultExport";
/** JavaScript exports property not found in declaration exports. */
ErrorKind["JsPropertyNotInDts"] = "JsPropertyNotInDts";
/** Declaration exports property not found in JavaScript exports. */
ErrorKind["DtsPropertyNotInJs"] = "DtsPropertyNotInJs";
/** JavaScript module has signatures, but declaration module does not. */
ErrorKind["JsSignatureNotInDts"] = "JsSignatureNotInDts";
/** Declaration module has signatures, but JavaScript module does not. */
ErrorKind["DtsSignatureNotInJs"] = "DtsSignatureNotInJs";
})(ErrorKind || (exports.ErrorKind = ErrorKind = {}));
function dtsCritic(dtsPath, sourcePath, options = { errors: new Map() }, debug = false) {
if (!sourcePath && require.main !== module) {
// dtslint will issue an error.
return [];
}
const name = findDtsName(dtsPath);
const packageJsonPath = path.join(path.dirname(path.resolve(dtsPath)), "package.json");
const header = parsePackageJson(name, JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")), path.dirname(dtsPath));
if (header === undefined) {
return [];
}
else if (header.nonNpm) {
const errors = [];
if (sourcePath) {
errors.push(...checkSource(name, dtsPath, sourcePath, options.errors, debug));
}
else if (require.main === module) {
console.log(`Warning: declaration provided is for a non-npm package.
If you want to check the declaration against the JavaScript source code, you must provide a path to the source file.`);
}
return errors;
}
else {
let sourceEntry;
if (!fs.statSync(sourcePath).isDirectory()) {
sourceEntry = sourcePath;
}
else {
sourceEntry = require.resolve(path.resolve(sourcePath));
}
return checkSource(name, dtsPath, sourceEntry, options.errors, debug);
}
}
function parsePackageJson(packageName, packageJson, dirPath) {
const result = headerParser.validatePackageJson(packageName, packageJson, headerParser.getTypesVersions(dirPath));
if (Array.isArray(result))
console.log(result.join("\n"));
return Array.isArray(result) ? undefined : result;
}
exports.defaultErrors = [ErrorKind.NeedsExportEquals, ErrorKind.NoDefaultExport];
function main() {
const argv = yargs
.usage("$0 --dts path-to-d.ts --js path-to-source [--debug]\n\nIf source-folder is not provided, I will look for a matching package on npm.")
.option("dts", {
describe: "Path of declaration file to be critiqued.",
type: "string",
})
.demandOption("dts", "Please provide a path to a d.ts file for me to critique.")
.option("js", {
describe: "Path of JavaScript file to be used as source.",
type: "string",
})
.demandOption("js", "Please provide a path to a JavaScript file for me to compare the d.ts against.")
.option("debug", {
describe: "Turn debug logging on.",
type: "boolean",
default: false,
})
.help()
.parseSync();
const opts = { mode: argv.mode, errors: new Map() };
const errors = dtsCritic(argv.dts, argv.js, opts, argv.debug);
if (errors.length === 0) {
console.log("No errors!");
}
else {
for (const error of errors) {
console.log("Error: " + error.message);
}
}
}
/**
* If dtsName is 'index' (as with DT) then look to the parent directory for the name.
*/
function findDtsName(dtsPath) {
const resolved = path.resolve(dtsPath);
const baseName = path.basename(resolved, ".d.ts");
if (baseName && baseName !== "index") {
return baseName;
}
return path.basename(path.dirname(resolved));
}
function checkSource(name, dtsPath, srcPath, enabledErrors, debug) {
const diagnostics = checkExports(name, dtsPath, srcPath);
if (debug) {
console.log(formatDebug(name, diagnostics));
}
return diagnostics.errors.filter((err) => enabledErrors.get(err.kind) ?? exports.defaultErrors.includes(err.kind));
}
function formatDebug(name, diagnostics) {
const lines = [];
lines.push(`\tDiagnostics for package ${name}.`);
lines.push("\tInferred source module structure:");
if (isSuccess(diagnostics.jsExportKind)) {
lines.push(diagnostics.jsExportKind.result);
}
else {
lines.push(`Could not infer type of JavaScript exports. Reason: ${diagnostics.jsExportKind.reason}`);
}
lines.push("\tInferred source export type:");
if (isSuccess(diagnostics.jsExportType)) {
lines.push(formatType(diagnostics.jsExportType.result));
}
else {
lines.push(`Could not infer type of JavaScript exports. Reason: ${diagnostics.jsExportType.reason}`);
}
if (diagnostics.dtsExportKind) {
lines.push("\tInferred declaration module structure:");
if (isSuccess(diagnostics.dtsExportKind)) {
lines.push(diagnostics.dtsExportKind.result);
}
else {
lines.push(`Could not infer type of declaration exports. Reason: ${diagnostics.dtsExportKind.reason}`);
}
}
if (diagnostics.dtsExportType) {
lines.push("\tInferred declaration export type:");
if (isSuccess(diagnostics.dtsExportType)) {
lines.push(formatType(diagnostics.dtsExportType.result));
}
else {
lines.push(`Could not infer type of declaration exports. Reason: ${diagnostics.dtsExportType.reason}`);
}
}
return lines.join("\n");
}
function formatType(type) {
const lines = [];
//@ts-ignore property `checker` of `ts.Type` is marked internal. The alternative is to have a TypeChecker parameter.
const checker = type.checker;
const properties = type.getProperties();
if (properties.length > 0) {
lines.push("Type's properties:");
lines.push(...properties.map((p) => p.getName()));
}
const signatures = type.getConstructSignatures().concat(type.getCallSignatures());
if (signatures.length > 0) {
lines.push("Type's signatures:");
lines.push(...signatures.map((s) => checker.signatureToString(s)));
}
lines.push(`Type string: ${checker.typeToString(type)}`);
return lines.join("\n");
}
const exportEqualsLink = "https://www.typescriptlang.org/docs/handbook/modules.html#export--and-import--require";
/**
* Checks exports of a declaration file against its JavaScript source.
*/
function checkExports(name, dtsPath, sourcePath) {
const tscOpts = {
allowJs: true,
};
const jsProgram = typescript_1.default.createProgram([sourcePath], tscOpts);
const jsFileNode = jsProgram.getSourceFile(sourcePath);
if (!jsFileNode) {
throw new Error(`TS compiler could not find source file ${sourcePath}.`);
}
const jsChecker = jsProgram.getTypeChecker();
const errors = [];
const sourceDiagnostics = inspectJs(jsFileNode, jsChecker, name);
const dtsDiagnostics = inspectDts(dtsPath, name);
if (isSuccess(sourceDiagnostics.exportEquals) &&
sourceDiagnostics.exportEquals.result.judgement === ExportEqualsJudgement.Required &&
isSuccess(dtsDiagnostics.exportKind) &&
dtsDiagnostics.exportKind.result !== DtsExportKind.ExportEquals) {
const error = {
kind: ErrorKind.NeedsExportEquals,
message: `The declaration doesn't match the JavaScript module '${name}'. Reason:
The declaration should use 'export =' syntax because the JavaScript source uses 'module.exports =' syntax and ${sourceDiagnostics.exportEquals.result.reason}.
To learn more about 'export =' syntax, see ${exportEqualsLink}.`,
};
errors.push(error);
}
const compatibility = exportTypesCompatibility(name, sourceDiagnostics.exportType, dtsDiagnostics.exportType, dtsDiagnostics.exportKind);
if (isSuccess(compatibility)) {
errors.push(...compatibility.result);
}
if (dtsDiagnostics.defaultExport && !sourceDiagnostics.exportsDefault) {
errors.push({
kind: ErrorKind.NoDefaultExport,
position: dtsDiagnostics.defaultExport,
message: `The declaration doesn't match the JavaScript module '${name}'. Reason:
The declaration specifies 'export default' but the JavaScript source does not mention 'default' anywhere.
The most common way to resolve this error is to use 'export =' syntax instead of 'export default'.
To learn more about 'export =' syntax, see ${exportEqualsLink}.`,
});
}
return {
jsExportKind: sourceDiagnostics.exportKind,
jsExportType: sourceDiagnostics.exportType,
dtsExportKind: dtsDiagnostics.exportKind,
dtsExportType: dtsDiagnostics.exportType,
errors,
};
}
function inspectJs(sourceFile, checker, packageName) {
const exportKind = getJsExportKind(sourceFile);
const exportType = getJSExportType(sourceFile, checker, exportKind);
const exportsDefault = sourceExportsDefault(sourceFile, packageName);
let exportEquals;
if (isSuccess(exportType) && isSuccess(exportKind) && exportKind.result === JsExportKind.CommonJs) {
exportEquals = moduleTypeNeedsExportEquals(exportType.result, checker);
}
else {
exportEquals = mergeErrors(exportType, exportKind);
}
return { exportKind, exportType, exportEquals, exportsDefault };
}
function getJsExportKind(sourceFile) {
// @ts-ignore property `commonJsModuleIndicator` of `ts.SourceFile` is marked internal.
if (sourceFile.commonJsModuleIndicator) {
return inferenceSuccess(JsExportKind.CommonJs);
}
// @ts-ignore property `externalModuleIndicator` of `ts.SourceFile` is marked internal.
if (sourceFile.externalModuleIndicator) {
return inferenceSuccess(JsExportKind.ES6);
}
return inferenceError("Could not infer export kind of source file.");
}
function getJSExportType(sourceFile, checker, exportKind) {
if (isSuccess(exportKind)) {
switch (exportKind.result) {
case JsExportKind.CommonJs: {
checker.getSymbolAtLocation(sourceFile); // TODO: get symbol in a safer way?
//@ts-ignore property `symbol` of `ts.Node` is marked internal.
const fileSymbol = sourceFile.symbol;
if (!fileSymbol) {
return inferenceError(`TS compiler could not find symbol for file node '${sourceFile.fileName}'.`);
}
const exportType = checker.getTypeOfSymbolAtLocation(fileSymbol, sourceFile);
return inferenceSuccess(exportType);
}
case JsExportKind.ES6: {
const fileSymbol = checker.getSymbolAtLocation(sourceFile);
if (!fileSymbol) {
return inferenceError(`TS compiler could not find symbol for file node '${sourceFile.fileName}'.`);
}
const exportType = checker.getTypeOfSymbolAtLocation(fileSymbol, sourceFile);
return inferenceSuccess(exportType);
}
}
}
return inferenceError(`Could not infer type of exports because exports kind is undefined.`);
}
/**
* Decide if a JavaScript source module could have a default export.
*/
function sourceExportsDefault(sourceFile, name) {
const src = sourceFile.getFullText(sourceFile);
return (isRealExportDefault(name) ||
src.indexOf("default") > -1 ||
src.indexOf("__esModule") > -1 ||
src.indexOf("react-side-effect") > -1 ||
src.indexOf("@flow") > -1 ||
src.indexOf("module.exports = require") > -1);
}
function moduleTypeNeedsExportEquals(type, checker) {
if (isBadType(type)) {
return inferenceError(`Inferred type '${checker.typeToString(type)}' is not good enough to be analyzed.`);
}
const isObject = type.getFlags() & typescript_1.default.TypeFlags.Object;
// @ts-ignore property `isArrayLikeType` of `ts.TypeChecker` is marked internal.
if (isObject && !hasSignatures(type) && !checker.isArrayLikeType(type)) {
const judgement = ExportEqualsJudgement.NotRequired;
const reason = "'module.exports' is an object which is neither a function, class, or array";
return inferenceSuccess({ judgement, reason });
}
if (hasSignatures(type)) {
const judgement = ExportEqualsJudgement.Required;
const reason = "'module.exports' can be called or constructed";
return inferenceSuccess({ judgement, reason });
}
const primitive = typescript_1.default.TypeFlags.Boolean | typescript_1.default.TypeFlags.String | typescript_1.default.TypeFlags.Number;
if (type.getFlags() & primitive) {
const judgement = ExportEqualsJudgement.Required;
const reason = `'module.exports' has primitive type ${checker.typeToString(type)}`;
return inferenceSuccess({ judgement, reason });
}
// @ts-ignore property `isArrayLikeType` of `ts.TypeChecker` is marked internal.
if (checker.isArrayLikeType(type)) {
const judgement = ExportEqualsJudgement.Required;
const reason = `'module.exports' has array-like type ${checker.typeToString(type)}`;
return inferenceSuccess({ judgement, reason });
}
return inferenceError(`Could not analyze type '${checker.typeToString(type)}'.`);
}
function hasSignatures(type) {
return type.getCallSignatures().length > 0 || type.getConstructSignatures().length > 0;
}
function inspectDts(dtsPath, name) {
dtsPath = path.resolve(dtsPath);
const program = createDtProgram(dtsPath);
const sourceFile = program.getSourceFile(path.resolve(dtsPath));
if (!sourceFile) {
throw new Error(`TS compiler could not find source file '${dtsPath}'.`);
}
const checker = program.getTypeChecker();
const symbolResult = getDtsModuleSymbol(sourceFile, checker, name);
const exportKindResult = getDtsExportKind(sourceFile);
const exportType = getDtsExportType(sourceFile, checker, symbolResult, exportKindResult);
const defaultExport = getDtsDefaultExport(sourceFile, exportType);
return { exportKind: exportKindResult, exportType, defaultExport };
}
function createDtProgram(dtsPath) {
const dtsDir = path.dirname(dtsPath);
const configPath = path.join(dtsDir, "tsconfig.json");
const { config } = typescript_1.default.readConfigFile(configPath, (p) => fs.readFileSync(p, { encoding: "utf8" }));
const parseConfigHost = {
fileExists: fs.existsSync,
readDirectory: typescript_1.default.sys.readDirectory,
readFile: (file) => fs.readFileSync(file, { encoding: "utf8" }),
useCaseSensitiveFileNames: true,
};
const parsed = typescript_1.default.parseJsonConfigFileContent(config, parseConfigHost, path.resolve(dtsDir));
const host = typescript_1.default.createCompilerHost(parsed.options, true);
return typescript_1.default.createProgram([path.resolve(dtsPath)], parsed.options, host);
}
function getDtsModuleSymbol(sourceFile, checker, name) {
if (matches(sourceFile, (node) => typescript_1.default.isModuleDeclaration(node))) {
const npmName = dtToNpmName(name);
const moduleSymbol = checker.getAmbientModules().find((symbol) => symbol.getName() === `"${npmName}"`);
if (moduleSymbol) {
return inferenceSuccess(moduleSymbol);
}
}
const fileSymbol = checker.getSymbolAtLocation(sourceFile);
if (fileSymbol && fileSymbol.getFlags() & typescript_1.default.SymbolFlags.ValueModule) {
return inferenceSuccess(fileSymbol);
}
return inferenceError(`Could not find module symbol for source file node.`);
}
function getDtsExportKind(sourceFile) {
if (matches(sourceFile, isExportEquals)) {
return inferenceSuccess(DtsExportKind.ExportEquals);
}
if (matches(sourceFile, isExportConstruct)) {
return inferenceSuccess(DtsExportKind.ES6Like);
}
return inferenceError("Could not infer export kind of declaration file.");
}
const exportEqualsSymbolName = "export=";
function getDtsExportType(sourceFile, checker, symbolResult, exportKindResult) {
if (isSuccess(symbolResult) && isSuccess(exportKindResult)) {
const symbol = symbolResult.result;
const exportKind = exportKindResult.result;
switch (exportKind) {
case DtsExportKind.ExportEquals: {
const exportSymbol = symbol.exports.get(exportEqualsSymbolName);
if (!exportSymbol) {
return inferenceError(`TS compiler could not find \`export=\` symbol.`);
}
const exportType = checker.getTypeOfSymbolAtLocation(exportSymbol, sourceFile);
return inferenceSuccess(exportType);
}
case DtsExportKind.ES6Like: {
const exportType = checker.getTypeOfSymbolAtLocation(symbol, sourceFile);
return inferenceSuccess(exportType);
}
}
}
return mergeErrors(symbolResult, exportKindResult);
}
/**
* Returns the position of the default export, if it exists.
*/
function getDtsDefaultExport(sourceFile, moduleType) {
if (isError(moduleType)) {
const src = sourceFile.getFullText(sourceFile);
const exportDefault = src.indexOf("export default");
if (exportDefault > -1 && src.indexOf("export =") === -1 && !/declare module ['"]/.test(src)) {
return {
start: exportDefault,
length: "export default".length,
};
}
return undefined;
}
const exportDefault = moduleType.result.getProperty("default");
if (exportDefault?.declarations) {
return {
start: exportDefault.declarations[0].getStart(),
length: exportDefault.declarations[0].getWidth(),
};
}
return undefined;
}
const ignoredProperties = ["__esModule", "prototype", "default", "F", "G", "S", "P", "B", "W", "U", "R"];
function ignoreProperty(property) {
const name = property.getName();
return name.startsWith("_") || ignoredProperties.includes(name);
}
/*
* Given the inferred type of the exports of both source and declaration, we make the following checks:
* 1. If source type has call or construct signatures, then declaration type should also have call or construct signatures.
* 2. If declaration type has call or construct signatures, then source type should also have call or construct signatures.
* 3. If source type has a property named "foo", then declaration type should also have a property named "foo".
* 4. If declaration type has a property named "foo", then source type should also have a property named "foo".
* Checks (2) and (4) don't work well in practice and should not be used for linting/verification purposes, because
* most of the times the error originates because the inferred type of the JavaScript source has missing information.
* Those checks are useful for finding examples where JavaScript type inference could be improved.
*/
function exportTypesCompatibility(name, sourceType, dtsType, dtsExportKind) {
if (isError(sourceType)) {
return inferenceError("Could not get type of exports of source module.");
}
if (isError(dtsType)) {
return inferenceError("Could not get type of exports of declaration module.");
}
if (isBadType(sourceType.result)) {
return inferenceError("Could not infer meaningful type of exports of source module.");
}
if (isBadType(dtsType.result)) {
return inferenceError("Could not infer meaningful type of exports of declaration module.");
}
const errors = [];
if (hasSignatures(sourceType.result) && !hasSignatures(dtsType.result)) {
if (isSuccess(dtsExportKind) && dtsExportKind.result === DtsExportKind.ExportEquals) {
errors.push({
kind: ErrorKind.JsSignatureNotInDts,
message: `The declaration doesn't match the JavaScript module '${name}'. Reason:
The JavaScript module can be called or constructed, but the declaration module cannot.`,
});
}
else {
errors.push({
kind: ErrorKind.JsSignatureNotInDts,
message: `The declaration doesn't match the JavaScript module '${name}'. Reason:
The JavaScript module can be called or constructed, but the declaration module cannot.
The most common way to resolve this error is to use 'export =' syntax.
To learn more about 'export =' syntax, see ${exportEqualsLink}.`,
});
}
}
if (hasSignatures(dtsType.result) && !hasSignatures(sourceType.result)) {
errors.push({
kind: ErrorKind.DtsSignatureNotInJs,
message: `The declaration doesn't match the JavaScript module '${name}'. Reason:
The declaration module can be called or constructed, but the JavaScript module cannot.`,
});
}
const sourceProperties = sourceType.result.getProperties();
const dtsProperties = dtsType.result.getProperties();
for (const sourceProperty of sourceProperties) {
// TODO: check `prototype` properties.
if (ignoreProperty(sourceProperty))
continue;
if (!dtsProperties.find((s) => s.getName() === sourceProperty.getName())) {
errors.push({
kind: ErrorKind.JsPropertyNotInDts,
message: `The declaration doesn't match the JavaScript module '${name}'. Reason:
The JavaScript module exports a property named '${sourceProperty.getName()}', which is missing from the declaration module.`,
});
}
}
for (const dtsProperty of dtsProperties) {
// TODO: check `prototype` properties.
if (ignoreProperty(dtsProperty))
continue;
if (!sourceProperties.find((s) => s.getName() === dtsProperty.getName())) {
const error = {
kind: ErrorKind.DtsPropertyNotInJs,
message: `The declaration doesn't match the JavaScript module '${name}'. Reason:
The declaration module exports a property named '${dtsProperty.getName()}', which is missing from the JavaScript module.`,
};
const declaration = dtsProperty.declarations && dtsProperty.declarations.length > 0 ? dtsProperty.declarations[0] : undefined;
if (declaration) {
error.position = {
start: declaration.getStart(),
length: declaration.getWidth(),
};
}
errors.push(error);
}
}
return inferenceSuccess(errors);
}
function isBadType(type) {
return !!(type.getFlags() & (typescript_1.default.TypeFlags.Any | typescript_1.default.TypeFlags.Unknown | typescript_1.default.TypeFlags.Undefined | typescript_1.default.TypeFlags.Null));
}
function isExportEquals(node) {
return typescript_1.default.isExportAssignment(node) && !!node.isExportEquals;
}
function isExportConstruct(node) {
return typescript_1.default.isExportAssignment(node) || typescript_1.default.isExportDeclaration(node) || hasExportModifier(node);
}
function hasExportModifier(node) {
if (typescript_1.default.canHaveModifiers(node)) {
return !!typescript_1.default.getModifiers(node)?.some((modifier) => modifier.kind === typescript_1.default.SyntaxKind.ExportKeyword);
}
return false;
}
function matches(srcFile, predicate) {
function matchesNode(node) {
if (predicate(node))
return true;
const children = node.getChildren(srcFile);
for (const child of children) {
if (matchesNode(child))
return true;
}
return false;
}
return matchesNode(srcFile);
}
function isRealExportDefault(name) {
return name.indexOf("react-native") > -1 || name === "ember-feature-flags" || name === "material-ui-datatables";
}
/**
* Converts a package name from the name used in DT repository to the name used in npm.
* @param baseName DT name of a package
*/
function dtToNpmName(baseName) {
if (/__/.test(baseName)) {
return "@" + baseName.replace("__", "/");
}
return baseName;
}
/**
* @param error case-insensitive name of the error
*/
function parseExportErrorKind(error) {
error = error.toLowerCase();
switch (error) {
case "needsexportequals":
return ErrorKind.NeedsExportEquals;
case "nodefaultexport":
return ErrorKind.NoDefaultExport;
case "jspropertynotindts":
return ErrorKind.JsPropertyNotInDts;
case "dtspropertynotinjs":
return ErrorKind.DtsPropertyNotInJs;
case "jssignaturenotindts":
return ErrorKind.JsSignatureNotInDts;
case "dtssignaturenotinjs":
return ErrorKind.DtsSignatureNotInJs;
}
return undefined;
}
var JsExportKind;
(function (JsExportKind) {
JsExportKind["CommonJs"] = "CommonJs";
JsExportKind["ES6"] = "ES6";
})(JsExportKind || (JsExportKind = {}));
var ExportEqualsJudgement;
(function (ExportEqualsJudgement) {
ExportEqualsJudgement["Required"] = "Required";
ExportEqualsJudgement["NotRequired"] = "Not required";
})(ExportEqualsJudgement || (ExportEqualsJudgement = {}));
var DtsExportKind;
(function (DtsExportKind) {
DtsExportKind["ExportEquals"] = "export =";
DtsExportKind["ES6Like"] = "ES6-like";
})(DtsExportKind || (DtsExportKind = {}));
var InferenceResultKind;
(function (InferenceResultKind) {
InferenceResultKind[InferenceResultKind["Error"] = 0] = "Error";
InferenceResultKind[InferenceResultKind["Success"] = 1] = "Success";
})(InferenceResultKind || (InferenceResultKind = {}));
function inferenceError(reason) {
return { kind: InferenceResultKind.Error, reason };
}
function inferenceSuccess(result) {
return { kind: InferenceResultKind.Success, result };
}
function isSuccess(inference) {
return inference.kind === InferenceResultKind.Success;
}
function isError(inference) {
return inference.kind === InferenceResultKind.Error;
}
function mergeErrors(...results) {
const reasons = [];
for (const result of results) {
if (typeof result === "string") {
reasons.push(result);
}
else if (isError(result) && result.reason) {
reasons.push(result.reason);
}
}
return inferenceError(reasons.join(" "));
}
if (require.main === module) {
main();
}
//# sourceMappingURL=index.js.map