Skip to content

Commit

Permalink
feat: add commentStart/commentEnd options. #57
Browse files Browse the repository at this point in the history
  • Loading branch information
jaywcjlove committed Jan 3, 2025
1 parent 7dbc78d commit bf2dc53
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 29 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,18 @@ Code block passing parameters

> Default Value: `true`
### `commentStart`

Optional start delimiter for comments @example `\\{\\*`

> Default Value: `<!--`
### `commentEnd`

Optional end delimiter for comments @example `\\*\\}`

> Default Value: `-->`
## Related

- [`rehype-video`](https://github.com/jaywcjlove/rehype-video) Add improved video syntax: links to `.mp4` and `.mov` turn into videos.
Expand Down
22 changes: 16 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,30 +46,40 @@ export type RehypeAttrsOptions = {
* Code block passing parameters
*/
codeBlockParames?: boolean;
/**
* Optional start delimiter for comments @example `\\{\\*`
* @default `<!--`
*/
commentStart?: string;
/**
* Optional end delimiter for comments @example `\\*\\}`
* @default `-->`
*/
commentEnd?: string;
}

const rehypeAttrs: Plugin<[RehypeAttrsOptions?], Root> = (options = {}) => {
const { properties = 'data', codeBlockParames = true } = options;
const { properties = 'data', codeBlockParames = true, commentStart = "<!--", commentEnd = "-->" } = options;
return (tree) => {
visit(tree, 'element', (node, index, parent) => {
if (codeBlockParames && node.tagName === 'pre' && node && Array.isArray(node.children) && parent && Array.isArray(parent.children) && parent.children.length > 1) {
const firstChild = node.children[0] as Element;
if (firstChild && firstChild.tagName === 'code' && typeof index === 'number') {
const child = prevChild(parent.children as Literal[], index);
if (child) {
const attr = getCommentObject(child);
const attr = getCommentObject(child, commentStart, commentEnd);
if (Object.keys(attr).length > 0) {
node.properties = { ...node.properties, ...{ 'data-type': 'rehyp' } }
firstChild.properties = propertiesHandle(firstChild.properties, attr, properties) as Properties
}
}
}
}

if (/^(em|strong|b|a|i|p|pre|kbd|blockquote|h(1|2|3|4|5|6)|code|table|img|del|ul|ol)$/.test(node.tagName) && parent && Array.isArray(parent.children) && typeof index === 'number') {
const child = nextChild(parent.children, index, '', codeBlockParames)
let rootnode = parent as Root
if ((/^(em|strong|b|a|i|p|pre|kbd|blockquote|h(1|2|3|4|5|6)|code|table|img|del|ul|ol)$/.test(node.tagName) || rootnode.type == "root") && parent && Array.isArray(parent.children) && typeof index === 'number') {
const child = nextChild(parent.children, index, '', codeBlockParames, commentStart, commentEnd)
if (child) {
const attr = getCommentObject(child as Comment)
const attr = getCommentObject(child as Comment, commentStart, commentEnd)
if (Object.keys(attr).length > 0) {
node.properties = propertiesHandle(node.properties, attr, properties) as Properties
}
Expand Down
52 changes: 35 additions & 17 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const prevChild = (data: Literal[] = [], index: number): Comment | undefi
return;
}

export const nextChild = (data: RootContent[] | ElementContent[] = [], index: number, tagName?: string, codeBlockParames?: boolean): ElementContent | undefined => {
export const nextChild = (data: RootContent[] | ElementContent[] = [], index: number, tagName?: string, codeBlockParames?: boolean, commentStart: string = "<!--", commentEnd: string = "-->"): ElementContent | undefined => {
let i = index;
while (i < data.length) {
i++;
Expand All @@ -34,18 +34,23 @@ export const nextChild = (data: RootContent[] | ElementContent[] = [], index: nu
} else {
const element = data[i] as ElementContent & Literal;
if (!element || element.type === 'element') return;
if (element.type === 'text' && element.value.replace(/(\n|\s)/g, '') !== '') return;
if (element.type && /^(comment|raw)$/ig.test(element.type)) {
if (element.value && !/^rehype:/.test(element.value.replace(/^(\s+)?<!--(.*?)-->/, '$2') || '')) {
if (element.type === 'text') {
const nextNode = nextChild(data, i, undefined, false)
if (nextNode) return nextNode;
};
if (element.type && /^(comment|raw|text)$/ig.test(element.type)) {
const regx = new RegExp(`^(\s+)?${commentStart}(.*?)${commentEnd}`);
if (element.value && !/^rehype:/.test(element.value.replace(/^(\n|\s)+/, '').replace(regx, '$2') || '')) {
return
};
let comment = element.value.replace(/^(\n|\s)+/, '');
if (codeBlockParames) {
const nextNode = nextChild(data, i, 'pre', codeBlockParames)
if (nextNode) return;
element.value = (element.value || '').replace(/^(\n|\s)+/, '')
element.value = comment
return element;
} else {
element.value = (element.value || '').replace(/^(\n|\s)+/, '')
element.value = comment
return element;
}
}
Expand All @@ -55,24 +60,37 @@ export const nextChild = (data: RootContent[] | ElementContent[] = [], index: nu
}

/**
* 获取代码注视的位置
* @param data 数据
* @param index 当前数据所在的位置
* @returns 返回 当前参数数据 Object,`{}`
* Get the position of the code comment
* @param data Comment
* @param start
* @param end
* @returns Returns the current parameter data Object, `{}`
*/
export const getCommentObject = ({ value = '' }: Comment): Properties => {
const param = getURLParameters(value.replace(/^<!--(.*?)-->/, '$1').replace(/^rehype:/, ''));
export const getCommentObject = ({ value = '' }: Comment, start: string = "<!--", end: string = "-->"): Properties => {
let regx: RegExp;
try {
// Construct a regular expression to match the comment content
regx = new RegExp(`^${start}(.*?)${end}`);
} catch (error) {
return {};
}
const match = value.match(regx);
const content = (match ? match[1] : value)
// Extract the comment content if it matches the regular expression
const commentContent = content.replace(/^rehype:/, '');
// Extract the comment content and parse it into a parameter object
const param = getURLParameters(commentContent);
// Iterate over the key-value pairs of the parameter object and perform type conversion
Object.keys(param).forEach((keyName: string) => {
if (param[keyName] === 'true') {
param[keyName] = true;
}
if (param[keyName] === 'false') {
} else if (param[keyName] === 'false') {
param[keyName] = false;
}
if (typeof param[keyName] === 'string' && !/^0/.test(param[keyName] as string) && !isNaN(+param[keyName])) {
} else if (typeof param[keyName] === 'string' && !/^0/.test(param[keyName] as string) && !isNaN(+param[keyName])) {
param[keyName] = +param[keyName];
}
})
});
// Return the processed parameter object
return param;
}

Expand Down
39 changes: 33 additions & 6 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,18 @@ describe('rehype-attr type raw test case', () => {
expect(htmlStr).toEqual(data.expected);
});
});

})

describe('rehype-attr function test case', () => {
it('getCommentObject', async () => {
expect(utils.getCommentObject({} as Comment)).toEqual({ });
expect(utils.getCommentObject({ value: 'rehype:title=Rehype Attrs' } as Comment)).toEqual({ title: 'Rehype Attrs' });
expect(utils.getCommentObject({ value: '<!--rehype:title=Rehype Attrs-->' } as Comment)).toEqual({ title: 'Rehype Attrs' });
expect(utils.getCommentObject({ value: '{*rehype:title=Rehype Attrs*}' } as Comment)).toEqual({ "{*rehype:title": "Rehype Attrs*}" });
const commentStart: string = "\\{\\*", commentEnd: string = "\\*\\}";
expect(utils.getCommentObject({ value: '{*rehype:title=Rehype Attrs*}' } as Comment, commentStart, commentEnd)).toEqual({ title: 'Rehype Attrs' });
expect(utils.getCommentObject({ value: '{*rehype:title=Rehype Attrs*} hello world {* hi *}' } as Comment, commentStart, commentEnd)).toEqual({ title: 'Rehype Attrs' });
expect(utils.getCommentObject({ value: '{*rehype:title=Rehype Attrs--> hello world }' } as Comment, commentStart, commentEnd)).toEqual({ "{*rehype:title": "Rehype Attrs--> hello world }" });
expect(utils.getCommentObject({ value: 'rehype:title=title3' } as Comment)).toEqual({ title: "title3" });
});
it('prevChild', async () => {
expect(utils.prevChild(undefined, 0)).toBeUndefined()
Expand Down Expand Up @@ -142,8 +147,8 @@ describe('rehype-attr test case', () => {
});

it('options="string" - Multiple value settings', async () => {
const markdown = "<!--rehype:title=Rehype Attrs-->\n```js\nconsole.log('')\n```\n\n```js\nconsole.log('')\n```\n<!--rehype:title=Rehype Attrs Sub-->\n```js\nconsole.log('')\n```\n"
const expected = `<!--rehype:title=Rehype Attrs-->\n<pre data-type="rehyp"><code class="language-js" data-config="{&#x22;title&#x22;:&#x22;Rehype Attrs&#x22;,&#x22;rehyp&#x22;:true}">console.log('')\n</code></pre>\n<pre><code class="language-js">console.log('')\n</code></pre>\n<!--rehype:title=Rehype Attrs Sub-->\n<pre data-type="rehyp"><code class="language-js" data-config="{&#x22;title&#x22;:&#x22;Rehype Attrs Sub&#x22;,&#x22;rehyp&#x22;:true}">console.log('')\n</code></pre>`
const markdown = "<!--rehype:title=Rehype Attrs-->\n```js\nconsole.log('1')\n```\n\n```js\nconsole.log('2')\n```\n\n<!--rehype:title=Rehype Attrs Sub-->\n```js\nconsole.log('3')\n```\n"
const expected = `<!--rehype:title=Rehype Attrs-->\n<pre data-type="rehyp"><code class="language-js" data-config="{&#x22;title&#x22;:&#x22;Rehype Attrs&#x22;,&#x22;rehyp&#x22;:true}">console.log('1')\n</code></pre>\n<pre data-config="{&#x22;title&#x22;:&#x22;Rehype Attrs Sub&#x22;,&#x22;rehyp&#x22;:true}"><code class="language-js">console.log('2')\n</code></pre>\n<!--rehype:title=Rehype Attrs Sub-->\n<pre data-type="rehyp"><code class="language-js" data-config="{&#x22;title&#x22;:&#x22;Rehype Attrs Sub&#x22;,&#x22;rehyp&#x22;:true}">console.log('3')\n</code></pre>`
const htmlStr = unified()
.use(remarkParse)
.use(remark2rehype, { allowDangerousHtml: true })
Expand Down Expand Up @@ -239,7 +244,7 @@ describe('rehype-attr test case', () => {
{
title: 'options="attr" - Code - 1',
markdown: 'test\n<!--rehype:title=Rehype Attrs-->\n```js\nconsole.log("")\n```',
expected: '<p>test</p>\n<!--rehype:title=Rehype Attrs-->\n<pre data-type="rehyp"><code class="language-js" title="Rehype Attrs">console.log("")\n</code></pre>',
expected: '<p title="Rehype Attrs">test</p>\n<!--rehype:title=Rehype Attrs-->\n<pre data-type="rehyp"><code class="language-js" title="Rehype Attrs">console.log("")\n</code></pre>',
},
{
title: 'options="attr" - Code - 2',
Expand All @@ -249,7 +254,7 @@ describe('rehype-attr test case', () => {
{
title: 'options="attr" - Code - 3',
markdown: 'test\n\n<!--rehype:title=Rehype Attrs-->\n```js\nconsole.log("")\n```',
expected: '<p>test</p>\n<!--rehype:title=Rehype Attrs-->\n<pre data-type="rehyp"><code class="language-js" title="Rehype Attrs">console.log("")\n</code></pre>',
expected: '<p title="Rehype Attrs">test</p>\n<!--rehype:title=Rehype Attrs-->\n<pre data-type="rehyp"><code class="language-js" title="Rehype Attrs">console.log("")\n</code></pre>',
},
{
title: 'options="attr" - Emphasis <em>',
Expand Down Expand Up @@ -447,6 +452,28 @@ describe('rehype-attr test case', () => {
.toString()
expect(htmlStr).toEqual(data.expected);
});
});

[
{
title: 'options="attr" - <p>',
markdown: '<p class="hello">text</p>{*rehype:className=text*}',
expected: '<p class="text">text</p>{*rehype:className=text*}',
},
{
title: 'options="attr" - <p>',
markdown: '<p class="hello">text</p>{*rehype:className=text*} hello',
expected: '<p class="text">text</p>{*rehype:className=text*} hello',
}
].forEach((data, idx) => {
it(data.title, async () => {
const htmlStr = rehype()
.data('settings', { fragment: true })
.use(rehypeAttrs, { properties: 'attr', commentStart: '\\{\\*', commentEnd: '\\*\\}' })
.processSync(data.markdown)
.toString()
expect(htmlStr).toEqual(data.expected);
});
})

});
Expand Down

0 comments on commit bf2dc53

Please sign in to comment.