diff options
Diffstat (limited to 'subprojects/docs/src/plugins')
-rw-r--r-- | subprojects/docs/src/plugins/remarkPosix2Windows.ts | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/subprojects/docs/src/plugins/remarkPosix2Windows.ts b/subprojects/docs/src/plugins/remarkPosix2Windows.ts new file mode 100644 index 00000000..66baca30 --- /dev/null +++ b/subprojects/docs/src/plugins/remarkPosix2Windows.ts | |||
@@ -0,0 +1,166 @@ | |||
1 | /* | ||
2 | * Copyright (c) Facebook, Inc. and its affiliates. | ||
3 | * Copyright (c) 2024 The Refinery Authors | ||
4 | * | ||
5 | * SPDX-License-Identifier: EPL-2.0 | ||
6 | * | ||
7 | * This file is based on | ||
8 | * https://github.com/facebook/docusaurus/blob/e4ecffe41878728acff55a8370bd7440706c02f7/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts | ||
9 | * but was changed to conver shell commands to POSIX to Windows syntax. | ||
10 | */ | ||
11 | |||
12 | import type { Code, Literal } from 'mdast'; | ||
13 | import type { MdxjsEsm, MdxJsxFlowElement } from 'mdast-util-mdx'; | ||
14 | import type { Transformer } from 'unified'; | ||
15 | import type { Node, Parent } from 'unist'; | ||
16 | import { visit } from 'unist-util-visit'; | ||
17 | |||
18 | function isLiteral(node: Node): node is Literal { | ||
19 | return node.type === 'mdxjsEsm'; | ||
20 | } | ||
21 | |||
22 | function isTabImport(node: Node): boolean { | ||
23 | return isLiteral(node) && node.value.includes('@theme/Tabs'); | ||
24 | } | ||
25 | |||
26 | function isParent(node: Node): node is Parent { | ||
27 | return 'children' in node && Array.isArray(node.children); | ||
28 | } | ||
29 | |||
30 | function isCode(node: Node): node is Code { | ||
31 | return node.type === 'code'; | ||
32 | } | ||
33 | |||
34 | function isPosix2Windows(node: Node): node is Code { | ||
35 | return isCode(node) && node.meta === 'posix2windows'; | ||
36 | } | ||
37 | |||
38 | function createTabItem( | ||
39 | code: string, | ||
40 | node: Code, | ||
41 | value: string, | ||
42 | label: string, | ||
43 | ): MdxJsxFlowElement { | ||
44 | return { | ||
45 | type: 'mdxJsxFlowElement', | ||
46 | name: 'TabItem', | ||
47 | attributes: [ | ||
48 | { | ||
49 | type: 'mdxJsxAttribute', | ||
50 | name: 'value', | ||
51 | value, | ||
52 | }, | ||
53 | { | ||
54 | type: 'mdxJsxAttribute', | ||
55 | name: 'label', | ||
56 | value: label, | ||
57 | }, | ||
58 | ], | ||
59 | children: [ | ||
60 | { | ||
61 | type: node.type, | ||
62 | lang: node.lang, | ||
63 | value: code, | ||
64 | }, | ||
65 | ], | ||
66 | }; | ||
67 | } | ||
68 | |||
69 | function transformNode(node: Code): MdxJsxFlowElement[] { | ||
70 | const posixCode = node.value; | ||
71 | const windowsCode = posixCode.replaceAll(/(?<=^\w*)\.\//gm, '.\\'); | ||
72 | return [ | ||
73 | { | ||
74 | type: 'mdxJsxFlowElement', | ||
75 | name: 'Tabs', | ||
76 | attributes: [ | ||
77 | { | ||
78 | type: 'mdxJsxAttribute', | ||
79 | name: 'groupId', | ||
80 | value: 'posix2windows', | ||
81 | }, | ||
82 | ], | ||
83 | children: [ | ||
84 | createTabItem(posixCode, node, 'posix', 'Linux or macOS'), | ||
85 | createTabItem(windowsCode, node, 'windows', 'Windows (PowerShell)'), | ||
86 | ], | ||
87 | }, | ||
88 | ]; | ||
89 | } | ||
90 | |||
91 | function createImportNode(): MdxjsEsm { | ||
92 | return { | ||
93 | type: 'mdxjsEsm', | ||
94 | value: | ||
95 | "import Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'", | ||
96 | data: { | ||
97 | estree: { | ||
98 | type: 'Program', | ||
99 | body: [ | ||
100 | { | ||
101 | type: 'ImportDeclaration', | ||
102 | specifiers: [ | ||
103 | { | ||
104 | type: 'ImportDefaultSpecifier', | ||
105 | local: { type: 'Identifier', name: 'Tabs' }, | ||
106 | }, | ||
107 | ], | ||
108 | source: { | ||
109 | type: 'Literal', | ||
110 | value: '@theme/Tabs', | ||
111 | raw: "'@theme/Tabs'", | ||
112 | }, | ||
113 | }, | ||
114 | { | ||
115 | type: 'ImportDeclaration', | ||
116 | specifiers: [ | ||
117 | { | ||
118 | type: 'ImportDefaultSpecifier', | ||
119 | local: { type: 'Identifier', name: 'TabItem' }, | ||
120 | }, | ||
121 | ], | ||
122 | source: { | ||
123 | type: 'Literal', | ||
124 | value: '@theme/TabItem', | ||
125 | raw: "'@theme/TabItem'", | ||
126 | }, | ||
127 | }, | ||
128 | ], | ||
129 | sourceType: 'module', | ||
130 | }, | ||
131 | }, | ||
132 | }; | ||
133 | } | ||
134 | |||
135 | export default function remarkPosix2Windows(): Transformer { | ||
136 | return (root) => { | ||
137 | let transformed = false; | ||
138 | let alreadyImported = false; | ||
139 | visit(root, (node) => { | ||
140 | if (isTabImport(node)) { | ||
141 | alreadyImported = true; | ||
142 | } | ||
143 | if (isParent(node)) { | ||
144 | let index = 0; | ||
145 | while (index < node.children.length) { | ||
146 | const child = node.children[index]; | ||
147 | if (child !== undefined && isPosix2Windows(child)) { | ||
148 | const result = transformNode(child); | ||
149 | node.children.splice(index, 1, ...result); | ||
150 | index += result.length; | ||
151 | transformed = true; | ||
152 | } else { | ||
153 | index += 1; | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | }); | ||
158 | if (transformed && !alreadyImported) { | ||
159 | if (isParent(root)) { | ||
160 | root.children.unshift(createImportNode()); | ||
161 | } else { | ||
162 | throw new Error("Cannot import '@theme/Tabs'"); | ||
163 | } | ||
164 | } | ||
165 | }; | ||
166 | } | ||