WIP - add extractor, generate snippet_data

This commit is contained in:
Stefan Fejes
2019-08-20 15:52:05 +02:00
parent 88084d3d30
commit cc8f1d8a7a
37396 changed files with 4588842 additions and 133 deletions

View File

@ -0,0 +1,83 @@
"use strict";
const _ = require(`lodash`);
const {
store
} = require(`../../redux`);
const nodeAPIs = require(`../../utils/api-node-docs`);
const browserAPIs = require(`../../utils/api-browser-docs`);
const ssrAPIs = require(`../../../cache-dir/api-ssr-docs`);
const loadPlugins = require(`./load`);
const {
collatePluginAPIs,
handleBadExports,
handleMultipleReplaceRenderers
} = require(`./validate`);
const getAPI = api => _.keys(api).reduce((merged, key) => {
merged[key] = _.keys(api[key]);
return merged;
}, {}); // Create a "flattened" array of plugins with all subplugins
// brought to the top-level. This simplifies running gatsby-* files
// for subplugins.
const flattenPlugins = plugins => {
const flattened = [];
const extractPlugins = plugin => {
plugin.pluginOptions.plugins.forEach(subPlugin => {
flattened.push(subPlugin);
extractPlugins(subPlugin);
});
};
plugins.forEach(plugin => {
flattened.push(plugin);
extractPlugins(plugin);
});
return flattened;
};
module.exports = async (config = {}, rootDir = null, latestAPIs = {}) => {
const apis = {
currentAPIs: getAPI({
browser: browserAPIs,
node: nodeAPIs,
ssr: ssrAPIs
}),
latestAPIs // Collate internal plugins, site config plugins, site default plugins
};
const plugins = loadPlugins(config, rootDir); // Create a flattened array of the plugins
let flattenedPlugins = flattenPlugins(plugins); // Work out which plugins use which APIs, including those which are not
// valid Gatsby APIs, aka 'badExports'
const x = collatePluginAPIs(Object.assign({}, apis, {
flattenedPlugins
}));
flattenedPlugins = x.flattenedPlugins;
const badExports = x.badExports; // Show errors for any non-Gatsby APIs exported from plugins
handleBadExports(Object.assign({}, apis, {
badExports
})); // Show errors when ReplaceRenderer has been implemented multiple times
flattenedPlugins = handleMultipleReplaceRenderers({
flattenedPlugins
}); // If we get this far, everything looks good. Update the store
store.dispatch({
type: `SET_SITE_FLATTENED_PLUGINS`,
payload: flattenedPlugins
});
return flattenedPlugins;
};
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/bootstrap/load-plugins/index.js"],"names":["_","require","store","nodeAPIs","browserAPIs","ssrAPIs","loadPlugins","collatePluginAPIs","handleBadExports","handleMultipleReplaceRenderers","getAPI","api","keys","reduce","merged","key","flattenPlugins","plugins","flattened","extractPlugins","plugin","pluginOptions","forEach","subPlugin","push","module","exports","config","rootDir","latestAPIs","apis","currentAPIs","browser","node","ssr","flattenedPlugins","x","badExports","dispatch","type","payload"],"mappings":";;AAAA,MAAMA,CAAC,GAAGC,OAAO,CAAE,QAAF,CAAjB;;AAEA,MAAM;AAAEC,EAAAA;AAAF,IAAYD,OAAO,CAAE,aAAF,CAAzB;;AACA,MAAME,QAAQ,GAAGF,OAAO,CAAE,2BAAF,CAAxB;;AACA,MAAMG,WAAW,GAAGH,OAAO,CAAE,8BAAF,CAA3B;;AACA,MAAMI,OAAO,GAAGJ,OAAO,CAAE,iCAAF,CAAvB;;AACA,MAAMK,WAAW,GAAGL,OAAO,CAAE,QAAF,CAA3B;;AACA,MAAM;AACJM,EAAAA,iBADI;AAEJC,EAAAA,gBAFI;AAGJC,EAAAA;AAHI,IAIFR,OAAO,CAAE,YAAF,CAJX;;AAMA,MAAMS,MAAM,GAAGC,GAAG,IAChBX,CAAC,CAACY,IAAF,CAAOD,GAAP,EAAYE,MAAZ,CAAmB,CAACC,MAAD,EAASC,GAAT,KAAiB;AAClCD,EAAAA,MAAM,CAACC,GAAD,CAAN,GAAcf,CAAC,CAACY,IAAF,CAAOD,GAAG,CAACI,GAAD,CAAV,CAAd;AACA,SAAOD,MAAP;AACD,CAHD,EAGG,EAHH,CADF,C,CAMA;AACA;AACA;;;AACA,MAAME,cAAc,GAAGC,OAAO,IAAI;AAChC,QAAMC,SAAS,GAAG,EAAlB;;AACA,QAAMC,cAAc,GAAGC,MAAM,IAAI;AAC/BA,IAAAA,MAAM,CAACC,aAAP,CAAqBJ,OAArB,CAA6BK,OAA7B,CAAqCC,SAAS,IAAI;AAChDL,MAAAA,SAAS,CAACM,IAAV,CAAeD,SAAf;AACAJ,MAAAA,cAAc,CAACI,SAAD,CAAd;AACD,KAHD;AAID,GALD;;AAOAN,EAAAA,OAAO,CAACK,OAAR,CAAgBF,MAAM,IAAI;AACxBF,IAAAA,SAAS,CAACM,IAAV,CAAeJ,MAAf;AACAD,IAAAA,cAAc,CAACC,MAAD,CAAd;AACD,GAHD;AAKA,SAAOF,SAAP;AACD,CAfD;;AAiBAO,MAAM,CAACC,OAAP,GAAiB,OAAOC,MAAM,GAAG,EAAhB,EAAoBC,OAAO,GAAG,IAA9B,EAAoCC,UAAU,GAAG,EAAjD,KAAwD;AACvE,QAAMC,IAAI,GAAG;AACXC,IAAAA,WAAW,EAAErB,MAAM,CAAC;AAClBsB,MAAAA,OAAO,EAAE5B,WADS;AAElB6B,MAAAA,IAAI,EAAE9B,QAFY;AAGlB+B,MAAAA,GAAG,EAAE7B;AAHa,KAAD,CADR;AAMXwB,IAAAA,UANW,CAQb;;AARa,GAAb;AASA,QAAMZ,OAAO,GAAGX,WAAW,CAACqB,MAAD,EAASC,OAAT,CAA3B,CAVuE,CAYvE;;AACA,MAAIO,gBAAgB,GAAGnB,cAAc,CAACC,OAAD,CAArC,CAbuE,CAevE;AACA;;AACA,QAAMmB,CAAC,GAAG7B,iBAAiB,mBAAMuB,IAAN;AAAYK,IAAAA;AAAZ,KAA3B;AACAA,EAAAA,gBAAgB,GAAGC,CAAC,CAACD,gBAArB;AACA,QAAME,UAAU,GAAGD,CAAC,CAACC,UAArB,CAnBuE,CAqBvE;;AACA7B,EAAAA,gBAAgB,mBAAMsB,IAAN;AAAYO,IAAAA;AAAZ,KAAhB,CAtBuE,CAwBvE;;AACAF,EAAAA,gBAAgB,GAAG1B,8BAA8B,CAAC;AAChD0B,IAAAA;AADgD,GAAD,CAAjD,CAzBuE,CA6BvE;;AACAjC,EAAAA,KAAK,CAACoC,QAAN,CAAe;AACbC,IAAAA,IAAI,EAAG,4BADM;AAEbC,IAAAA,OAAO,EAAEL;AAFI,GAAf;AAKA,SAAOA,gBAAP;AACD,CApCD","sourcesContent":["const _ = require(`lodash`)\n\nconst { store } = require(`../../redux`)\nconst nodeAPIs = require(`../../utils/api-node-docs`)\nconst browserAPIs = require(`../../utils/api-browser-docs`)\nconst ssrAPIs = require(`../../../cache-dir/api-ssr-docs`)\nconst loadPlugins = require(`./load`)\nconst {\n collatePluginAPIs,\n handleBadExports,\n handleMultipleReplaceRenderers,\n} = require(`./validate`)\n\nconst getAPI = api =>\n _.keys(api).reduce((merged, key) => {\n merged[key] = _.keys(api[key])\n return merged\n }, {})\n\n// Create a \"flattened\" array of plugins with all subplugins\n// brought to the top-level. This simplifies running gatsby-* files\n// for subplugins.\nconst flattenPlugins = plugins => {\n const flattened = []\n const extractPlugins = plugin => {\n plugin.pluginOptions.plugins.forEach(subPlugin => {\n flattened.push(subPlugin)\n extractPlugins(subPlugin)\n })\n }\n\n plugins.forEach(plugin => {\n flattened.push(plugin)\n extractPlugins(plugin)\n })\n\n return flattened\n}\n\nmodule.exports = async (config = {}, rootDir = null, latestAPIs = {}) => {\n const apis = {\n currentAPIs: getAPI({\n browser: browserAPIs,\n node: nodeAPIs,\n ssr: ssrAPIs,\n }),\n latestAPIs,\n }\n // Collate internal plugins, site config plugins, site default plugins\n const plugins = loadPlugins(config, rootDir)\n\n // Create a flattened array of the plugins\n let flattenedPlugins = flattenPlugins(plugins)\n\n // Work out which plugins use which APIs, including those which are not\n // valid Gatsby APIs, aka 'badExports'\n const x = collatePluginAPIs({ ...apis, flattenedPlugins })\n flattenedPlugins = x.flattenedPlugins\n const badExports = x.badExports\n\n // Show errors for any non-Gatsby APIs exported from plugins\n handleBadExports({ ...apis, badExports })\n\n // Show errors when ReplaceRenderer has been implemented multiple times\n flattenedPlugins = handleMultipleReplaceRenderers({\n flattenedPlugins,\n })\n\n // If we get this far, everything looks good. Update the store\n store.dispatch({\n type: `SET_SITE_FLATTENED_PLUGINS`,\n payload: flattenedPlugins,\n })\n\n return flattenedPlugins\n}\n"],"file":"index.js"}

