├── site ├── static │ ├── .nojekyll │ ├── example2.png │ ├── img │ │ ├── Saly-38.png │ │ ├── Saly-39.png │ │ ├── Saly-40.png │ │ ├── Saly-42.png │ │ ├── Saly-43.png │ │ ├── Saly-44.png │ │ ├── favicon.ico │ │ ├── docusaurus.png │ │ ├── logo.svg │ │ ├── undraw_docusaurus_tree.svg │ │ ├── undraw_docusaurus_mountain.svg │ │ └── undraw_docusaurus_react.svg │ ├── example-alias.png │ ├── example-list.png │ ├── example-runner.png │ ├── example-yarn.png │ ├── example-at-first.png │ ├── example-at-then.png │ ├── example-separate.png │ ├── example-simplified.png │ ├── example-at-then-yarn.png │ └── example-separate-final.png ├── docs │ ├── getting-started │ │ ├── _category_.json │ │ ├── separate-configuration.md │ │ ├── simplify-package-json.md │ │ ├── installation.md │ │ └── add-emoji-and-description.md │ ├── intro.md │ └── configuration.md ├── .example-docs │ ├── tutorial-extras │ │ ├── img │ │ │ ├── localeDropdown.png │ │ │ └── docsVersionDropdown.png │ │ ├── _category_.json │ │ ├── manage-docs-versions.md │ │ └── translate-your-site.md │ └── tutorial-basics │ │ ├── _category_.json │ │ ├── deploy-your-site.md │ │ ├── congratulations.md │ │ ├── create-a-blog-post.md │ │ ├── create-a-page.md │ │ ├── create-a-document.md │ │ └── markdown-features.mdx ├── babel.config.js ├── src │ ├── pages │ │ ├── markdown-page.md │ │ ├── index.module.css │ │ └── index.js │ ├── components │ │ ├── HomepageFeatures │ │ │ ├── styles.module.css │ │ │ └── index.js │ │ └── components.js │ └── css │ │ └── custom.css ├── .example-blog │ ├── 2021-08-26-welcome │ │ ├── docusaurus-plushie-banner.jpeg │ │ └── index.md │ ├── 2019-05-28-first-blog-post.md │ ├── authors.yml │ ├── 2021-08-01-mdx-blog-post.mdx │ └── 2019-05-29-long-blog-post.md ├── .gitignore ├── sidebars.js ├── README.md ├── package.json └── docusaurus.config.js ├── jsconfig.json ├── static ├── logo.png ├── example.png ├── example2.png ├── logo-square.png ├── example-alias.png ├── example-yarn.png ├── example-at-first.png └── contributors │ ├── Garker.svg │ ├── annoyc.svg │ └── iamyoki.svg ├── lib ├── getPkg.js ├── errorHandler.js ├── getUserPkg.js ├── getScriptByName.js ├── execSync.js ├── types.d.ts ├── commands │ ├── runCommand.js │ ├── listCommand.js │ └── defaultCommand.js ├── runScript.js ├── getUserConfig.js ├── parseUserConfig.js └── schema.json ├── scripts ├── utils │ ├── getImageBase64.js │ ├── getContributors.js │ └── writeContributorsAvatar.js ├── generate-jsonschema.js ├── sort-scripts-config.js └── generate-md-contributors.js ├── scripts.json ├── TODO.md ├── package.json ├── bin └── better-scripts.js ├── .gitignore └── README.md /site/static/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": ["node_modules", "dist"] 3 | } 4 | -------------------------------------------------------------------------------- /static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/static/logo.png -------------------------------------------------------------------------------- /static/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/static/example.png -------------------------------------------------------------------------------- /static/example2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/static/example2.png -------------------------------------------------------------------------------- /static/logo-square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/static/logo-square.png -------------------------------------------------------------------------------- /site/static/example2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/example2.png -------------------------------------------------------------------------------- /static/example-alias.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/static/example-alias.png -------------------------------------------------------------------------------- /static/example-yarn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/static/example-yarn.png -------------------------------------------------------------------------------- /site/static/img/Saly-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/img/Saly-38.png -------------------------------------------------------------------------------- /site/static/img/Saly-39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/img/Saly-39.png -------------------------------------------------------------------------------- /site/static/img/Saly-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/img/Saly-40.png -------------------------------------------------------------------------------- /site/static/img/Saly-42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/img/Saly-42.png -------------------------------------------------------------------------------- /site/static/img/Saly-43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/img/Saly-43.png -------------------------------------------------------------------------------- /site/static/img/Saly-44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/img/Saly-44.png -------------------------------------------------------------------------------- /site/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/img/favicon.ico -------------------------------------------------------------------------------- /static/example-at-first.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/static/example-at-first.png -------------------------------------------------------------------------------- /site/static/example-alias.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/example-alias.png -------------------------------------------------------------------------------- /site/static/example-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/example-list.png -------------------------------------------------------------------------------- /site/static/example-runner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/example-runner.png -------------------------------------------------------------------------------- /site/static/example-yarn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/example-yarn.png -------------------------------------------------------------------------------- /site/static/img/docusaurus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/img/docusaurus.png -------------------------------------------------------------------------------- /site/static/example-at-first.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/example-at-first.png -------------------------------------------------------------------------------- /site/static/example-at-then.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/example-at-then.png -------------------------------------------------------------------------------- /site/static/example-separate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/example-separate.png -------------------------------------------------------------------------------- /site/static/example-simplified.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/example-simplified.png -------------------------------------------------------------------------------- /site/static/example-at-then-yarn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/example-at-then-yarn.png -------------------------------------------------------------------------------- /site/static/example-separate-final.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/static/example-separate-final.png -------------------------------------------------------------------------------- /site/docs/getting-started/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Getting Started", 3 | "position": 2, 4 | "link": { 5 | "type": "generated-index" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /site/.example-docs/tutorial-extras/img/localeDropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/.example-docs/tutorial-extras/img/localeDropdown.png -------------------------------------------------------------------------------- /site/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | require.resolve('@docusaurus/core/lib/babel/preset'), 4 | '@emotion/babel-preset-css-prop' 5 | ] 6 | }; 7 | -------------------------------------------------------------------------------- /site/src/pages/markdown-page.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown page example 3 | --- 4 | 5 | # Markdown page example 6 | 7 | You don't need React to write simple standalone pages. 8 | -------------------------------------------------------------------------------- /site/.example-docs/tutorial-extras/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Tutorial - Extras", 3 | // "position": 3, 4 | "link": { 5 | "type": "generated-index" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /site/.example-docs/tutorial-extras/img/docsVersionDropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/.example-docs/tutorial-extras/img/docsVersionDropdown.png -------------------------------------------------------------------------------- /site/.example-blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamyoki/better-scripts/HEAD/site/.example-blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg -------------------------------------------------------------------------------- /site/src/components/HomepageFeatures/styles.module.css: -------------------------------------------------------------------------------- 1 | .features { 2 | display: flex; 3 | align-items: center; 4 | padding: 2rem 0; 5 | width: 100%; 6 | } 7 | 8 | .featureSvg { 9 | height: 200px; 10 | width: 200px; 11 | } 12 | -------------------------------------------------------------------------------- /lib/getPkg.js: -------------------------------------------------------------------------------- 1 | import {createRequire} from 'node:module'; 2 | 3 | // Get internal source package.json 4 | export function getPkg() { 5 | const require = createRequire(import.meta.url); 6 | const pkg = require('../package.json'); 7 | return pkg; 8 | } 9 | -------------------------------------------------------------------------------- /site/.example-docs/tutorial-basics/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Tutorial - Basics", 3 | // "position": 2, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "5 minutes to learn the most important Docusaurus concepts." 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lib/errorHandler.js: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | 3 | export function errorHandler(err) { 4 | console.error(chalk.bgRed.bold(err.name)); 5 | console.error(chalk.red(err.message)); 6 | if (process.env.TRACK_ERROR === 'true') console.error(chalk.red(err.stack)); 7 | process.exit(1); 8 | } 9 | -------------------------------------------------------------------------------- /site/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /lib/getUserPkg.js: -------------------------------------------------------------------------------- 1 | import {createRequire} from 'node:module'; 2 | import {pathToFileURL} from 'node:url'; 3 | import {packageDirectorySync} from 'pkg-dir'; 4 | 5 | export function getUserPkg() { 6 | const pkgDir = packageDirectorySync(); 7 | const filePath = pathToFileURL(pkgDir).toString(); 8 | const require = createRequire(filePath + '/package.json'); 9 | const pkg = require('./package.json'); 10 | return pkg; 11 | } 12 | -------------------------------------------------------------------------------- /site/.example-blog/2019-05-28-first-blog-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: first-blog-post 3 | title: First Blog Post 4 | authors: 5 | name: Gao Wei 6 | title: Docusaurus Core Team 7 | url: https://github.com/wgao19 8 | image_url: https://github.com/wgao19.png 9 | tags: [hola, docusaurus] 10 | --- 11 | 12 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 13 | -------------------------------------------------------------------------------- /scripts/utils/getImageBase64.js: -------------------------------------------------------------------------------- 1 | import https from 'node:https'; 2 | 3 | export function getImageBase64(url) { 4 | return new Promise(resolve => { 5 | https.get(url, res => { 6 | let data = ''; 7 | 8 | res.setEncoding('base64'); 9 | 10 | res.on('data', chunk => { 11 | data += chunk; 12 | }); 13 | 14 | res.on('end', () => { 15 | resolve(`data:${res.headers['content-type']};base64,${data}`); 16 | }); 17 | }); 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /site/.example-blog/authors.yml: -------------------------------------------------------------------------------- 1 | endi: 2 | name: Endilie Yacop Sucipto 3 | title: Maintainer of Docusaurus 4 | url: https://github.com/endiliey 5 | image_url: https://github.com/endiliey.png 6 | 7 | yangshun: 8 | name: Yangshun Tay 9 | title: Front End Engineer @ Facebook 10 | url: https://github.com/yangshun 11 | image_url: https://github.com/yangshun.png 12 | 13 | slorber: 14 | name: Sébastien Lorber 15 | title: Docusaurus maintainer 16 | url: https://sebastienlorber.com 17 | image_url: https://github.com/slorber.png 18 | -------------------------------------------------------------------------------- /lib/getScriptByName.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {import('./types').ParsedUserConfig} parsedUserConfig 3 | * @param {string} name 4 | * @returns {import('./types').Script} 5 | */ 6 | export function getScriptByName(parsedUserConfig, name) { 7 | const keys = name.split('.'); 8 | 9 | return keys.reduce( 10 | (prev, key) => { 11 | if (!prev.scripts[key]) { 12 | throw new Error(`Cannot find "${key}" script in config`); 13 | } 14 | return prev.scripts[key]; 15 | }, 16 | {scripts: parsedUserConfig} 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /site/src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | /** 2 | * CSS files with the .module.css suffix will be treated as CSS modules 3 | * and scoped locally. 4 | */ 5 | 6 | .heroBanner { 7 | padding: 4rem 0; 8 | text-align: center; 9 | position: relative; 10 | overflow: hidden; 11 | /* background-color: rgba(0, 0, 0, .9); 12 | color: white; */ 13 | } 14 | 15 | @media screen and (max-width: 996px) { 16 | .heroBanner { 17 | padding: 2rem; 18 | } 19 | } 20 | 21 | .buttons { 22 | display: flex; 23 | align-items: center; 24 | justify-content: center; 25 | } 26 | -------------------------------------------------------------------------------- /site/.example-blog/2021-08-01-mdx-blog-post.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | slug: mdx-blog-post 3 | title: MDX Blog Post 4 | authors: [slorber] 5 | tags: [docusaurus] 6 | --- 7 | 8 | Blog posts support [Docusaurus Markdown features](https://docusaurus.io/docs/markdown-features), such as [MDX](https://mdxjs.com/). 9 | 10 | :::tip 11 | 12 | Use the power of React to create interactive blog posts. 13 | 14 | ```js 15 | 16 | ``` 17 | 18 | 19 | 20 | ::: 21 | -------------------------------------------------------------------------------- /lib/execSync.js: -------------------------------------------------------------------------------- 1 | import child_process from 'node:child_process'; 2 | import {arch} from 'node:os'; 3 | 4 | const isPlatform32 = 5 | process.platform === 'win32' || ['ia32', 'x64'].includes(arch()); 6 | 7 | /** 8 | * @param {string} command 9 | * @param {child_process.SpawnSyncOptionsWithStringEncoding} options 10 | * */ 11 | export function execSync(command, options) { 12 | if (!command) return; 13 | 14 | child_process.spawnSync(command.split(' ')[0], command.split(' ').slice(1), { 15 | stdio: 'inherit', 16 | shell: isPlatform32, 17 | ...options 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /scripts.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./lib/schema.json", 3 | "generate-contributors": { 4 | "alias": "📄 Generate Contributors", 5 | "command": "node scripts/generate-md-contributors.js", 6 | "desc": "Generate contributors in README.md" 7 | }, 8 | "generate-schema": { 9 | "alias": "📄 Generate Schema", 10 | "command": "node scripts/generate-jsonschema.js", 11 | "desc": "Generate json schema file" 12 | }, 13 | "sort-config": { 14 | "alias": "🔮 Sort Config", 15 | "command": "node scripts/sort-scripts-config.js", 16 | "desc": "Sort and format scripts config" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /site/docs/getting-started/separate-configuration.md: -------------------------------------------------------------------------------- 1 | # 📄 Separate configuration 2 | 3 | ## Create a configuration 4 | 5 | Creata a `scripts.json` file at the root of your project directory. 6 | 7 | > [See all supported configuration file fomats](/) 8 | 9 | ```json title="scripts.json" 10 | { 11 | "dev": { 12 | "alias": "🌟 Dev", 13 | "command": "yarn start", 14 | "desc": "Start a development server" 15 | }, 16 | "build": { 17 | "alias": "📦 Build", 18 | "command": "yarn build", 19 | "desc": "Create a production build" 20 | }, 21 | "test": { 22 | "alias": "🧪 Test", 23 | "command": "yarn test", 24 | "desc": "Run tests" 25 | } 26 | } 27 | ``` 28 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # TODO 2 | 3 | ## Features 4 | 5 | - ~~Add pre and post~~ 6 | - ~~Prev and Post support env scripts ...~~ 7 | - ~~Add env~~ 8 | - Add `init` command 9 | - Ask user whether use magic to move current scripts to config 10 | - Ask user where to place the config scripts: package.json ? or scripts.json ? 11 | - Do the magic 12 | - Select multiple scripts 13 | - run sequentially 14 | - run parallel 15 | - yarn scripts run "builds.cjs" "builds.esm" 16 | - sequentially by default 17 | - yarn scripts run "builds.cjs" "builds.esm" -p 18 | - add a -p or --parallel flag to run in parallel mode 19 | 20 | ## Bugs 21 | 22 | - ~~`.better-scriptsrc` not working~~ 23 | 24 | - ~~scripts in prescript doesn't working~~ 25 | -------------------------------------------------------------------------------- /scripts/generate-jsonschema.js: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | import {writeFileSync} from 'node:fs'; 3 | import path from 'node:path'; 4 | import {fileURLToPath} from 'node:url'; 5 | import * as TJS from 'typescript-json-schema'; 6 | 7 | const __filename = fileURLToPath(import.meta.url); 8 | const __dirname = path.dirname(__filename); 9 | 10 | const program = TJS.getProgramFromFiles([ 11 | path.resolve(__dirname, '../lib/types.d.ts') 12 | ]); 13 | 14 | const schema = TJS.generateSchema(program, 'UserConfig', {required: true}); 15 | 16 | const filename = path.join(__dirname, '../lib', 'schema.json') 17 | 18 | writeFileSync(filename, JSON.stringify(schema, null, 2)); 19 | 20 | console.log(chalk.green('📄 Schema file generated:'), chalk.bgGreen(`${filename}`)) 21 | -------------------------------------------------------------------------------- /site/sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating a sidebar enables you to: 3 | - create an ordered group of docs 4 | - render a sidebar for each doc of that group 5 | - provide next/previous navigation 6 | 7 | The sidebars can be generated from the filesystem, or explicitly defined here. 8 | 9 | Create as many sidebars as you want. 10 | */ 11 | 12 | // @ts-check 13 | 14 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 15 | const sidebars = { 16 | // By default, Docusaurus generates a sidebar from the docs folder structure 17 | tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], 18 | 19 | // But you can create a sidebar manually 20 | /* 21 | tutorialSidebar: [ 22 | { 23 | type: 'category', 24 | label: 'Tutorial', 25 | items: ['hello'], 26 | }, 27 | ], 28 | */ 29 | }; 30 | 31 | module.exports = sidebars; 32 | -------------------------------------------------------------------------------- /lib/types.d.ts: -------------------------------------------------------------------------------- 1 | export type Valueof = T[keyof T]; 2 | 3 | export interface Script { 4 | name: string; 5 | alias?: string; 6 | command?: string; 7 | desc?: string; 8 | scripts?: {[key: string]: Script}; 9 | prescript?: Script; 10 | postscript?: Script; 11 | env?: { 12 | [key: string]: string; 13 | }; 14 | } 15 | 16 | export interface UserConfig { 17 | [key: string]: 18 | | string 19 | | [string, string] 20 | | { 21 | alias?: string; 22 | command?: string; 23 | desc?: string; 24 | description?: string; 25 | describe?: string; 26 | scripts?: UserConfig; 27 | prescript?: Valueof; 28 | postscript?: Valueof; 29 | env?: { 30 | [key: string]: string; 31 | }; 32 | }; 33 | } 34 | 35 | export type ParsedUserConfig = Script['scripts']; 36 | -------------------------------------------------------------------------------- /site/.example-docs/tutorial-basics/deploy-your-site.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 5 3 | --- 4 | 5 | # Deploy your site 6 | 7 | Docusaurus is a **static-site-generator** (also called **[Jamstack](https://jamstack.org/)**). 8 | 9 | It builds your site as simple **static HTML, JavaScript and CSS files**. 10 | 11 | ## Build your site 12 | 13 | Build your site **for production**: 14 | 15 | ```bash 16 | npm run build 17 | ``` 18 | 19 | The static files are generated in the `build` folder. 20 | 21 | ## Deploy your site 22 | 23 | Test your production build locally: 24 | 25 | ```bash 26 | npm run serve 27 | ``` 28 | 29 | The `build` folder is now served at [http://localhost:3000/](http://localhost:3000/). 30 | 31 | You can now deploy the `build` folder **almost anywhere** easily, **for free** or very small cost (read the **[Deployment Guide](https://docusaurus.io/docs/deployment)**). 32 | -------------------------------------------------------------------------------- /site/.example-blog/2021-08-26-welcome/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: welcome 3 | title: Welcome 4 | authors: [slorber, yangshun] 5 | tags: [facebook, hello, docusaurus] 6 | --- 7 | 8 | [Docusaurus blogging features](https://docusaurus.io/docs/blog) are powered by the [blog plugin](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog). 9 | 10 | Simply add Markdown files (or folders) to the `blog` directory. 11 | 12 | Regular blog authors can be added to `authors.yml`. 13 | 14 | The blog post date can be extracted from filenames, such as: 15 | 16 | - `2019-05-30-welcome.md` 17 | - `2019-05-30-welcome/index.md` 18 | 19 | A blog post folder can be convenient to co-locate blog post images: 20 | 21 | ![Docusaurus Plushie](./docusaurus-plushie-banner.jpeg) 22 | 23 | The blog supports tags as well! 24 | 25 | **And if you don't want a blog**: just delete this directory, and use `blog: false` in your Docusaurus config. 26 | -------------------------------------------------------------------------------- /site/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. 4 | 5 | ### Installation 6 | 7 | ``` 8 | $ yarn 9 | ``` 10 | 11 | ### Local Development 12 | 13 | ``` 14 | $ yarn start 15 | ``` 16 | 17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ### Build 20 | 21 | ``` 22 | $ yarn build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | 27 | ### Deployment 28 | 29 | Using SSH: 30 | 31 | ``` 32 | $ USE_SSH=true yarn deploy 33 | ``` 34 | 35 | Not using SSH: 36 | 37 | ``` 38 | $ GIT_USER= yarn deploy 39 | ``` 40 | 41 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 42 | -------------------------------------------------------------------------------- /lib/commands/runCommand.js: -------------------------------------------------------------------------------- 1 | import {getScriptByName} from '../getScriptByName.js'; 2 | import {getUserConfig} from '../getUserConfig.js'; 3 | import {parseUserConfig} from '../parseUserConfig.js'; 4 | import {runScript} from '../runScript.js'; 5 | 6 | export async function runCommand(argv) { 7 | const {config: configPath, name, skip} = argv; 8 | 9 | const userConfig = await getUserConfig(configPath); 10 | const parsedUserConfig = parseUserConfig(userConfig); 11 | 12 | const script = getScriptByName(parsedUserConfig, name); 13 | 14 | if (skip) { 15 | runScript(script); 16 | } else { 17 | const keys = name.split('.'); 18 | keys 19 | .reduce((prev, cur) => { 20 | const lastArr = prev[prev.length - 1] ?? []; 21 | return [...prev, lastArr.concat(cur)]; 22 | }, []) 23 | .forEach(name => { 24 | const script = getScriptByName(parsedUserConfig, name.join('.')); 25 | runScript(script); 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /site/.example-docs/tutorial-basics/congratulations.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 6 3 | --- 4 | 5 | # Congratulations! 6 | 7 | You have just learned the **basics of Docusaurus** and made some changes to the **initial template**. 8 | 9 | Docusaurus has **much more to offer**! 10 | 11 | Have **5 more minutes**? Take a look at **[versioning](../tutorial-extras/manage-docs-versions.md)** and **[i18n](../tutorial-extras/translate-your-site.md)**. 12 | 13 | Anything **unclear** or **buggy** in this tutorial? [Please report it!](https://github.com/facebook/docusaurus/discussions/4610) 14 | 15 | ## What's next? 16 | 17 | - Read the [official documentation](https://docusaurus.io/). 18 | - Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout) 19 | - Add a [search bar](https://docusaurus.io/docs/search) 20 | - Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase) 21 | - Get involved in the [Docusaurus Community](https://docusaurus.io/community/support) 22 | -------------------------------------------------------------------------------- /site/.example-docs/tutorial-basics/create-a-blog-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | 5 | # Create a Blog Post 6 | 7 | Docusaurus creates a **page for each blog post**, but also a **blog index page**, a **tag system**, an **RSS** feed... 8 | 9 | ## Create your first Post 10 | 11 | Create a file at `blog/2021-02-28-greetings.md`: 12 | 13 | ```md title="blog/2021-02-28-greetings.md" 14 | --- 15 | slug: greetings 16 | title: Greetings! 17 | authors: 18 | - name: Joel Marcey 19 | title: Co-creator of Docusaurus 1 20 | url: https://github.com/JoelMarcey 21 | image_url: https://github.com/JoelMarcey.png 22 | - name: Sébastien Lorber 23 | title: Docusaurus maintainer 24 | url: https://sebastienlorber.com 25 | image_url: https://github.com/slorber.png 26 | tags: [greetings] 27 | --- 28 | 29 | Congratulations, you have made your first post! 30 | 31 | Feel free to play around and edit this post as much you like. 32 | ``` 33 | 34 | A new blog post is now available at [http://localhost:3000/blog/greetings](http://localhost:3000/blog/greetings). 35 | -------------------------------------------------------------------------------- /scripts/sort-scripts-config.js: -------------------------------------------------------------------------------- 1 | import {writeFileSync} from 'node:fs'; 2 | import {createRequire} from 'node:module'; 3 | import {execSync} from '../lib/execSync.js'; 4 | import chalk from 'chalk'; 5 | 6 | const require = createRequire(import.meta.url); 7 | 8 | // sort 9 | const config = require('../scripts.json'); 10 | const sortedConfig = sort(config); 11 | const configPath = require.resolve('../scripts.json'); 12 | writeFileSync(configPath, JSON.stringify(sortedConfig, null, 2)); 13 | console.log( 14 | chalk.green('📄 Config file sorted:'), 15 | chalk.bgGreen(`${configPath}`) 16 | ); 17 | 18 | // format 19 | execSync(`npx --yes prettier --write ${configPath}`, { 20 | stdio: 'ignore' 21 | }); 22 | console.log( 23 | chalk.green('📄 Config file formated:'), 24 | chalk.bgGreen(`${configPath}`) 25 | ); 26 | 27 | function sort(obj) { 28 | return Object.fromEntries( 29 | Object.entries(obj) 30 | .sort(([a], [b]) => (a < b ? -1 : 1)) 31 | .map(([key, value]) => [ 32 | key, 33 | typeof value === 'object' ? sort(value) : value 34 | ]) 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /scripts/utils/getContributors.js: -------------------------------------------------------------------------------- 1 | import https from 'node:https'; 2 | import {getImageBase64} from './getImageBase64.js'; 3 | 4 | const CONTRIBUTOR_API_URL = 5 | 'https://api.github.com/repos/iamyoki/better-scripts/contributors'; 6 | 7 | export function getContributors() { 8 | return new Promise(resolve => { 9 | https.get( 10 | CONTRIBUTOR_API_URL, 11 | { 12 | headers: { 13 | 'User-Agent': 'https://api.github.com/meta' 14 | } 15 | }, 16 | res => { 17 | let data = ''; 18 | res.setEncoding('utf8'); 19 | res.on('data', chunk => { 20 | data += chunk; 21 | }); 22 | res.on('end', async () => { 23 | const constributors = JSON.parse(data); 24 | const result = await Promise.all( 25 | constributors.map(async c => { 26 | const base64 = await getImageBase64(c.avatar_url + '&s=80'); 27 | return { 28 | base64, 29 | ...c 30 | }; 31 | }) 32 | ); 33 | resolve(result); 34 | }); 35 | } 36 | ); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /lib/commands/listCommand.js: -------------------------------------------------------------------------------- 1 | import CliTable3 from 'cli-table3'; 2 | import {getScriptByName} from '../getScriptByName.js'; 3 | import {getUserConfig} from '../getUserConfig.js'; 4 | import {parseUserConfig} from '../parseUserConfig.js'; 5 | 6 | export async function listCommand(argv) { 7 | const {config: configPath, name, compact} = argv; 8 | 9 | const userConfig = await getUserConfig(configPath); 10 | const parsedUserConfig = parseUserConfig(userConfig); 11 | const scripts = name 12 | ? getScriptByName(parsedUserConfig, name).scripts 13 | : parsedUserConfig; 14 | 15 | // List one's child scripts 16 | if (!scripts) throw new Error(`Script "${name}" doesn't have child scripts`); 17 | 18 | const table = new CliTable3({ 19 | head: ['Name', 'Command', 'Description', 'Scripts'], 20 | style: { 21 | compact, 22 | head: ['magenta'] 23 | } 24 | }); 25 | 26 | table.push( 27 | ...Object.values(scripts).map((script, index) => [ 28 | script.name, 29 | script.command, 30 | script.desc, 31 | script.scripts && Object.keys(script.scripts).join('\n') 32 | ]) 33 | ); 34 | 35 | console.log(table.toString()); 36 | } 37 | -------------------------------------------------------------------------------- /site/.example-docs/tutorial-basics/create-a-page.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Create a Page 6 | 7 | Add **Markdown or React** files to `src/pages` to create a **standalone page**: 8 | 9 | - `src/pages/index.js` → `localhost:3000/` 10 | - `src/pages/foo.md` → `localhost:3000/foo` 11 | - `src/pages/foo/bar.js` → `localhost:3000/foo/bar` 12 | 13 | ## Create your first React Page 14 | 15 | Create a file at `src/pages/my-react-page.js`: 16 | 17 | ```jsx title="src/pages/my-react-page.js" 18 | import React from 'react'; 19 | import Layout from '@theme/Layout'; 20 | 21 | export default function MyReactPage() { 22 | return ( 23 | 24 |

