@netlify/content-engine
Version:
170 lines • 7.44 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.handleBadExports = handleBadExports;
exports.collatePluginAPIs = collatePluginAPIs;
exports.warnOnIncompatiblePeerDependency = warnOnIncompatiblePeerDependency;
const node_fs_1 = __importDefault(require("node:fs"));
const lodash_topairs_1 = __importDefault(require("lodash.topairs"));
const lodash_difference_1 = __importDefault(require("lodash.difference"));
const lodash_intersection_1 = __importDefault(require("lodash.intersection"));
const lodash_get_1 = __importDefault(require("lodash.get"));
const path_1 = __importDefault(require("path"));
const semver = __importStar(require("semver"));
const stringSimilarity = __importStar(require("string-similarity"));
const reporter_1 = __importDefault(require("../../reporter"));
const pkg_dir_1 = __importDefault(require("pkg-dir"));
// import { trackCli } from "gatsby-telemetry"
const resolve_module_exports_1 = require("../resolve-module-exports");
const get_latest_apis_1 = require("../../utils/get-latest-apis");
const { version: gatsbyVersion } = JSON.parse(node_fs_1.default.readFileSync(path_1.default.join(pkg_dir_1.default.sync(__dirname), "package.json"), "utf8"));
const getGatsbyUpgradeVersion = (entries) => entries.reduce((version, entry) => {
if (entry.api && entry.api.version) {
return semver.gt(entry.api.version, version || `0.0.0`)
? entry.api.version
: version;
}
return version;
}, ``);
// Given a plugin object, an array of the API names it exports and an
// array of valid API names, return an array of invalid API exports.
function getBadExports(plugin, pluginAPIKeys, apis) {
let badExports = [];
// Discover any exports from plugins which are not "known"
badExports = badExports.concat((0, lodash_difference_1.default)(pluginAPIKeys, apis).map((e) => {
return {
exportName: e,
pluginName: plugin.name,
pluginVersion: plugin.version,
};
}));
return badExports;
}
function getErrorContext(badExports, exportType, currentAPIs, latestAPIs) {
const entries = badExports.map((ex) => {
return {
...ex,
api: latestAPIs[exportType][ex.exportName],
};
});
const gatsbyUpgradeVersion = getGatsbyUpgradeVersion(entries);
const errors = [];
const fixes = gatsbyUpgradeVersion
? [`npm install gatsby@^${gatsbyUpgradeVersion}`]
: [];
entries.forEach((entry) => {
const similarities = stringSimilarity.findBestMatch(entry.exportName, currentAPIs[exportType]);
const isDefaultPlugin = entry.pluginName == `default-site-plugin`;
const message = entry.api
? entry.api.version
? `was introduced in gatsby@${entry.api.version}`
: `is not available in your version of Gatsby`
: `is not a known API`;
if (isDefaultPlugin) {
errors.push(`- Your local gatsby-${exportType}.js is using the API "${entry.exportName}" which ${message}.`);
}
else {
errors.push(`- The plugin ${entry.pluginName}@${entry.pluginVersion} is using the API "${entry.exportName}" which ${message}.`);
}
if (similarities.bestMatch.rating > 0.5) {
fixes.push(`Rename "${entry.exportName}" -> "${similarities.bestMatch.target}"`);
}
});
return {
errors,
entries,
exportType,
fixes,
sourceMessage: [
`Your plugins must export known APIs from their gatsby-node.js.`,
]
.concat(errors)
.concat(fixes.length > 0
? [`\n`, `Some of the following may help fix the error(s):`, ...fixes]
: [])
.filter(Boolean)
.join(`\n`),
};
}
async function handleBadExports({ currentAPIs, badExports, }) {
const hasBadExports = Object.keys(badExports).find((api) => badExports[api].length > 0);
if (hasBadExports) {
const latestAPIs = await (0, get_latest_apis_1.getLatestAPIs)();
// Output error messages for all bad exports
(0, lodash_topairs_1.default)(badExports).forEach((badItem) => {
const [exportType, entries] = badItem;
if (entries.length > 0) {
const context = getErrorContext(entries, exportType, currentAPIs, latestAPIs);
reporter_1.default.error({
id: `11329`,
context,
});
}
});
}
}
/**
* Identify which APIs each plugin exports
*/
async function collatePluginAPIs({ currentAPIs, flattenedPlugins, rootDir, }) {
// Get a list of bad exports
const badExports = {
node: [],
};
for (const plugin of flattenedPlugins) {
plugin.nodeAPIs = [];
// Discover which APIs this plugin implements and store an array against
// the plugin node itself *and* in an API to plugins map for faster lookups
// later.
const pluginNodeExports = await (0, resolve_module_exports_1.resolveModuleExports)(plugin.resolvedCompiledGatsbyNode ?? `${plugin.resolve}/gatsby-node`, {
rootDir,
});
if (pluginNodeExports.length > 0) {
plugin.nodeAPIs = (0, lodash_intersection_1.default)(pluginNodeExports, currentAPIs.node);
badExports.node = badExports.node.concat(getBadExports(plugin, pluginNodeExports, currentAPIs.node)); // Collate any bad exports
}
}
return {
flattenedPlugins: flattenedPlugins,
badExports,
};
}
function warnOnIncompatiblePeerDependency(name, packageJSON) {
// Note: In the future the peer dependency should be enforced for all plugins.
const gatsbyPeerDependency = (0, lodash_get_1.default)(packageJSON, [
"peerDependencies",
"@netlify/content-engine",
]);
if (gatsbyPeerDependency &&
!semver.satisfies(gatsbyVersion, gatsbyPeerDependency, {
includePrerelease: true,
})) {
reporter_1.default.warn(`Plugin ${name} is not compatible with your gatsby version ${gatsbyVersion} - It requires @netlify/content-engine@${gatsbyPeerDependency}`);
}
}
//# sourceMappingURL=validate.js.map
;