Skip to content

Commit

Permalink
fix: unexpected transform for tags within attribute (#1872)
Browse files Browse the repository at this point in the history
* fix: unexpected transform for tags within attribute

* refactor: handle single quotes case
  • Loading branch information
PeachScript authored Sep 15, 2023
1 parent f588407 commit 8d40a74
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,10 @@ export default (ret: IMdTransformerResult) => {
expect(ret.content).toContain('bar2=""');
expect(ret.content).toContain('<HelloWorld>');
expect(ret.content).toContain('<invalid />');

// don't transform tagName which is part of attr value
expect(ret.content).toContain('value="Array<Function>"');
expect(ret.content).toContain('html="<Some a></Some>"');
expect(ret.content).toContain('value="<Some a></Some>"');
expect(ret.content).toContain('html=&quot;<Other a></Other>&quot');
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@
<HelloWorld>dumi</HelloWorld>

<inValid></inValid>

<API value="Array<Function>">
<APIField html="<Some a></Some>"></APIField>
</API>

<input value='<Some a></Some>' />
<input value='<Some html="<Other a></Other>"></Some>' />
22 changes: 16 additions & 6 deletions src/loaders/markdown/transformer/rehypeRaw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { IMdTransformerOptions } from '.';

let raw: typeof import('hast-util-raw').raw;
let visit: typeof import('unist-util-visit').visit;
const COMPONENT_NAME_REGEX = /<[A-Z][a-zA-Z\d]*/g;
const COMPONENT_NAME_REGEX = /(<)([A-Z][a-zA-Z\d]*)([\s|>])/g;
const COMPONENT_PROP_REGEX = /\s[a-z][a-z\d]*[A-Z]+[a-zA-Z\d]*(=|\s|>)/g;
const COMPONENT_STUB_ATTR = '$tag-name';
const PROP_STUB_ATTR = '-$u';
Expand All @@ -29,11 +29,21 @@ export default function rehypeRaw(opts: IRehypeRawOptions): Transformer<Root> {
if (node.type === 'raw' && COMPONENT_NAME_REGEX.test(node.value)) {
// mark tagName for all custom react component
// because the parse5 within hast-util-raw will lowercase all tag names
node.value = node.value.replace(COMPONENT_NAME_REGEX, (str) => {
const tagName = str.slice(1);
node.value = node.value.replace(
COMPONENT_NAME_REGEX,
(str, bracket, tagName, next, i, full) => {
const isWithinQuotes =
(/="[^"]*$/.test(full.slice(0, i)) &&
/^[^"]*"/.test(full.slice(i))) ||
(/='[^']*$/.test(full.slice(0, i)) &&
/^[^']*'/.test(full.slice(i)));

return `${str} ${COMPONENT_STUB_ATTR}="${tagName}"`;
});
// skip if tagName is part of attr value
return isWithinQuotes
? str
: `${bracket}${tagName} ${COMPONENT_STUB_ATTR}="${tagName}"${next}`;
},
);
// mark all camelCase props for all custom react component
// because the parse5 within hast-util-raw will lowercase all attr names
node.value = node.value.replace(COMPONENT_PROP_REGEX, (str) => {
Expand All @@ -55,7 +65,7 @@ File: ${opts.fileAbsPath}`);
}
});

const newTree = raw(tree, vFile) as Root;
const newTree = raw(tree, { file: vFile }) as Root;

visit<Root, 'element'>(newTree, 'element', (node) => {
if (node.properties?.[COMPONENT_STUB_ATTR]) {
Expand Down

0 comments on commit 8d40a74

Please sign in to comment.