import { deepFilterObjectKeys } from '../../utils/object.js'; import { PluginBuilder, PluginFs } from '../Plugin.js'; export const JSON_PLUGIN_IGNORED_KEYS = new Set([ 'symbol', 'declaration', 'decorator', 'enumDeclaration', 'type', 'node', 'file', 'signature', 'returnType', 'heritage', ]); export interface JsonPluginConfig extends Record { cwd: string; outFile: string; ignoredKeys: Set; extendIgnoredKeys: Set; // eslint-disable-next-line @typescript-eslint/no-explicit-any transformJson?: (json: Record) => Record; } export const JSON_PLUGIN_DEFAULT_CONFIG: JsonPluginConfig = { cwd: process.cwd(), outFile: './elements.json', ignoredKeys: JSON_PLUGIN_IGNORED_KEYS, extendIgnoredKeys: new Set(), }; export async function normalizeJsonPluginConfig( config: Partial, fs: PluginFs, ): Promise { return fs.resolveConfigPaths(config.cwd ?? JSON_PLUGIN_DEFAULT_CONFIG.cwd, { ...JSON_PLUGIN_DEFAULT_CONFIG, ...config, }); } /** * Transforms component metadata into JSON format. This will run in the `transform` plugin * lifecycle step. * * @option cwd - The current working directory, defaults to `process.cwd()`. * @option outFile - Custom path to where the JSON file should be output. * @option ignoredKeys - Set of keys anywhere in the `ComponentMeta` you'd like to ignore. * * @example * ```ts * // FILE: celement.config.ts * * import { jsonPlugin } from '@celement/cli'; * * export default [ * jsonPlugin({ * // Configuration options here. * outFile: './elements.json', * }), * ]; * ``` */ export const jsonPlugin: PluginBuilder> = ( config = {}, ) => ({ name: '@celement/json', async transform(components, fs) { const normalizedConfig = await normalizeJsonPluginConfig(config, fs); // eslint-disable-next-line @typescript-eslint/no-explicit-any const output: any = { components: [], }; const ignoredKeys = new Set([ ...normalizedConfig.ignoredKeys, ...normalizedConfig.extendIgnoredKeys, ]); components .map(component => ({ ...component, dependencies: component.dependencies.map(c => c.tagName), dependents: component.dependents.map(c => c.tagName), })) .map(component => deepFilterObjectKeys(component, ignoredKeys)) .forEach(component => { output.components.push(component); }); await fs.ensureFile(normalizedConfig.outFile); await fs.writeFile( normalizedConfig.outFile, JSON.stringify( normalizedConfig.transformJson?.(output) ?? output, undefined, 2, ), ); }, });