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:
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 *
@@ -34,15 +29,6 @@ function visitor(node) {
3429 if ( ! node . properties . className ?. includes ( 'code-highlight' ) ) {
3530 return ;
3631 }
37-
38- const meta = /** @type {string } */ (
39- node ?. data ?. meta || node ?. properties ?. metastring || ''
40- ) ;
41-
42- if ( meta . includes ( 'onboardingOptions' ) ) {
43- handle_metadata_options ( node , meta ) ;
44- return ;
45- }
4632 handle_inline_options ( node ) ;
4733}
4834
@@ -70,74 +56,3 @@ function handle_inline_options(node) {
7056 }
7157 } ) ;
7258}
73-
74- /**
75- * Parse the line numbers from the metastring
76- * @param {string } meta
77- * @return {number[] }
78- * @example
79- * parseLines('1, 3-4') // [1, 3, 4]
80- * parseLines('') // []
81- */
82- const parseLines = meta => {
83- const RE = / ( [ \d , - ] + ) / ;
84- // Remove space between {} e.g. {1, 3}
85- const parsedMeta = meta
86- . split ( ',' )
87- . map ( str => str . trim ( ) )
88- . join ( ',' ) ;
89- if ( RE . test ( parsedMeta ) ) {
90- const strlineNumbers = RE . exec ( parsedMeta ) ?. [ 1 ] ;
91- if ( ! strlineNumbers ) {
92- return [ ] ;
93- }
94- const lineNumbers = rangeParser ( strlineNumbers ) ;
95- return lineNumbers ;
96- }
97- return [ ] ;
98- } ;
99-
100- /**
101- * Create a closure that returns an onboarding option `id` for a given line if it exists
102- *
103- * @param {string } meta
104- * @return { (index:number) => string | undefined }
105- */
106- const getOptionForLine = meta => {
107- // match the onboardingOptions object, but avoid `other stuff`
108- const optionsRE = / { " o n b o a r d i n g O p t i o n s " : \s * ( { [ ^ } ] * } ) \s * } / ;
109- let linesForOptions = { } ;
110- const options = optionsRE . exec ( meta ) ?. [ 1 ] ;
111- if ( ! options ) {
112- return ( ) => undefined ;
113- }
114-
115- // eval provides the convenience of not having to wrap the object properties in quotes
116- const parsedOptions = JSON . parse ( options ) ;
117- linesForOptions = Object . keys ( parsedOptions ) . reduce ( ( acc , key ) => {
118- acc [ key ] = parseLines ( parsedOptions [ key ] ) ;
119- return acc ;
120- } , { } ) ;
121- return index => {
122- for ( const key in linesForOptions ) {
123- if ( linesForOptions [ key ] . includes ( index + 1 ) ) {
124- return key ;
125- }
126- }
127- return undefined ;
128- } ;
129- } ;
130-
131- /**
132- * @param {Element } node
133- */
134- function handle_metadata_options ( node , meta ) {
135- const optionForLine = getOptionForLine ( meta ) ;
136-
137- node . children . forEach ( ( line , index ) => {
138- const option = optionForLine ( index ) ;
139- if ( option ) {
140- line . properties [ 'data-onboarding-option' ] = option ;
141- }
142- } ) ;
143- }
0 commit comments