import { Root } from 'mdast'; import { matter } from 'vfile-matter'; import { Metadata, Settings, Theme } from '@xyd-js/core'; import { getMetaComponent } from '@xyd-js/context'; import { Reference, TypeDocReferenceContext } from '@xyd-js/uniform'; import { uniformToMiniUniform } from '@xyd-js/sources/ts'; import { FunctionName } from '../functions/types'; import { parseFunctionCall, parseImportPath } from '../functions/utils'; import { processUniformFunctionCall } from '../functions/uniformProcessor'; import { componentLike } from '../utils'; import { SymbolxVfile } from '../types'; export interface MdMetaOptions { resolveFrom?: string } // TODO: IT SHOULD BE PART OF COMPOSER export function mdMeta(settings?: Settings, options?: MdMetaOptions) { return function() { return async (tree: Root, file: SymbolxVfile) => { console.time('plugin:mdMeta:total'); console.time('plugin:mdMeta:frontmatter'); // Parse frontmatter and expose it at file.data.matter matter(file as any); console.timeEnd('plugin:mdMeta:frontmatter'); if (!file.data.matter) { console.timeEnd('plugin:mdMeta:total'); return } console.time('plugin:mdMeta:metaProcessing'); const meta = file.data.matter as Metadata> if (!meta) { console.timeEnd('plugin:mdMeta:metaProcessing'); console.timeEnd('plugin:mdMeta:total'); return } let uniformMeta = false if (meta?.uniform || meta?.openapi || meta?.graphql) { uniformMeta = true if (meta.graphql) { meta.uniform = meta.graphql } else if (meta.openapi) { meta.uniform = meta.openapi } meta.component = "atlas" if (typeof meta.uniform === "string") { meta.componentProps = { references: `@uniform('${meta.uniform}')` } } else if (typeof meta.uniform === "object") { const uniformArgs = {} if (meta.uniform.eager) { // TODO: support eager line ranges? const { filePath, regions } = parseImportPath(meta.uniform.path) if (regions.length > 1) { console.warn("Eager uniform with multiple regions is not supported") } if (regions.length) { uniformArgs["eager"] = regions[0].name } meta.uniform.path = filePath } meta.componentProps = { references: `@uniform('${meta.uniform.path}', ${JSON.stringify(uniformArgs)})` } } } if (!meta || !meta.component) { console.timeEnd('plugin:mdMeta:metaProcessing'); console.timeEnd('plugin:mdMeta:total'); return } const metaComponent = getMetaComponent(meta.component) if (!metaComponent) { console.timeEnd('plugin:mdMeta:metaProcessing'); console.timeEnd('plugin:mdMeta:total'); return } console.timeEnd('plugin:mdMeta:metaProcessing'); console.time('plugin:mdMeta:propsProcessing'); const promises: Promise[] = [] let resolvedProps: Record = {} if (uniformMeta && meta.componentProps && typeof meta.componentProps === "object") { // TODO: ??? TO DELETE ??? for (const key in meta.componentProps) { // TODO: support nested props const value = meta.componentProps[key] const result = parseFunctionCall({ children: [ { type: "text", value: value } ] }, FunctionName.Uniform); if (!result) { resolvedProps[key] = value continue } const importPath = result[0] const importArgs = result[1]; if (!importPath) { continue } const promise = (async () => { let references = await processUniformFunctionCall( importPath, file, options?.resolveFrom, settings, ); if (importArgs?.eager && references) { // TODO: move to `processUniformFunctionCall` // TODO: rename uniformToMiniUniform eager // TODO: support multile regions references = uniformToMiniUniform(importArgs.eager, references as Reference[]); } resolvedProps[key] = references })() promises.push(promise) } } else { resolvedProps = meta.componentProps || {} } await Promise.all(promises) console.timeEnd('plugin:mdMeta:propsProcessing'); console.time('plugin:mdMeta:transform'); const resolvedComponentProps = await metaComponent.transform( (settings?.theme || {}) as Theme, resolvedProps, file.data.outputVars, Object.freeze(tree.children) as any, meta, // @ts-ignore settings ) console.timeEnd('plugin:mdMeta:transform'); console.time('plugin:mdMeta:componentCreation'); const exportNode = componentLike( metaComponent.componentName, resolvedComponentProps, [] ) tree.children = [ ...treeSanitize(tree), ...exportNode.children ] console.timeEnd('plugin:mdMeta:componentCreation'); console.timeEnd('plugin:mdMeta:total'); } } } // TODO: add more / BETTER SOLUTION FOR CLEARIN const allowedNodes = [ "mdxjsEsm", // "outputVars", // TODO: !!! cuz some issues with outputvars + containerDirective !!! ] function treeSanitize(tree: Root) { return tree.children.filter((child) => { if (allowedNodes.includes(child.type)) { return true } return false }) }