import path from 'path'; import { createRequire } from 'module'; import fs from 'fs-extra'; import cheerio from 'cheerio'; import _ from 'lodash'; import * as logger from '../utils/logger.js'; import * as urlUtil from '../utils/urlUtil.js'; import type { NodeProcessorConfig } from '../html/NodeProcessor.js'; import { NodeOrText } from '../utils/node.js'; import '../patches/htmlparser2.js'; const require = createRequire(import.meta.url); const PLUGIN_OUTPUT_SITE_ASSET_FOLDER_NAME = 'plugins'; export type PluginContext = Record; export type FrontMatter = Record; type TagConfigAttributes = { name: string, isRelative: boolean, isSourceFile: boolean }; export type TagConfigs = { isSpecial?: boolean, attributes?: TagConfigAttributes[], isCustomElement?: boolean, }; /** * Wrapper class around a loaded plugin module */ export class Plugin { pluginName: string; plugin: { beforeSiteGenerate: (...args: any[]) => any; getLinks: (pluginContext?: PluginContext, frontmatter?: FrontMatter, content?: string) => string[]; getScripts: (pluginContext?: PluginContext, frontmatter?: FrontMatter, content?: string) => string[]; postRender: (pluginContext: PluginContext, frontmatter: FrontMatter, content: string) => string; processNode: (pluginContext: PluginContext, node: NodeOrText, config?: NodeProcessorConfig) => string; postProcessNode: (pluginContext: PluginContext, node: NodeOrText, config?: NodeProcessorConfig) => string; tagConfig: Record; }; pluginOptions: PluginContext; pluginAbsolutePath: string; pluginAssetOutputPath: string; constructor(pluginName: string, pluginPath: string, pluginOptions: PluginContext, siteOutputPath: string) { this.pluginName = pluginName; /** * The plugin module */ // eslint-disable-next-line import/no-dynamic-require this.plugin = require(pluginPath); this.pluginOptions = pluginOptions || {}; // For resolving plugin asset source paths later this.pluginAbsolutePath = path.dirname(pluginPath); this.pluginAssetOutputPath = path.join(siteOutputPath, PLUGIN_OUTPUT_SITE_ASSET_FOLDER_NAME, path.basename(pluginPath, path.extname(pluginPath))); } executeBeforeSiteGenerate() { if (this.plugin.beforeSiteGenerate) { this.plugin.beforeSiteGenerate(this.pluginOptions); } } /** * Resolves a resource specified as an attribute in a html asset tag * (eg. '