195
node_modules/gatsby/dist/bootstrap/load-plugins/load.js generated vendored Normal file
View File

@ -0,0 +1,195 @@
"use strict";
const _ = require(`lodash`);
const slash = require(`slash`);
const fs = require(`fs`);
const path = require(`path`);
const crypto = require(`crypto`);
const glob = require(`glob`);
const {
warnOnIncompatiblePeerDependency
} = require(`./validate`);
const {
store
} = require(`../../redux`);
const existsSync = require(`fs-exists-cached`).sync;
const createNodeId = require(`../../utils/create-node-id`);
const createRequireFromPath = require(`../../utils/create-require-from-path`);
function createFileContentHash(root, globPattern) {
const hash = crypto.createHash(`md5`);
const files = glob.sync(`${root}/${globPattern}`, {
nodir: true
});
files.forEach(filepath => {
hash.update(fs.readFileSync(filepath));
});
return hash.digest(`hex`);
}
/**
* Make sure key is unique to plugin options. E.g there could
* be multiple source-filesystem plugins, with different names
* (docs, blogs).
* @param {*} name Name of the plugin
* @param {*} pluginObject
*/
const createPluginId = (name, pluginObject = null) => createNodeId(name + (pluginObject ? JSON.stringify(pluginObject.options) : ``), `Plugin`);
/**
* @typedef {Object} PluginInfo
* @property {string} resolve The absolute path to the plugin
* @property {string} name The plugin name
* @property {string} version The plugin version (can be content hash)
*/
/**
* resolvePlugin
* @param {string} pluginName
* This can be a name of a local plugin, the name of a plugin located in
* node_modules, or a Gatsby internal plugin. In the last case the pluginName
* will be an absolute path.
* @param {string} rootDir
* This is the project location, from which are found the plugins
* @return {PluginInfo}
*/
function resolvePlugin(pluginName, rootDir) {
// Only find plugins when we're not given an absolute path
if (!existsSync(pluginName)) {
// Find the plugin in the local plugins folder
const resolvedPath = slash(path.resolve(`./plugins/${pluginName}`));
if (existsSync(resolvedPath)) {
if (existsSync(`${resolvedPath}/package.json`)) {
const packageJSON = JSON.parse(fs.readFileSync(`${resolvedPath}/package.json`, `utf-8`));
const name = packageJSON.name || pluginName;
warnOnIncompatiblePeerDependency(name, packageJSON);
return {
resolve: resolvedPath,
name,
id: createPluginId(name),
version: packageJSON.version || createFileContentHash(resolvedPath, `**`)
};
} else {
// Make package.json a requirement for local plugins too
throw new Error(`Plugin ${pluginName} requires a package.json file`);
}
}
}
/**
* Here we have an absolute path to an internal plugin, or a name of a module
* which should be located in node_modules.
*/
try {
const requireSource = rootDir !== null ? createRequireFromPath(`${rootDir}/:internal:`) : require;
const resolvedPath = slash(path.dirname(requireSource.resolve(pluginName)));
const packageJSON = JSON.parse(fs.readFileSync(`${resolvedPath}/package.json`, `utf-8`));
warnOnIncompatiblePeerDependency(packageJSON.name, packageJSON);
return {
resolve: resolvedPath,
id: createPluginId(packageJSON.name),
name: packageJSON.name,
version: packageJSON.version
};
} catch (err) {
throw new Error(`Unable to find plugin "${pluginName}". Perhaps you need to install its package?`);
}
}
module.exports = (config = {}, rootDir = null) => {
// Instantiate plugins.
const plugins = []; // Create fake little site with a plugin for testing this
// w/ snapshots. Move plugin processing to its own module.
// Also test adding to redux store.
const processPlugin = plugin => {
if (_.isString(plugin)) {
const info = resolvePlugin(plugin, rootDir);
return Object.assign({}, info, {
pluginOptions: {
plugins: []
}
});
} else {
plugin.options = plugin.options || {}; // Plugins can have plugins.
const subplugins = [];
if (plugin.options.plugins) {
plugin.options.plugins.forEach(p => {
subplugins.push(processPlugin(p));
});
plugin.options.plugins = subplugins;
} // Add some default values for tests as we don't actually
// want to try to load anything during tests.
if (plugin.resolve === `___TEST___`) {
const name = `TEST`;
return {
id: createPluginId(name, plugin),
name,
pluginOptions: {
plugins: []
}
};
}
const info = resolvePlugin(plugin.resolve, rootDir);
return Object.assign({}, info, {
id: createPluginId(info.name, plugin),
pluginOptions: _.merge({
plugins: []
}, plugin.options)
});
}
}; // Add internal plugins
const internalPlugins = [`../../internal-plugins/dev-404-page`, `../../internal-plugins/load-babel-config`, `../../internal-plugins/internal-data-bridge`, `../../internal-plugins/prod-404`, `../../internal-plugins/webpack-theme-component-shadowing`];
internalPlugins.forEach(relPath => {
const absPath = path.join(__dirname, relPath);
plugins.push(processPlugin(absPath));
}); // Add plugins from the site config.
if (config.plugins) {
config.plugins.forEach(plugin => {
plugins.push(processPlugin(plugin));
});
} // Add the site's default "plugin" i.e. gatsby-x files in root of site.
plugins.push({
resolve: slash(process.cwd()),
id: createPluginId(`default-site-plugin`),
name: `default-site-plugin`,
version: createFileContentHash(process.cwd(), `gatsby-*`),
pluginOptions: {
plugins: []
}
});
const program = store.getState().program;
plugins.push(processPlugin({
resolve: require.resolve(`gatsby-plugin-page-creator`),
options: {
path: slash(path.join(program.directory, `src/pages`)),
pathCheck: false
}
}));
return plugins;
};
//# sourceMappingURL=load.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,200 @@
"use strict";
const _ = require(`lodash`);
const semver = require(`semver`);
const stringSimiliarity = require(`string-similarity`);
const {
version: gatsbyVersion
} = require(`gatsby/package.json`);
const reporter = require(`gatsby-cli/lib/reporter`);
const resolveModuleExports = require(`../resolve-module-exports`);
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.
const getBadExports = (plugin, pluginAPIKeys, apis) => {
let badExports = []; // Discover any exports from plugins which are not "known"
badExports = badExports.concat(_.difference(pluginAPIKeys, apis).map(e => {
return {
exportName: e,
pluginName: plugin.name,
pluginVersion: plugin.version
};
}));
return badExports;
};
const getErrorContext = (badExports, exportType, currentAPIs, latestAPIs) => {
const entries = badExports.map(ex => {
return Object.assign({}, ex, {
api: latestAPIs[exportType][ex.exportName]
});
});
const gatsbyUpgradeVersion = getGatsbyUpgradeVersion(entries);
let errors = [];
let fixes = [].concat(gatsbyUpgradeVersion ? [`npm install gatsby@^${gatsbyUpgradeVersion}`] : []);
entries.forEach(entry => {
const similarities = stringSimiliarity.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,
// note: this is a fallback if gatsby-cli is not updated with structured error
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`)
};
};
const handleBadExports = ({
currentAPIs,
latestAPIs,
badExports
}) => {
// Output error messages for all bad exports
_.toPairs(badExports).forEach(badItem => {
const [exportType, entries] = badItem;
if (entries.length > 0) {
const context = getErrorContext(entries, exportType, currentAPIs, latestAPIs);
reporter.error({
id: `11329`,
context
});
}
});
};
/**
* Identify which APIs each plugin exports
*/
const collatePluginAPIs = ({
currentAPIs,
flattenedPlugins
}) => {
// Get a list of bad exports
const badExports = {
node: [],
browser: [],
ssr: []
};
flattenedPlugins.forEach(plugin => {
plugin.nodeAPIs = [];
plugin.browserAPIs = [];
plugin.ssrAPIs = []; // 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 = resolveModuleExports(`${plugin.resolve}/gatsby-node`, {
mode: `require`
});
const pluginBrowserExports = resolveModuleExports(`${plugin.resolve}/gatsby-browser`);
const pluginSSRExports = resolveModuleExports(`${plugin.resolve}/gatsby-ssr`);
if (pluginNodeExports.length > 0) {
plugin.nodeAPIs = _.intersection(pluginNodeExports, currentAPIs.node);
badExports.node = badExports.node.concat(getBadExports(plugin, pluginNodeExports, currentAPIs.node)); // Collate any bad exports
}
if (pluginBrowserExports.length > 0) {
plugin.browserAPIs = _.intersection(pluginBrowserExports, currentAPIs.browser);
badExports.browser = badExports.browser.concat(getBadExports(plugin, pluginBrowserExports, currentAPIs.browser)); // Collate any bad exports
}
if (pluginSSRExports.length > 0) {
plugin.ssrAPIs = _.intersection(pluginSSRExports, currentAPIs.ssr);
badExports.ssr = badExports.ssr.concat(getBadExports(plugin, pluginSSRExports, currentAPIs.ssr)); // Collate any bad exports
}
});
return {
flattenedPlugins,
badExports
};
};
const handleMultipleReplaceRenderers = ({
flattenedPlugins
}) => {
// multiple replaceRenderers may cause problems at build time
const rendererPlugins = flattenedPlugins.filter(plugin => plugin.ssrAPIs.includes(`replaceRenderer`)).map(plugin => plugin.name);
if (rendererPlugins.length > 1) {
if (rendererPlugins.includes(`default-site-plugin`)) {
reporter.warn(`replaceRenderer API found in these plugins:`);
reporter.warn(rendererPlugins.join(`, `));
reporter.warn(`This might be an error, see: https://www.gatsbyjs.org/docs/debugging-replace-renderer-api/`);
} else {
console.log(``);
reporter.error(`Gatsby's replaceRenderer API is implemented by multiple plugins:`);
reporter.error(rendererPlugins.join(`, `));
reporter.error(`This will break your build`);
reporter.error(`See: https://www.gatsbyjs.org/docs/debugging-replace-renderer-api/`);
if (process.env.NODE_ENV === `production`) process.exit(1);
} // Now update plugin list so only final replaceRenderer will run
const ignorable = rendererPlugins.slice(0, -1); // For each plugin in ignorable, set a skipSSR flag to true
// This prevents apiRunnerSSR() from attempting to run it later
const messages = [];
flattenedPlugins.forEach((fp, i) => {
if (ignorable.includes(fp.name)) {
messages.push(`Duplicate replaceRenderer found, skipping gatsby-ssr.js for plugin: ${fp.name}`);
flattenedPlugins[i].skipSSR = true;
}
});
if (messages.length > 0) {
console.log(``);
messages.forEach(m => reporter.warn(m));
console.log(``);
}
}
return flattenedPlugins;
};
function warnOnIncompatiblePeerDependency(name, packageJSON) {
// Note: In the future the peer dependency should be enforced for all plugins.
const gatsbyPeerDependency = _.get(packageJSON, `peerDependencies.gatsby`);
if (gatsbyPeerDependency && !semver.satisfies(gatsbyVersion, gatsbyPeerDependency, {
includePrerelease: true
})) {
reporter.warn(`Plugin ${name} is not compatible with your gatsby version ${gatsbyVersion} - It requires gatsby@${gatsbyPeerDependency}`);
}
}
module.exports = {
collatePluginAPIs,
handleBadExports,
handleMultipleReplaceRenderers,
warnOnIncompatiblePeerDependency
};
//# sourceMappingURL=validate.js.map

File diff suppressed because one or more lines are too long