Skip to content

Commit 1d20520

Browse files
committed
keep support for both product options syntax options
+more readable mdx bundler errors
1 parent 8200601 commit 1d20520

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

src/mdx.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,10 @@ export async function getFileBySlug(slug: string) {
456456

457457
return options;
458458
},
459+
}).catch(e => {
460+
// eslint-disable-next-line no-console
461+
console.error('Error occurred during MDX compilation:', e.errors);
462+
throw e;
459463
});
460464

461465
const {code, frontmatter} = result;

src/rehype-onboarding-lines.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* @typedef {import('hast').Root} Root
44
*/
55
import {toString} from 'hast-util-to-string';
6+
import rangeParser from 'parse-numeric-range';
67
import {visit} from 'unist-util-visit';
78

89
/**
@@ -34,6 +35,18 @@ function visitor(node) {
3435
return;
3536
}
3637

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+
}
46+
handle_inline_options(node);
47+
}
48+
49+
function handle_inline_options(node) {
3750
/* @type {string | undefined} */
3851
let currentOption;
3952

@@ -57,3 +70,74 @@ function visitor(node) {
5770
}
5871
});
5972
}
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 = /{"onboardingOptions":\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

Comments
 (0)