@azerion/bunosaurus-remark-plugin-npm2yarn 0.0.0-stage → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +92 -2
- package/example.png +0 -0
- package/lib/index.d.ts +17 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +161 -0
- package/lib/index.js.map +1 -0
- package/package.json +35 -4
- package/src/index.ts +208 -0
package/README.md
CHANGED
|
@@ -1,3 +1,93 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@docusaurus/remark-plugin-npm2yarn`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Motivation:
|
|
4
|
+
|
|
5
|
+
Transforms npm bash command code blocks to Docusaurus tabs:
|
|
6
|
+
|
|
7
|
+
The following (remove the `//`):
|
|
8
|
+
|
|
9
|
+
````bash
|
|
10
|
+
// ```bash npm2yarn
|
|
11
|
+
// npm run build
|
|
12
|
+
// ```
|
|
13
|
+
````
|
|
14
|
+
|
|
15
|
+
Becomes:
|
|
16
|
+
|
|
17
|
+

|
|
18
|
+
|
|
19
|
+
**Note**: it only works when used with Docusaurus themes that have the `Tabs` and `TabItems` components.
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @docusaurus/remark-plugin-npm2yarn
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
It is a Remark plugin, **not a Docusaurus plugin**, so you have to install it as a Remark plugin in the config of your Docusaurus plugins.
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
module.exports = {
|
|
31
|
+
presets: [
|
|
32
|
+
[
|
|
33
|
+
'@docusaurus/preset-classic',
|
|
34
|
+
{
|
|
35
|
+
docs: {
|
|
36
|
+
// ...
|
|
37
|
+
remarkPlugins: [
|
|
38
|
+
[require('@docusaurus/remark-plugin-npm2yarn'), {sync: true}],
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
blog: {
|
|
42
|
+
// ...
|
|
43
|
+
remarkPlugins: [
|
|
44
|
+
[require('@docusaurus/remark-plugin-npm2yarn'), {sync: true}],
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
pages: {
|
|
48
|
+
// ...
|
|
49
|
+
remarkPlugins: [
|
|
50
|
+
[require('@docusaurus/remark-plugin-npm2yarn'), {sync: true}],
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
// ...
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
],
|
|
57
|
+
// ...
|
|
58
|
+
};
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Options
|
|
62
|
+
|
|
63
|
+
| Property | Type | Default | Description |
|
|
64
|
+
| --- | --- | --- | --- |
|
|
65
|
+
| `sync` | `boolean` | `false` | Syncing tab choices (Yarn and npm). See https://docusaurus.io/docs/markdown-features/#syncing-tab-choices for details. |
|
|
66
|
+
| `converters` | `array` | `['yarn', 'pnpm', 'bun']` | The list of converters to use. The order of the converters is important, as the first converter will be used as the default choice. |
|
|
67
|
+
|
|
68
|
+
## Custom converters
|
|
69
|
+
|
|
70
|
+
In case you want to convert npm commands to something else than `yarn`, `pnpm` or `bun`, you can use custom converters:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
type CustomConverter = [name: string, cb: (npmCode: string) => string];
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
{
|
|
78
|
+
remarkPlugins: [
|
|
79
|
+
[
|
|
80
|
+
require('@docusaurus/remark-plugin-npm2yarn'),
|
|
81
|
+
{
|
|
82
|
+
sync: true,
|
|
83
|
+
converters: [
|
|
84
|
+
'yarn',
|
|
85
|
+
'pnpm',
|
|
86
|
+
'bun',
|
|
87
|
+
['Turbo', (code) => code.replace(/npm/g, 'turbo')],
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
];
|
|
92
|
+
}
|
|
93
|
+
```
|
package/example.png
ADDED
|
Binary file
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import type { Plugin } from 'unified';
|
|
8
|
+
type KnownConverter = 'yarn' | 'pnpm' | 'bun';
|
|
9
|
+
type CustomConverter = [name: string, cb: (npmCode: string) => string];
|
|
10
|
+
type Converter = CustomConverter | KnownConverter;
|
|
11
|
+
type PluginOptions = {
|
|
12
|
+
sync?: boolean;
|
|
13
|
+
converters?: Converter[];
|
|
14
|
+
};
|
|
15
|
+
declare const plugin: Plugin<[PluginOptions?]>;
|
|
16
|
+
export default plugin;
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,KAAK,EAAc,MAAM,EAAC,MAAM,SAAS,CAAC;AAEjD,KAAK,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAE9C,KAAK,eAAe,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;AAEvE,KAAK,SAAS,GAAG,eAAe,GAAG,cAAc,CAAC;AAElD,KAAK,aAAa,GAAG;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;CAC1B,CAAC;AAuJF,QAAA,MAAM,MAAM,EAAE,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CA+BpC,CAAC;eAEa,MAAM"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
const tslib_1 = require("tslib");
|
|
10
|
+
const unist_util_visit_1 = require("unist-util-visit");
|
|
11
|
+
const npm_to_yarn_1 = tslib_1.__importDefault(require("npm-to-yarn"));
|
|
12
|
+
function createAttribute(attributeName, attributeValue) {
|
|
13
|
+
return {
|
|
14
|
+
type: 'mdxJsxAttribute',
|
|
15
|
+
name: attributeName,
|
|
16
|
+
value: attributeValue,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function createTabItem({ code, node, value, label, }) {
|
|
20
|
+
return {
|
|
21
|
+
type: 'mdxJsxFlowElement',
|
|
22
|
+
name: 'TabItem',
|
|
23
|
+
attributes: [
|
|
24
|
+
createAttribute('value', value),
|
|
25
|
+
label && createAttribute('label', label),
|
|
26
|
+
].filter((attr) => Boolean(attr)),
|
|
27
|
+
children: [
|
|
28
|
+
{
|
|
29
|
+
type: node.type,
|
|
30
|
+
lang: node.lang,
|
|
31
|
+
value: code,
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const transformNode = (node, isSync, converters) => {
|
|
37
|
+
const groupIdProp = isSync
|
|
38
|
+
? {
|
|
39
|
+
type: 'mdxJsxAttribute',
|
|
40
|
+
name: 'groupId',
|
|
41
|
+
value: 'npm2yarn',
|
|
42
|
+
}
|
|
43
|
+
: undefined;
|
|
44
|
+
const npmCode = node.value;
|
|
45
|
+
function createConvertedTabItem(converter) {
|
|
46
|
+
if (typeof converter === 'string') {
|
|
47
|
+
return createTabItem({
|
|
48
|
+
code: (0, npm_to_yarn_1.default)(npmCode, converter),
|
|
49
|
+
node,
|
|
50
|
+
value: converter,
|
|
51
|
+
label: getLabelForConverter(converter),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
const [converterName, converterFn] = converter;
|
|
55
|
+
return createTabItem({
|
|
56
|
+
code: converterFn(npmCode),
|
|
57
|
+
node,
|
|
58
|
+
value: converterName,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function getLabelForConverter(converter) {
|
|
62
|
+
switch (converter) {
|
|
63
|
+
case 'yarn':
|
|
64
|
+
return 'Yarn';
|
|
65
|
+
case 'bun':
|
|
66
|
+
return 'Bun';
|
|
67
|
+
default:
|
|
68
|
+
return converter;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return [
|
|
72
|
+
{
|
|
73
|
+
type: 'mdxJsxFlowElement',
|
|
74
|
+
name: 'Tabs',
|
|
75
|
+
attributes: [groupIdProp].filter(Boolean),
|
|
76
|
+
children: [
|
|
77
|
+
createTabItem({ code: npmCode, node, value: 'npm' }),
|
|
78
|
+
...converters.flatMap(createConvertedTabItem),
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
];
|
|
82
|
+
};
|
|
83
|
+
const isMdxEsmLiteral = (node) => node.type === 'mdxjsEsm';
|
|
84
|
+
// TODO legacy approximation, good-enough for now but not 100% accurate
|
|
85
|
+
const isTabsImport = (node) => isMdxEsmLiteral(node) && node.value.includes('@theme/Tabs');
|
|
86
|
+
const isParent = (node) => Array.isArray(node.children);
|
|
87
|
+
const isNpm2Yarn = (node) => node.type === 'code' && node.meta === 'npm2yarn';
|
|
88
|
+
function createImportNode() {
|
|
89
|
+
return {
|
|
90
|
+
type: 'mdxjsEsm',
|
|
91
|
+
value: "import Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'",
|
|
92
|
+
data: {
|
|
93
|
+
estree: {
|
|
94
|
+
type: 'Program',
|
|
95
|
+
body: [
|
|
96
|
+
{
|
|
97
|
+
type: 'ImportDeclaration',
|
|
98
|
+
specifiers: [
|
|
99
|
+
{
|
|
100
|
+
type: 'ImportDefaultSpecifier',
|
|
101
|
+
local: { type: 'Identifier', name: 'Tabs' },
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
source: {
|
|
105
|
+
type: 'Literal',
|
|
106
|
+
value: '@theme/Tabs',
|
|
107
|
+
raw: "'@theme/Tabs'",
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
type: 'ImportDeclaration',
|
|
112
|
+
specifiers: [
|
|
113
|
+
{
|
|
114
|
+
type: 'ImportDefaultSpecifier',
|
|
115
|
+
local: { type: 'Identifier', name: 'TabItem' },
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
source: {
|
|
119
|
+
type: 'Literal',
|
|
120
|
+
value: '@theme/TabItem',
|
|
121
|
+
raw: "'@theme/TabItem'",
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
sourceType: 'module',
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
const plugin = (options = {}) => {
|
|
131
|
+
const { sync = false, converters = ['yarn', 'pnpm', 'bun'] } = options;
|
|
132
|
+
return (root) => {
|
|
133
|
+
let transformed = false;
|
|
134
|
+
let alreadyImported = false;
|
|
135
|
+
(0, unist_util_visit_1.visit)(root, (node) => {
|
|
136
|
+
if (isTabsImport(node)) {
|
|
137
|
+
alreadyImported = true;
|
|
138
|
+
}
|
|
139
|
+
if (isParent(node)) {
|
|
140
|
+
let index = 0;
|
|
141
|
+
while (index < node.children.length) {
|
|
142
|
+
const child = node.children[index];
|
|
143
|
+
if (isNpm2Yarn(child)) {
|
|
144
|
+
const result = transformNode(child, sync, converters);
|
|
145
|
+
node.children.splice(index, 1, ...result);
|
|
146
|
+
index += result.length;
|
|
147
|
+
transformed = true;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
index += 1;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
if (transformed && !alreadyImported) {
|
|
156
|
+
root.children.unshift(createImportNode());
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
exports.default = plugin;
|
|
161
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,uDAAuC;AACvC,sEAAoC;AAiBpC,SAAS,eAAe,CACtB,aAAqB,EACrB,cAAwC;IAExC,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,cAAc;KACtB,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,EACrB,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,KAAK,GAMN;IACC,OAAO;QACL,IAAI,EAAE,mBAAmB;QACzB,IAAI,EAAE,SAAS;QACf,UAAU,EAAE;YACV,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC;YAC/B,KAAK,IAAI,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC;SACzC,CAAC,MAAM,CAAC,CAAC,IAAI,EAA2B,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1D,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK,EAAE,IAAI;aACZ;SACF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,aAAa,GAAG,CACpB,IAAU,EACV,MAAe,EACf,UAAuB,EACvB,EAAE;IACF,MAAM,WAAW,GAAG,MAAM;QACxB,CAAC,CAAC;YACE,IAAI,EAAE,iBAAiB;YACvB,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,UAAU;SAClB;QACH,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC;IAE3B,SAAS,sBAAsB,CAAC,SAAoB;QAClD,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;YAClC,OAAO,aAAa,CAAC;gBACnB,IAAI,EAAE,IAAA,qBAAS,EAAC,OAAO,EAAE,SAAS,CAAC;gBACnC,IAAI;gBACJ,KAAK,EAAE,SAAS;gBAChB,KAAK,EAAE,oBAAoB,CAAC,SAAS,CAAC;aACvC,CAAC,CAAC;QACL,CAAC;QACD,MAAM,CAAC,aAAa,EAAE,WAAW,CAAC,GAAG,SAAS,CAAC;QAC/C,OAAO,aAAa,CAAC;YACnB,IAAI,EAAE,WAAW,CAAC,OAAO,CAAC;YAC1B,IAAI;YACJ,KAAK,EAAE,aAAa;SACrB,CAAC,CAAC;IACL,CAAC;IAED,SAAS,oBAAoB,CAAC,SAAyB;QACrD,QAAQ,SAAS,EAAE,CAAC;YAClB,KAAK,MAAM;gBACT,OAAO,MAAM,CAAC;YAChB,KAAK,KAAK;gBACR,OAAO,KAAK,CAAC;YACf;gBACE,OAAO,SAAS,CAAC;QACrB,CAAC;IACH,CAAC;IAED,OAAO;QACL;YACE,IAAI,EAAE,mBAAmB;YACzB,IAAI,EAAE,MAAM;YACZ,UAAU,EAAE,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;YACzC,QAAQ,EAAE;gBACR,aAAa,CAAC,EAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAC,CAAC;gBAClD,GAAG,UAAU,CAAC,OAAO,CAAC,sBAAsB,CAAC;aAC9C;SACF;KACO,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,IAAU,EAAmB,EAAE,CACtD,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC;AAC3B,uEAAuE;AACvE,MAAM,YAAY,GAAG,CAAC,IAAU,EAAW,EAAE,CAC3C,eAAe,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;AAE9D,MAAM,QAAQ,GAAG,CAAC,IAAU,EAAkB,EAAE,CAC9C,KAAK,CAAC,OAAO,CAAE,IAAe,CAAC,QAAQ,CAAC,CAAC;AAC3C,MAAM,UAAU,GAAG,CAAC,IAAU,EAAgB,EAAE,CAC9C,IAAI,CAAC,IAAI,KAAK,MAAM,IAAK,IAAa,CAAC,IAAI,KAAK,UAAU,CAAC;AAE7D,SAAS,gBAAgB;IACvB,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,KAAK,EACH,sEAAsE;QACxE,IAAI,EAAE;YACJ,MAAM,EAAE;gBACN,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE;oBACJ;wBACE,IAAI,EAAE,mBAAmB;wBACzB,UAAU,EAAE;4BACV;gCACE,IAAI,EAAE,wBAAwB;gCAC9B,KAAK,EAAE,EAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAC;6BAC1C;yBACF;wBACD,MAAM,EAAE;4BACN,IAAI,EAAE,SAAS;4BACf,KAAK,EAAE,aAAa;4BACpB,GAAG,EAAE,eAAe;yBACrB;qBACF;oBACD;wBACE,IAAI,EAAE,mBAAmB;wBACzB,UAAU,EAAE;4BACV;gCACE,IAAI,EAAE,wBAAwB;gCAC9B,KAAK,EAAE,EAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAC;6BAC7C;yBACF;wBACD,MAAM,EAAE;4BACN,IAAI,EAAE,SAAS;4BACf,KAAK,EAAE,gBAAgB;4BACvB,GAAG,EAAE,kBAAkB;yBACxB;qBACF;iBACF;gBACD,UAAU,EAAE,QAAQ;aACrB;SACF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,MAAM,GAA6B,CAAC,OAAO,GAAG,EAAE,EAAe,EAAE;IACrE,MAAM,EAAC,IAAI,GAAG,KAAK,EAAE,UAAU,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAC,GAAG,OAAO,CAAC;IACrE,OAAO,CAAC,IAAI,EAAE,EAAE;QACd,IAAI,WAAW,GAAG,KAAK,CAAC;QACxB,IAAI,eAAe,GAAG,KAAK,CAAC;QAE5B,IAAA,wBAAK,EAAC,IAAI,EAAE,CAAC,IAAU,EAAE,EAAE;YACzB,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvB,eAAe,GAAG,IAAI,CAAC;YACzB,CAAC;YAED,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnB,IAAI,KAAK,GAAG,CAAC,CAAC;gBACd,OAAO,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;oBACpC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAE,CAAC;oBACpC,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;wBACtB,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;wBACtD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC;wBAC1C,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC;wBACvB,WAAW,GAAG,IAAI,CAAC;oBACrB,CAAC;yBAAM,CAAC;wBACN,KAAK,IAAI,CAAC,CAAC;oBACb,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,WAAW,IAAI,CAAC,eAAe,EAAE,CAAC;YACnC,IAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;QACxD,CAAC;IACH,CAAC,CAAC;AACJ,CAAC,CAAC;kBAEa,MAAM"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@azerion/bunosaurus-remark-plugin-npm2yarn",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "4.0.0",
|
|
4
|
+
"description": "Remark plugin for converting npm commands to Yarn commands as tabs.",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"watch": "tsc --watch"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/azerion/bunosaurus.git",
|
|
16
|
+
"directory": "packages/docusaurus-remark-plugin-npm2yarn"
|
|
17
|
+
},
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"mdast-util-mdx": "^3.0.0",
|
|
21
|
+
"npm-to-yarn": "^3.2.0",
|
|
22
|
+
"tslib": "^2.8.1",
|
|
23
|
+
"unified": "^11.0.5",
|
|
24
|
+
"unist-util-visit": "^5.1.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/mdast": "^4.0.4",
|
|
28
|
+
"@types/unist": "^3.0.3",
|
|
29
|
+
"dedent": "^1.7.2",
|
|
30
|
+
"remark": "^15.0.1",
|
|
31
|
+
"remark-mdx": "^3.1.1",
|
|
32
|
+
"to-vfile": "^8.0.0"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"bun": ">=1.4.1"
|
|
36
|
+
}
|
|
37
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {visit} from 'unist-util-visit';
|
|
9
|
+
import npmToYarn from 'npm-to-yarn';
|
|
10
|
+
import type {Code, Literal} from 'mdast';
|
|
11
|
+
import type {MdxJsxFlowElement, MdxJsxAttribute} from 'mdast-util-mdx';
|
|
12
|
+
import type {Node, Parent} from 'unist';
|
|
13
|
+
import type {Transformer, Plugin} from 'unified';
|
|
14
|
+
|
|
15
|
+
type KnownConverter = 'yarn' | 'pnpm' | 'bun';
|
|
16
|
+
|
|
17
|
+
type CustomConverter = [name: string, cb: (npmCode: string) => string];
|
|
18
|
+
|
|
19
|
+
type Converter = CustomConverter | KnownConverter;
|
|
20
|
+
|
|
21
|
+
type PluginOptions = {
|
|
22
|
+
sync?: boolean;
|
|
23
|
+
converters?: Converter[];
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function createAttribute(
|
|
27
|
+
attributeName: string,
|
|
28
|
+
attributeValue: MdxJsxAttribute['value'],
|
|
29
|
+
): MdxJsxAttribute {
|
|
30
|
+
return {
|
|
31
|
+
type: 'mdxJsxAttribute',
|
|
32
|
+
name: attributeName,
|
|
33
|
+
value: attributeValue,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function createTabItem({
|
|
38
|
+
code,
|
|
39
|
+
node,
|
|
40
|
+
value,
|
|
41
|
+
label,
|
|
42
|
+
}: {
|
|
43
|
+
code: string;
|
|
44
|
+
node: Code;
|
|
45
|
+
value: string;
|
|
46
|
+
label?: string;
|
|
47
|
+
}): MdxJsxFlowElement {
|
|
48
|
+
return {
|
|
49
|
+
type: 'mdxJsxFlowElement',
|
|
50
|
+
name: 'TabItem',
|
|
51
|
+
attributes: [
|
|
52
|
+
createAttribute('value', value),
|
|
53
|
+
label && createAttribute('label', label),
|
|
54
|
+
].filter((attr): attr is MdxJsxAttribute => Boolean(attr)),
|
|
55
|
+
children: [
|
|
56
|
+
{
|
|
57
|
+
type: node.type,
|
|
58
|
+
lang: node.lang,
|
|
59
|
+
value: code,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const transformNode = (
|
|
66
|
+
node: Code,
|
|
67
|
+
isSync: boolean,
|
|
68
|
+
converters: Converter[],
|
|
69
|
+
) => {
|
|
70
|
+
const groupIdProp = isSync
|
|
71
|
+
? {
|
|
72
|
+
type: 'mdxJsxAttribute',
|
|
73
|
+
name: 'groupId',
|
|
74
|
+
value: 'npm2yarn',
|
|
75
|
+
}
|
|
76
|
+
: undefined;
|
|
77
|
+
const npmCode = node.value;
|
|
78
|
+
|
|
79
|
+
function createConvertedTabItem(converter: Converter) {
|
|
80
|
+
if (typeof converter === 'string') {
|
|
81
|
+
return createTabItem({
|
|
82
|
+
code: npmToYarn(npmCode, converter),
|
|
83
|
+
node,
|
|
84
|
+
value: converter,
|
|
85
|
+
label: getLabelForConverter(converter),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
const [converterName, converterFn] = converter;
|
|
89
|
+
return createTabItem({
|
|
90
|
+
code: converterFn(npmCode),
|
|
91
|
+
node,
|
|
92
|
+
value: converterName,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function getLabelForConverter(converter: KnownConverter) {
|
|
97
|
+
switch (converter) {
|
|
98
|
+
case 'yarn':
|
|
99
|
+
return 'Yarn';
|
|
100
|
+
case 'bun':
|
|
101
|
+
return 'Bun';
|
|
102
|
+
default:
|
|
103
|
+
return converter;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return [
|
|
108
|
+
{
|
|
109
|
+
type: 'mdxJsxFlowElement',
|
|
110
|
+
name: 'Tabs',
|
|
111
|
+
attributes: [groupIdProp].filter(Boolean),
|
|
112
|
+
children: [
|
|
113
|
+
createTabItem({code: npmCode, node, value: 'npm'}),
|
|
114
|
+
...converters.flatMap(createConvertedTabItem),
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
] as any[];
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const isMdxEsmLiteral = (node: Node): node is Literal =>
|
|
121
|
+
node.type === 'mdxjsEsm';
|
|
122
|
+
// TODO legacy approximation, good-enough for now but not 100% accurate
|
|
123
|
+
const isTabsImport = (node: Node): boolean =>
|
|
124
|
+
isMdxEsmLiteral(node) && node.value.includes('@theme/Tabs');
|
|
125
|
+
|
|
126
|
+
const isParent = (node: Node): node is Parent =>
|
|
127
|
+
Array.isArray((node as Parent).children);
|
|
128
|
+
const isNpm2Yarn = (node: Node): node is Code =>
|
|
129
|
+
node.type === 'code' && (node as Code).meta === 'npm2yarn';
|
|
130
|
+
|
|
131
|
+
function createImportNode() {
|
|
132
|
+
return {
|
|
133
|
+
type: 'mdxjsEsm',
|
|
134
|
+
value:
|
|
135
|
+
"import Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'",
|
|
136
|
+
data: {
|
|
137
|
+
estree: {
|
|
138
|
+
type: 'Program',
|
|
139
|
+
body: [
|
|
140
|
+
{
|
|
141
|
+
type: 'ImportDeclaration',
|
|
142
|
+
specifiers: [
|
|
143
|
+
{
|
|
144
|
+
type: 'ImportDefaultSpecifier',
|
|
145
|
+
local: {type: 'Identifier', name: 'Tabs'},
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
source: {
|
|
149
|
+
type: 'Literal',
|
|
150
|
+
value: '@theme/Tabs',
|
|
151
|
+
raw: "'@theme/Tabs'",
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
type: 'ImportDeclaration',
|
|
156
|
+
specifiers: [
|
|
157
|
+
{
|
|
158
|
+
type: 'ImportDefaultSpecifier',
|
|
159
|
+
local: {type: 'Identifier', name: 'TabItem'},
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
source: {
|
|
163
|
+
type: 'Literal',
|
|
164
|
+
value: '@theme/TabItem',
|
|
165
|
+
raw: "'@theme/TabItem'",
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
sourceType: 'module',
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const plugin: Plugin<[PluginOptions?]> = (options = {}): Transformer => {
|
|
176
|
+
const {sync = false, converters = ['yarn', 'pnpm', 'bun']} = options;
|
|
177
|
+
return (root) => {
|
|
178
|
+
let transformed = false;
|
|
179
|
+
let alreadyImported = false;
|
|
180
|
+
|
|
181
|
+
visit(root, (node: Node) => {
|
|
182
|
+
if (isTabsImport(node)) {
|
|
183
|
+
alreadyImported = true;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (isParent(node)) {
|
|
187
|
+
let index = 0;
|
|
188
|
+
while (index < node.children.length) {
|
|
189
|
+
const child = node.children[index]!;
|
|
190
|
+
if (isNpm2Yarn(child)) {
|
|
191
|
+
const result = transformNode(child, sync, converters);
|
|
192
|
+
node.children.splice(index, 1, ...result);
|
|
193
|
+
index += result.length;
|
|
194
|
+
transformed = true;
|
|
195
|
+
} else {
|
|
196
|
+
index += 1;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
if (transformed && !alreadyImported) {
|
|
203
|
+
(root as Parent).children.unshift(createImportNode());
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
export default plugin;
|