Skip to content

Commit

Permalink
feat(plugin): support directive syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
d3m1d0v committed Nov 18, 2024
1 parent fe2c3d1 commit 5b141d1
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 16 deletions.
27 changes: 22 additions & 5 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 @@ -52,6 +52,9 @@
"npm-run-all": "^4.1.5",
"typescript": "^5.6.3"
},
"dependencies": {
"@diplodoc/directive": "^0.2.0"
},
"peerDependencies": {
"markdown-it": "^13.0.0"
}
Expand Down
62 changes: 62 additions & 0 deletions src/plugin/directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import type {FileOptions} from './plugin';

import {
directiveParser,
enableInlineDirectives,
registerInlineDirective,
} from '@diplodoc/directive';

import {fileRenderer} from './renderer';
import {FILE_TOKEN, FileClassName, LinkHtmlAttr} from './const';

const ALLOWED_ATTRS: readonly string[] = [
LinkHtmlAttr.ReferrerPolicy,
LinkHtmlAttr.Rel,
LinkHtmlAttr.Target,
LinkHtmlAttr.Type,
LinkHtmlAttr.HrefLang,
];

export const fileDirective: markdownit.PluginWithOptions<FileOptions> = (md, opts = {}) => {
const {fileExtraAttrs} = opts;

fileRenderer(md);

md.use(directiveParser());

enableInlineDirectives(md);

registerInlineDirective(md, 'file', (state, params) => {
if (!params.content || !params.dests) {
return false;
}

const filename = params.content.raw;
const filelink = params.dests.link || '';

const token = state.push(FILE_TOKEN, '', 0);
token.block = false;
token.markup = ':file';
token.content = params.content.raw;

token.attrSet('class', FileClassName.Link);
token.attrSet(LinkHtmlAttr.Href, filelink);
token.attrSet(LinkHtmlAttr.Download, filename);

if (params.attrs) {
for (const attrName of ALLOWED_ATTRS) {
if (params.attrs[attrName]) {
token.attrSet(attrName, params.attrs[attrName]);
}
}
}

if (Array.isArray(fileExtraAttrs)) {
for (const [name, value] of fileExtraAttrs) {
token.attrSet(name, value);
}
}

return true;
});
};
13 changes: 4 additions & 9 deletions src/plugin/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type MarkdownIt from 'markdown-it';

import {
ENV_FLAG_NAME,
FILE_TOKEN,
Expand All @@ -12,12 +10,15 @@ import {
REQUIRED_ATTRS,
RULE_NAME,
} from './const';
import {fileRenderer} from './renderer';

export type FileOptions = {
fileExtraAttrs?: [string, string][];
};

export const filePlugin: MarkdownIt.PluginWithOptions<FileOptions> = (md, opts) => {
export const filePlugin: markdownit.PluginWithOptions<FileOptions> = (md, opts) => {
fileRenderer(md);

md.inline.ruler.push(RULE_NAME, (state, silent) => {
if (state.src.substring(state.pos, state.pos + PREFIX_LENGTH) !== PREFIX) {
return false;
Expand Down Expand Up @@ -82,10 +83,4 @@ export const filePlugin: MarkdownIt.PluginWithOptions<FileOptions> = (md, opts)

return true;
});

md.renderer.rules[FILE_TOKEN] = (tokens, idx, _opts, _env, self) => {
const token = tokens[idx];
const iconHtml = `<span class="${md.utils.escapeHtml(FileClassName.Icon)}"></span>`;
return `<a${self.renderAttrs(token)}>${iconHtml}${md.utils.escapeHtml(token.content)}</a>`;
};
};
9 changes: 9 additions & 0 deletions src/plugin/renderer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {FILE_TOKEN, FileClassName} from './const';

export const fileRenderer: markdownit.PluginSimple = (md) => {
md.renderer.rules[FILE_TOKEN] = (tokens, idx, _opts, _env, self) => {
const token = tokens[idx];
const iconHtml = `<span class="${md.utils.escapeHtml(FileClassName.Icon)}"></span>`;
return `<a${self.renderAttrs(token)}>${iconHtml}${md.utils.escapeHtml(token.content)}</a>`;
};
};
24 changes: 22 additions & 2 deletions src/plugin/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import MarkdownIt from 'markdown-it';
import {type FileOptions, filePlugin} from './plugin';
import {ENV_FLAG_NAME} from './const';
import {hidden} from './utils';
import {fileDirective} from './directive';

export type PluginOptions = FileOptions & {
output?: string;
Expand All @@ -14,6 +15,16 @@ export type TransformOptions = {
runtime?: string | {style: string};
bundle?: boolean;
extraAttrs?: FileOptions['fileExtraAttrs'];
/**
* Enables directive syntax of yfm-file.
*
* - 'disabled' – directive syntax is disabled.
* - 'enabled' – directive syntax is enabled; old syntax is also enabled.
* - 'only' – enabled only directive syntax; old syntax is disabled.
*
* @default 'disabled'
*/
directiveSyntax?: 'disabled' | 'enabled' | 'only';
/** @internal */
onBundle?: (env: {bundled: Set<string>}, output: string, runtime: RuntimeObj) => void;
};
Expand All @@ -26,13 +37,20 @@ const registerTransform = (
onBundle,
runtime,
output,
directiveSyntax,
}: Pick<TransformOptions, 'extraAttrs' | 'onBundle'> & {
bundle: boolean;
runtime: {style: string};
output: string;
directiveSyntax: NonNullable<TransformOptions['directiveSyntax']>;
},
) => {
filePlugin(md, {fileExtraAttrs: extraAttrs});
if (directiveSyntax === 'disabled' || directiveSyntax === 'enabled') {
filePlugin(md, {fileExtraAttrs: extraAttrs});
}
if (directiveSyntax === 'enabled' || directiveSyntax === 'only') {
fileDirective(md, {fileExtraAttrs: extraAttrs});
}

md.core.ruler.push('yfm_file_after', ({env}) => {
if (env?.[ENV_FLAG_NAME]) {
Expand All @@ -49,7 +67,7 @@ const registerTransform = (
};

export const transform = (opts: TransformOptions = {}) => {
const {bundle = true} = opts;
const {bundle = true, directiveSyntax = 'disabled'} = opts;

if (bundle && typeof opts.runtime === 'string') {
throw new TypeError('Option `runtime` should be record when `bundle` is enabled.');
Expand All @@ -68,6 +86,7 @@ export const transform = (opts: TransformOptions = {}) => {
bundle,
runtime,
output,
directiveSyntax,
onBundle: opts.onBundle,
extraAttrs: fileExtraAttrs ?? opts.extraAttrs,
});
Expand All @@ -79,6 +98,7 @@ export const transform = (opts: TransformOptions = {}) => {
registerTransform(md, {
bundle,
runtime,
directiveSyntax,
output: destRoot,
onBundle: opts.onBundle,
extraAttrs: opts.extraAttrs,
Expand Down

0 comments on commit 5b141d1

Please sign in to comment.