Skip to content

Commit

Permalink
feat(plugin-code-blocks): use pluginutils ABasePlugin, use new option…
Browse files Browse the repository at this point in the history
…s format
  • Loading branch information
GerkinDev committed Feb 25, 2022
1 parent 335095a commit 33b1700
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 105 deletions.
4 changes: 4 additions & 0 deletions packages/typedoc-plugin-code-blocks/package.json
Expand Up @@ -32,7 +32,11 @@
"prepublish": "npm run build:clean && npm run build",
"test": "jest --config jest.config.js"
},
"dependencies": {
"@knodes/typedoc-pluginutils": "*"
},
"peerDependencies": {
"lodash": "^4.17.0",
"typedoc": "^0.22.12"
},
"devDependencies": {
Expand Down
9 changes: 1 addition & 8 deletions packages/typedoc-plugin-code-blocks/src/index.ts
@@ -1,8 +1 @@
import { Application, MarkdownEvent } from 'typedoc';

import { CodeBlockPlugin } from './code-block-plugin';

export const load = ( app: Application ) => {
const plugin = new CodeBlockPlugin( app );
app.renderer.on( MarkdownEvent.PARSE, plugin.processMarkdown.bind( plugin ) );
};
export * from './load';
5 changes: 5 additions & 0 deletions packages/typedoc-plugin-code-blocks/src/load.ts
@@ -0,0 +1,5 @@
import { autoload } from '@knodes/typedoc-pluginutils';

import { CodeBlockPlugin } from './plugin';

export const load = autoload( CodeBlockPlugin );
1 change: 0 additions & 1 deletion packages/typedoc-plugin-code-blocks/src/options.ts

This file was deleted.

@@ -1,7 +1,7 @@
import { resolve } from 'path';

import mockFs from 'mock-fs';
import { Application, MarkdownEvent } from 'typedoc';
import { Application } from 'typedoc';

/* eslint-disable @typescript-eslint/no-var-requires */
jest.mock( 'marked' );
Expand All @@ -10,45 +10,54 @@ jest.mock( './code-sample-file' );
const { readCodeSample } = require( './code-sample-file' ) as jest.Mocked<typeof import( './code-sample-file' )>;
/* eslint-enable @typescript-eslint/no-var-requires */

import { CodeBlockPlugin } from './code-block-plugin';
import { DEFAULT_BLOCK_NAME } from './code-sample-file';
import { DIRECTORY } from './options';
import { CodeBlockPlugin } from './plugin';

let application: Application;
let plugin: CodeBlockPlugin;
const rootDir = resolve( __dirname, '..' );
const DIRECTORIES = 'pluginCodeBlocks:directories';
beforeEach( () => {
process.chdir( rootDir );
jest.clearAllMocks();
application = new Application();
plugin = new CodeBlockPlugin( application );
plugin.initialize();
} );
afterEach( mockFs.restore );
describe( 'Options', () => {
describe( DIRECTORY, () => {
const tryOption = ( value: any ) => () => {
application.options.setValue( DIRECTORIES, value );
plugin.directoriesOption.getValue();
};
describe( DIRECTORIES, () => {
it( 'should throw an error if value is not an object', () => {
expect( () => application.options.setValue( DIRECTORY, null ) ).toThrow();
expect( () => application.options.setValue( DIRECTORY, undefined ) ).toThrow();
expect( () => application.options.setValue( DIRECTORY, [] ) ).toThrow();
expect( () => application.options.setValue( DIRECTORY, 42 ) ).toThrow();
expect( () => application.options.setValue( DIRECTORY, 'foo' ) ).toThrow();
expect( tryOption( [] ) ).toThrow();
expect( tryOption( 42 ) ).toThrow();
expect( tryOption( 'foo' ) ).toThrow();
} );
it.each( [ '/', ' ' ] )( 'should throw an error if it contains invalid key', k => {
expect( () => application.options.setValue( DIRECTORY, { [k]: './test' } ) ).toThrow();
expect( tryOption( { [k]: './test' } ) ).toThrow();
} );
it.each( [ '/test', 'hello' ] )( 'should throw an error if a value is not a relative path', path => {
expect( () => application.options.setValue( DIRECTORY, { foo: path } ) ).toThrow();
expect( tryOption( { foo: path } ) ).toThrow();
} );
it.each( [ '/foo', '/bar' ] )( 'should throw an error if the path does not exist', path => {
// existsSpy.mockReturnValue( false );
expect( () => application.options.setValue( DIRECTORY, { foo: path } ) ).toThrow();
expect( tryOption( { foo: path } ) ).toThrow();
} );
it( 'should throw if trying to set a forbidden value ~~', () => {
mockFs( {
hello: {},
} );
expect( tryOption( { '~~': './hello' } ) ).toThrow();
} );
it( 'should pass with valid options', () => {
mockFs( {
hello: {},
world: {},
} );
application.options.setValue( DIRECTORY, { hello: './hello', world: './world' } );
expect( tryOption( { hello: './hello', world: './world' } ) ).not.toThrow();
} );
} );
} );
Expand All @@ -65,20 +74,16 @@ describe( 'Behavior', () => {
...CSS_FS,
foo: {},
} );
application.options.setValue( DIRECTORY, { foo: './foo' } );
application.options.setValue( DIRECTORIES, { foo: './foo' } );
} );
it( 'should not affect text if no code block', () => {
const event = new MarkdownEvent( MarkdownEvent.PARSE, '', 'Hello world' );
const eventBck = { ...event };
plugin.processMarkdown( event );
expect( event ).toEqual( eventBck );
const text = 'Hello world' ;
expect( plugin.replaceCodeBlocks( text ) ).toEqual( text );
} );
describe( 'Code block wrapper generation', ()=> {
it( 'should output a code block', () => {
readCodeSample.mockReturnValue( new Map( [[ DEFAULT_BLOCK_NAME, { code: 'Content of foo/qux.txt', startLine: 1, endLine: 1 } ]] ) );
const event = new MarkdownEvent( MarkdownEvent.PARSE, '', '*Hello world !*\n\n{@codeblock foo/qux.txt}' );
plugin.processMarkdown( event );
expect( event.parsedText ).toMatchInlineSnapshot( `
expect( plugin.replaceCodeBlocks( '*Hello world !*\n\n{@codeblock foo/qux.txt}' ) ).toMatchInlineSnapshot( `
"<style>@CSS</style>
*Hello world !*
Expand All @@ -88,9 +93,7 @@ describe( 'Behavior', () => {
} );
it( 'should output a folded code block', () => {
readCodeSample.mockReturnValue( new Map( [[ DEFAULT_BLOCK_NAME, { code: 'Content of foo/qux.txt', startLine: 1, endLine: 1 } ]] ) );
const event = new MarkdownEvent( MarkdownEvent.PARSE, '', '*Hello world !*\n\n{@codeblock folded foo/qux.txt}' );
plugin.processMarkdown( event );
expect( event.parsedText ).toMatchInlineSnapshot( `
expect( plugin.replaceCodeBlocks( '*Hello world !*\n\n{@codeblock folded foo/qux.txt}' ) ).toMatchInlineSnapshot( `
"<style>@CSS</style>
*Hello world !*
Expand All @@ -100,9 +103,7 @@ describe( 'Behavior', () => {
} );
it( 'should output a foldable code block', () => {
readCodeSample.mockReturnValue( new Map( [[ DEFAULT_BLOCK_NAME, { code: 'Content of foo/qux.txt', startLine: 1, endLine: 1 } ]] ) );
const event = new MarkdownEvent( MarkdownEvent.PARSE, '', '*Hello world !*\n\n{@codeblock foldable foo/qux.txt}' );
plugin.processMarkdown( event );
expect( event.parsedText ).toMatchInlineSnapshot( `
expect( plugin.replaceCodeBlocks( '*Hello world !*\n\n{@codeblock foldable foo/qux.txt}' ) ).toMatchInlineSnapshot( `
"<style>@CSS</style>
*Hello world !*
Expand All @@ -112,15 +113,15 @@ describe( 'Behavior', () => {
} );
} );
describe( 'Header generation', () => {
const extractHeader = ( event: MarkdownEvent ) => {
const matchComplex = event.parsedText.match( /##\(From \[(.+?)\]\((.+?)\)\)##/ );
const extractHeader = ( text: string ) => {
const matchComplex = text.match( /##\(From \[(.+?)\]\((.+?)\)\)##/ );
if( matchComplex ){
return {
file: matchComplex[1],
url: matchComplex[2],
};
}
const matchSimple = event.parsedText.match( /##\(From (.+?)\)##/ );
const matchSimple = text.match( /##\(From (.+?)\)##/ );
if( matchSimple ){
return {
file: matchSimple[1],
Expand All @@ -139,36 +140,32 @@ describe( 'Behavior', () => {
describe( 'Filename', () => {
it( 'should generate the correct default header', () => {
readCodeSample.mockReturnValue( new Map( [[ DEFAULT_BLOCK_NAME, { code: 'Content of foo/qux.txt', startLine: 1, endLine: 1 } ]] ) );
const event = new MarkdownEvent( MarkdownEvent.PARSE, '', '*Hello world !*\n\n{@codeblock foo/qux.txt}' );
plugin.processMarkdown( event );
expect( extractHeader( event ) ).toEqual( {
const replaced = plugin.replaceCodeBlocks( '*Hello world !*\n\n{@codeblock foo/qux.txt}' );
expect( extractHeader( replaced ) ).toEqual( {
file: './foo/qux.txt',
url: undefined,
} );
} );
it( 'should generate the correct header with explicit name', () => {
readCodeSample.mockReturnValue( new Map( [[ DEFAULT_BLOCK_NAME, { code: 'Content of foo/qux.txt', startLine: 1, endLine: 1 } ]] ) );
const event = new MarkdownEvent( MarkdownEvent.PARSE, '', '*Hello world !*\n\n{@codeblock foo/qux.txt | test.txt}' );
plugin.processMarkdown( event );
expect( extractHeader( event ) ).toEqual( {
const replaced = plugin.replaceCodeBlocks( '*Hello world !*\n\n{@codeblock foo/qux.txt | test.txt}' );
expect( extractHeader( replaced ) ).toEqual( {
file: 'test.txt',
url: undefined,
} );
} );
it( 'should generate the correct header with region', () => {
readCodeSample.mockReturnValue( new Map( [[ 'hello', { code: 'Content of foo/qux.txt', startLine: 13, endLine: 24 } ]] ) );
const event = new MarkdownEvent( MarkdownEvent.PARSE, '', '*Hello world !*\n\n{@codeblock foo/qux.txt#hello}' );
plugin.processMarkdown( event );
expect( extractHeader( event ) ).toEqual( {
const replaced = plugin.replaceCodeBlocks( '*Hello world !*\n\n{@codeblock foo/qux.txt#hello}' );
expect( extractHeader( replaced ) ).toEqual( {
file: './foo/qux.txt#13~24',
url: undefined,
} );
} );
it( 'should generate the correct header with region & explicit name', () => {
readCodeSample.mockReturnValue( new Map( [[ 'hello', { code: 'Content of foo/qux.txt', startLine: 13, endLine: 24 } ]] ) );
const event = new MarkdownEvent( MarkdownEvent.PARSE, '', '*Hello world !*\n\n{@codeblock foo/qux.txt#hello | test.txt}' );
plugin.processMarkdown( event );
expect( extractHeader( event ) ).toEqual( {
const replaced = plugin.replaceCodeBlocks( '*Hello world !*\n\n{@codeblock foo/qux.txt#hello | test.txt}' );
expect( extractHeader( replaced ) ).toEqual( {
file: 'test.txt',
url: undefined,
} );
Expand All @@ -181,19 +178,17 @@ describe( 'Behavior', () => {
const file = resolve( rootDir, 'foo/qux.txt' );
it( 'should generate the correct default URL', () => {
readCodeSample.mockReturnValue( new Map( [[ DEFAULT_BLOCK_NAME, { code: 'Content of foo/qux.txt', startLine: 1, endLine: 1 } ]] ) );
const event = new MarkdownEvent( MarkdownEvent.PARSE, '', '*Hello world !*\n\n{@codeblock foo/qux.txt | test.txt}' );
plugin.processMarkdown( event );
expect( extractHeader( event ).url ).toEqual( `${FakeGitHub.REPO_URL}` );
const replaced = plugin.replaceCodeBlocks( '*Hello world !*\n\n{@codeblock foo/qux.txt | test.txt}' );
expect( extractHeader( replaced ).url ).toEqual( `${FakeGitHub.REPO_URL}` );
expect( FakeGitHub.getGitHubURL ).toHaveBeenCalledTimes( 1 );
expect( FakeGitHub.getGitHubURL ).toHaveBeenCalledWith( file );
expect( FakeGitHub.getRepository ).toHaveBeenCalledTimes( 1 );
expect( FakeGitHub.getRepository ).toHaveBeenCalledWith( file );
} );
it( 'should generate the correct URL with region', () => {
readCodeSample.mockReturnValue( new Map( [[ 'hello', { code: 'Content of foo/qux.txt', startLine: 13, endLine: 24 } ]] ) );
const event = new MarkdownEvent( MarkdownEvent.PARSE, '', '*Hello world !*\n\n{@codeblock foo/qux.txt#hello | test.txt}' );
plugin.processMarkdown( event );
expect( extractHeader( event ).url ).toEqual( `${FakeGitHub.REPO_URL}#L13-L24` );
const replaced = plugin.replaceCodeBlocks( '*Hello world !*\n\n{@codeblock foo/qux.txt#hello | test.txt}' );
expect( extractHeader( replaced ).url ).toEqual( `${FakeGitHub.REPO_URL}#L13-L24` );
expect( FakeGitHub.getGitHubURL ).toHaveBeenCalledTimes( 1 );
expect( FakeGitHub.getGitHubURL ).toHaveBeenCalledWith( file );
expect( FakeGitHub.getRepository ).toHaveBeenCalledTimes( 1 );
Expand Down

0 comments on commit 33b1700

Please sign in to comment.