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 Nov 1, 2024
1 parent 61c41c9 commit 4497929
Show file tree
Hide file tree
Showing 12 changed files with 10,361 additions and 8,658 deletions.
2 changes: 1 addition & 1 deletion esbuild/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import {build} from 'esbuild';

import tsConfig from '../tsconfig.json' assert { type: "json" };
import tsConfig from '../tsconfig.json' assert {type: 'json'};

const outDir = 'build';

Expand Down
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.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,17 @@
"build": "run-p build:*",
"build:js": "./esbuild/build.mjs",
"build:declarations": "tsc --emitDeclarationOnly --outDir ./build",
"test": "cd tests && npm ci && npm test",
"test": "cd tests && npm ci && npm test -- --ci",
"typecheck": "tsc --noEmit",
"prepublishOnly": "npm run build",
"lint": "lint update && lint",
"lint:fix": "lint update && lint fix",
"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;
127 changes: 127 additions & 0 deletions src/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import type MarkdownIt from 'markdown-it';
import type {MarkdownItWithDirectives} from 'markdown-it-directive';
import type {
BlockDirectiveHandler,
BlockDirectiveParams,
InlineDirectiveHandler,
InlineDirectiveParams,
StateBlock,
StateInline,
} 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 registerInlineDirective(
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 registerBlockDirective(
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: StateInline,
content: NonNullable<InlineDirectiveParams['content']>,
): void {
const oldPos = state.pos;
const oldPosMax = state.posMax;

state.pos = content.startPos;
state.posMax = content.endPos;

state.md.inline.tokenize(state);

state.pos = oldPos;
state.posMax = oldPosMax;
}

export function createBlockInlineToken(
state: StateBlock,
{inlineContent, startLine}: BlockDirectiveParams,
): MarkdownIt.Token {
const token = state.push('inline', '', 0);
token.children = [];
token.content = inlineContent?.raw || '';
token.map = [startLine, startLine + 1];
return token;
}

export function tokenizeBlockContent(
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;
}
48 changes: 46 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,49 @@
import type MarkdownIt from 'markdown-it';

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

export default directive;
import {disableInlineDirectives} from './helpers';

export {
registerBlockDirective,
registerInlineDirective,
disableBlockDirectives,
disableInlineDirectives,
tokenizeBlockContent,
tokenizeInlineContent,
createBlockInlineToken,
} from './helpers';

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

export type DirectiveParams = {
inlineDirectives?: boolean;
};

// eslint-disable-next-line valid-jsdoc
/**
* Inline directives are disabled by default.
*
* They will be enabled after this error is fixed: https://github.com/hilookas/markdown-it-directive/issues/5
*
* To enable inline directives, pass `inlineDirectives: true`
*/
export const directive = (params?: DirectiveParams): MarkdownIt.PluginSimple => {
return (md) => {
direcitivePlugin(
// @ts-expect-error – bad types in markdown-it-directive
md,
);

if (params?.inlineDirectives !== true) {
disableInlineDirectives(md);
}
};
};
40 changes: 40 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
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};

// TODO: re-export from markdown-it-directive after https://github.com/hilookas/markdown-it-directive/pull/7
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 4497929

Please sign in to comment.