Skip to content

Commit

Permalink
feat(contented): ability to customize unified plugins (#629)
Browse files Browse the repository at this point in the history
#### What this PR does / why we need it:

Make it easier to customize content processor with subset of plugins.
  • Loading branch information
fuxingloh authored Oct 3, 2023
1 parent a39b7dd commit 465e0e4
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 12 deletions.
10 changes: 6 additions & 4 deletions packages/contented-example/docs/04-markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ processor
.use(remarkParse)
.use(remarkLink)
.use(remarkDirective)
.use(remarkDirectiveRehypeCodeblockHeader)
.use(remarkDirectiveRehypeCodeblockGroup)
.use(remarkDirectiveRehype)
.use(collectFields)
.use(resolveFields)
.use(validateFields)
.use(remarkFrontmatterCollect)
.use(remarkFrontmatterResolve)
.use(remarkFrontmatterValidate)
.use(options.remarks)
.use(remarkRehype)
.use(options.rehypes)
Expand All @@ -28,7 +30,7 @@ processor
.use(rehypeToc)
.use(rehypeHeading)
.use(rehypeMermaid)
.use(rehypeShiki, { highlighter })
.use(rehypeShiki)
.use(rehypeStringify)
.use(options.after);
```
Expand Down
21 changes: 19 additions & 2 deletions packages/contented-pipeline-md/src/MarkdownPipeline.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import console from 'node:console';
import { join } from 'node:path';

import { ContentedPipeline, FileContent, FileIndex } from '@contentedjs/contented-pipeline';
import { ContentedPipeline, FileContent, FileIndex, Pipeline } from '@contentedjs/contented-pipeline';
import { read } from 'to-vfile';
import { Processor, unified } from 'unified';
import { VFile } from 'vfile';
Expand All @@ -13,7 +13,7 @@ export class MarkdownPipeline extends ContentedPipeline {
protected readonly processor: Processor = unified();

async init() {
await initProcessor(this.processor);
initProcessor(this.processor);
}

protected override async processFileIndex(
Expand Down Expand Up @@ -56,6 +56,23 @@ export class MarkdownPipeline extends ContentedPipeline {
fields: contented.fields,
};
}

/**
* Create a new MarkdownPipeline with a custom processor.
* This is useful for only using a subset of the plugins that you need.
* @param processor is a function that takes a Processor and adds plugins to it.
*/
static withProcessor(
processor: (processor: Processor) => void,
): new (rootPath: string, pipeline: Pipeline) => ContentedPipeline {
class WithProcessor extends MarkdownPipeline {
async init(): Promise<void> {
processor(this.processor);
}
}

return WithProcessor;
}
}

export class MarkdownVFile extends VFile {
Expand Down
31 changes: 31 additions & 0 deletions packages/contented-pipeline-md/src/MarkdownPipeline.unit.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { join } from 'node:path';

import { MarkdownPipeline } from './MarkdownPipeline';
import { rehypeStringify, remarkParse, remarkRehype } from './UnifiedProcessor';

const rootPath = join(__dirname, '../fixtures');

Expand Down Expand Up @@ -95,3 +96,33 @@ describe('Without Config', () => {
]);
});
});

describe('Custom Pipeline', () => {
const pipeline = new (MarkdownPipeline.withProcessor((processor) => {
processor.use(remarkParse).use(remarkRehype).use(rehypeStringify);
}))(__dirname, {
type: 'Markdown',
pattern: '/See.Nothing.md',
processor: 'md',
});

beforeAll(async () => {
await pipeline.init();
});

it('should process See.Nothing.md', async () => {
const content = await pipeline.process(rootPath, 'See.Nothing.md');
expect(content).toStrictEqual([
{
type: 'Markdown',
fields: {},
headings: [],
path: '/see-nothing',
sections: [],
fileId: expect.stringMatching(/[0-f]{64}/),
modifiedDate: expect.any(Number),
html: '<h1>Nothing To See</h1>\n<p>Markdown for testing <code>MarkdownPipeline.unit.ts</code>.</p>',
},
]);
});
});
35 changes: 32 additions & 3 deletions packages/contented-pipeline-md/src/UnifiedProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ import {
remarkDirectiveRehypeCodeblockHeader,
} from './plugins/RemarkCodeblock.js';
import { remarkDirectiveRehype } from './plugins/RemarkDirectiveRehype.js';
import { collectFields, resolveFields, validateFields } from './plugins/RemarkFrontmatter.js';
import {
remarkFrontmatterCollect,
remarkFrontmatterResolve,
remarkFrontmatterValidate,
} from './plugins/RemarkFrontmatter.js';
import { remarkLink } from './plugins/RemarkLink.js';

export interface UnifiedOptions {
Expand All @@ -28,7 +32,7 @@ export interface UnifiedOptions {
after?: Plugin[];
}

export async function initProcessor(processor: Processor, options?: UnifiedOptions) {
export function initProcessor(processor: Processor, options?: UnifiedOptions): Processor {
options?.before?.forEach((plugin) => {
processor.use(plugin);
});
Expand All @@ -43,7 +47,7 @@ export async function initProcessor(processor: Processor, options?: UnifiedOptio
.use(remarkDirectiveRehypeCodeblockGroup)
.use(remarkDirectiveRehype);

processor.use(collectFields).use(resolveFields).use(validateFields);
processor.use(remarkFrontmatterCollect).use(remarkFrontmatterResolve).use(remarkFrontmatterValidate);

options?.remarks?.forEach((plugin) => {
processor.use(plugin);
Expand All @@ -69,4 +73,29 @@ export async function initProcessor(processor: Processor, options?: UnifiedOptio
options?.after?.forEach((plugin) => {
processor.use(plugin);
});

return processor;
}

export {
rehypeAutolinkHeadings,
rehypeExternalLinks,
rehypeHeading,
rehypeMermaid,
rehypeShiki,
rehypeSlug,
rehypeStringify,
rehypeToc,
remarkDirective,
remarkDirectiveRehype,
remarkDirectiveRehypeCodeblockGroup,
remarkDirectiveRehypeCodeblockHeader,
remarkFrontmatter,
remarkFrontmatterCollect,
remarkFrontmatterResolve,
remarkFrontmatterValidate,
remarkGfm,
remarkLink,
remarkParse,
remarkRehype,
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { VFile } from 'vfile';

import { UnifiedContented } from './Plugin.js';

export function collectFields(): Transformer<Parent> {
export function remarkFrontmatterCollect(): Transformer<Parent> {
return (tree: Parent, file) => {
const node = tree.children?.[0];
if (node?.type === 'yaml') {
Expand Down Expand Up @@ -49,7 +49,7 @@ function visitDescription(file: VFile): (node: Paragraph) => void {
};
}

export function resolveFields(): Transformer<Parent> {
export function remarkFrontmatterResolve(): Transformer<Parent> {
return async (tree: Parent, file) => {
const contented = file.data.contented as UnifiedContented;
const entries = Object.entries(contented.pipeline.fields ?? {});
Expand All @@ -70,7 +70,7 @@ export function resolveFields(): Transformer<Parent> {
};
}

export function validateFields(): Transformer<Parent> {
export function remarkFrontmatterValidate(): Transformer<Parent> {
return async (tree: Parent, file) => {
const contented = file.data.contented as UnifiedContented;
const entries = Object.entries(contented.pipeline.fields ?? {});
Expand Down

0 comments on commit 465e0e4

Please sign in to comment.