mirror of
https://github.com/tenrok/vue-select.git
synced 2026-06-10 07:52:23 +03:00
docs(slots): generate slot documentation with extra properties
This commit is contained in:
@@ -75,6 +75,11 @@ module.exports = {
|
||||
'@vuepress/plugin-search',
|
||||
'@vuepress/plugin-nprogress',
|
||||
],
|
||||
extraWatchFiles: [
|
||||
'.vuepress/generateApiDocs/**/*.js',
|
||||
'../src/**.*.js',
|
||||
'../src/**.*.vue',
|
||||
],
|
||||
themeConfig: {
|
||||
repo: 'sagalbot/vue-select',
|
||||
editLinks: true,
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
const generator = require('./utils/node/generator');
|
||||
const {green} = require('chalk');
|
||||
|
||||
/**
|
||||
* Dynamically generates all API documentation with vue-docgen-api.
|
||||
* The resulting object can be imported and used client-side via:
|
||||
*
|
||||
* import documentation from '@dynamic/api'
|
||||
*
|
||||
* @return {Promise<{name: string, content: string}>}
|
||||
*/
|
||||
async function clientDynamicModules (sourceDir) {
|
||||
const docs = await generator(sourceDir);
|
||||
|
||||
console.log(green('✅ Generated API documentation for Select.vue'));
|
||||
|
||||
return {
|
||||
name: 'api.js',
|
||||
content: `export default ${JSON.stringify(docs)}`,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = clientDynamicModules;
|
||||
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div>
|
||||
<ul>
|
||||
<li v-for="slot in slots">
|
||||
<h2 :id="slot.name">
|
||||
<a :href="`#${slot.name}`" aria-hidden="true" class="header-anchor">#</a>
|
||||
{{ slot.name }}
|
||||
</h2>
|
||||
<ul v-if="slot.bindings">
|
||||
<li>
|
||||
<h4>Bindings</h4>
|
||||
</li>
|
||||
<li v-for="(key, value) in slot.bindings">
|
||||
<code>{{value}}: {{key}}</code>
|
||||
</li>
|
||||
</ul>
|
||||
<pre><code v-html="slot.rendered"></code></pre>
|
||||
<Content :slot-key="slot.name"></Content>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import docs from "@dynamic/api";
|
||||
import markdown from "../utils/markdown";
|
||||
import highlight from "../utils/highlight";
|
||||
|
||||
export default {
|
||||
name: "ApiSlots",
|
||||
methods: {
|
||||
markdown
|
||||
},
|
||||
computed: {
|
||||
slots() {
|
||||
return docs.slots
|
||||
.map(slot => ({
|
||||
...slot,
|
||||
rendered: highlight(slot.content, "html"),
|
||||
}))
|
||||
.sort((a, b) => a.name > b.name);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped src="../assets/listing.css"></style>
|
||||
@@ -0,0 +1,10 @@
|
||||
const getSlotDefinitions = require('./utils/node/getAdditionalSlotProperties');
|
||||
const generator = require('./utils/node/generator');
|
||||
|
||||
(async () => {
|
||||
|
||||
const component = await generator('/Users/sagalbot/Sites/vue-select/docs');
|
||||
|
||||
debugger;
|
||||
|
||||
})();
|
||||
@@ -1,8 +1,10 @@
|
||||
// import docs from '@dynamic/api.js';
|
||||
import ApiProps from './components/ApiProps';
|
||||
import ApiEvents from './components/ApiEvents';
|
||||
import ApiSlots from './components/ApiSlots';
|
||||
|
||||
export default ({Vue, options, router, siteData}) => {
|
||||
Vue.component('api-props', ApiProps);
|
||||
Vue.component('api-slots', ApiSlots);
|
||||
Vue.component('api-events', ApiEvents);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const generator = require('./generator');
|
||||
const generator = require('./utils/node/generator');
|
||||
|
||||
module.exports = async function (page) {
|
||||
const section = ['props', 'events', 'slots', 'methods'].find(
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
const docs = require('vue-docgen-api');
|
||||
const path = require('path');
|
||||
// const getMemberFilter = require('vue-docgen-api/dist/utils/getMemberFilter.js');
|
||||
const getMemberFilter = require('vue-docgen-api/dist/utils/getPropsFilter');
|
||||
const bt = require('@babel/types');
|
||||
const {NodePath} = require('ast-types');
|
||||
const {Documentation, ParseOptions, ComponentDoc} = require('vue-docgen-api');
|
||||
|
||||
/**
|
||||
* Generate an object of API documentation.
|
||||
* @param documentationRootDir
|
||||
* @return {Promise<ComponentDoc>}
|
||||
*/
|
||||
module.exports = async (documentationRootDir) => {
|
||||
const file = path.resolve(documentationRootDir,
|
||||
'../src/components/Select.vue');
|
||||
return await docs.parse(file, {
|
||||
jsx: false,
|
||||
// addScriptHandlers: [
|
||||
// /**
|
||||
// * @param {Documentation} docs
|
||||
// * @param {NodePath} path
|
||||
// * @param {bt.File} astPath
|
||||
// * @param {ParseOptions} options
|
||||
// * @return {Promise<void>}
|
||||
// */
|
||||
// function (docs, path, astPath, options) {
|
||||
// if (bt.isObjectExpression(path.node)) {
|
||||
// const propsPath = path
|
||||
// .get('properties')
|
||||
// .filter(nodePath => bt.isObjectProperty(nodePath.node) &&
|
||||
// getMemberFilter('props')(nodePath));
|
||||
//
|
||||
//
|
||||
// }
|
||||
// },
|
||||
// ],
|
||||
});
|
||||
};
|
||||
@@ -1,7 +1,6 @@
|
||||
const path = require('path');
|
||||
const chalk = require('chalk');
|
||||
const generator = require('./generator');
|
||||
const extendPageData = require('./extendPageData');
|
||||
const clientDynamicModules = require('./clientDynamicModules');
|
||||
|
||||
/**
|
||||
* @param options
|
||||
@@ -12,22 +11,12 @@ module.exports = (options, {sourceDir}) => ({
|
||||
name: 'vuepress-docgen',
|
||||
|
||||
/**
|
||||
* Dynamically generates all API documentation with vue-docgen-api.
|
||||
* The resulting object can be imported and used client-side via:
|
||||
*
|
||||
* import documentation from '@dynamic/api'
|
||||
* Generates API documentation for use on the client side.
|
||||
*
|
||||
* @see https://vuepress.vuejs.org/plugin/option-api.html#clientdynamicmodules
|
||||
* @return {Promise<{name: string, content: string}>}
|
||||
*/
|
||||
async clientDynamicModules () {
|
||||
const docs = await generator(sourceDir);
|
||||
console.log(chalk.green('✅ Generated API documentation for Select.vue'));
|
||||
return {
|
||||
name: 'api.js',
|
||||
content: `export default ${JSON.stringify(docs)}`,
|
||||
};
|
||||
},
|
||||
clientDynamicModules: async () => await clientDynamicModules(sourceDir),
|
||||
|
||||
/**
|
||||
* @see https://vuepress.vuejs.org/plugin/option-api.html#enhanceappfiles
|
||||
|
||||
@@ -3,6 +3,9 @@ import { highlight, languages } from 'prismjs';
|
||||
/**
|
||||
* Returns code block with prism markup.
|
||||
* @param {String} snippet
|
||||
* @param {String} language
|
||||
* @return {*}
|
||||
*/
|
||||
export default snippet => highlight(snippet, languages.javascript, 'javascript')
|
||||
export default (snippet, language = 'javascript') => {
|
||||
return highlight(snippet, languages[language], language);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
module.exports = class Slots {
|
||||
constructor (slots = {}) {
|
||||
this.slots = slots;
|
||||
}
|
||||
|
||||
add (name, slot) {
|
||||
this.slots[name] = slot;
|
||||
return this;
|
||||
}
|
||||
|
||||
get definitions () {
|
||||
return this.slots;
|
||||
}
|
||||
|
||||
absorb (slots) {
|
||||
this.slots.map()
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
const path = require('path');
|
||||
const bt = require('@babel/types');
|
||||
const docs = require('vue-docgen-api');
|
||||
const {NodePath} = require('ast-types');
|
||||
const {Documentation, ParseOptions, ComponentDoc} = require('vue-docgen-api');
|
||||
const additionalSlotProperties = require('./getAdditionalSlotProperties');
|
||||
|
||||
/**
|
||||
* Generate an object of API documentation.
|
||||
* @param documentationRootDir
|
||||
* @return {Promise<ComponentDoc>}
|
||||
*/
|
||||
module.exports = async (documentationRootDir) => {
|
||||
|
||||
const file = path.resolve(
|
||||
documentationRootDir,
|
||||
'../src/components/Select.vue',
|
||||
);
|
||||
|
||||
const documentation = await docs.parse(file, {
|
||||
jsx: false,
|
||||
addScriptHandlers: [
|
||||
/**
|
||||
* @param {Documentation} docs
|
||||
* @param {NodePath} path
|
||||
* @param {bt.File} astPath
|
||||
* @param {ParseOptions} options
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
function (docs, path, astPath, options) {
|
||||
|
||||
},
|
||||
],
|
||||
addTemplateHandlers: [
|
||||
/**
|
||||
* @param {Documentation} docs
|
||||
* @param {ASTElement} templateAst
|
||||
* @param {TemplateParserOptions} options
|
||||
*/
|
||||
function (docs, templateAst, options) {
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const definitions = additionalSlotProperties(file);
|
||||
|
||||
documentation.slots = documentation.slots.map(slot => ({ ...slot, ...definitions[slot.name] }));
|
||||
|
||||
return documentation;
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const cheerio = require('cheerio');
|
||||
const pick = require('lodash/pick');
|
||||
const prettier = require('prettier');
|
||||
const compiler = require('vue-template-compiler');
|
||||
const Slots = require('./Slots');
|
||||
|
||||
const t = require('@babel/types');
|
||||
const {parse} = require('@babel/parser');
|
||||
const traverse = require('@babel/traverse');
|
||||
|
||||
function pickBindingsFromElement ({attribs}) {
|
||||
return pick(
|
||||
attribs,
|
||||
Object.keys(attribs)
|
||||
.filter(attr => attr.indexOf(':') === 0 || attr === 'v-bind'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pathToComponent
|
||||
* @return {Object}
|
||||
*/
|
||||
function getAdditionalSlotProperties (pathToComponent) {
|
||||
const slots = new Slots();
|
||||
const file = fs.readFileSync(path.resolve(pathToComponent)).toString();
|
||||
const {template} = compiler.parseComponent(file);
|
||||
const $ = cheerio.load(template.content);
|
||||
|
||||
$('slot').each(function (index, element) {
|
||||
const bindings = pickBindingsFromElement(element) || {};
|
||||
const slotName = element.attribs.name || 'default';
|
||||
const content = prettier.format($.html(element), {parser: 'html'});
|
||||
|
||||
slots.add(slotName, {
|
||||
content,
|
||||
bindings,
|
||||
});
|
||||
});
|
||||
|
||||
return slots.definitions;
|
||||
}
|
||||
|
||||
module.exports = getAdditionalSlotProperties;
|
||||
+12
-63
@@ -1,65 +1,14 @@
|
||||
::: tip
|
||||
Vue Select leverages scoped slots to allow for total customization of the presentation layer.
|
||||
Slots can be used to change the look and feel of the UI, or to simply swap out text.
|
||||
---
|
||||
title: API/Slots
|
||||
api: slots
|
||||
---
|
||||
|
||||
# Vue Select Slots
|
||||
|
||||
::: tip Using These Docs
|
||||
The documentation below displays the slots **as they are written in the template**. This lets you
|
||||
see the default implementation as written in the Vue Select component, as well as any bindings that
|
||||
a scoped slot offers.
|
||||
:::
|
||||
|
||||
## Selected Option(s)
|
||||
|
||||
### `selected-option`
|
||||
|
||||
#### Scope:
|
||||
|
||||
- `option {Object}` - A selected option
|
||||
|
||||
```html
|
||||
<slot name="selected-option" v-bind="(typeof option === 'object')?option:{[label]: option}">
|
||||
{{ getOptionLabel(option) }}
|
||||
</slot>
|
||||
```
|
||||
|
||||
### `selected-option-container`
|
||||
|
||||
#### Scope:
|
||||
|
||||
- `option {Object}` - A selected option
|
||||
- `deselect {Function}` - Method used to deselect a given option when `multiple` is true
|
||||
- `disabled {Boolean}` - Determine if the component is disabled
|
||||
- `multiple {Boolean}` - If the component supports the selection of multiple values
|
||||
|
||||
```html
|
||||
<slot v-for="option in valueAsArray" name="selected-option-container"
|
||||
:option="(typeof option === 'object')?option:{[label]: option}" :deselect="deselect" :multiple="multiple" :disabled="disabled">
|
||||
<span class="selected-tag" v-bind:key="option.index">
|
||||
<slot name="selected-option" v-bind="(typeof option === 'object')?option:{[label]: option}">
|
||||
{{ getOptionLabel(option) }}
|
||||
</slot>
|
||||
<button v-if="multiple" :disabled="disabled" @click="deselect(option)" type="button" class="close" aria-label="Remove option">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</span>
|
||||
</slot>
|
||||
```
|
||||
|
||||
## Component Actions
|
||||
|
||||
### `spinner`
|
||||
|
||||
```html
|
||||
<slot name="spinner">
|
||||
<div class="spinner" v-show="mutableLoading">Loading...</div>
|
||||
</slot>
|
||||
```
|
||||
|
||||
## Dropdown
|
||||
|
||||
### `option`
|
||||
|
||||
#### Scope:
|
||||
|
||||
- `option {Object}` - The currently iterated option from `filteredOptions`
|
||||
|
||||
```html
|
||||
<slot name="option" v-bind="(typeof option === 'object')?option:{[label]: option}">
|
||||
{{ getOptionLabel(option) }}
|
||||
</slot>
|
||||
```
|
||||
<api-slots />
|
||||
|
||||
@@ -18,15 +18,19 @@
|
||||
"@vuepress/plugin-search": "^1.2.0",
|
||||
"ast-types": "^0.13.2",
|
||||
"chalk": "^3.0.0",
|
||||
"cheerio": "^1.0.0-rc.3",
|
||||
"cross-env": "^5.2.0",
|
||||
"fuse.js": "^3.4.4",
|
||||
"gh-pages": "^0.11.0",
|
||||
"lodash": "^4.17.15",
|
||||
"markdown-it": "^10.0.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"prettier": "^1.19.1",
|
||||
"prismjs": "^1.17.1",
|
||||
"sass-loader": "^7.1.0",
|
||||
"vue": "^2.6.10",
|
||||
"vue-docgen-api": "^4.0.4",
|
||||
"vue-template-compiler": "^2.6.10",
|
||||
"vuepress": "^1.2.0",
|
||||
"vuex": "^3.1.0"
|
||||
}
|
||||
|
||||
+36
-4
@@ -2020,6 +2020,18 @@ character-parser@^2.1.1:
|
||||
dependencies:
|
||||
is-regex "^1.0.3"
|
||||
|
||||
cheerio@^1.0.0-rc.3:
|
||||
version "1.0.0-rc.3"
|
||||
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.3.tgz#094636d425b2e9c0f4eb91a46c05630c9a1a8bf6"
|
||||
integrity sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==
|
||||
dependencies:
|
||||
css-select "~1.2.0"
|
||||
dom-serializer "~0.1.1"
|
||||
entities "~1.1.1"
|
||||
htmlparser2 "^3.9.1"
|
||||
lodash "^4.15.0"
|
||||
parse5 "^3.0.1"
|
||||
|
||||
chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.1.6:
|
||||
version "2.1.8"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
|
||||
@@ -2518,7 +2530,7 @@ css-select-base-adapter@^0.1.1:
|
||||
resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7"
|
||||
integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==
|
||||
|
||||
css-select@^1.1.0:
|
||||
css-select@^1.1.0, css-select@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858"
|
||||
integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=
|
||||
@@ -2915,6 +2927,14 @@ dom-serializer@0:
|
||||
domelementtype "^2.0.1"
|
||||
entities "^2.0.0"
|
||||
|
||||
dom-serializer@~0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0"
|
||||
integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==
|
||||
dependencies:
|
||||
domelementtype "^1.3.0"
|
||||
entities "^1.1.1"
|
||||
|
||||
dom-walk@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018"
|
||||
@@ -2925,7 +2945,7 @@ domain-browser@^1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
|
||||
integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
|
||||
|
||||
domelementtype@1, domelementtype@^1.3.1:
|
||||
domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
|
||||
integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
|
||||
@@ -3926,7 +3946,7 @@ html-tags@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-2.0.0.tgz#10b30a386085f43cede353cc8fa7cb0deeea668b"
|
||||
integrity sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=
|
||||
|
||||
htmlparser2@^3.3.0:
|
||||
htmlparser2@^3.3.0, htmlparser2@^3.9.1:
|
||||
version "3.10.1"
|
||||
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f"
|
||||
integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==
|
||||
@@ -4779,7 +4799,7 @@ lodash.uniq@^4.5.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
|
||||
|
||||
lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10:
|
||||
lodash@^4.0.0, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10:
|
||||
version "4.17.15"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
||||
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
||||
@@ -5743,6 +5763,13 @@ parse-json@^4.0.0:
|
||||
error-ex "^1.3.1"
|
||||
json-parse-better-errors "^1.0.1"
|
||||
|
||||
parse5@^3.0.1:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
|
||||
integrity sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
parseurl@~1.3.2, parseurl@~1.3.3:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
|
||||
@@ -6248,6 +6275,11 @@ prettier@1.16.3:
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.3.tgz#8c62168453badef702f34b45b6ee899574a6a65d"
|
||||
integrity sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw==
|
||||
|
||||
prettier@^1.19.1:
|
||||
version "1.19.1"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
|
||||
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
|
||||
|
||||
pretty-bytes@^5.1.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2"
|
||||
|
||||
Reference in New Issue
Block a user