-
Notifications
You must be signed in to change notification settings - Fork 0
/
remark.server.ts
96 lines (84 loc) · 2.64 KB
/
remark.server.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import { visit } from 'unist-util-visit'
import type { Parent } from 'unist'
import { transformSync } from '@babel/core'
// @ts-expect-error no types
import tsPreset from '@babel/preset-typescript'
import { format, type Options as PrettierOptions } from 'prettier'
import type { Transformer } from 'unified'
import type { Code } from 'mdast'
import fs from 'fs'
const isTypescriptCodeBlock = (lang: string) => ['ts', 'tsx', 'typescript'].includes(lang)
const getJavascriptType = (lang: string) => (lang === 'tsx' ? 'jsx' : 'js')
let prettierConfig: PrettierOptions
try {
prettierConfig = JSON.parse(fs.readFileSync('./src/data/.prettierrc', 'utf8')) as PrettierOptions
} catch {
prettierConfig = {
semi: false,
tabWidth: 2,
printWidth: 80,
singleQuote: true,
trailingComma: 'es5',
arrowParens: 'avoid',
proseWrap: 'always',
}
}
export const remarkTypeScriptTransform = (): Transformer => {
const visitor = (node: Code, index: number, parent: Parent) => {
const { lang, value, meta, data, type } = node
if (!lang) {
node.lang = 'text'
return
}
if (!isTypescriptCodeBlock(lang) || meta?.match(/\bnojs\b/)) {
node.meta = meta?.replace(/\bnojs\b/, '')
return
}
const transformedLang = getJavascriptType(lang)
const transformedCode =
transformSync(value, {
filename: `file.${lang === 'tsx' ? 'tsx' : 'ts'}`,
retainLines: true,
presets: [tsPreset],
})?.code ?? ''
const formattedCode = !meta?.match(/\bnoformat\b/i)
? format(transformedCode, { ...prettierConfig, parser: 'babel' }).trim()
: transformedCode
let jsMeta = meta
const hasJsLines = meta?.match(/\bjsLines="(?<lines>[^"]+)"/)
const removeTsLines = !meta?.match(/\bjsKeepLines\b/) || hasJsLines
if (removeTsLines) {
jsMeta = jsMeta?.replace(/{[^}]*}/g, '')
if (hasJsLines) {
const jsLines = hasJsLines.groups?.lines
if (jsLines) {
jsMeta = jsMeta?.replace(hasJsLines[0], '') + ` {${jsLines}}`
}
}
}
const jsNode: Code = {
type,
meta: jsMeta?.trim(),
// meta,
data: data,
lang: transformedLang,
value: formattedCode,
}
node.lang = node.lang === 'tsx' ? 'tsx' : 'ts'
const wrapper = {
type: 'mdxJsxFlowElement',
name: 'TsJsSwitcher',
attributes: [
{
type: 'mdxJsxAttribute',
name: 'data-jsx',
value: (node.lang === 'jsx').toString(),
},
],
children: [node, jsNode],
properties: { a: true },
}
parent.children.splice(index, 1, wrapper)
}
return tree => visit(tree, 'code', visitor)
}