Parsing Functions

ULLD exposes a parsing method for various different file formats, before they are rendered to React. This gives you, the developer, the opportunity to modify the content of a user's note before it is displayed. Any modification to the user's note at this stage will not be reflected in the user's database or in the file content directly, but will instead be injected during the rendering process.

Note:

Currently, only the .mdx parser is enabled throughout the compiled application, but support for parsing tabular file types is on the way shortly.

This gives you the opportunity to add unique syntax to a specific file type, or to conditionally parse an entire .mdx file to a single component or layout based on the note's front matter.

Like other ULLD export fields, the parsing function must be the default export from the file with which it is included, and that export must match an export field in your plugin's package.json file. You're permitted at most 1 async function per file type, but there is a applyRecursiveMdxParsers utility method exported from @ulld/api/applyRecursiveMdxParser. With this utility method, you can apply multiple parsing functions easily as:

src/parser.ts
const coreMdxParser: UnifiedMdxParser = async (data) => {
  return await applyRecursiveMdxParsers(data, [
        parseDefinitionTags,
        parseTags,
        parseVideoTimeStampLinks,
        parseQuickLinks
    ]);
};
 
export default coreMdxParser;

File Type Parsers

There is a UnifiedParserOfType type exported from @ulld/api/types that accepts and ParserKey as it's first generic parameter, and an optional object as it's second parameter. The second parameter is an optional object that can be used to extend a note's front matter or to gather data which can then be used within your components.

All file type parsers will be passed an object which they can append data any data they require to, and this data will be exposed to all nested components of that given note via the useFrontMatter hook exported from @ulld/hooks/useFrontMatter. For .mdx files this object will be initially populated with the note's front matter, but this object may be initially empty for other file types.

Mdx

The .mdx file type parsing function is of type UnifiedMdxParser, exported from @ulld/api/types. Like all parsing functions, this function is asynchronous and must return an object with two keys:

Promise<{
    content: string
    data: object // FrontMatter type for mdx files
}>
Note:

The content field will be of another type for other file types as ULLD continues to grow, but the data field will always be of an extensible object.

Keep in mind, because this parsing is occuring just before the file's content is passed to React, you can generate React component syntax directly in the user's note. However, be sure to only include internal ULLD components or components provided by your own plugin to be sure that you are not generating a component that the application of the end user doesn't have provide.

Parameters

Properties

@ulld/api/types
export interface UnifiedMdxParserParams {
    content: string;
    docTypeData: AppConfigSchemaOutput["noteTypes"][number] | {};
    data: Partial<FrontMatterType>
    appConfig: MinimalParsableAppConfigOutput
    serverClient: typeof serverClient // Trpc router
    db: MdxDetailsReturnType
}

Example

export const parseMathTags: UnifiedMdxParser = async (data) => {
    let results: string[] = [];
    const regex = /\[eq:(?<equationId>[\w|\d]+)\]/gm;
    let c = data.content;
    let m;
    do {
        m = regex.exec(c);
        if (
            m &&
            m.groups?.equationId &&
            m.groups?.equationId.trim() !== "" &&
            m.groups.equationId !== "\n"
        ) {
            let _link = `<EquationTag equationId="${m.groups.equationId}" />`;
            c = replaceRecursively(
                c,
                new RegExp(`\\[eq:${m.groups.equationId}\\]`, "gm"),
                _link,
            );
            results.push(m.groups.value);
        }
    } while (m);
    return {
        content: c,
    };
};

And then this parser can be added to a single parsing function for the given file type:

src/parsers/mdx.ts
import { parseMathTags } from "./mathTagParser";
 
interface MyAdditionalFrontMatterData {
    ...
}
 
const mathParsers: UnifiedMdxParser<MyAdditionalFrontMatterData> = async (data) => {
    return await applyRecursiveMdxParsers(data, [parseMathTags]);
}
 
 
export default mathParsers

On this page