My React page

25 |

This is a React page

26 |
27 | ); 28 | } 29 | ``` 30 | 31 | A new page is now available at [http://localhost:3000/my-react-page](http://localhost:3000/my-react-page). 32 | 33 | ## Create your first Markdown Page 34 | 35 | Create a file at `src/pages/my-markdown-page.md`: 36 | 37 | ```mdx title="src/pages/my-markdown-page.md" 38 | # My Markdown page 39 | 40 | This is a Markdown page 41 | ``` 42 | 43 | A new page is now available at [http://localhost:3000/my-markdown-page](http://localhost:3000/my-markdown-page). 44 | -------------------------------------------------------------------------------- /site/.example-docs/tutorial-basics/create-a-document.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Create a Document 6 | 7 | Documents are **groups of pages** connected through: 8 | 9 | - a **sidebar** 10 | - **previous/next navigation** 11 | - **versioning** 12 | 13 | ## Create your first Doc 14 | 15 | Create a Markdown file at `docs/hello.md`: 16 | 17 | ```md title="docs/hello.md" 18 | # Hello 19 | 20 | This is my **first Docusaurus document**! 21 | ``` 22 | 23 | A new document is now available at [http://localhost:3000/docs/hello](http://localhost:3000/docs/hello). 24 | 25 | ## Configure the Sidebar 26 | 27 | Docusaurus automatically **creates a sidebar** from the `docs` folder. 28 | 29 | Add metadata to customize the sidebar label and position: 30 | 31 | ```md title="docs/hello.md" {1-4} 32 | --- 33 | sidebar_label: 'Hi!' 34 | sidebar_position: 3 35 | --- 36 | 37 | # Hello 38 | 39 | This is my **first Docusaurus document**! 40 | ``` 41 | 42 | It is also possible to create your sidebar explicitly in `sidebars.js`: 43 | 44 | ```js title="sidebars.js" 45 | module.exports = { 46 | tutorialSidebar: [ 47 | { 48 | type: 'category', 49 | label: 'Tutorial', 50 | // highlight-next-line 51 | items: ['hello'], 52 | }, 53 | ], 54 | }; 55 | ``` 56 | -------------------------------------------------------------------------------- /site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "site", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids" 15 | }, 16 | "dependencies": { 17 | "@docusaurus/core": "2.0.1", 18 | "@docusaurus/preset-classic": "2.0.1", 19 | "@emotion/react": "^11.10.0", 20 | "@emotion/styled": "^11.10.0", 21 | "@mdx-js/react": "^1.6.22", 22 | "clsx": "^1.2.1", 23 | "polished": "^4.2.2", 24 | "prism-react-renderer": "^1.3.5", 25 | "react": "^17.0.2", 26 | "react-dom": "^17.0.2", 27 | "rebass": "^4.0.7" 28 | }, 29 | "devDependencies": { 30 | "@docusaurus/module-type-aliases": "2.0.1", 31 | "@emotion/babel-preset-css-prop": "^11.10.0" 32 | }, 33 | "browserslist": { 34 | "production": [ 35 | ">0.5%", 36 | "not dead", 37 | "not op_mini all" 38 | ], 39 | "development": [ 40 | "last 1 chrome version", 41 | "last 1 firefox version", 42 | "last 1 safari version" 43 | ] 44 | }, 45 | "engines": { 46 | "node": ">=16.14" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/runScript.js: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | import {execSync} from './execSync.js'; 3 | 4 | /** 5 | * @param {import('./types.js').Script} script 6 | * @param {Promise} next 7 | */ 8 | export async function runScript(script, next) { 9 | const {prescript, postscript, isPrescript, isPostscript, env} = script; 10 | 11 | // prev 12 | if (prescript) { 13 | prescript.isPrescript = true; 14 | await runScript(prescript, next); 15 | } 16 | 17 | // now 18 | const displayName = script.desc ?? script.name; 19 | const logRunMessage = isPrescript 20 | ? `\n${chalk.bgGrey.bold(' PREV ➤ ')} ${chalk.magenta.bold(displayName)}` 21 | : isPostscript 22 | ? `\n${chalk.bgGrey.bold(' POST ➤ ')} ${chalk.magenta.bold(displayName)}` 23 | : `\n${chalk.bgMagenta.bold(' RUNS ➤ ')} ${chalk.magenta.bold( 24 | displayName 25 | )}`; 26 | console.log(logRunMessage); 27 | 28 | if (script.command) { 29 | console.log(chalk.grey(script.command)); 30 | execSync(script.command, { 31 | env: { 32 | ...process.env, 33 | ...env 34 | } 35 | }); 36 | console.log(); 37 | } 38 | 39 | if (script.scripts && next && typeof next === 'function') 40 | await next(script.scripts); 41 | 42 | // post 43 | if (postscript) { 44 | postscript.isPostscript = true; 45 | await runScript(postscript, next); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /site/.example-docs/tutorial-extras/manage-docs-versions.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Manage Docs Versions 6 | 7 | Docusaurus can manage multiple versions of your docs. 8 | 9 | ## Create a docs version 10 | 11 | Release a version 1.0 of your project: 12 | 13 | ```bash 14 | npm run docusaurus docs:version 1.0 15 | ``` 16 | 17 | The `docs` folder is copied into `versioned_docs/version-1.0` and `versions.json` is created. 18 | 19 | Your docs now have 2 versions: 20 | 21 | - `1.0` at `http://localhost:3000/docs/` for the version 1.0 docs 22 | - `current` at `http://localhost:3000/docs/next/` for the **upcoming, unreleased docs** 23 | 24 | ## Add a Version Dropdown 25 | 26 | To navigate seamlessly across versions, add a version dropdown. 27 | 28 | Modify the `docusaurus.config.js` file: 29 | 30 | ```js title="docusaurus.config.js" 31 | module.exports = { 32 | themeConfig: { 33 | navbar: { 34 | items: [ 35 | // highlight-start 36 | { 37 | type: 'docsVersionDropdown', 38 | }, 39 | // highlight-end 40 | ], 41 | }, 42 | }, 43 | }; 44 | ``` 45 | 46 | The docs version dropdown appears in your navbar: 47 | 48 | ![Docs Version Dropdown](./img/docsVersionDropdown.png) 49 | 50 | ## Update an existing version 51 | 52 | It is possible to edit versioned docs in their respective folder: 53 | 54 | - `versioned_docs/version-1.0/hello.md` updates `http://localhost:3000/docs/hello` 55 | - `docs/hello.md` updates `http://localhost:3000/docs/next/hello` 56 | -------------------------------------------------------------------------------- /site/src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | @import url('https://rsms.me/inter/inter.css'); 8 | body { 9 | font-family: 'Inter', sans-serif; 10 | } 11 | @supports (font-variation-settings: normal) { 12 | body { 13 | font-family: 'Inter var', sans-serif; 14 | } 15 | } 16 | 17 | :root { 18 | --ifm-color-primary: #755bdc; 19 | --ifm-color-primary-dark: #5f41d7; 20 | --ifm-color-primary-darker: #5535d4; 21 | --ifm-color-primary-darkest: #4326b3; 22 | --ifm-color-primary-light: #8b75e1; 23 | --ifm-color-primary-lighter: #9581e4; 24 | --ifm-color-primary-lightest: #b6a8ec; 25 | --ifm-heading-font-family: 'Inter var', sans-serif; 26 | --docusaurus-highlighted-code-line-bg: rgba(0,0,0,.08); 27 | } 28 | 29 | [data-theme='dark'] { 30 | --ifm-color-primary: #a08bf0; 31 | --ifm-color-primary-dark: #8569ec; 32 | --ifm-color-primary-darker: #7759e9; 33 | --ifm-color-primary-darkest: #4e26e3; 34 | --ifm-color-primary-light: #bbadf4; 35 | --ifm-color-primary-lighter: #c9bdf7; 36 | --ifm-color-primary-lightest: #f2f0fd; 37 | --docusaurus-highlighted-code-line-bg: rgba(255,255,255,.2); 38 | } 39 | 40 | h1, 41 | h2, 42 | h3, 43 | h4, 44 | h5 { 45 | font-weight: 800; 46 | letter-spacing: -0.05em; 47 | } 48 | 49 | .footer__col { 50 | display: flex; 51 | flex-direction: column; 52 | align-items: center; 53 | text-align: center; 54 | } 55 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "better-scripts", 3 | "description": "The next level of npm scripts. An npm scripts runner. A better way to organize your npm scripts. Make redundant NPM scripts easier to read, maintain and use.", 4 | "version": "0.4.3", 5 | "type": "module", 6 | "bin": { 7 | "better-scripts": "bin/better-scripts.js" 8 | }, 9 | "scripts": { 10 | "scripts": "./bin/better-scripts.js" 11 | }, 12 | "files": [ 13 | "bin", 14 | "lib" 15 | ], 16 | "dependencies": { 17 | "chalk": "^5.0.1", 18 | "cli-table3": "^0.6.2", 19 | "cosmiconfig": "^7.0.1", 20 | "pkg-dir": "^6.0.1", 21 | "prompts": "^2.4.2", 22 | "unist-util-visit": "^4.1.0", 23 | "yargs": "^17.5.1" 24 | }, 25 | "homepage": "https://better-scripts.vercel.app", 26 | "keywords": [ 27 | "better scripts", 28 | "cli", 29 | "command", 30 | "commandline", 31 | "tool", 32 | "npm", 33 | "npm-scripts", 34 | "run", 35 | "task" 36 | ], 37 | "engines": { 38 | "node": "^14.13.1 || >=16.0.0" 39 | }, 40 | "author": "Yoki Yu ", 41 | "repository": { 42 | "type": "git", 43 | "url": "https://github.com/iamyoki/better-scripts.git" 44 | }, 45 | "license": "MIT", 46 | "devDependencies": { 47 | "mdast-builder": "^1.1.1", 48 | "mdast-util-heading-range": "^3.1.0", 49 | "remark-gfm": "^3.0.1", 50 | "remark-parse": "^10.0.1", 51 | "remark-stringify": "^10.0.2", 52 | "typescript-json-schema": "^0.54.0", 53 | "unified": "^10.1.2" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /site/docs/getting-started/simplify-package-json.md: -------------------------------------------------------------------------------- 1 | # ✂️ Simplify package.json 2 | 3 | ## Remove previous scripts 4 | 5 | Since we add a configuration in `scripts.json`, we don't need to maintain npm scripts in two places. 6 | 7 | Now let's remove previous. 8 | 9 | ```json title="package.json" 10 | { 11 | "scripts": { 12 | "scripts": "better-scripts", 13 | # highlight-start 14 | - "start": "react-scripts start", 15 | - "build": "react-scripts build", 16 | - "test": "react-scripts test" 17 | # highlight-end 18 | } 19 | } 20 | ``` 21 | 22 | ## Edit config command 23 | 24 | Now command `yarn xxx` in config won't work, so we need change it to real command. 25 | 26 | - `yarn start` → `react-scripts start` 27 | - `yarn build` → `react-scripts build` 28 | - `yarn test` → `react-scripts test` 29 | 30 | ```json title="scripts.json" 31 | { 32 | "dev": { 33 | "alias": "🌟 Dev", 34 | # highlight-next-line 35 | "command": "react-scripts start", 36 | "desc": "Start a development server" 37 | }, 38 | "build": { 39 | "alias": "📦 Build", 40 | # highlight-next-line 41 | "command": "react-scripts build", 42 | "desc": "Create a production build" 43 | }, 44 | "test": { 45 | "alias": "🧪 Test", 46 | # highlight-next-line 47 | "command": "react-scripts test", 48 | "desc": "Run tests" 49 | } 50 | } 51 | ``` 52 | 53 | ## Final 54 | 55 | 56 |    57 | 58 | 59 | 🎉 Great! Your package.json will always be clean and tidy. 60 | -------------------------------------------------------------------------------- /lib/commands/defaultCommand.js: -------------------------------------------------------------------------------- 1 | import prompts from 'prompts'; 2 | import {getUserConfig} from '../getUserConfig.js'; 3 | import {parseUserConfig} from '../parseUserConfig.js'; 4 | import {runScript} from '../runScript.js'; 5 | 6 | /** 7 | * @param {import('../types').ParsedUserConfig} parsedUserConfig 8 | */ 9 | async function promptsAndRun(parsedUserConfig) { 10 | const choices = Object.values(parsedUserConfig).map(script => { 11 | if (!script) throw new Error('Failed parsing config script'); 12 | return { 13 | title: script.alias ?? script.name, 14 | value: script, 15 | description: script.desc ?? script.command 16 | }; 17 | }); 18 | 19 | /** @type {{script: import('../types.js').Script}} */ 20 | const {script} = await prompts({ 21 | type: 'autocomplete', 22 | name: 'script', 23 | message: 'Select a script to run', 24 | suggest: (input, choices) => 25 | Promise.resolve( 26 | choices.filter(choice => 27 | choice.title.toLowerCase().includes(input.toLowerCase()) 28 | ) 29 | ), 30 | clearFirst: true, 31 | choices 32 | }); 33 | 34 | // Exit if no script value 35 | if (!script) process.exit(0); 36 | 37 | // Run script recursively 38 | await runScript(script, nextScripts => { 39 | return promptsAndRun(nextScripts); 40 | }); 41 | } 42 | 43 | export async function defaultCommand(argv) { 44 | const {config: configPath} = argv; 45 | 46 | const userConfig = await getUserConfig(configPath); 47 | const parsedUserConfig = parseUserConfig(userConfig); 48 | 49 | await promptsAndRun(parsedUserConfig); 50 | } 51 | -------------------------------------------------------------------------------- /site/docs/getting-started/installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Installation 6 | 7 | :::tip 8 | The following instruction will use `yarn` as default pacakge manager, you can use `npm` or `pnpm` instead. 9 | ::: 10 | 11 | ## Install locally 12 | 13 | `better-scripts` is recommend to be installed as a **dev** dependency. 14 | 15 | import Tabs from '@theme/Tabs'; 16 | import TabItem from '@theme/TabItem'; 17 | 18 | 19 | 20 | 21 | ```shell 22 | yarn add better-scripts -D 23 | ``` 24 | 25 | 26 | 27 | 28 | 29 | ```shell 30 | npm install better-scripts --save-dev 31 | ``` 32 | 33 | 34 | 35 | 36 | 37 | ```shell 38 | pnpm add better-scripts -D 39 | ``` 40 | 41 | 42 | 43 | 44 | ## Install globally 45 | 46 | 47 | 48 | 49 | ```shell 50 | yarn global add better-scripts 51 | ``` 52 | 53 | 54 | 55 | 56 | 57 | ```shell 58 | npm install better-scripts -g 59 | ``` 60 | 61 | 62 | 63 | 64 | 65 | ```shell 66 | pnpm global add better-scripts 67 | ``` 68 | 69 | 70 | 71 | 72 | ## Add a simplified script in `package.json` 73 | 74 | ```json title="package.json" 75 | { 76 | "scripts": { 77 | ... 78 | "scripts": "better-scripts" 79 | } 80 | } 81 | ``` 82 | 83 | ## Run 84 | 85 | ```shell 86 | yarn scripts 87 | ``` 88 | -------------------------------------------------------------------------------- /lib/getUserConfig.js: -------------------------------------------------------------------------------- 1 | import {cosmiconfig} from 'cosmiconfig'; 2 | import {getPkg} from './getPkg.js'; 3 | import {getUserPkg} from './getUserPkg.js'; 4 | 5 | const moduleName = getPkg().name; 6 | const explorer = cosmiconfig(moduleName, { 7 | packageProp: 'better-scripts', 8 | searchPlaces: [ 9 | 'package.json', 10 | 'scripts.json', 11 | `${moduleName}.json`, 12 | `.${moduleName}rc`, 13 | `.${moduleName}rc.json`, 14 | `.${moduleName}rc.yaml`, 15 | `.${moduleName}rc.yml`, 16 | `.${moduleName}rc.js`, 17 | `.${moduleName}rc.cjs`, 18 | `${moduleName}.config.js`, 19 | `${moduleName}.config.cjs` 20 | ] 21 | }); 22 | 23 | /** Get user config object (haven't parsed yet) 24 | * @param {string} configPath Custom specified config path 25 | * @returns {Promise} 26 | */ 27 | export async function getUserConfig(configPath) { 28 | const result = await (configPath 29 | ? explorer.load(configPath).catch(() => { 30 | throw new Error(`Config file "${configPath}" doesn't exist`); 31 | }) 32 | : explorer.search()); 33 | 34 | const userPkg = getUserPkg(); 35 | 36 | // falsy 37 | if (!result?.config && !userPkg?.scripts) { 38 | throw new Error( 39 | 'Config validation failed, you probably forgot to write ”better-scripts“ in package.json or "scripts.json" config file' 40 | ); 41 | } 42 | 43 | // empty 44 | if ( 45 | result && 46 | (result?.isEmpty || !Object.keys(result.config).length) && 47 | !userPkg?.scripts 48 | ) { 49 | throw new Error('Config validation failed, your config is empty'); 50 | } 51 | 52 | return result?.config ?? userPkg.scripts; 53 | } 54 | -------------------------------------------------------------------------------- /site/docs/getting-started/add-emoji-and-description.md: -------------------------------------------------------------------------------- 1 | # 🥳 Add emoji and description 2 | 3 | 4 | 5 | ## Previous 6 | 7 | Beforehand, we have npm scripts like this that need to add emoji and desc. 8 | 9 | ```json title="package.json" 10 | { 11 | "scripts": { 12 | "scripts": "better-scripts", 13 | "start": "react-scripts start", 14 | "build": "react-scripts build", 15 | "test": "react-scripts test" 16 | } 17 | } 18 | ``` 19 | 20 | :::tip 21 | By default, better-scripts reads the `scripts` field in `package.json` if config is not found, but now we need to add some config for emoji and description. 22 | ::: 23 | 24 | ## Add description 25 | 26 | Add a `better-scripts` field in `pacakge.json` and write command and description 27 | 28 | ```json title="package.json" 29 | { 30 | "scripts": {...}, 31 | "better-scripts": { 32 | "start": ["react-scripts start", "Start a development server"], 33 | "build": ["react-scripts build", "Create a production build"], 34 | "test": ["react-scripts test", "Run tests"] 35 | } 36 | } 37 | ``` 38 | 39 | > `scriptName`: [`command`, `desc`] 40 | 41 | ## Add emoji 42 | 43 | An array formed script value can only place command and desc, we need change it to an object in order to add emoji. 44 | 45 | ```json title="package.json" 46 | { 47 | "scripts": {...}, 48 | "better-scripts": { 49 | "dev": { 50 | "alias": "🌟 Dev", 51 | "command": "yarn start", 52 | "desc": "Start a development server" 53 | }, 54 | "build": { 55 | "alias": "📦 Build", 56 | "command": "yarn build", 57 | "desc": "Create a production build" 58 | }, 59 | "test": { 60 | "alias": "🧪 Test", 61 | "command": "yarn test", 62 | "desc": "Run tests" 63 | } 64 | } 65 | } 66 | ``` 67 | -------------------------------------------------------------------------------- /site/src/components/components.js: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled'; 2 | import {rgba} from 'polished'; 3 | 4 | export const Header = styled.header` 5 | display: flex; 6 | align-items: center; 7 | justify-content: center; 8 | gap: 60px; 9 | margin-bottom: 60px; 10 | margin-top: 40px; 11 | text-align: center; 12 | 13 | @media screen and (max-width: 996px) { 14 | margin-top: 0; 15 | margin-bottom: 20px; 16 | } 17 | `; 18 | 19 | export const Title = styled.h1` 20 | font-size: 60px; 21 | font-weight: 800; 22 | color: transparent; 23 | background: linear-gradient(to right bottom, #5d3fd1, #d98df7); 24 | -webkit-background-clip: text; 25 | background-clip: text; 26 | letter-spacing: -0.03em; 27 | 28 | @media screen and (max-width: 996px) { 29 | font-size: 40px; 30 | } 31 | `; 32 | 33 | export const Caption = styled.p` 34 | /* font-weight: bold; */ 35 | font-size: 16px; 36 | opacity: 0.5; 37 | margin-bottom: 10px; 38 | 39 | @media screen and (max-width: 996px) { 40 | font-size: 12px; 41 | } 42 | `; 43 | 44 | export const Tagline = styled.p` 45 | font-weight: bold; 46 | font-size: 18px; 47 | white-space: pre-wrap; 48 | opacity: 0.8; 49 | 50 | @media screen and (max-width: 996px) { 51 | font-size: 16px; 52 | } 53 | `; 54 | 55 | export const Main = styled.main` 56 | display: flex; 57 | flex-direction: column; 58 | width: 100%; 59 | max-width: 1280px; 60 | padding: 20px 80px; 61 | margin: 0 auto; 62 | margin-top: 40px; 63 | 64 | @media screen and (max-width: 996px) { 65 | padding: 10px 20px; 66 | } 67 | `; 68 | 69 | export const Image = styled.img` 70 | width: 100%; 71 | height: 100%; 72 | max-height: 400px; 73 | object-fit: contain; 74 | border-radius: 20px; 75 | box-shadow: 0 20px 20px ${rgba('#5d3fd1', 0.2)}; 76 | 77 | @media screen and (max-width: 996px) { 78 | max-height: 200px; 79 | } 80 | `; 81 | -------------------------------------------------------------------------------- /scripts/generate-md-contributors.js: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | import m from 'mdast-builder'; 3 | import {headingRange} from 'mdast-util-heading-range'; 4 | import {readFileSync, writeFileSync} from 'node:fs'; 5 | import {createRequire} from 'node:module'; 6 | import remarkGfm from 'remark-gfm'; 7 | import remarkParse from 'remark-parse'; 8 | import remarkStringify from 'remark-stringify'; 9 | import {unified} from 'unified'; 10 | import {getContributors} from './utils/getContributors.js'; 11 | import {writeContributorsAvatar} from './utils/writeContributorsAvatar.js'; 12 | 13 | const require = createRequire(import.meta.url); 14 | 15 | const md = readFileSync(require.resolve('../README.md'), 'utf8'); 16 | 17 | (async () => { 18 | await writeContributorsAvatar(); 19 | const file = await unified() 20 | .use(remarkParse) 21 | .use(remarkGfm) 22 | .use(() => async (tree, file, next) => { 23 | const contributors = await getContributors(); 24 | headingRange(tree, 'Contributors', (start, nodes, end) => [ 25 | start, 26 | m.table('center', [ 27 | m.tableRow(contributors.map(c => m.tableCell(m.text(c.login)))), 28 | m.tableRow( 29 | contributors.map(c => 30 | m.tableCell( 31 | m.link( 32 | c.html_url, 33 | c.login, 34 | m.image( 35 | `./static/contributors/${c.login}.svg`, 36 | c.login, 37 | c.login 38 | ) 39 | ) 40 | ) 41 | ) 42 | ) 43 | ]), 44 | end 45 | ]); 46 | next(); 47 | }) 48 | .use(remarkStringify) 49 | .process(md); 50 | 51 | const result = String(file); 52 | 53 | writeFileSync(require.resolve('../README.md'), result, 'utf8'); 54 | 55 | console.log( 56 | chalk.green('📄 Contributors added:'), 57 | chalk.bgGreen(`${require.resolve('../README.md')}`) 58 | ); 59 | })(); 60 | -------------------------------------------------------------------------------- /site/.example-docs/tutorial-extras/translate-your-site.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Translate your site 6 | 7 | Let's translate `docs/intro.md` to French. 8 | 9 | ## Configure i18n 10 | 11 | Modify `docusaurus.config.js` to add support for the `fr` locale: 12 | 13 | ```js title="docusaurus.config.js" 14 | module.exports = { 15 | i18n: { 16 | defaultLocale: 'en', 17 | locales: ['en', 'fr'], 18 | }, 19 | }; 20 | ``` 21 | 22 | ## Translate a doc 23 | 24 | Copy the `docs/intro.md` file to the `i18n/fr` folder: 25 | 26 | ```bash 27 | mkdir -p i18n/fr/docusaurus-plugin-content-docs/current/ 28 | 29 | cp docs/intro.md i18n/fr/docusaurus-plugin-content-docs/current/intro.md 30 | ``` 31 | 32 | Translate `i18n/fr/docusaurus-plugin-content-docs/current/intro.md` in French. 33 | 34 | ## Start your localized site 35 | 36 | Start your site on the French locale: 37 | 38 | ```bash 39 | npm run start -- --locale fr 40 | ``` 41 | 42 | Your localized site is accessible at [http://localhost:3000/fr/](http://localhost:3000/fr/) and the `Getting Started` page is translated. 43 | 44 | :::caution 45 | 46 | In development, you can only use one locale at a same time. 47 | 48 | ::: 49 | 50 | ## Add a Locale Dropdown 51 | 52 | To navigate seamlessly across languages, add a locale dropdown. 53 | 54 | Modify the `docusaurus.config.js` file: 55 | 56 | ```js title="docusaurus.config.js" 57 | module.exports = { 58 | themeConfig: { 59 | navbar: { 60 | items: [ 61 | // highlight-start 62 | { 63 | type: 'localeDropdown', 64 | }, 65 | // highlight-end 66 | ], 67 | }, 68 | }, 69 | }; 70 | ``` 71 | 72 | The locale dropdown now appears in your navbar: 73 | 74 | ![Locale Dropdown](./img/localeDropdown.png) 75 | 76 | ## Build your localized site 77 | 78 | Build your site for a specific locale: 79 | 80 | ```bash 81 | npm run build -- --locale fr 82 | ``` 83 | 84 | Or build your site to include all the locales at once: 85 | 86 | ```bash 87 | npm run build 88 | ``` 89 | -------------------------------------------------------------------------------- /bin/better-scripts.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import chalk from 'chalk'; 4 | import yargs from 'yargs'; 5 | import {hideBin} from 'yargs/helpers'; 6 | import {defaultCommand} from '../lib/commands/defaultCommand.js'; 7 | import {listCommand} from '../lib/commands/listCommand.js'; 8 | import {runCommand} from '../lib/commands/runCommand.js'; 9 | import {errorHandler} from '../lib/errorHandler.js'; 10 | import {getPkg} from '../lib/getPkg.js'; 11 | 12 | const pkg = getPkg(); 13 | 14 | process.on('uncaughtException', errorHandler); 15 | process.on('unhandledRejection', errorHandler); 16 | 17 | if (hideBin(process.argv).includes('--track')) { 18 | process.env.TRACK_ERROR = 'true'; 19 | } 20 | 21 | const argv = yargs(hideBin(process.argv)) 22 | .usage(chalk.magenta('\n' + pkg.description)) 23 | .option('config', { 24 | alias: 'c', 25 | desc: 'Specified config filepath', 26 | type: 'string' 27 | }) 28 | .option('track', { 29 | desc: 'Show tracked error stack message' 30 | }) 31 | .help('help') 32 | .alias('help', 'h') 33 | .alias('version', 'v') 34 | .command('$0', 'Run script interactively', {}, defaultCommand) 35 | .command( 36 | 'run ', 37 | 'Run script imperatively', 38 | { 39 | skip: { 40 | alias: 's', 41 | desc: 'Skip the chaining paths', 42 | boolean: true 43 | } 44 | }, 45 | runCommand 46 | ) 47 | .command( 48 | ['list [name]', 'ls [name]'], 49 | 'Show all scripts in table', 50 | { 51 | compact: { 52 | desc: 'Compact mode', 53 | boolean: true 54 | } 55 | }, 56 | listCommand 57 | ) 58 | .example('npx $0', '- Run your script interactive') 59 | .example('npx $0 run dev', '- Run "dev" script non-interactive') 60 | .example( 61 | 'npx $0 run build.deploy', 62 | '- Run "build" and "deploy" child script in chain order' 63 | ) 64 | .example('npx $0 list', '- Show all scripts in table') 65 | .strict(true) 66 | .wrap(null) 67 | .fail((msg, err, yargs) => { 68 | if (err) throw err; // preserve stack 69 | if (msg) { 70 | console.log(yargs.help() + '\n'); 71 | throw new Error(msg); 72 | } 73 | }).argv; 74 | -------------------------------------------------------------------------------- /site/docs/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Introduction 6 | 7 | Better scripts is **a better way, a CLI tool, a consistent conventional** that helps you organize and make better use of your npm scripts. 8 | 9 | ## The benefits 10 | 11 | ⚡️ Forget about reading redundant `package.json` and start doing everything you want with just **one single command**. 12 | 13 | 💅🏻 Human readable **description** and **emoji** for your scripts. 14 | 15 | 🔎 **Searchable interactive CLI tool** to help you find the command you want to run faster. 16 | 17 | 🧠 **Consistent convention** to reduce your cognitive load on different projects. 18 | 19 | ✂️ **Simplify your package.json** and separate npm scripting to another file like `scripts.json`. 20 | 21 | ⚙️ A more powerful **script runner** that can inject **cross-platform envs**, execute commands in **serialized** and **parallel** way even **chaining**. 22 | 23 | ## Quick examples 24 | 25 | :::tip 26 | 27 | These examples only show you how it works like, if you already know please follow [Getting Started](/docs/getting-started/installation). 28 | 29 | ::: 30 | 31 | Start by one-time command `npx better-scripts`, and you will get this. 32 | 33 | 34 | 35 |

