UNPKG

@netlify/content-engine

Version:
170 lines 7.44 kB
"use strict"; 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