|
1 | | -import fs from 'node:fs' |
2 | | - |
3 | 1 | const targets = new Set(['expand', 'inline']) |
4 | 2 |
|
5 | | -// TODO: refactor to a Promise so we can use async readFile |
6 | | -const plugin = (() => tree => { |
7 | | - const process = node => { |
8 | | - /** |
9 | | - * Don't expand link tags that are not explicitly marked as such |
10 | | - */ |
11 | | - if (node?.attrs && ![...targets].some(attr => attr in node.attrs)) { |
12 | | - for (const attr of targets) { |
13 | | - node.attrs[attr] = false |
| 3 | +const expandLinkPlugin = () => tree => { |
| 4 | + return new Promise((resolve, reject) => { |
| 5 | + const isNode = typeof process !== 'undefined' && process.versions?.node |
| 6 | + |
| 7 | + const loadFile = async href => { |
| 8 | + if (isNode) { |
| 9 | + const { readFile } = await import('node:fs/promises') |
| 10 | + return await readFile(href, 'utf8') |
14 | 11 | } |
15 | 12 |
|
16 | | - return node |
17 | | - } |
| 13 | + const res = await fetch(href) |
| 14 | + |
| 15 | + if (!res.ok) { |
| 16 | + throw new Error(`Failed to fetch ${href}: ${res.statusText}`) |
| 17 | + } |
18 | 18 |
|
19 | | - if ( |
20 | | - node |
21 | | - && node.tag === 'link' |
22 | | - && node.attrs |
23 | | - && node.attrs.href |
24 | | - && node.attrs.rel === 'stylesheet' |
25 | | - ) { |
26 | | - node.content = [fs.readFileSync(node.attrs.href, 'utf8')] |
27 | | - node.tag = 'style' |
28 | | - node.attrs = {} |
| 19 | + return await res.text() |
29 | 20 | } |
30 | 21 |
|
31 | | - return node |
32 | | - } |
| 22 | + const promises = [] |
33 | 23 |
|
34 | | - return tree.walk(process) |
35 | | -})() |
| 24 | + try { |
| 25 | + tree.walk(node => { |
| 26 | + if (node?.attrs && ![...targets].some(attr => attr in node.attrs)) { |
| 27 | + for (const attr of targets) { |
| 28 | + node.attrs[attr] = false |
| 29 | + } |
| 30 | + return node |
| 31 | + } |
| 32 | + |
| 33 | + if ( |
| 34 | + node?.tag === 'link' && |
| 35 | + node.attrs?.href && |
| 36 | + node.attrs.rel === 'stylesheet' |
| 37 | + ) { |
| 38 | + const promise = loadFile(node.attrs.href).then(content => { |
| 39 | + node.tag = 'style' |
| 40 | + node.attrs = {} |
| 41 | + node.content = [content] |
| 42 | + }) |
| 43 | + |
| 44 | + promises.push(promise) |
| 45 | + } |
| 46 | + |
| 47 | + return node |
| 48 | + }) |
| 49 | + |
| 50 | + Promise.all(promises) |
| 51 | + .then(() => resolve(tree)) |
| 52 | + .catch(reject) |
| 53 | + } catch (err) { |
| 54 | + reject(err) |
| 55 | + } |
| 56 | + }) |
| 57 | +} |
36 | 58 |
|
37 | | -export default plugin |
| 59 | +export default expandLinkPlugin |
0 commit comments