36 | 37 | Now add some descriptions for your scripts into separate `scripts.json` file in root. 38 | 39 | ```json title="scripts.json" 40 | { 41 | "dev": { 42 | "alias": "🌟 Dev", 43 | "command": "yarn start", 44 | "desc": "Start a development server" 45 | }, 46 | "build": { 47 | "alias": "📦 Build", 48 | "command": "yarn build", 49 | "desc": "Create a production build" 50 | }, 51 | "test": { 52 | "alias": "🧪 Test", 53 | "command": "yarn test", 54 | "desc": "Run tests" 55 | } 56 | } 57 | 58 | ``` 59 | 60 | Run again, it's cool! 61 | 62 | 63 | 64 |

65 | 66 | Shows a table list for all of your scripts by running `list` command 67 | 68 | 69 | 70 |

71 | 72 | Use as a runner without interactive 73 | 74 | 75 | -------------------------------------------------------------------------------- /scripts/utils/writeContributorsAvatar.js: -------------------------------------------------------------------------------- 1 | import {existsSync, mkdirSync, writeFileSync} from 'node:fs'; 2 | import path, {dirname} from 'node:path'; 3 | import {fileURLToPath} from 'node:url'; 4 | import {getContributors} from './getContributors.js'; 5 | 6 | const __filename = fileURLToPath(import.meta.url); 7 | const __dirname = dirname(__filename); 8 | 9 | const dirpath = path.resolve(__dirname, '../../static/contributors'); 10 | 11 | if (!existsSync(dirpath)) { 12 | mkdirSync(dirpath); 13 | } 14 | 15 | export function writeContributorsAvatar() { 16 | return getContributors().then(contributors => { 17 | contributors.map(c => { 18 | const {base64, login} = c; 19 | writeFileSync( 20 | path.resolve(dirpath, `${login}.svg`), 21 | ` 27 | 28 | 29 | 30 | 31 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 59 | ${login} 60 | 61 | 62 | ` 63 | ); 64 | }); 65 | }); 66 | } 67 | -------------------------------------------------------------------------------- /site/src/components/HomepageFeatures/index.js: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled'; 2 | import clsx from 'clsx'; 3 | import {size} from 'polished'; 4 | import React from 'react'; 5 | import styles from './styles.module.css'; 6 | 7 | const FeatureList = [ 8 | { 9 | title: 'Easy to Use', 10 | img: require('@site/static/img/Saly-38.png').default, 11 | description: ( 12 | <> 13 | Better scripts can be used with zero-config. Though 14 | your can progressively add description, env, child scripts... for your 15 | scripts. 16 | 17 | ) 18 | }, 19 | { 20 | title: 'Better DX', 21 | img: require('@site/static/img/Saly-39.png').default, 22 | description: ( 23 | <> 24 | It provides you a better development experience with a simple command to 25 | start with. 26 | 27 | ) 28 | }, 29 | { 30 | title: 'Consistent', 31 | img: require('@site/static/img/Saly-40.png').default, 32 | description: ( 33 | <> 34 | Once you use better-scripts for all your projects, you will get a 35 | consistent scriping experience. 36 | 37 | ) 38 | } 39 | ]; 40 | 41 | const ImageWrapper = styled.div` 42 | padding: 20px; 43 | background-color: rgb(114 109 197 / 8%); 44 | display: flex; 45 | justify-content: center; 46 | align-items: center; 47 | border-radius: 20px; 48 | margin-bottom: 30px; 49 | `; 50 | 51 | const Image = styled.img` 52 | ${size(240)} 53 | object-fit: contain; 54 | 55 | @media screen and (max-width: 996px) { 56 | ${size(180)} 57 | } 58 | `; 59 | 60 | function Feature({img, title, description}) { 61 | return ( 62 |
63 | 64 | 65 | 66 |
67 |

