├── examples
├── assets
│ ├── a.js
│ ├── b.js
│ ├── c.js
│ ├── demo1
│ │ ├── demo1_a.js
│ │ ├── demo1_a.md
│ │ ├── demo1_b.js
│ │ └── demo1_b.md
│ ├── demo2
│ │ ├── demo2_a.js
│ │ ├── demo2_a.md
│ │ ├── demo2_b.js
│ │ └── demo2_b.md
│ ├── a.md
│ ├── b.md
│ └── c.md
├── basic
│ ├── .gitignore
│ ├── src
│ │ └── main.ts
│ └── package.json
├── suziprc
│ ├── package.json
│ └── .suziprc.json
├── README.md
└── pkg
│ └── package.json
├── pnpm-workspace.yaml
├── .eslintignore
├── .npmrc
├── src
├── index.ts
├── y18n.ts
├── cli
│ ├── index.ts
│ └── zip.ts
├── types.ts
├── util.ts
└── archive.ts
├── .gitignore
├── bin
└── suzip.js
├── .suziprc.json
├── .vscode
├── settings.json
└── i18n-ally-custom-framework.yml
├── .eslintrc
├── .github
└── workflows
│ ├── push-release.yml
│ └── release.yml
├── tsconfig.json
├── LICENSE
├── locales
├── zh_CN.json
└── en.json
├── package.json
├── README_ZH.md
├── README.md
└── pnpm-lock.yaml
/examples/assets/a.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/assets/b.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/assets/c.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/assets/demo1/demo1_a.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/assets/demo1/demo1_a.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/assets/demo1/demo1_b.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/assets/demo1/demo1_b.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/assets/demo2/demo2_a.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/assets/demo2/demo2_a.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/assets/demo2/demo2_b.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/assets/demo2/demo2_b.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - examples/*
3 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | example
2 | node_modules
3 | .output
4 | dist
5 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | shamefully-hoist = true
2 | ignore-workspace-root-check = true
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './archive'
2 | export * from './types'
3 |
--------------------------------------------------------------------------------
/examples/basic/.gitignore:
--------------------------------------------------------------------------------
1 | src
2 | !src/main.ts
3 | .output
4 | node_modules
5 |
--------------------------------------------------------------------------------
/examples/assets/a.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliuq/suzip/master/examples/assets/a.md
--------------------------------------------------------------------------------
/examples/assets/b.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliuq/suzip/master/examples/assets/b.md
--------------------------------------------------------------------------------
/examples/assets/c.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aliuq/suzip/master/examples/assets/c.md
--------------------------------------------------------------------------------
/examples/basic/src/main.ts:
--------------------------------------------------------------------------------
1 | import { zip } from 'suzip'
2 |
3 | zip({
4 | output: '.output/test.zip',
5 | cwd: '../assets',
6 | })
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | __test__
2 | test
3 | node_modules
4 | lib
5 | dist
6 | note.md
7 | *.zip
8 | *.tar.gz
9 | *.tar
10 | .output.json
11 | *.log
12 | .output
13 |
--------------------------------------------------------------------------------
/bin/suzip.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict'
3 | if (typeof __dirname !== 'undefined')
4 | require('../dist/cli.cjs')
5 | else import('../dist/cli.mjs')
6 |
--------------------------------------------------------------------------------
/.suziprc.json:
--------------------------------------------------------------------------------
1 | {
2 | "zip": {
3 | "output": "./.output/source.json",
4 | "cwd": "./",
5 | "ignoreFile": "./.gitignore",
6 | "dot": true
7 | }
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/examples/suziprc/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "suziprc",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "suzip -h",
7 | "zip": "suzip"
8 | },
9 | "dependencies": {
10 | "suzip": "workspace:*"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "i18n-ally.localesPaths": [
3 | "locales"
4 | ],
5 | "i18n-ally.regex.key": ".*?",
6 | "i18n-ally.enabledFrameworks": [
7 | "custom"
8 | ],
9 | "i18n-ally.keystyle": "flat",
10 | "i18n-ally.sourceLanguage": "zh"
11 | }
12 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@aliuq",
3 | "overrides": [
4 | {
5 | "files": ["*locales*/*.json"],
6 | "rules": {
7 | "jsonc/sort-keys": ["error", "asc", {
8 | "caseSensitive": true,
9 | "natural": true
10 | }]
11 | }
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/.github/workflows/push-release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on: push
4 |
5 | jobs:
6 | release:
7 | runs-on: ubuntu-latest
8 | if: |
9 | contains(github.event.head_commit.message, 'CI: push release')
10 | steps:
11 | - uses: actions/checkout@v2
12 | with:
13 | fetch-depth: 0
14 | - run: npx conventional-github-releaser -p angular
15 | env:
16 | CONVENTIONAL_GITHUB_RELEASER_TOKEN: ${{secrets.GITHUB_TOKEN}}
17 |
--------------------------------------------------------------------------------
/src/y18n.ts:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | // @ts-expect-error global
3 | import _y18n from 'y18n'
4 |
5 | export default function y18n(locale?: string) {
6 | return _y18n({
7 | directory: path.join(__dirname, '../locales'),
8 | updateFiles: false,
9 | locale: locale || getLocale(),
10 | })
11 | }
12 |
13 | function getLocale() {
14 | const locale = process.env.LC_ALL || process.env.LC_MESSAGES || process.env.LANG || process.env.LANGUAGE || 'en_US'
15 | return locale.replace(/[.:].*/, '')
16 | }
17 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "ESNext",
4 | "target": "es2020",
5 | "lib": [
6 | "ESNext",
7 | "DOM"
8 | ],
9 | "esModuleInterop": true,
10 | "strict": true,
11 | "strictNullChecks": true,
12 | "moduleResolution": "Node",
13 | "resolveJsonModule": true,
14 | "skipLibCheck": true,
15 | "jsx": "preserve"
16 | },
17 | "exclude": [
18 | "**/dist",
19 | "**/node_modules",
20 | "**/test",
21 | "**/.output"
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'v*'
7 |
8 | jobs:
9 | release:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v2
13 | with:
14 | fetch-depth: 0
15 | - uses: actions/setup-node@v2
16 | with:
17 | node-version: '14'
18 | registry-url: https://registry.npmjs.org/
19 | - run: npm i -g pnpm
20 | - run: pnpm install -F suzip --frozen-lockfile
21 | - run: npm publish --access public
22 | env:
23 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
24 | - run: npx conventional-github-releaser -p angular
25 | env:
26 | CONVENTIONAL_GITHUB_RELEASER_TOKEN: ${{secrets.GITHUB_TOKEN}}
27 |
--------------------------------------------------------------------------------
/examples/basic/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "basic",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "suzip -h",
7 | "zip": "suzip -s ../assets -o ./.output/dist.zip",
8 | "tar": "suzip -s ../assets -o ./.output/dist.tar",
9 | "tar:gz": "suzip -s ../assets -o ./.output/dist.tar.gz",
10 | "zip:2": "suzip -s ../assets -p **/*.md -o ./.output/dist_md.zip",
11 | "zip:3": "suzip -s ../assets -i **/*.js -o ./.output/dist_ignore_js.zip",
12 | "zip:4": "cross-env SUZIP_DEBUG=debug esno src/main.ts",
13 | "zip:5": "suzip -s ./ -o ./.output/dist_ignore.zip -I ./.gitignore"
14 | },
15 | "dependencies": {
16 | "suzip": "workspace:*"
17 | },
18 | "devDependencies": {
19 | "cross-env": "^7.0.3",
20 | "esno": "^0.14.1"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 liuq
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/locales/zh_CN.json:
--------------------------------------------------------------------------------
1 | {
2 | "Compression files or directories": "压缩文件或目录",
3 | "Debug mode, print more information, modified by process.env.SUZIP_DEBUG environment variable": "调试模式,打印更多日志,由环境变量`process.env.SUZIP_DEBUG`控制",
4 | "Example 1": "1.压缩src目录下的所有文件到.output/dist.zip文件中",
5 | "Example 2": "2.压缩当前目录下所有除了node_modules和dist目录的文件到.output/dist.zip文件中",
6 | "Example 3": "3.指定ignore文件,压缩除匹配到的其他所有文件到.output/dist.zip文件中,注意,ignore文件中的规则需要补全,比如`node_modules`需要调整为`node_modules/**`",
7 | "File path to ignore output": "忽略输出的文件路径",
8 | "Include dot files": "包含以.符号开头的文件",
9 | "Input Sources (only one can be specified)": "输入源(只能指定一个)",
10 | "Only one input source can be specified": "仅支持指定一个输入源",
11 | "Only one output file can be specified": "仅支持指定一个输出文件",
12 | "Output File Path": "输出文件的位置",
13 | "Please specify the input source and output file": "请指定输入源和输出文件路径",
14 | "Regular expression matching input source file": "匹配输入源文件的正则表达式",
15 | "Regular expression to ignore output": "忽略输出文件的正则表达式",
16 | "Show examples": "显示示例",
17 | "Working directory path, default to current directory": "工作目录路径,默认为当前目录",
18 | "Zip option attribute in package-json file": "package.json文件中的zip选项属性"
19 | }
20 |
--------------------------------------------------------------------------------
/examples/suziprc/.suziprc.json:
--------------------------------------------------------------------------------
1 | {
2 | "zip": [
3 | {
4 | "output": "./.output/assets.zip",
5 | "context": "../assets",
6 | "cwd": "."
7 | },
8 | {
9 | "output": "./.output/dist.zip",
10 | "cwd": "../assets"
11 | },
12 | {
13 | "output": "./.output/dist.tar",
14 | "cwd": "../assets"
15 | },
16 | {
17 | "output": "./.output/dist.tar.gz",
18 | "cwd": "../assets"
19 | },
20 | {
21 | "output": "./.output/dist_separate_md_js.zip",
22 | "sources": [
23 | {
24 | "cwd": "../assets",
25 | "pattern": "**/*.md",
26 | "prefix": "markdown_file"
27 | },
28 | {
29 | "cwd": "../assets",
30 | "pattern": "**/*.js",
31 | "prefix": "javascript_file"
32 | }
33 | ]
34 | },
35 | {
36 | "output": "./.output/dist_separate_a_b.zip",
37 | "sources": [
38 | {
39 | "cwd": "../assets",
40 | "pattern": "**/*a*.*",
41 | "prefix": "name_a"
42 | },
43 | {
44 | "cwd": "../assets",
45 | "pattern": "**/b.*",
46 | "prefix": "name_b"
47 | }
48 | ]
49 | }
50 | ]
51 | }
52 |
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | # Examples
2 |
3 | + `assets` is an example of a directory that contains assets.
4 | + `basic` is an example of a directory that contains some basic usage.
5 | + `pkg` is an example of options in package.json file.
6 | + `suziprc` is an example of options in `.suziprc.json` file.
7 |
8 | Basic
9 |
10 | ```json
11 | {
12 | "scripts": {
13 | "dev": "suzip -h",
14 | "zip": "suzip -s ../assets -o ./.output/dist.zip",
15 | "tar": "suzip -s ../assets -o ./.output/dist.tar",
16 | "tar:gz": "suzip -s ../assets -o ./.output/dist.tar.gz",
17 | "zip:2": "suzip -s ../assets -p **/*.md -o ./.output/dist_md.zip",
18 | "zip:3": "suzip -s ../assets -i **/*.js -o ./.output/dist_ignore_js.zip",
19 | "zip:4": "cross-env SUZIP_DEBUG=debug esno src/main.ts",
20 | "zip:5": "suzip -s ./ -o ./.output/dist_ignore.zip -I ./.gitignore"
21 | }
22 | }
23 | ```
24 |
25 | ```bash
26 | # pnpm -F basic [Script Name]
27 |
28 | pnpm -F basic dev
29 | pnpm -F basic dev --debug
30 |
31 | # For test .gitignore file 'zip:5', you have to create a new file in src directory
32 | # Then
33 | pnpm -F basic zip:5 --debug
34 | ```
35 |
36 | pkg
37 |
38 | ```bash
39 | pnpm -F pkg zip
40 | ```
41 |
42 | suziprc
43 |
44 | ```bash
45 | pnpm -F suziprc zip
46 | ```
47 |
--------------------------------------------------------------------------------
/.vscode/i18n-ally-custom-framework.yml:
--------------------------------------------------------------------------------
1 | # .vscode/i18n-ally-custom-framework.yml
2 |
3 | # An array of strings which contain Language Ids defined by VS Code
4 | # You can check avaliable language ids here: https://code.visualstudio.com/docs/languages/overview#_language-id
5 | languageIds:
6 | - javascript
7 | - typescript
8 | - javascriptreact
9 | - typescriptreact
10 |
11 | # An array of RegExes to find the key usage. **The key should be captured in the first match group**.
12 | # You should unescape RegEx strings in order to fit in the YAML file
13 | # To help with this, you can use https://www.freeformatter.com/json-escape.html
14 | usageMatchRegex:
15 | # The following example shows how to detect `t("your.i18n.keys")`
16 | # the `{key}` will be placed by a proper keypath matching regex,
17 | # you can ignore it and use your own matching rules as well
18 | # __`demo` or __('demo') __("demo")
19 | - '__n?\(?[`''"]({key})[`''"]\)?'
20 |
21 | # An array of strings containing refactor templates.
22 | # The "$1" will be replaced by the keypath specified.
23 | # Optional: uncomment the following two lines to use
24 |
25 | # refactorTemplates:
26 | # - i18n.get("$1")
27 |
28 | # If set to true, only enables this custom framework (will disable all built-in frameworks)
29 | monopoly: true
30 |
--------------------------------------------------------------------------------
/examples/pkg/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pkg",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "suzip -h",
7 | "zip": "suzip"
8 | },
9 | "suzip": {
10 | "zip": [
11 | {
12 | "output": "./.output/assets.zip",
13 | "context": "../assets",
14 | "cwd": "."
15 | },
16 | {
17 | "output": "./.output/dist.zip",
18 | "cwd": "../assets"
19 | },
20 | {
21 | "output": "./.output/dist.tar",
22 | "cwd": "../assets"
23 | },
24 | {
25 | "output": "./.output/dist.tar.gz",
26 | "cwd": "../assets"
27 | },
28 | {
29 | "output": "./.output/dist_separate_md_js.zip",
30 | "sources": [
31 | {
32 | "cwd": "../assets",
33 | "pattern": "**/*.md",
34 | "prefix": "markdown_file"
35 | },
36 | {
37 | "cwd": "../assets",
38 | "pattern": "**/*.js",
39 | "prefix": "javascript_file"
40 | }
41 | ]
42 | },
43 | {
44 | "output": "./.output/dist_separate_a_b.zip",
45 | "sources": [
46 | {
47 | "cwd": "../assets",
48 | "pattern": "**/*a*.*",
49 | "prefix": "name_a"
50 | },
51 | {
52 | "cwd": "../assets",
53 | "pattern": "**/b.*",
54 | "prefix": "name_b"
55 | }
56 | ]
57 | }
58 | ]
59 | },
60 | "dependencies": {
61 | "suzip": "workspace:*"
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "suzip",
3 | "version": "0.1.5",
4 | "description": "archive file package",
5 | "keywords": [
6 | "suzip",
7 | "archive",
8 | "archiver",
9 | "zip",
10 | "gzip"
11 | ],
12 | "license": "MIT",
13 | "author": "liuq",
14 | "repository": "https://github.com/aliuq/suzip.git",
15 | "main": "dist/index.cjs",
16 | "module": "dist/index.mjs",
17 | "types": "dist/index.d.ts",
18 | "files": [
19 | "locales",
20 | "dist",
21 | "bin",
22 | "*.d.ts"
23 | ],
24 | "bin": {
25 | "suzip": "./bin/suzip.js"
26 | },
27 | "sideEffects": false,
28 | "scripts": {
29 | "dev": "esno src/index.ts",
30 | "dev:cli": "esno src/cli/index.ts",
31 | "build": "unbuild",
32 | "lint": "eslint .",
33 | "test": "node bin/suzip.js -h",
34 | "prepublishOnly": "npm run build",
35 | "release": "npx bumpp --push --tag --commit"
36 | },
37 | "dependencies": {
38 | "@aliuq/eslint-config": "^0.0.3",
39 | "archiver": "^5.1.0",
40 | "byte-size": "^8.1.0",
41 | "find-up": "^6.3.0",
42 | "fs-extra": "^9.0.1",
43 | "kolorist": "^1.5.1",
44 | "lodash": "^4.17.20",
45 | "y18n": "^5.0.8",
46 | "yargs": "^17.4.1"
47 | },
48 | "devDependencies": {
49 | "@types/fs-extra": "^9.0.13",
50 | "@types/glob": "^7.2.0",
51 | "@types/lodash-es": "^4.17.6",
52 | "@types/yargs": "^17.0.10",
53 | "eslint": "^8.14.0",
54 | "esno": "^0.14.1",
55 | "unbuild": "^0.7.4"
56 | },
57 | "bugs": "https://github.com/aliuq/suzip/issues",
58 | "homepage": "https://github.com/aliuq/suzip",
59 | "engines": {
60 | "node": ">=14.0.0"
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/locales/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "Compression files or directories": "Compression files or directories",
3 | "Debug mode, print more information, modified by process.env.SUZIP_DEBUG environment variable": "Debug mode, print more information, modified by `process.env.SUZIP_DEBUG` environment variable",
4 | "Example 1": "1.Compress all files in the src directory into the .output/dist.zip file",
5 | "Example 2": "2.Compress all files in the current directory except node_modules and dist into a .output/dist.zip file",
6 | "Example 3": "3.Specify the ignore file to compress all files except the matched ones into the .output/dist.zip file, note that the rules in the ignore file need to be completed, for example, `node_modules` needs to be adjusted to `node_modules/**`.",
7 | "File path to ignore output": "File path to ignore output",
8 | "Include dot files": "Include files starting with the . symbol",
9 | "Input Sources (only one can be specified)": "Input Sources (only one can be specified)",
10 | "Only one input source can be specified": "Only supports specifying one input source",
11 | "Only one output file can be specified": "Only one output file can be specified",
12 | "Output File Path": "Output File Path",
13 | "Please specify the input source and output file": "Please specify the input source and output file",
14 | "Regular expression matching input source file": "Regular expression matching input source file",
15 | "Regular expression to ignore output": "Regular expression to ignore output",
16 | "Show examples": "Show examples",
17 | "Working directory path, default to current directory": "Working directory path, default to current directory",
18 | "Zip option attribute in package-json file": "Zip option attribute in package.json file"
19 | }
20 |
--------------------------------------------------------------------------------
/src/cli/index.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-expressions */
2 | import { bold, gray, green, red, reset, underline } from 'kolorist'
3 | import yargs from 'yargs'
4 | import { hideBin } from 'yargs/helpers'
5 | import fs from 'fs-extra'
6 | import y18n from '../y18n'
7 | import { bugs, name, version } from '../../package.json'
8 | import zip from './zip'
9 |
10 | (async () => {
11 | const { __ } = y18n()
12 | let config
13 | let configPath
14 | try {
15 | const { findUp } = await import('find-up')
16 | configPath = await findUp(['.suziprc', '.suziprc.json'], { stopAt: process.cwd() })
17 | config = configPath ? JSON.parse(await fs.readFile(configPath, 'utf-8')) : {}
18 | }
19 | catch (err: any) {
20 | console.error(`${gray(`[${name.toUpperCase()}]`)} ${bold(red('An internal error occurred.'))}`)
21 | console.error(`${gray(`[${name.toUpperCase()}]`)} Found a config file path at ${green(configPath as string)} but failed to parse it.\n`)
22 | console.error(red(err.message))
23 | console.error(err)
24 | process.exit(1)
25 | }
26 |
27 | yargs(hideBin(process.argv))
28 | .scriptName('suzip')
29 | .usage('$0 [command] [option]')
30 | .command(zip)
31 | .command('*', __`Compression files or directories`, zip)
32 | .strict()
33 | .alias('h', 'help')
34 | .version(`v${version}`)
35 | .alias('v', 'version')
36 | .config(config)
37 | .pkgConf('suzip')
38 | .showHelpOnFail(false)
39 | .fail((msg, err, yargs) => {
40 | if (msg) {
41 | console.error(`\n${red(msg)}\n`)
42 | yargs.showHelp()
43 | process.exit(1)
44 | }
45 | else {
46 | console.error(`\n${gray(`[${name.toUpperCase()}]`)} ${bold(red('An internal error occurred.'))}`)
47 | console.error(`${gray(`[${name.toUpperCase()}]`)} ${reset(`Please report an issue, if none already exists: ${underline(bugs)}`)}`)
48 | yargs.exit(1, err)
49 | }
50 | })
51 | .argv
52 | })()
53 |
--------------------------------------------------------------------------------
/README_ZH.md:
--------------------------------------------------------------------------------
1 |
2 |
SUZIP
3 |
4 |
5 | English | 中文
6 |
7 |
8 | 一个简单好用的文件压缩工具
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ## 功能
18 |
19 | + 支持zip、tar、gzip格式
20 | + 提供命令行工具,支持配置文件
21 |
22 | ## 安装
23 |
24 | ```bash
25 | npm install suzip -D
26 | # or
27 | yarn add suzip -D
28 | # or
29 | pnpm add suzip -D
30 | ```
31 |
32 | ## 使用
33 |
34 | Node
35 |
36 | ```ts
37 | import { zip } from 'suzip'
38 |
39 | zip({
40 | cwd: './',
41 | output: './.output/dist.zip',
42 | ignore: ['node_modules/**', '.output/**', 'dist/**'],
43 | dot: true,
44 | })
45 | ```
46 |
47 | 设置`SUZIP_DEBUG=debug`环境变量以启动调试模式
48 |
49 | Command Line
50 |
51 | ```bash
52 | suzip [command] [option]
53 |
54 | Commands:
55 | suzip zip [options] Compression files or directories
56 | suzip Compression files or directories [default]
57 |
58 | Options:
59 | -s, --cwd Input Sources (only one can be specified) [string]
60 | -c, --context Working directory path, default to current directory[string]
61 | -o, --output Output File Path
62 | -p, --pattern Regular expression matching input source file [string]
63 | -i, --ignore Regular expression to ignore output [array]
64 | -I, --ignoreFile File path to ignore output [string]
65 | --dot Include dot files [boolean]
66 | --zip Zip option attribute in package.json file
67 | --example Show examples [boolean]
68 | -h, --help Show help [boolean]
69 | -v, --version Show version number [boolean]
70 | ```
71 |
72 | 查看更多示例,参考[examples](./examples/)目录
73 |
74 | ## 选项
75 |
76 | 详细选项类型,参考[源文件](https://github.com/aliuq/suzip/blob/ca4c97e3265a4d3a115460fa8d9ba2f25a66d447/src/types.ts#L96)
77 |
78 | + context: string, 默认为当前目录`process.cwd()`,它会影响其他值为相对路径的选项参数
79 | + output: string, 输出文件路径,默认为当前目录下的dist.zip
80 | + cwd: string, 输入源,只能指定一个
81 | + pattern: string, 正则表达式匹配输入源文件,默认为cwd指定路径下所有文件
82 | + ignore: string | string[], 正则表达式忽略输出,默认为空
83 | + ignoreFile: string | boolean, 指定一个ignore文件,如果为true,则使用cwd目录下的**.gitignore**文件
84 | + prefix: string,输出文件前缀
85 | + dot: boolean,是否包含`·`开头的文件
86 | + globOption: object,glob模块的选项, 更多详情参考[node-readdir-glob](https://github.com/yqnn/node-readdir-glob#options)、[node-glob](https://github.com/isaacs/node-glob#options)
87 | + globEntryData: object,glob模块的输入参数,更多详情参考[node-archiver](https://www.archiverjs.com/docs/archiver#entry-data)
88 | + archiverOption: object,archiver模块的选项,更多详情参考[node-archiver](https://www.archiverjs.com/docs/archiver#options)
89 | + sources: object[],输入源组,每个对象包含cwd、pattern、ignore、ignoreFile、prefix、dot、globOption、globEntryData属性
90 |
91 | ## 关于suzip
92 |
93 | suzip是在原来arch-file的基础上进行了重构和重命名,使用typescript进行类型管理,使用unbuild(rollup + esbuild)进行打包构建,新增了命令行工具,这能让压缩文件操作脱离webpack或vite编译流程,可以直接在命令行中使用,同样,在对应的hooks下,也能很方便的集成。
94 |
95 | ## License
96 |
97 | [MIT](./LICENSE)
98 |
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | import type { ZlibOptions } from 'zlib'
2 | import type { Stats } from 'fs'
3 | import type { IOptions } from 'glob'
4 |
5 | interface EntryData {
6 | /** Sets the entry name including internal path */
7 | name?: string
8 | /** Sets the entry date */
9 | date?: Date | string
10 | /** Sets the entry permissions */
11 | mode?: number
12 | /**
13 | * Sets a path prefix for the entry name. Useful when working with methods like directory or glob
14 | * @link https://www.archiverjs.com/docs/archiver/#directory
15 | * @link https://www.archiverjs.com/docs/archiver/#glob
16 | */
17 | prefix?: string
18 | /** Sets the stat data for this entry allowing for reduction of fs.stat calls. */
19 | stats?: Stats
20 | }
21 |
22 | interface EntryZipData {
23 | /** Prepends a forward slash to archive file paths */
24 | namePrependSlash?: boolean
25 | /** Sets the compression method to STORE */
26 | store?: boolean
27 | }
28 |
29 | interface ArchiveCoreOptions {
30 | /**
31 | * Sets the number of workers used to process the internal fs stat queue.
32 | * @default 4
33 | */
34 | statConcurrency?: number
35 | }
36 |
37 | export interface ArchiverZipOptions extends ArchiveCoreOptions {
38 | /** Sets the zip archive comment */
39 | comment?: string
40 | /** Forces the archive to contain local file times instead of UTC */
41 | forceLocalTime?: boolean
42 | /** Forces the archive to contain ZIP64 headers */
43 | forceZip64?: boolean
44 | /** Prepends a forward slash to archive file paths */
45 | namePrependSlash?: boolean
46 | /** Sets the compression method to STORE */
47 | store?: boolean
48 | /**
49 | * Passed to zlib to control compression
50 | * @link https://nodejs.org/api/zlib.html#zlib_class_options
51 | */
52 | zlib?: ZlibOptions
53 | }
54 |
55 | /**
56 | * @link https://www.archiverjs.com/docs/archiver#constructor
57 | * @link https://www.npmjs.com/package/tar-stream
58 | */
59 | export interface ArchiverTarOptions extends ArchiveCoreOptions {
60 | /** Compress the tar archive using gzip */
61 | gzip?: boolean
62 | /** Passed to zlib to control compression. */
63 | gzipOptions?: ZlibOptions
64 | }
65 |
66 | export interface Source {
67 | /**
68 | * The current working directory in which to search
69 | * @default `process.cwd()`
70 | */
71 | cwd?: string
72 | /** pattern to search for */
73 | pattern?: string | string[]
74 | /** Add a pattern or an array of glob patterns to exclude matches. */
75 | ignore?: string | string[]
76 | /** ignore file, likes `.gitignore` */
77 | ignoreFile?: string | boolean
78 | /** prefix directory to the pattern */
79 | prefix?: string
80 | /**
81 | * Allow pattern to match filenames starting with a period,
82 | * even if the pattern does not explicitly have a period in that spot.
83 | */
84 | dot?: boolean
85 | /**
86 | * glob another option
87 | *
88 | * @see node-readdir-glob / https://github.com/yqnn/node-readdir-glob#options
89 | * @see node-glob / https://github.com/isaacs/node-glob#options
90 | */
91 | globOption?: IOptions | Record
92 | /** The entry data object */
93 | globEntryData?: EntryData & EntryZipData
94 | }
95 |
96 | export type LogLevel = 'error' | 'warn' | 'info' | 'debug'
97 |
98 | export interface Option extends Source {
99 | context?: string
100 | archiverOption?: ArchiverZipOptions | ArchiverTarOptions
101 | source?: Source
102 | sources?: Source[]
103 | output?: string
104 | }
105 |
106 | export type Format = 'zip' | 'tar' | 'json'
107 |
108 | export interface ArchiveOption {
109 | format: Format
110 | sources: Source[]
111 | path: string
112 | filename: string
113 | archiverOption: ArchiverZipOptions | ArchiverTarOptions
114 | }
115 |
--------------------------------------------------------------------------------
/src/util.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 | import path from 'path'
3 | import { bgCyan, black, blue, gray, green, lightBlue, lightGray, lightMagenta, lightRed, lightYellow } from 'kolorist'
4 | import pkg from '../package.json'
5 | import type { LogLevel } from './types'
6 |
7 | // Get absolute path
8 | export function getAbsPath(p: string, context: string) {
9 | return slash(path.isAbsolute(p) ? p : path.join(context, p))
10 | }
11 |
12 | // convert `\/` to `path.sep`
13 | export function slash(p: string) {
14 | return p.replace(/[\/]/g, path.sep)
15 | }
16 |
17 | export function createLogger(level: LogLevel = 'info') {
18 | const levelMaps = {
19 | error: 0,
20 | warn: 1,
21 | info: 2,
22 | debug: 3,
23 | }
24 | const levelInt = typeof levelMaps[level] === 'undefined' ? levelMaps.info : levelMaps[level]
25 | const name = black(bgCyan(` ${pkg.name.toUpperCase()} `))
26 | const log = (...args: any) => console.log(`${name} ${args}`)
27 | const now = () => gray(new Date().toISOString())
28 | return {
29 |
30 | debug(message: any) {
31 | if (levelInt >= 3)
32 | log(`${lightBlue('[debug]')} ${now()} ${message}`)
33 | },
34 |
35 | debugNormal(...message: any) {
36 | if (levelInt >= 3)
37 | console.log(...message)
38 | },
39 |
40 | info(message: any) {
41 | if (levelInt >= 2)
42 | log(`${lightGray('[info]')} ${now()} ${message}`)
43 | },
44 |
45 | warn(message: any) {
46 | if (levelInt >= 1)
47 | log(`${lightYellow('[warn]')} ${now()} ${message}`)
48 | },
49 |
50 | error(message: any) {
51 | if (levelInt >= 0)
52 | log(`${lightRed('[error]')} ${now()} ${message}`)
53 | },
54 |
55 | table(...message: any) {
56 | if (levelInt >= 3)
57 | console.table(...message)
58 | },
59 |
60 | pretter(msgs: any, opts: PretterOptions) {
61 | if (levelInt >= 3)
62 | pretterInfo(msgs, opts)
63 | },
64 |
65 | group(message: any) {
66 | if (levelInt >= 3)
67 | console.group(message)
68 | },
69 |
70 | groupEnd() {
71 | if (levelInt >= 3)
72 | console.groupEnd()
73 | },
74 | }
75 | }
76 |
77 | interface PretterOptions {
78 | title: string
79 | root?: boolean
80 | }
81 |
82 | function pretterInfo(data: any, opts: PretterOptions) {
83 | const root = typeof opts.root === 'undefined' ? true : opts.root
84 | opts.title = UpperFirstWord(opts.title)
85 | // Start
86 | if (root)
87 | console.group(`${lightMagenta('Tasks:')} ${green(opts.title)}`)
88 |
89 | // Array
90 | if (Array.isArray(data)) {
91 | const hasObject = data.some(item => typeof item === 'object')
92 | if (!root && hasObject)
93 | console.groupCollapsed(`${gray(opts.title)}:`)
94 |
95 | if (hasObject) {
96 | data.forEach((d, i) => {
97 | pretterInfo(d, { title: `${opts.title} ${i + 1}`, root: false })
98 | if (i === data.length - 1)
99 | console.groupEnd()
100 | })
101 | }
102 | else {
103 | console.log(`${gray(opts.title)}: ${data.map(d => blue(d)).join('、')}`)
104 | }
105 | }
106 | // Object
107 | else if (typeof data === 'object') {
108 | const keys = Object.keys(data)
109 | if (!keys.length) {
110 | console.log(`${gray(opts.title)}: ${JSON.stringify(data)}`)
111 | }
112 | else {
113 | if (!root)
114 | console.groupCollapsed(`${gray(opts.title)}:`)
115 |
116 | keys.forEach((key, i) => {
117 | pretterInfo(data[key], { title: key, root: false })
118 | if (i === keys.length - 1)
119 | console.groupEnd()
120 | })
121 | }
122 | }
123 | // Other types
124 | else {
125 | console.log(`${gray(opts.title)}: ${green(data)}`)
126 | }
127 | }
128 |
129 | function UpperFirstWord(str: string) {
130 | return str.replace(/^\w/, c => c.toUpperCase())
131 | }
132 |
--------------------------------------------------------------------------------
/src/cli/zip.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Compress a file or a directory.
3 | *
4 | * @examples see {@link generateExamples}
5 | */
6 |
7 | import type { CommandModule, Options } from 'yargs'
8 | import yargs from 'yargs'
9 | import { pick } from 'lodash'
10 | import { red } from 'kolorist'
11 | import type { Option } from '../types'
12 | import y18n from '../y18n'
13 | import { zip } from '../archive'
14 |
15 | const { __ } = y18n()
16 |
17 | type ZipOption = Pick