aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/docs/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/docs/src/plugins')
-rw-r--r--subprojects/docs/src/plugins/remarkPosix2Windows.ts166
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
12import type { Code, Literal } from 'mdast';
13import type { MdxjsEsm, MdxJsxFlowElement } from 'mdast-util-mdx';
14import type { Transformer } from 'unified';
15import type { Node, Parent } from 'unist';
16import { visit } from 'unist-util-visit';
17
18function isLiteral(node: Node): node is Literal {
19 return node.type === 'mdxjsEsm';
20}
21
22function isTabImport(node: Node): boolean {
23 return isLiteral(node) && node.value.includes('@theme/Tabs');
24}
25
26function isParent(node: Node): node is Parent {
27 return 'children' in node && Array.isArray(node.children);
28}
29
30function isCode(node: Node): node is Code {
31 return node.type === 'code';
32}
33
34function isPosix2Windows(node: Node): node is Code {
35 return isCode(node) && node.meta === 'posix2windows';
36}
37
38function 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
69function 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
91function 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
135export 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}