Skip to content

Commit

Permalink
feat: add directive plugin and helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
d3m1d0v committed Oct 31, 2024
1 parent 61c41c9 commit e250360
Show file tree
Hide file tree
Showing 11 changed files with 9,735 additions and 8,656 deletions.
31 changes: 17 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
"pre-commit": "lint update && lint-staged",
"prepare": "husky"
},
"dependencies": {
"markdown-it-directive": "^2.0.2"
},
"devDependencies": {
"@diplodoc/lint": "^1.2.0",
"@diplodoc/tsconfig": "^1.0.2",
Expand Down
4 changes: 4 additions & 0 deletions src/const.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const RULE = {
Inline: 'inline_directive',
Block: 'block_directive',
} as const;
110 changes: 110 additions & 0 deletions src/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import type MarkdownIt from 'markdown-it';
import type {MarkdownItWithDirectives} from 'markdown-it-directive';
import type {
BlockDirectiveHandler,
BlockDirectiveParams,
InlineDirectiveHandler,
InlineDirectiveParams,
StateBlock,
} from './types';

import {RULE} from './const';

export function disableInlineDirectives(md: MarkdownIt): void {
md.inline.ruler.disable(RULE.Inline, true);
}

export function disableBlockDirectives(md: MarkdownIt): void {
md.block.ruler.disable(RULE.Block, true);
}

export function applyInlineDirective(
md: MarkdownIt,
name: string,
handler: InlineDirectiveHandler,
): void {
(md as MarkdownItWithDirectives).inlineDirectives[name] = (args) => {
const params: InlineDirectiveParams = {
startPos: args.directiveStart,
endPos: args.directiveEnd,
};
if (args.attrs !== undefined) {
params.attrs = args.attrs as unknown as InlineDirectiveParams['attrs'];
}
if (args.dests !== undefined) {
params.dests = args.dests as unknown as InlineDirectiveParams['dests'];
}
if (args.content !== undefined) {
params.content = {
raw: args.content,
startPos: args.contentStart!, // eslint-disable-line @typescript-eslint/no-non-null-assertion
endPos: args.contentEnd!, // eslint-disable-line @typescript-eslint/no-non-null-assertion
};
}
return handler(args.state, params);
};
}

export function applyBlockDirective(
md: MarkdownIt,
name: string,
handler: BlockDirectiveHandler,
): void {
(md as MarkdownItWithDirectives).blockDirectives[name] = (args) => {
const params: BlockDirectiveParams = {
startLine: args.directiveStartLine,
endLine: args.directiveEndLine,
};
if (args.attrs !== undefined) {
params.attrs = args.attrs as unknown as BlockDirectiveParams['attrs'];
}
if (args.dests !== undefined) {
params.dests = args.dests as unknown as BlockDirectiveParams['dests'];
}
if (args.inlineContent !== undefined) {
params.inlineContent = {
raw: args.inlineContent,
startPos: args.inlineContentStart!, // eslint-disable-line @typescript-eslint/no-non-null-assertion
endPos: args.inlineContentEnd!, // eslint-disable-line @typescript-eslint/no-non-null-assertion
};
}
if (args.content !== undefined) {
params.content = {
raw: args.content,
startLine: args.contentStartLine!, // eslint-disable-line @typescript-eslint/no-non-null-assertion
endLine: args.contentEndLine!, // eslint-disable-line @typescript-eslint/no-non-null-assertion
};
}
return handler(args.state, params);
};
}

export function tokenizeInlineContent(
state: StateBlock,
params: Required<Pick<BlockDirectiveParams, 'startLine' | 'endLine' | 'inlineContent'>>,
): void {
const {inlineContent: content, startLine} = params;
const token = state.push('inline', '', 0);
token.children = [];
token.content = content.raw;
token.map = [startLine, startLine + 1];
}

export function tokenizeContent(
state: StateBlock,
content: NonNullable<BlockDirectiveParams['content']>,
parentType?: string,
): void {
const oldParent = state.parentType;
const oldLineMax = state.lineMax;

// @ts-expect-error bad types of state.parentType
state.parentType = parentType ?? 'directive';
state.line = content.startLine;
state.lineMax = content.endLine;

state.md.block.tokenize(state, content.startLine, content.endLine);

state.lineMax = oldLineMax;
state.parentType = oldParent;
}
28 changes: 26 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
import type MarkdownIt from 'markdown-it';

export const directive: MarkdownIt.PluginSimple = () => {};
import direcitivePlugin from 'markdown-it-directive';

export default directive;
export {
applyBlockDirective,
applyInlineDirective,
disableBlockDirectives,
disableInlineDirectives,
tokenizeContent,
} from './helpers';

export type {
DirectiveAttrs,
DirectiveDests,
BlockDirectiveParams,
BlockDirectiveHandler,
InlineDirectiveParams,
InlineDirectiveHandler,
} from './types';

export const directive = (): MarkdownIt.PluginSimple => {
return (md) => {
direcitivePlugin(
// @ts-expect-error – bad types in markdown-it-directive
md,
);
};
};
38 changes: 38 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type StateBlock from 'markdown-it/lib/rules_block/state_block';
import type StateInline from 'markdown-it/lib/rules_inline/state_inline';

export type {StateBlock, StateInline};

export type DirectiveAttrs = Record<string, string>;
export type DirectiveDests = ['link' | 'string', string][];

type InlineContent = {
raw: string;
startPos: number;
endPos: number;
};

type BlockContent = {
raw: string;
startLine: number;
endLine: number;
};

export type BlockDirectiveParams = {
startLine: number;
endLine: number;
attrs?: DirectiveAttrs;
dests?: DirectiveDests;
content?: BlockContent;
inlineContent?: InlineContent;
};
export type InlineDirectiveParams = {
startPos: number;
endPos: number;
attrs?: DirectiveAttrs;
dests?: DirectiveDests;
content?: InlineContent;
};

export type BlockDirectiveHandler = (state: StateBlock, params: BlockDirectiveParams) => boolean;
export type InlineDirectiveHandler = (state: StateInline, params: InlineDirectiveParams) => boolean;
2 changes: 1 addition & 1 deletion tests/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
/** @type {import('jest').Config} */
module.exports = {
testEnvironment: 'jsdom',
transformIgnorePatterns: [],
Expand Down
Loading

0 comments on commit e250360

Please sign in to comment.