{title}

68 |

{description}

69 |
70 |
71 | ); 72 | } 73 | 74 | export default function HomepageFeatures() { 75 | return ( 76 |
77 |
78 |
79 | {FeatureList.map((props, idx) => ( 80 | 81 | ))} 82 |
83 |
84 |
85 | ); 86 | } 87 | -------------------------------------------------------------------------------- /site/src/pages/index.js: -------------------------------------------------------------------------------- 1 | import Link from '@docusaurus/Link'; 2 | import {useColorMode} from '@docusaurus/theme-common'; 3 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 4 | import Layout from '@theme/Layout'; 5 | import React from 'react'; 6 | import {Box, Flex} from 'rebass'; 7 | import {css} from '@emotion/react'; 8 | 9 | import HomepageFeatures from '../components/HomepageFeatures/index'; 10 | import { 11 | Caption, 12 | Header, 13 | Image, 14 | Main, 15 | Tagline, 16 | Title 17 | } from '../components/components'; 18 | 19 | function HomepageHeader() { 20 | const {siteConfig} = useDocusaurusContext(); 21 | const {colorMode} = useColorMode(); 22 | 23 | return ( 24 |
25 | 26 | {siteConfig.title} 27 | The next level of npm scripts 28 | 29 | An npm scripts runner.
30 | A better way to organize your npm scripts.
31 | Make redundant NPM scripts easier to read, maintain and use. 32 |
33 | 45 | 53 | Get Started → 54 | 55 | 56 | 59 | View on Github → 60 | 61 | 62 |
63 | {/* 64 | 65 | */} 66 |
67 | ); 68 | } 69 | 70 | export default function Home() { 71 | const {siteConfig} = useDocusaurusContext(); 72 | return ( 73 | 76 |
77 | 78 | 79 |
80 |
81 | ); 82 | } 83 | -------------------------------------------------------------------------------- /lib/parseUserConfig.js: -------------------------------------------------------------------------------- 1 | const excludeNameRegexp = [/^\/\//, /^(scripts|\$schema|better-scripts)$/]; 2 | 3 | /** Parse user config 4 | * @param {import('./types').UserConfig} userConfig 5 | * @returns {import('./types').ParsedUserConfig} 6 | */ 7 | export function parseUserConfig(userConfig) { 8 | const entries = Object.entries(userConfig).map(([name, value]) => [ 9 | name, 10 | parseUserConfigValue( 11 | name, 12 | value, 13 | userConfig['pre' + name], 14 | userConfig['post' + name] 15 | ) 16 | ]); 17 | 18 | const filteredEntries = entries.filter( 19 | ([name]) => !excludeNameRegexp.some(reg => reg.test(name)) 20 | ); 21 | 22 | const parsedUserConfig = Object.fromEntries(filteredEntries); 23 | 24 | // Remove prev, post keys if script exists 25 | for (const key in parsedUserConfig) { 26 | const [, name] = key.match(/^(?:pre|post)(.*)/) ?? []; 27 | if (name) delete parsedUserConfig[key]; 28 | } 29 | 30 | return parsedUserConfig; 31 | } 32 | 33 | /** Parse user config value into Script object 34 | * @param {import('./types').Valueof} value 35 | * @param {import('./types').Valueof} prevalue 36 | * @param {import('./types').Valueof} postvalue 37 | */ 38 | function parseUserConfigValue(name, value, prevalue, postvalue) { 39 | /** @type {import('./types').Script} */ 40 | const script = { 41 | name, 42 | prescript: prevalue && parseUserConfigValue('pre' + name, prevalue), 43 | postscript: postvalue && parseUserConfigValue('post' + name, postvalue) 44 | }; 45 | 46 | // string 47 | if (typeof value === 'string') script.command = value; 48 | 49 | // array 50 | if (Array.isArray(value)) { 51 | script.command = value[0]; 52 | script.desc = value[1]; 53 | } 54 | 55 | // object 56 | if (!Array.isArray(value) && typeof value === 'object') { 57 | const { 58 | alias, 59 | command, 60 | desc, 61 | describe, 62 | description, 63 | scripts, 64 | prescript, 65 | postscript, 66 | env 67 | } = value; 68 | 69 | script.alias = alias; 70 | script.command = command; 71 | script.desc = desc ?? describe ?? description; 72 | script.scripts = scripts && parseUserConfig(scripts); 73 | if (prescript) 74 | script.prescript = { 75 | name: 'pre' + script.name, 76 | command: prescript?.command, 77 | desc: prescript?.desc ?? prescript?.describe ?? prescript?.description 78 | }; 79 | if (postscript) 80 | script.postscript = { 81 | name: 'post' + script.name, 82 | command: postscript?.command, 83 | desc: 84 | postscript?.desc ?? postscript?.describe ?? postscript?.description 85 | }; 86 | script.env = env; 87 | } 88 | 89 | return script; 90 | } 91 | -------------------------------------------------------------------------------- /site/.example-blog/2019-05-29-long-blog-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: long-blog-post 3 | title: Long Blog Post 4 | authors: endi 5 | tags: [hello, docusaurus] 6 | --- 7 | 8 | This is the summary of a very long blog post, 9 | 10 | Use a `` comment to limit blog post size in the list view. 11 | 12 | 13 | 14 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 15 | 16 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 17 | 18 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 19 | 20 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 21 | 22 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 23 | 24 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 25 | 26 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 27 | 28 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 29 | 30 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 31 | 32 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 33 | 34 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 35 | 36 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 37 | 38 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 39 | 40 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 41 | 42 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 43 | 44 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* 131 | 132 | # General 133 | .DS_Store 134 | .AppleDouble 135 | .LSOverride 136 | 137 | # Icon must end with two \r 138 | Icon 139 | 140 | # Thumbnails 141 | ._* 142 | 143 | # Files that might appear in the root of a volume 144 | .DocumentRevisions-V100 145 | .fseventsd 146 | .Spotlight-V100 147 | .TemporaryItems 148 | .Trashes 149 | .VolumeIcon.icns 150 | .com.apple.timemachine.donotpresent 151 | 152 | # Directories potentially created on remote AFP share 153 | .AppleDB 154 | .AppleDesktop 155 | Network Trash Folder 156 | Temporary Items 157 | .apdisk 158 | -------------------------------------------------------------------------------- /lib/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$ref": "#/definitions/UserConfig", 3 | "definitions": { 4 | "UserConfig": { 5 | "type": "object", 6 | "additionalProperties": { 7 | "anyOf": [ 8 | { 9 | "type": "array", 10 | "items": [ 11 | { 12 | "type": "string" 13 | }, 14 | { 15 | "type": "string" 16 | } 17 | ], 18 | "minItems": 2, 19 | "maxItems": 2 20 | }, 21 | { 22 | "$ref": "#/definitions/{alias?:string;command?:string;desc?:string;description?:string;describe?:string;scripts?:UserConfig;prescript?:Valueof;postscript?:Valueof;env?:{[key:string]:string;};}" 23 | }, 24 | { 25 | "type": "string" 26 | } 27 | ] 28 | } 29 | }, 30 | "{alias?:string;command?:string;desc?:string;description?:string;describe?:string;scripts?:UserConfig;prescript?:Valueof;postscript?:Valueof;env?:{[key:string]:string;};}": { 31 | "type": "object", 32 | "properties": { 33 | "alias": { 34 | "type": "string" 35 | }, 36 | "command": { 37 | "type": "string" 38 | }, 39 | "desc": { 40 | "type": "string" 41 | }, 42 | "description": { 43 | "type": "string" 44 | }, 45 | "describe": { 46 | "type": "string" 47 | }, 48 | "scripts": { 49 | "$ref": "#/definitions/UserConfig" 50 | }, 51 | "prescript": { 52 | "anyOf": [ 53 | { 54 | "type": "array", 55 | "items": [ 56 | { 57 | "type": "string" 58 | }, 59 | { 60 | "type": "string" 61 | } 62 | ], 63 | "minItems": 2, 64 | "maxItems": 2 65 | }, 66 | { 67 | "$ref": "#/definitions/{alias?:string;command?:string;desc?:string;description?:string;describe?:string;scripts?:UserConfig;prescript?:Valueof;postscript?:Valueof;env?:{[key:string]:string;};}" 68 | }, 69 | { 70 | "type": "string" 71 | } 72 | ] 73 | }, 74 | "postscript": { 75 | "anyOf": [ 76 | { 77 | "type": "array", 78 | "items": [ 79 | { 80 | "type": "string" 81 | }, 82 | { 83 | "type": "string" 84 | } 85 | ], 86 | "minItems": 2, 87 | "maxItems": 2 88 | }, 89 | { 90 | "$ref": "#/definitions/{alias?:string;command?:string;desc?:string;description?:string;describe?:string;scripts?:UserConfig;prescript?:Valueof;postscript?:Valueof;env?:{[key:string]:string;};}" 91 | }, 92 | { 93 | "type": "string" 94 | } 95 | ] 96 | }, 97 | "env": { 98 | "type": "object", 99 | "additionalProperties": { 100 | "type": "string" 101 | } 102 | } 103 | } 104 | } 105 | }, 106 | "$schema": "http://json-schema.org/draft-07/schema#" 107 | } -------------------------------------------------------------------------------- /static/contributors/Garker.svg: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 39 | Garker 40 | 41 | 42 | -------------------------------------------------------------------------------- /site/.example-docs/tutorial-basics/markdown-features.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | --- 4 | 5 | # Markdown Features 6 | 7 | Docusaurus supports **[Markdown](https://daringfireball.net/projects/markdown/syntax)** and a few **additional features**. 8 | 9 | ## Front Matter 10 | 11 | Markdown documents have metadata at the top called [Front Matter](https://jekyllrb.com/docs/front-matter/): 12 | 13 | ```text title="my-doc.md" 14 | // highlight-start 15 | --- 16 | id: my-doc-id 17 | title: My document title 18 | description: My document description 19 | slug: /my-custom-url 20 | --- 21 | // highlight-end 22 | 23 | ## Markdown heading 24 | 25 | Markdown text with [links](./hello.md) 26 | ``` 27 | 28 | ## Links 29 | 30 | Regular Markdown links are supported, using url paths or relative file paths. 31 | 32 | ```md 33 | Let's see how to [Create a page](/create-a-page). 34 | ``` 35 | 36 | ```md 37 | Let's see how to [Create a page](./create-a-page.md). 38 | ``` 39 | 40 | **Result:** Let's see how to [Create a page](./create-a-page.md). 41 | 42 | ## Images 43 | 44 | Regular Markdown images are supported. 45 | 46 | You can use absolute paths to reference images in the static directory (`static/img/docusaurus.png`): 47 | 48 | ```md 49 | ![Docusaurus logo](/img/docusaurus.png) 50 | ``` 51 | 52 | ![Docusaurus logo](/img/docusaurus.png) 53 | 54 | You can reference images relative to the current file as well, as shown in [the extra guides](../tutorial-extras/manage-docs-versions.md). 55 | 56 | ## Code Blocks 57 | 58 | Markdown code blocks are supported with Syntax highlighting. 59 | 60 | ```jsx title="src/components/HelloDocusaurus.js" 61 | function HelloDocusaurus() { 62 | return ( 63 |

Hello, Docusaurus!

64 | ) 65 | } 66 | ``` 67 | 68 | ```jsx title="src/components/HelloDocusaurus.js" 69 | function HelloDocusaurus() { 70 | return

Hello, Docusaurus!

; 71 | } 72 | ``` 73 | 74 | ## Admonitions 75 | 76 | Docusaurus has a special syntax to create admonitions and callouts: 77 | 78 | :::tip My tip 79 | 80 | Use this awesome feature option 81 | 82 | ::: 83 | 84 | :::danger Take care 85 | 86 | This action is dangerous 87 | 88 | ::: 89 | 90 | :::tip My tip 91 | 92 | Use this awesome feature option 93 | 94 | ::: 95 | 96 | :::danger Take care 97 | 98 | This action is dangerous 99 | 100 | ::: 101 | 102 | ## MDX and React Components 103 | 104 | [MDX](https://mdxjs.com/) can make your documentation more **interactive** and allows using any **React components inside Markdown**: 105 | 106 | ```jsx 107 | export const Highlight = ({children, color}) => ( 108 | { 117 | alert(`You clicked the color ${color} with label ${children}`) 118 | }}> 119 | {children} 120 | 121 | ); 122 | 123 | This is Docusaurus green ! 124 | 125 | This is Facebook blue ! 126 | ``` 127 | 128 | export const Highlight = ({children, color}) => ( 129 | { 138 | alert(`You clicked the color ${color} with label ${children}`); 139 | }}> 140 | {children} 141 | 142 | ); 143 | 144 | This is Docusaurus green ! 145 | 146 | This is Facebook blue ! 147 | -------------------------------------------------------------------------------- /static/contributors/annoyc.svg: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 39 | annoyc 40 | 41 | 42 | -------------------------------------------------------------------------------- /site/docs/configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | 5 | import Tabs from '@theme/Tabs'; 6 | import TabItem from '@theme/TabItem'; 7 | 8 | # Configuration 9 | 10 | ## Supported file formats 11 | 12 | - a `better-scripts` property in package.json (⭐️ Recommended) 13 | - `scripts.json` (⭐️⭐️ Recommended) 14 | 15 |
See more formats 16 |

17 | 18 | - `better-scripts.json` 19 | - `.better-scriptsrc` 20 | - `.better-scriptsrc.json` 21 | - `.better-scriptsrc.yaml` 22 | - `.better-scriptsrc.yml` 23 | - `.better-scriptsrc.js` 24 | - `.better-scriptsrc.cjs` 25 | - `better-scriptsrc.config.js` 26 | - `better-scriptsrc.config.cjs` 27 | 28 |

29 |
30 | 31 | 32 | ## Specification 33 | 34 | 35 | 36 | 37 | ```json title="scripts.json" 38 | { 39 | "dev": "react-scripts start" 40 | } 41 | ``` 42 | 43 | > "`scriptName`": "`command`" 44 | 45 | 46 | 47 | 48 | 49 | ```json title="scripts.json" 50 | { 51 | "dev": ["react-scripts start", "Start a development server"] 52 | } 53 | ``` 54 | 55 | > "`scriptName`": ["`command`", "`desc`"] 56 | 57 | 58 | 59 | 60 | 61 | ```json title="scripts.json" 62 | { 63 | "dev": { 64 | "alias": "🌟 Dev", 65 | "command": "react-scripts start", 66 | "desc": "Start a development server", 67 | } 68 | } 69 | ``` 70 | 71 | ### Config Object 72 | 73 | | Property | Type | Description | Required | 74 | | ---------- | ----------------------------------------- | ------------------------------ | -------- | 75 | | scriptName | `Script`: string \| array \| object | The key of the `Script` object | ✅ | 76 | 77 | ### Script Object 78 | 79 | | Property | Type | Description | Required | 80 | | ------------------------------- | ------------------ | -------------------------------------------------------------------------------------------- | -------- | 81 | | alias | string | 🥳 Displayed name. Defaults to scriptName | | 82 | | command | string | The key of the script object | | 83 | | desc \| describe \| description | string | Explain what this script does | | 84 | | scripts | `Config`: object | Nested child scripts. Run step by step | | 85 | | prescript | `Config`: `Script` | Pre-runs. [Same as npm.](https://docs.npmjs.com/cli/v8/using-npm/scripts#pre--post-scripts) | | 86 | | postscript | `Config`: `Script` | Post-runs. [Same as npm.](https://docs.npmjs.com/cli/v8/using-npm/scripts#pre--post-scripts) | | 87 | | env | `Env`: object | Cross-platform environment virables | | 88 | 89 |
90 | TS Interface 91 | 92 | ```ts 93 | interface UserConfig { 94 | alias?: string; 95 | command?: string; 96 | desc?: string; 97 | description?: string; 98 | describe?: string; 99 | scripts?: UserConfig; 100 | prescript?: Valueof; 101 | postscript?: Valueof; 102 | env?: { 103 | [key: string]: string; 104 | }; 105 | } 106 | ``` 107 | 108 |
109 | 110 |
111 |
112 | -------------------------------------------------------------------------------- /static/contributors/iamyoki.svg: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 39 | iamyoki 40 | 41 | 42 | -------------------------------------------------------------------------------- /site/docusaurus.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Note: type annotations allow type checking and IDEs autocompletion 3 | 4 | const lightCodeTheme = require('prism-react-renderer/themes/github'); 5 | const darkCodeTheme = require('prism-react-renderer/themes/dracula'); 6 | 7 | /** @type {import('@docusaurus/types').Config} */ 8 | const config = { 9 | title: 'Better Scripts', 10 | tagline: 'A better way to run your npm scripts.', 11 | url: 'https://your-docusaurus-test-site.com', 12 | baseUrl: '/', 13 | onBrokenLinks: 'throw', 14 | onBrokenMarkdownLinks: 'warn', 15 | favicon: 'img/favicon.ico', 16 | 17 | // GitHub pages deployment config. 18 | // If you aren't using GitHub pages, you don't need these. 19 | organizationName: 'iamyoki', // Usually your GitHub org/user name. 20 | projectName: 'better-scripts', // Usually your repo name. 21 | 22 | // Even if you don't use internalization, you can use this field to set useful 23 | // metadata like html lang. For example, if your site is Chinese, you may want 24 | // to replace "en" with "zh-Hans". 25 | i18n: { 26 | defaultLocale: 'en', 27 | locales: ['en'] 28 | }, 29 | 30 | presets: [ 31 | [ 32 | 'classic', 33 | /** @type {import('@docusaurus/preset-classic').Options} */ 34 | ({ 35 | docs: { 36 | sidebarPath: require.resolve('./sidebars.js'), 37 | // Please change this to your repo. 38 | // Remove this to remove the "edit this page" links. 39 | editUrl: 40 | 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/' 41 | }, 42 | blog: { 43 | showReadingTime: true, 44 | // Please change this to your repo. 45 | // Remove this to remove the "edit this page" links. 46 | editUrl: 47 | 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/' 48 | }, 49 | theme: { 50 | customCss: require.resolve('./src/css/custom.css') 51 | } 52 | }) 53 | ] 54 | ], 55 | 56 | themeConfig: 57 | /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ 58 | ({ 59 | navbar: { 60 | title: '➤_ Better Scripts', 61 | style: 'dark', 62 | hideOnScroll: true, 63 | // logo: { 64 | // alt: 'My Site Logo', 65 | // src: 'img/logo.svg', 66 | // }, 67 | items: [ 68 | { 69 | type: 'doc', 70 | docId: 'intro', 71 | position: 'left', 72 | label: 'Docs' 73 | }, 74 | // {to: '/blog', label: 'Blog', position: 'left'}, 75 | { 76 | href: 'https://github.com/iamyoki/better-scripts', 77 | label: 'GitHub', 78 | position: 'right' 79 | } 80 | ] 81 | }, 82 | footer: { 83 | style: 'light', 84 | links: [ 85 | { 86 | title: 'Docs', 87 | items: [ 88 | { 89 | label: 'Docs', 90 | to: '/docs/intro' 91 | } 92 | ] 93 | }, 94 | // { 95 | // title: 'Community', 96 | // items: [ 97 | // { 98 | // label: 'Stack Overflow', 99 | // href: 'https://stackoverflow.com/questions/tagged/docusaurus', 100 | // }, 101 | // { 102 | // label: 'Discord', 103 | // href: 'https://discordapp.com/invite/docusaurus', 104 | // }, 105 | // { 106 | // label: 'Twitter', 107 | // href: 'https://twitter.com/docusaurus', 108 | // }, 109 | // ], 110 | // }, 111 | // { 112 | // title: 'Blogs', 113 | // items: [ 114 | // { 115 | // label: 'Example', 116 | // to: '/example' 117 | // } 118 | // ] 119 | // }, 120 | { 121 | title: 'More', 122 | items: [ 123 | { 124 | label: 'Npm', 125 | href: 'https://www.npmjs.com/package/better-scripts' 126 | }, 127 | { 128 | label: 'GitHub', 129 | href: 'https://github.com/iamyoki/better-scripts' 130 | } 131 | ] 132 | } 133 | ], 134 | copyright: `Copyright © ${new Date().getFullYear()} Better Scripts. Built by iamyoki.` 135 | }, 136 | prism: { 137 | theme: lightCodeTheme, 138 | darkTheme: darkCodeTheme 139 | } 140 | }) 141 | }; 142 | 143 | module.exports = config; 144 | -------------------------------------------------------------------------------- /site/static/img/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |

➤_ Better Scripts

4 | 5 |
6 | 7 |

A better way to organize your npm scripts

8 |

See better-scripts.vercel.app

9 |
10 | 11 |

12 | example 13 |

14 | 15 | * [Installation](#installation) 16 | * [Usage](#usage) 17 | * [Basic setup](#basic-setup) 18 | * [Add script description](#add-script-description) 19 | * [Script as object](#script-as-object) 20 | * [Separate configuration file](#separate-configuration-file) 21 | * [Specified configuration file](#specified-configuration-file) 22 | * [Command line](#command-line) 23 | * [Default](#default) 24 | * [Run](#run) 25 | * [List](#list) 26 | * [Advanced](#advanced) 27 | * [Contributors](#contributors) 28 | * [License](#license) 29 | 30 | ## Installation 31 | 32 | Install with yarn 33 | 34 | ```sh 35 | yarn add better-scripts -D 36 | ``` 37 | 38 | Or install with npm 39 | 40 | ```sh 41 | npm install better-scripts --save-dev 42 | ``` 43 | 44 | Or install with pnpm 45 | 46 | ```sh 47 | pnpm add better-scripts -D 48 | ``` 49 | 50 | Or use npx for one-time use 51 | 52 | ```sh 53 | npx better-scripts 54 | ``` 55 | 56 | ## Usage 57 | 58 | ### Basic setup 59 | 60 | Simply run `npx better-scripts` will read your existing scripts, let's give it a try at first 61 | 62 | ```sh 63 | npx better-scripts 64 | ``` 65 | 66 |

67 | example-at-first 68 |

69 | 70 | Now, let's move all `scripts` into `better-scripts` and add only one `"scripts": "better-scripts"` in `scripts` 71 | 72 | ```json 73 | { 74 | "scripts": { 75 | "scripts": "better-scripts" 76 | }, 77 | "better-scripts": { 78 | "dev": "react-scripts start", 79 | "build": "react-scripts build", 80 | "test": "react-scripts test" 81 | } 82 | } 83 | ``` 84 | 85 | Then run `yarn scripts` will read your scripts from `better-scripts` 86 | 87 | ```sh 88 | yarn scripts 89 | ``` 90 | 91 | ### Add script description 92 | 93 | Second value as description in array form 94 | 95 | ```json 96 | { 97 | "better-scripts": { 98 | "dev": ["react-scripts start", "Start a development server"] 99 | } 100 | } 101 | ``` 102 | 103 |

104 | example-at-first 105 |

106 | 107 | ### Script as object 108 | 109 | You can add more properties in object form 110 | 111 | ```json 112 | { 113 | "better-scripts": { 114 | "dev": { 115 | "alias": "🧑🏻‍💻 Dev", 116 | "command": "react-scripts start", 117 | "desc": "Start a development server" 118 | } 119 | } 120 | } 121 | ``` 122 | 123 |

124 | example-at-first 125 |

126 | 127 | ### Separate configuration file 128 | 129 | You can write your "better-scriprts" out of `package.json` 130 | 131 | Create a `scripts.json` file in the root directory 132 | 133 | ```json 134 | { 135 | "dev": "react-scripts start", 136 | "build": "react-scripts build", 137 | "test": "react-scripts test" 138 | } 139 | ``` 140 | 141 | Supported file formats 142 | 143 | * a `better-scripts` property in package.json (⭐️ Recommended) 144 | * `scripts.json` (⭐️⭐️ Recommended) 145 | * `better-scripts.json` 146 | * `.better-scriptsrc` 147 | * `.better-scriptsrc.json` 148 | * `.better-scriptsrc.yaml` 149 | * `.better-scriptsrc.yml` 150 | * `.better-scriptsrc.js` 151 | * `.better-scriptsrc.cjs` 152 | * `better-scriptsrc.config.js` 153 | * `better-scriptsrc.config.cjs` 154 | 155 | ### Specified configuration file 156 | 157 | ```sh 158 | yarn scripts --config custom-config.json 159 | ``` 160 | 161 | ## Command line 162 | 163 | ```sh 164 | yarn scripts --help 165 | 166 | ➤_ A better way to organize your npm scripts 167 | 168 | Commands: 169 | better-scripts Run your script [default] 170 | better-scripts run Run script non-interactive, usually in CI mode 171 | better-scripts list [name] Show all scripts 172 | 173 | Options: 174 | -v, --version Show version number [boolean] 175 | -c, --config Specified config filepath [string] 176 | --track Show tracked error stack message 177 | -h, --help Show help [boolean] 178 | 179 | Examples: 180 | npx better-scripts - Run your script interactive 181 | npx better-scripts run dev - Run "dev" script non-interactive 182 | npx better-scripts run build.deploy - Run "build" and "deploy" child script in chain order 183 | npx better-scripts list - Show all scripts 184 | ``` 185 | 186 | ### Default 187 | 188 | Interactive with one simple command 189 | 190 | ```sh 191 | yarn scripts 192 | ``` 193 | 194 | ### Run 195 | 196 | Non-interactive with specific command 197 | 198 | ```sh 199 | yarn scripts run 200 | ``` 201 | 202 | > `` is your script name that defined in config 203 | 204 | Chain operation 205 | 206 | ```sh 207 | yarn scripts run 208 | ``` 209 | 210 | Skip chaining paths 211 | 212 | ```sh 213 | yarn scripts run --skip 214 | ``` 215 | 216 | > \-s, --skip 217 | 218 | ### List 219 | 220 | Show all your scripts 221 | 222 | ```sh 223 | yarn scripts list 224 | ``` 225 | 226 | Compact mode 227 | 228 | ```sh 229 | yarn scripts list --compact 230 | ``` 231 | 232 | Show specific script name's scripts 233 | 234 | ```sh 235 | yarn scripts list 236 | ``` 237 | 238 | ```sh 239 | yarn scripts list 240 | ``` 241 | 242 | ## Advanced 243 | 244 | The API is not stable yet 245 | 246 | ## Contributors 247 | 248 | | iamyoki | Garker | annoyc | 249 | | :---------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------: | 250 | | [![iamyoki](./static/contributors/iamyoki.svg "iamyoki")](https://github.com/iamyoki "iamyoki") | [![Garker](./static/contributors/Garker.svg "Garker")](https://github.com/Garker "Garker") | [![annoyc](./static/contributors/annoyc.svg "annoyc")](https://github.com/annoyc "annoyc") | 251 | 252 | ## License 253 | 254 | [MIT](https://choosealicense.com/licenses/mit/) 255 | -------------------------------------------------------------------------------- /site/static/img/undraw_docusaurus_tree.svg: -------------------------------------------------------------------------------- 1 | 2 | Focus on What Matters 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 | -------------------------------------------------------------------------------- /site/static/img/undraw_docusaurus_mountain.svg: -------------------------------------------------------------------------------- 1 | 2 | Easy to Use 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 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /site/static/img/undraw_docusaurus_react.svg: -------------------------------------------------------------------------------- 1 | 2 | Powered by React 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 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | --------------------------------------------------------------------------------