-
-
Notifications
You must be signed in to change notification settings - Fork 9k
refactor(theme-common, theme-classic, theme-live-codeblock): Parse metastring
into metaOptions
and use it across components
#11019
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
✅ [V2]Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify site configuration. |
⚡️ Lighthouse report for the deploy preview of this PR
|
2d0eeef
to
29d2c19
Compare
/** | ||
* The supported types for {@link CodeBlockMetaOptions} values. | ||
*/ | ||
export type CodeMetaOptionValue = string | number | boolean | undefined; | ||
|
||
/** | ||
* A property bag for custom options specified by the user via metastring | ||
* to control aspects like title and line numbers. | ||
*/ | ||
export type CodeBlockMetaOptions = { | ||
[key: string]: CodeMetaOptionValue; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not typesafe, we'd rather use an interface as explained here #11011 (comment)
import Playground from '@theme/Playground'; | ||
import ReactLiveScope from '@theme/ReactLiveScope'; | ||
import CodeBlock, {type Props} from '@theme-init/CodeBlock'; | ||
|
||
const withLiveEditor = (Component: typeof CodeBlock) => { | ||
function WrappedComponent(props: Props) { | ||
if (props.live) { | ||
return <Playground scope={ReactLiveScope} {...props} />; | ||
const metaOptions = parseCodeBlockMetaOptions( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this going to lead to parsing 3 times the metastring?
We don't want to parse it for:
- the live code block
- the code block
- the playground
We only want to parse options once
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I tried to ensure we parse it only once. Its a bit explained in the PR motivation:
Due to the way the live code editor works the metaOptions is introduced as component prop. This way we can parse it once and pass it through. The possible overlap between prop<->metaOptions is the same like prop<->metastring before.
I added a new metaOptions
prop for this purpose to pass it from parent to child when possible. The forwarding is happening here in line 26 and 32.
parseCodeBlockMetaOptions
prioritizes the bag from the props if available.
import Playground from '@theme/Playground'; | ||
import ReactLiveScope from '@theme/ReactLiveScope'; | ||
import CodeBlock, {type Props} from '@theme-init/CodeBlock'; | ||
|
||
const withLiveEditor = (Component: typeof CodeBlock) => { | ||
function WrappedComponent(props: Props) { | ||
if (props.live) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to keep it for retrocompatibility
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The prop is still there (see line 21)
|
||
// Retrocompatible support for live codeblock metastring | ||
// Not really the appropriate place to handle that :s | ||
node.data.hProperties.live = node.meta?.split(' ').includes('live'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Historically, with MDX 1 (Docusaurus v2), the live code block component would receive a "live" prop.
Our users have swizzled the live code block component, so if you remove this line, their component won't receive the live=true
prop anymore and it might break their site. I'd prefer to keep it, and eventually only remove this for Docusaurus v4.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the further insight. This area was a bit sensitive for me as I wasn't sure about all the affected parts (also considering the note above in line 17).
The normal @theme/CodeBlock
doesn't have a live
property, it only comes via docusaurus-theme-live-codeblock
(as @theme-init/CodeBlock
) And I thought there users would rather swizzle the Playground
component.
I didn't try all scenarios, but normally swizzling a CodeBlock
gives you props without live
. But it might be risky that people might have relied on a hidden live property in older code and declared a live
property themselves.
Unfortunately this is the docusaurus-mdx-loader
package which has no access to the codeBlockUtils
. So we would need to keep this code as it is. I don't think we can rely on the metaOptions
easily.
0b4addf
to
f8b3736
Compare
// we keep the old custom logic which was moved from their old spots to here. | ||
|
||
// normal codeblock | ||
const title = metastring?.match(codeBlockTitleRegex)?.groups!.title; |
Check failure
Code scanning / CodeQL
Polynomial regular expression used on uncontrolled data High
regular expression
library input
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pre-existing code was just moved. Regex pattern and input values are unchanged.
f8b3736
to
dbb2dcc
Compare
dbb2dcc
to
7136e71
Compare
Added, see #11017 (comment) |
Pre-flight checklist
Motivation
This PR is part of a series related to #11008 and it superceeds #11011 in the goal to splitup the work into more isolated refactoring/feature parts.
Note that this PR also includes the changes of previous steps and therefore the overall diff can be misleading. The best approach will be to review and merge every step individually and then rebase accordingly.
Intermediately the specific changes can be checked here: Danielku15/docusaurus@feature/codeblock-meta...Danielku15:docusaurus:feature/codeblock-meta-2
Step 1 (#11017): Splitup current parseLines logic (separation of concerns)
Step 2 (this PR): Parse metastring into metaOptions and use it across components.
Step 3 (#11021): Add parsing of any options specified in the metastring.
Step 4 (#11022): Add CodeBlockToken component to customize DOM of highlighted tokens.
Step 5 (#11023): Pass
metaOptions
to whole codeblock component tree.The motivation of this part is to centralize the
metastring
parsing across components to a central location without changing the parsing logic itself.To achieve the central parsing a new
metaOptions
is introduced and the old inline logic is adapted everywhere.Due to the way the live code editor works the
metaOptions
is introduced as component prop. This way we can parse it once and pass it through. The possible overlap between prop<->metaOptions is the same like prop<->metastring before.We could split this PR further but I think it makes sense to update all components to use
metaOptions
in one go. The refactoring per component of clearly visible in individual commits.Test Plan
Automatic testing relies on existing integration tests.
Manual testing by checking
/docs/markdown-features/code-blocks
showed no impact of the change.Test links
Deploy preview: https://deploy-preview-11019--docusaurus-2.netlify.app
Code Blocks: https://deploy-preview-11019--docusaurus-2.netlify.app/docs/markdown-features/code-blocks/
Related issues/PRs