33 * @typedef {import('hast').Root } Root
44 */
55import { toString } from 'hast-util-to-string' ;
6- import rangeParser from 'parse-numeric-range' ;
76import { visit } from 'unist-util-visit' ;
87
98/**
10- * Rehype plugin that adds the `data-onboarding-option="some-option-id"` attribute and `hidden` class name
11- * to each line of code based on the metastring of the code block.
12- *
13- * The metastring should be in the format of (legacy method):
14- * `{"onboardingOptions": {"performance": "1, 3-4", "profiling": "5-6"}}`
15- * where the keys are the onboarding options, the line numbers can be individual or ranges separated by a comma.
9+ * a Rehype plugin that adds the `data-onboarding-option="option-id"` attribute and `hidden` class name
10+ * to each line of code enclosed within a `___PRODUCT_OPTION_START___ option-id` and `___PRODUCT_OPTION_END___ option-id` markers.
1611 *
1712 * These lines will be hidden by default and shown based on the user's selection of `<OnboardingOptionsButtons ... />`
1813 *
1914 * **Note**: This plugin should be used after `rehype-prism-plus` as it relies on its output.
20- * **Note**: the recommended way to specify the onboarding options now is to use the inline syntax.
2115 *
2216 * @return {import('unified').Plugin<[], Root> }
2317 */
@@ -35,15 +29,6 @@ function visitor(node) {
3529 if ( ! node . properties . className ?. includes ( 'code-highlight' ) ) {
3630 return ;
3731 }
38-
39- const meta = /** @type {string } */ (
40- node ?. data ?. meta || node ?. properties ?. metastring || ''
41- ) ;
42-
43- if ( meta . includes ( 'onboardingOptions' ) ) {
44- handle_metadata_options ( node , meta ) ;
45- return ;
46- }
4732 handle_inline_options ( node ) ;
4833}
4934
@@ -71,74 +56,3 @@ function handle_inline_options(node) {
7156 }
7257 } ) ;
7358}
74-
75- /**
76- * Parse the line numbers from the metastring
77- * @param {string } meta
78- * @return {number[] }
79- * @example
80- * parseLines('1, 3-4') // [1, 3, 4]
81- * parseLines('') // []
82- */
83- const parseLines = meta => {
84- const RE = / ( [ \d , - ] + ) / ;
85- // Remove space between {} e.g. {1, 3}
86- const parsedMeta = meta
87- . split ( ',' )
88- . map ( str => str . trim ( ) )
89- . join ( ',' ) ;
90- if ( RE . test ( parsedMeta ) ) {
91- const strlineNumbers = RE . exec ( parsedMeta ) ?. [ 1 ] ;
92- if ( ! strlineNumbers ) {
93- return [ ] ;
94- }
95- const lineNumbers = rangeParser ( strlineNumbers ) ;
96- return lineNumbers ;
97- }
98- return [ ] ;
99- } ;
100-
101- /**
102- * Create a closure that returns an onboarding option `id` for a given line if it exists
103- *
104- * @param {string } meta
105- * @return { (index:number) => string | undefined }
106- */
107- const getOptionForLine = meta => {
108- // match the onboardingOptions object, but avoid `other stuff`
109- const optionsRE = / { " o n b o a r d i n g O p t i o n s " : \s * ( { [ ^ } ] * } ) \s * } / ;
110- let linesForOptions = { } ;
111- const options = optionsRE . exec ( meta ) ?. [ 1 ] ;
112- if ( ! options ) {
113- return ( ) => undefined ;
114- }
115-
116- // eval provides the convenience of not having to wrap the object properties in quotes
117- const parsedOptions = JSON . parse ( options ) ;
118- linesForOptions = Object . keys ( parsedOptions ) . reduce ( ( acc , key ) => {
119- acc [ key ] = parseLines ( parsedOptions [ key ] ) ;
120- return acc ;
121- } , { } ) ;
122- return index => {
123- for ( const key in linesForOptions ) {
124- if ( linesForOptions [ key ] . includes ( index + 1 ) ) {
125- return key ;
126- }
127- }
128- return undefined ;
129- } ;
130- } ;
131-
132- /**
133- * @param {Element } node
134- */
135- function handle_metadata_options ( node , meta ) {
136- const optionForLine = getOptionForLine ( meta ) ;
137-
138- node . children . forEach ( ( line , index ) => {
139- const option = optionForLine ( index ) ;
140- if ( option ) {
141- line . properties [ 'data-onboarding-option' ] = option ;
142- }
143- } ) ;
144- }
0 commit comments