@baseplate-dev/sync
Version:
Library for syncing Baseplate descriptions
111 lines • 4.18 kB
JavaScript
import { toposort } from '@baseplate-dev/utils';
import { TemplateExtractorContext } from './template-extractor-context.js';
/**
* Initializes template extractor plugins by extracting all plugins from template extractors,
* sorting them by dependencies using topological sort, and initializing them in correct order.
*
* @param input - The input object containing template extractors and context
* @returns An object containing the plugin map and collected hooks
*/
export async function initializeTemplateExtractorPlugins({ templateExtractors, context, }) {
// Step 1: Extract all plugins from template extractors recursively
const allPlugins = extractPluginsRecursively(templateExtractors);
// Step 2: Sort plugins by dependencies using topological sort
const sortedPlugins = sortPluginsByDependencies(allPlugins);
// Step 3: Initialize plugins in dependency order and populate context plugins map
const initializedPlugins = new Map();
const allHooks = {
afterExtract: [],
afterWrite: [],
};
for (const plugin of sortedPlugins) {
// Create a temporary context with currently initialized plugins for this plugin
const pluginContext = new TemplateExtractorContext({
configLookup: context.configLookup,
logger: context.logger,
outputDirectory: context.outputDirectory,
plugins: initializedPlugins,
fileContainer: context.fileContainer,
});
// Create plugin API with hooks support
const pluginApi = createPluginApi(allHooks);
// Initialize the plugin
const pluginInstance = await plugin.getInstance({
context: pluginContext,
api: pluginApi,
});
// Add to both our return map and the context's plugins map
initializedPlugins.set(plugin.name, pluginInstance);
context.plugins.set(plugin.name, pluginInstance);
}
return {
pluginMap: initializedPlugins,
hooks: allHooks,
};
}
/**
* Extracts all plugins from template extractors and their dependencies recursively.
*/
function extractPluginsRecursively(templateExtractors) {
const pluginMap = new Map();
const visited = new Set();
function collectPlugins(plugins = []) {
for (const plugin of plugins) {
if (visited.has(plugin.name)) {
continue;
}
visited.add(plugin.name);
pluginMap.set(plugin.name, plugin);
// Recursively collect plugin dependencies
if (plugin.pluginDependencies) {
collectPlugins(plugin.pluginDependencies);
}
}
}
// Collect plugins from all template extractors
for (const extractor of templateExtractors) {
if (extractor.pluginDependencies) {
collectPlugins(extractor.pluginDependencies);
}
}
return [...pluginMap.values()];
}
/**
* Sorts plugins by their dependencies using topological sort.
*/
function sortPluginsByDependencies(plugins) {
const pluginMap = new Map();
for (const plugin of plugins) {
pluginMap.set(plugin.name, plugin);
}
// Create dependency edges: [dependency, dependent] - dependencies come before dependents
const edges = [];
for (const plugin of plugins) {
if (plugin.pluginDependencies) {
for (const dependency of plugin.pluginDependencies) {
edges.push([dependency.name, plugin.name]);
}
}
}
// Sort plugin names by dependencies
const sortedNames = toposort(plugins.map((p) => p.name), edges);
// Return plugins in sorted order
return sortedNames.map((name) => {
const plugin = pluginMap.get(name);
if (!plugin) {
throw new Error(`Plugin ${name} not found in plugin map`);
}
return plugin;
});
}
/**
* Creates a plugin API with hook registration support.
*/
function createPluginApi(allHooks) {
return {
registerHook(hook, callback) {
allHooks[hook].push(callback);
},
};
}
//# sourceMappingURL=initialize-template-extractor-plugins.js.map