diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 73b4df8..b13e922 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -43,19 +43,18 @@ jobs: - name: โœ… Validate run: yarn validate - - name: โšก Build release executable - run: yarn build:release - - - name: ๐Ÿ“ฆ Create npm package - run: yarn script:package-npm && yarn copy-files - - - name: ๐Ÿงช Smoke-test npm package - run: yarn package:smoke + - name: ๐Ÿ“ฆ Build cross-platform package + run: yarn package - name: ๐Ÿ”Ž Verify artifact layout run: | test -f dist/portal/browser/index.html - test -x dist/quick-commitlint/bin/quick-commitlint + test -x dist/quick-commitlint/bin/quick-commitlint.js + test -x dist/quick-commitlint/bin/native/darwin-arm64/quick-commitlint + test -x dist/quick-commitlint/bin/native/darwin-x64/quick-commitlint + test -x dist/quick-commitlint/bin/native/linux-arm64/quick-commitlint + test -x dist/quick-commitlint/bin/native/linux-x64/quick-commitlint + test -f dist/quick-commitlint/bin/native/win32-x64/quick-commitlint.exe test -f dist/quick-commitlint/package.json - name: ๐Ÿš€ Publish npm diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 59e409b..7cea68a 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -59,20 +59,49 @@ jobs: with: coverage-file: coverage/merged/kcov-merged/cobertura.xml - - name: โšก Build release executable - run: yarn build:release - - - name: ๐Ÿ“ฆ Create npm package - run: yarn script:package-npm && yarn copy-files - - - name: ๐Ÿงช Smoke-test npm package - run: yarn package:smoke + - name: ๐Ÿ“ฆ Build cross-platform package + run: yarn package - name: ๐Ÿ”Ž Verify artifact layout run: | test -f dist/portal/browser/index.html - test -x dist/quick-commitlint/bin/quick-commitlint + test -x dist/quick-commitlint/bin/quick-commitlint.js + test -x dist/quick-commitlint/bin/native/darwin-arm64/quick-commitlint + test -x dist/quick-commitlint/bin/native/darwin-x64/quick-commitlint + test -x dist/quick-commitlint/bin/native/linux-arm64/quick-commitlint + test -x dist/quick-commitlint/bin/native/linux-x64/quick-commitlint + test -f dist/quick-commitlint/bin/native/win32-x64/quick-commitlint.exe test -f dist/quick-commitlint/package.json - name: ๐Ÿ Benchmark performance gate run: yarn benchmark + + package-smoke-test: + name: ๐Ÿ“ฆ Package Smoke Test (${{ matrix.os }}) + strategy: + fail-fast: false + matrix: + os: [macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + + steps: + - name: ๐Ÿ—œ๏ธ Checkout + uses: actions/checkout@v7 + + - name: ๐Ÿ—œ๏ธ Setup Node + uses: actions/setup-node@v6 + with: + node-version: 24 + + - name: ๐Ÿ—œ๏ธ Setup Zig + uses: mlugg/setup-zig@v2 + with: + version: 0.16.0 + + - name: ๐Ÿ› ๏ธ Install dependencies + uses: ./.github/actions/cached-deps + with: + caching: 'false' + + - name: ๐Ÿ“ฆ Build and smoke-test cross-platform package + run: yarn package diff --git a/AGENTS.md b/AGENTS.md index 2c2fd6d..09d0829 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,7 +3,7 @@ ## Toolchain - Use Zig 0.16.0, Node.js 24, and Yarn 1.22.22. -- Node is used for development and publishing only; the published command must execute the Zig binary directly. +- Node is used for development, publishing, and the small platform launcher; all linting executes in the bundled Zig binary. - Treat `package.json` as the sole source of truth for the release version. Keep `build.zig.zon` at the neutral `0.0.0` placeholder and derive build/test/package expectations from `package.json`. - Never change the `build.zig.zon` fingerprint. diff --git a/README.md b/README.md index 0c8bcbc..d227015 100644 --- a/README.md +++ b/README.md @@ -18,14 +18,14 @@ -`quick-commitlint` checks Conventional Commit messages with a native Linux x86-64 executable. Node and Yarn are used to distribute the package, but the installed command starts the Zig binary directly and has no runtime dependencies. +`quick-commitlint` checks Conventional Commit messages with native Zig executables for macOS, Linux, and Windows. A small Node.js launcher selects the executable bundled for the current platform; the package has no runtime npm dependencies. ## โœจ Why use it? | Feature | Details | | -------------------------------- | --------------------------------------------------------------------------------- | -| โšก **Fast native executable** | Starts in about one millisecond without loading a JavaScript runtime. | -| ๐Ÿ“ฆ **Zero runtime dependencies** | npm installs a standalone, statically linked Zig binary. | +| โšก **Fast native linting** | A thin launcher hands all linting work to the bundled Zig executable. | +| ๐Ÿ“ฆ **Zero package dependencies** | All supported native executables ship in the npm package. | | ๐Ÿงฉ **Familiar configuration** | Uses commitlint-style rule tuples with built-in conventional and Angular presets. | | ๐Ÿ”’ **Strict and predictable** | Rejects malformed JSON, unknown options, duplicate keys, and invalid UTF-8. | | ๐ŸŒ **International subjects** | Counts Unicode code points while keeping syntax checks fast and ASCII-based. | @@ -40,7 +40,7 @@ npm install quick-commitlint --save-dev yarn add quick-commitlint --dev ``` -The initial release supports Linux x86-64 only. +The package includes native executables for macOS arm64/x64, Linux arm64/x64, and Windows x64. The launcher requires Node.js 24 or 25. ## ๐Ÿช Use in a commit hook @@ -131,15 +131,12 @@ yarn install yarn validate ``` -Build the publishable Linux x86-64 package and test its tarball: +Build the publishable cross-platform package and test its tarball: ```bash yarn clean yarn validate -yarn build:release -yarn script:package-npm -yarn copy-files -yarn package:smoke +yarn package ``` Build artifacts are kept as sibling outputs with no overlap between the website and published native package: @@ -149,7 +146,9 @@ dist/ โ”œโ”€โ”€ portal/ โ”‚ โ””โ”€โ”€ browser/ # Angular SSG output for GitHub Pages โ””โ”€โ”€ quick-commitlint/ - โ”œโ”€โ”€ bin/quick-commitlint # Native Zig executable + โ”œโ”€โ”€ bin/ + โ”‚ โ”œโ”€โ”€ quick-commitlint.js # Platform launcher + โ”‚ โ””โ”€โ”€ native/ # Five platform-specific Zig executables โ”œโ”€โ”€ LICENSE โ”œโ”€โ”€ README.md โ””โ”€โ”€ package.json # Publishable npm manifest @@ -169,7 +168,6 @@ yarn benchmark The README animation is defined in `docs/terminal-demo.tape` and rendered with the official VHS Docker image: ```bash -yarn build:release yarn demo:render ``` diff --git a/npm/quick-commitlint.js b/npm/quick-commitlint.js new file mode 100644 index 0000000..d28e06c --- /dev/null +++ b/npm/quick-commitlint.js @@ -0,0 +1,71 @@ +#!/usr/bin/env node +'use strict'; + +const { spawnSync } = require('node:child_process'); +const { existsSync } = require('node:fs'); +const { join } = require('node:path'); + +const supportedPlatforms = new Map([ + ['darwin-arm64', 'quick-commitlint'], + ['darwin-x64', 'quick-commitlint'], + ['linux-arm64', 'quick-commitlint'], + ['linux-x64', 'quick-commitlint'], + ['win32-x64', 'quick-commitlint.exe'], +]); + +function getBinaryPath(platform = process.platform, arch = process.arch, baseDir = __dirname) { + const id = `${platform}-${arch}`; + const binary = supportedPlatforms.get(id); + + if (!binary) { + throw new Error( + `Unsupported platform ${id}. Supported platforms: ${[...supportedPlatforms.keys()].join(', ')}.`, + ); + } + + return join(baseDir, 'native', id, binary); +} + +function resolveBinary(platform = process.platform, arch = process.arch, baseDir = __dirname) { + const id = `${platform}-${arch}`; + const binaryPath = getBinaryPath(platform, arch, baseDir); + if (!existsSync(binaryPath)) { + throw new Error(`The package is missing its ${id} executable at ${binaryPath}.`); + } + + return binaryPath; +} + +function shouldUseExecve(platform = process.platform, getExecve = () => process.execve) { + if (platform !== 'darwin' && platform !== 'linux') return false; + return typeof getExecve() === 'function'; +} + +function run(args = process.argv.slice(2)) { + const binaryPath = resolveBinary(); + if (shouldUseExecve()) { + process.execve(binaryPath, [binaryPath, ...args], process.env); + } + + const result = spawnSync(binaryPath, args, { stdio: 'inherit' }); + + if (result.error) throw result.error; + if (result.signal) { + process.kill(process.pid, result.signal); + return; + } + + process.exitCode = result.status ?? 1; +} + +if (require.main === module) { + try { + run(); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.error(`quick-commitlint: ${message}`); + process.exitCode = 1; + } +} + +module.exports = { getBinaryPath, resolveBinary, run, shouldUseExecve }; diff --git a/package.json b/package.json index 73f2e76..440ad4c 100644 --- a/package.json +++ b/package.json @@ -10,20 +10,22 @@ "private": false, "description": "A very fast native commit message linter built with Zig", "scripts": { - "validate": "yarn format:check && yarn typecheck:scripts && yarn build && yarn test && yarn test:integration && yarn test:differential && yarn portal:validate", + "validate": "yarn format:check && yarn typecheck:scripts && yarn test:launcher && yarn build && yarn test && yarn test:integration && yarn test:differential && yarn portal:validate", "format:check": "zig fmt --check src/root.zig src/main.zig src/cli.zig src/config.zig src/lint.zig build.zig", "typecheck:scripts": "tsc --project scripts/tsconfig.json", "build": "zig build", - "build:release": "zig build -Doptimize=ReleaseFast -Dtarget=x86_64-linux -Dcpu=baseline", + "build:platforms": "tsx ./scripts/build-platforms.ts", + "build:release": "yarn build:platforms", "start": "zig build run", "test": "zig build test", + "test:launcher": "node --test ./scripts/quick-commitlint.test.cjs", "test:integration": "tsx ./scripts/integration.ts", "test:differential": "tsx ./scripts/differential.ts", "coverage:build": "rimraf coverage zig-out/coverage-tests && zig build coverage", "fuzz:build": "zig build fuzz", "clean": "rimraf zig-out dist projects/portal/dist", "prepare": "husky", - "copy-files": "copyfiles -u 2 zig-out/bin/quick-commitlint dist/quick-commitlint/bin && copyfiles README.md LICENSE dist/quick-commitlint", + "package": "yarn build:release && yarn script:package-npm && yarn package:smoke", "script:package-npm": "tsx ./scripts/package-npm.ts", "script:package-github": "tsx ./scripts/package-github.ts", "package:smoke": "tsx ./scripts/smoke-package.ts", @@ -31,7 +33,7 @@ "demo:render": "bash ./.agents/skills/recreate-terminal-demo/scripts/render-demo.sh", "version": "auto-changelog -p && git add CHANGELOG.md", "postversion": "git push && git push --follow-tags", - "publish:beta": "yarn && yarn clean && yarn validate && yarn build:release && yarn script:package-npm && yarn copy-files && npm publish --folder dist/quick-commitlint --tag beta", + "publish:beta": "yarn && yarn clean && yarn validate && yarn package && npm publish --folder dist/quick-commitlint --tag beta", "release:beta": "npm version prerelease -m \"chore(update): prerelease %s ฮฒ\"", "release:patch": "git checkout master && npm version patch -m \"chore(update): patch release %s ๐Ÿ›\"", "release:minor": "git checkout master && npm version minor -m \"chore(update): release %s ๐Ÿš€\"", @@ -42,7 +44,7 @@ "portal:build": "ng build portal", "portal:build:pages": "ng build portal --base-href /quick-commitlint/", "portal:ssg:verify": "node --experimental-strip-types --no-warnings ./scripts/verify-portal-ssg.ts", - "portal:format:check": "prettier --check README.md package.json \"projects/portal/src/**/*.{ts,html,css,md}\" projects/portal/.postcssrc.json angular.json eslint.config.js projects/portal/eslint.config.js scripts/verify-portal-ssg.ts scripts/package-npm.ts scripts/package-github.ts scripts/smoke-package.ts scripts/benchmark.ts \".github/workflows/*.yml\"", + "portal:format:check": "prettier --check README.md package.json \"projects/portal/src/**/*.{ts,html,css,md}\" projects/portal/.postcssrc.json angular.json eslint.config.js projects/portal/eslint.config.js npm/quick-commitlint.js scripts/verify-portal-ssg.ts scripts/build-platforms.ts scripts/platforms.ts scripts/quick-commitlint.test.cjs scripts/package-npm.ts scripts/package-github.ts scripts/smoke-package.ts scripts/benchmark.ts \".github/workflows/*.yml\"", "portal:validate": "yarn portal:format:check && yarn portal:lint && yarn portal:test && yarn portal:build && yarn portal:ssg:verify" }, "devDependencies": { @@ -70,7 +72,6 @@ "angular-eslint": "22.1.0", "auto-changelog": "^2.6.0", "axe-core": "^4.10.3", - "copyfiles": "^2.4.1", "eslint": "^10.6.0", "fs-extra": "^11.3.6", "husky": "^9.1.7", diff --git a/projects/portal/src/app/docs/content/compatibility.md b/projects/portal/src/app/docs/content/compatibility.md index a5f6412..d49a2a3 100644 --- a/projects/portal/src/app/docs/content/compatibility.md +++ b/projects/portal/src/app/docs/content/compatibility.md @@ -1,6 +1,6 @@ # Commitlint compatibility -Quick Commitlint is a focused native implementation of a tested subset of commitlint behavior. It is designed for projects that want the included Conventional or Angular rules without starting Node.js for every commit. +Quick Commitlint is a focused native implementation of a tested subset of commitlint behavior. It is designed for projects that want the included Conventional or Angular rules without loading commitlint's JavaScript configuration and rule stack for every commit. It is not a drop-in replacement for every commitlint configuration. @@ -19,7 +19,7 @@ The repository runs differential cases against `@commitlint/cli`, `@commitlint/c | Area | Quick Commitlint | Full commitlint | | --------------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------- | -| Runtime | Native Linux x86-64 Zig binary | Node.js | +| Runtime | Small Node.js launcher plus a native Zig linting executable | Node.js | | Default configuration | Built-in `conventional` when no config is found | Normally requires a discovered or supplied configuration | | Configuration files | Strict `.quick-commitlint.json` JSON | Multiple JS/TS/JSON/YAML formats through its configuration stack | | Presets | Exactly `conventional` and `angular` | Shareable npm configurations and `extends` | @@ -58,7 +58,7 @@ Quick Commitlint is a good fit when: - one of the two built-in presets is close to the desired policy; - the supported JSON overrides are sufficient; -- fast native startup and a dependency-free installed command matter; -- Linux x86-64 is the deployment platform. +- fast native linting and no additional runtime npm dependencies matter; +- macOS arm64/x64, Linux arm64/x64, or Windows x64 is the deployment platform. Use full commitlint when the project depends on shareable npm configurations, plugins, custom parsers, custom ignores, or rules outside the supported subset. diff --git a/projects/portal/src/app/docs/content/development.md b/projects/portal/src/app/docs/content/development.md index 6bbad81..64fc2b1 100644 --- a/projects/portal/src/app/docs/content/development.md +++ b/projects/portal/src/app/docs/content/development.md @@ -20,10 +20,7 @@ yarn validate ```bash yarn clean yarn validate -yarn build:release -yarn script:package-npm -yarn copy-files -yarn package:smoke +yarn package ``` ## Benchmark @@ -49,9 +46,9 @@ Packaging changes require the release build and smoke test in addition to normal ```bash yarn build:release yarn script:package-npm -yarn copy-files yarn package:smoke +yarn script:package-github git diff --check ``` -The portal builds into `dist/portal`; the native npm package builds into `dist/quick-commitlint`. +The portal builds into `dist/portal`; the cross-platform npm package builds into `dist/quick-commitlint`. diff --git a/projects/portal/src/app/docs/content/getting-started.md b/projects/portal/src/app/docs/content/getting-started.md index d37a61f..0313270 100644 --- a/projects/portal/src/app/docs/content/getting-started.md +++ b/projects/portal/src/app/docs/content/getting-started.md @@ -1,6 +1,6 @@ # Getting started -Quick Commitlint is a native Linux x86-64 command that checks commit messages against a focused set of commitlint-compatible rules. The installed command starts the Zig binary directly and has no Node.js runtime dependencies. +Quick Commitlint checks commit messages against a focused set of commitlint-compatible rules using a native Zig executable. A small Node.js launcher selects the executable bundled for the current platform, with no additional runtime npm dependencies. ## Install @@ -41,4 +41,4 @@ Continue with [Usage](docs/usage/), review the accepted [commit message format]( ## Platform support -The current package supports Linux x86-64. Node and a package manager are only used to download the package; the command itself is a native executable. +The package supports macOS arm64/x64, Linux arm64/x64, and Windows x64. The launcher requires Node.js 24 or 25 and uses it only to select and spawn the matching bundled Zig executable. diff --git a/projects/portal/src/app/pages/home/home.html b/projects/portal/src/app/pages/home/home.html index 67fe60f..cdcd722 100644 --- a/projects/portal/src/app/pages/home/home.html +++ b/projects/portal/src/app/pages/home/home.html @@ -3,8 +3,8 @@

Native Conventional Commit linting

Commit message checks at native speed.

- Quick Commitlint is a strict, dependency-free linter built with Zig. It starts in about a - millisecond and understands familiar commitlint-style presets and rule tuples. + Quick Commitlint is a strict native linter built with Zig. It understands familiar + commitlint-style presets and rule tuples across macOS, Linux, and Windows.

Get started @@ -29,17 +29,17 @@

Small tool, focused job

Fast native executable - Starts without loading a JavaScript runtime and reports elapsed lint time with every - result. + A thin platform launcher hands linting to a bundled Zig executable and reports elapsed + lint time with every result. Zero runtime dependenciesZero package dependencies - npm distributes a standalone Zig binary. Node and Yarn are only used for delivery and - development. + The npm package includes all supported native executables without installing additional + runtime packages. @@ -56,7 +56,7 @@

Small tool, focused job

Ready in one command

Install as a development tool

-

The current package targets Linux x86-64.

+

Supports macOS arm64/x64, Linux arm64/x64, and Windows x64.

npm install quick-commitlint --save-dev
diff --git a/projects/portal/src/index.html b/projects/portal/src/index.html index 96b38d5..28edd3d 100644 --- a/projects/portal/src/index.html +++ b/projects/portal/src/index.html @@ -39,7 +39,7 @@ "@type": "SoftwareApplication", "name": "Quick Commitlint", "applicationCategory": "DeveloperApplication", - "operatingSystem": "Linux x86-64", + "operatingSystem": "macOS arm64/x64, Linux arm64/x64, Windows x64", "url": "https://celtian.github.io/quick-commitlint/", "codeRepository": "https://github.com/Celtian/quick-commitlint" } diff --git a/scripts/benchmark.ts b/scripts/benchmark.ts index a6f99ae..03f65f9 100644 --- a/scripts/benchmark.ts +++ b/scripts/benchmark.ts @@ -4,7 +4,7 @@ import { tmpdir } from 'os'; import { join, resolve } from 'path'; const root = resolve(__dirname, '..'); -const native = resolve(root, 'dist', 'quick-commitlint', 'bin', 'quick-commitlint'); +const packaged = resolve(root, 'dist', 'quick-commitlint', 'bin', 'quick-commitlint.js'); const commitlint = resolve(root, 'node_modules', '@commitlint', 'cli', 'cli.js'); const iterations = Number(process.env.BENCHMARK_ITERATIONS ?? 40); const temp = mkdtempSync(join(tmpdir(), 'quick-commitlint-benchmark-')); @@ -38,11 +38,15 @@ function measure(command: string, args: string[], input?: string): number { } try { - const nativeFile = measure(native, [messagePath]); - const nativeStdin = measure(native, [], 'feat(benchmark): measure native startup'); - const nativeConfig = measure( - native, - ['--config', configPath], + const packagedFile = measure(process.execPath, [packaged, messagePath]); + const packagedStdin = measure( + process.execPath, + [packaged], + 'feat(benchmark): measure native startup', + ); + const packagedConfig = measure( + process.execPath, + [packaged, '--config', configPath], 'feat(benchmark): measure native startup', ); const nodeStdin = measure( @@ -50,10 +54,10 @@ try { [commitlint, '--extends', '@commitlint/config-conventional'], 'feat(benchmark): measure native startup', ); - const ratio = nodeStdin / nativeStdin; - console.log(`quick-commitlint file median: ${nativeFile.toFixed(3)} ms`); - console.log(`quick-commitlint stdin median: ${nativeStdin.toFixed(3)} ms`); - console.log(`quick-commitlint JSON config median: ${nativeConfig.toFixed(3)} ms`); + const ratio = nodeStdin / packagedStdin; + console.log(`quick-commitlint file median: ${packagedFile.toFixed(3)} ms`); + console.log(`quick-commitlint stdin median: ${packagedStdin.toFixed(3)} ms`); + console.log(`quick-commitlint JSON config median: ${packagedConfig.toFixed(3)} ms`); console.log(`commitlint stdin median: ${nodeStdin.toFixed(3)} ms`); console.log(`cold-process improvement: ${ratio.toFixed(1)}x`); if (ratio < 10) throw new Error(`Performance gate failed: ${ratio.toFixed(1)}x is below 10x.`); diff --git a/scripts/build-platforms.ts b/scripts/build-platforms.ts new file mode 100644 index 0000000..962bcc6 --- /dev/null +++ b/scripts/build-platforms.ts @@ -0,0 +1,31 @@ +import { spawnSync } from 'child_process'; +import { emptyDirSync, ensureDirSync } from 'fs-extra'; +import { resolve } from 'path'; + +import { platforms } from './platforms'; + +const rootDir = resolve(__dirname, '..'); +const outputDir = resolve(rootDir, 'zig-out', 'platforms'); +emptyDirSync(outputDir); + +for (const platform of platforms) { + const prefix = resolve(outputDir, platform.id); + ensureDirSync(prefix); + console.log(`Building ${platform.id} (${platform.target})...`); + + const result = spawnSync( + 'zig', + [ + 'build', + `-Dtarget=${platform.target}`, + '-Dcpu=baseline', + '-Doptimize=ReleaseFast', + '--prefix', + prefix, + ], + { cwd: rootDir, stdio: 'inherit' }, + ); + + if (result.error) throw result.error; + if (result.status !== 0) process.exit(result.status ?? 1); +} diff --git a/scripts/package-github.ts b/scripts/package-github.ts index 029c4a9..a5cab13 100644 --- a/scripts/package-github.ts +++ b/scripts/package-github.ts @@ -1,25 +1,14 @@ -import { ensureDirSync, writeFileSync } from 'fs-extra'; +import { readJsonSync, writeFileSync } from 'fs-extra'; import { join, resolve } from 'path'; -const pkg = require(resolve(__dirname, '..', 'package.json')); +const distDir = resolve(__dirname, '..', 'dist', 'quick-commitlint'); +const pkg = readJsonSync(join(distDir, 'package.json')); -pkg.scripts = undefined; -pkg.devDependencies = undefined; -pkg.packageManager = undefined; -pkg.engines = undefined; -pkg.files = undefined; -pkg.bin = { - 'quick-commitlint': 'bin/quick-commitlint', -}; -pkg.os = ['linux']; -pkg.cpu = ['x64']; pkg.name = '@celtian/quick-commitlint'; pkg.publishConfig = { registry: 'https://npm.pkg.github.com', }; -const distDir = join(__dirname, '..', 'dist', 'quick-commitlint'); -ensureDirSync(distDir); writeFileSync(join(distDir, 'package.json'), JSON.stringify(pkg, null, 2) + '\n'); -console.log('Generated the GitHub Packages manifest in dist/quick-commitlint/.'); +console.log('Prepared dist/quick-commitlint/package.json for GitHub Packages.'); diff --git a/scripts/package-npm.ts b/scripts/package-npm.ts index d757e01..00dc40b 100644 --- a/scripts/package-npm.ts +++ b/scripts/package-npm.ts @@ -1,21 +1,52 @@ -import { ensureDirSync, writeFileSync } from 'fs-extra'; +import { + chmodSync, + copyFileSync, + emptyDirSync, + ensureDirSync, + pathExistsSync, + writeFileSync, +} from 'fs-extra'; import { join, resolve } from 'path'; -const pkg = require(resolve(__dirname, '..', 'package.json')); +import { platforms } from './platforms'; + +const rootDir = resolve(__dirname, '..'); +const pkg = require(join(rootDir, 'package.json')); pkg.scripts = undefined; pkg.devDependencies = undefined; pkg.packageManager = undefined; -pkg.engines = undefined; +pkg.engines = { node: pkg.engines.node }; pkg.files = undefined; pkg.bin = { - 'quick-commitlint': 'bin/quick-commitlint', + 'quick-commitlint': 'bin/quick-commitlint.js', }; -pkg.os = ['linux']; -pkg.cpu = ['x64']; -const distDir = join(__dirname, '..', 'dist', 'quick-commitlint'); -ensureDirSync(distDir); +const distDir = join(rootDir, 'dist', 'quick-commitlint'); +emptyDirSync(distDir); writeFileSync(join(distDir, 'package.json'), JSON.stringify(pkg, null, 2) + '\n'); -console.log('Generated the npm package manifest in dist/quick-commitlint/.'); +for (const file of ['README.md', 'LICENSE']) { + copyFileSync(join(rootDir, file), join(distDir, file)); +} + +const binDir = join(distDir, 'bin'); +ensureDirSync(binDir); +const launcherPath = join(binDir, 'quick-commitlint.js'); +copyFileSync(join(rootDir, 'npm', 'quick-commitlint.js'), launcherPath); +chmodSync(launcherPath, 0o755); + +for (const platform of platforms) { + const source = join(rootDir, 'zig-out', 'platforms', platform.id, 'bin', platform.binary); + if (!pathExistsSync(source)) { + throw new Error(`Missing ${platform.id} binary. Run "yarn build:release" first.`); + } + + const nativeDir = join(binDir, 'native', platform.id); + ensureDirSync(nativeDir); + const destination = join(nativeDir, platform.binary); + copyFileSync(source, destination); + if (platform.os !== 'win32') chmodSync(destination, 0o755); +} + +console.log('Created the cross-platform npm package in dist/quick-commitlint/.'); diff --git a/scripts/platforms.ts b/scripts/platforms.ts new file mode 100644 index 0000000..0918384 --- /dev/null +++ b/scripts/platforms.ts @@ -0,0 +1,45 @@ +export type Platform = { + id: string; + os: NodeJS.Platform; + arch: NodeJS.Architecture; + target: string; + binary: string; +}; + +export const platforms: Platform[] = [ + { + id: 'darwin-arm64', + os: 'darwin', + arch: 'arm64', + target: 'aarch64-macos', + binary: 'quick-commitlint', + }, + { + id: 'darwin-x64', + os: 'darwin', + arch: 'x64', + target: 'x86_64-macos', + binary: 'quick-commitlint', + }, + { + id: 'linux-arm64', + os: 'linux', + arch: 'arm64', + target: 'aarch64-linux-musl', + binary: 'quick-commitlint', + }, + { + id: 'linux-x64', + os: 'linux', + arch: 'x64', + target: 'x86_64-linux-musl', + binary: 'quick-commitlint', + }, + { + id: 'win32-x64', + os: 'win32', + arch: 'x64', + target: 'x86_64-windows', + binary: 'quick-commitlint.exe', + }, +]; diff --git a/scripts/quick-commitlint.test.cjs b/scripts/quick-commitlint.test.cjs new file mode 100644 index 0000000..27abd2f --- /dev/null +++ b/scripts/quick-commitlint.test.cjs @@ -0,0 +1,61 @@ +'use strict'; + +const assert = require('node:assert/strict'); +const { mkdtempSync, rmSync } = require('node:fs'); +const { tmpdir } = require('node:os'); +const { join } = require('node:path'); +const { test } = require('node:test'); + +const { getBinaryPath, resolveBinary, shouldUseExecve } = require('../npm/quick-commitlint.js'); + +test('resolves every supported platform to its bundled binary', () => { + const cases = [ + ['darwin', 'arm64', 'darwin-arm64', 'quick-commitlint'], + ['darwin', 'x64', 'darwin-x64', 'quick-commitlint'], + ['linux', 'arm64', 'linux-arm64', 'quick-commitlint'], + ['linux', 'x64', 'linux-x64', 'quick-commitlint'], + ['win32', 'x64', 'win32-x64', 'quick-commitlint.exe'], + ]; + + for (const [platform, arch, id, binary] of cases) { + const expected = join(__dirname, '..', 'npm', 'native', id, binary); + assert.equal(getBinaryPath(platform, arch, join(__dirname, '..', 'npm')), expected); + } +}); + +test('reports unsupported platforms clearly', () => { + assert.throws( + () => getBinaryPath('freebsd', 'x64'), + /Unsupported platform freebsd-x64.*darwin-arm64.*win32-x64/, + ); +}); + +test('reports a missing supported executable clearly', () => { + const baseDir = mkdtempSync(join(tmpdir(), 'quick-commitlint-launcher-')); + try { + assert.throws(() => resolveBinary('linux', 'x64', baseDir), /missing its linux-x64 executable/); + } finally { + rmSync(baseDir, { recursive: true, force: true }); + } +}); + +test('uses execve only on supported POSIX platforms when it is available', () => { + const available = () => () => {}; + + assert.equal(shouldUseExecve('darwin', available), true); + assert.equal(shouldUseExecve('linux', available), true); + assert.equal( + shouldUseExecve('linux', () => undefined), + false, + ); + + let windowsAccesses = 0; + assert.equal( + shouldUseExecve('win32', () => { + windowsAccesses += 1; + return () => {}; + }), + false, + ); + assert.equal(windowsAccesses, 0); +}); diff --git a/scripts/smoke-package.ts b/scripts/smoke-package.ts index 7dafbe5..441aebe 100644 --- a/scripts/smoke-package.ts +++ b/scripts/smoke-package.ts @@ -1,10 +1,13 @@ -import { execFileSync } from 'child_process'; -import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'fs'; +import { spawnSync } from 'child_process'; +import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'fs'; import { tmpdir } from 'os'; import { join, resolve } from 'path'; +import { platforms } from './platforms'; + const projectRoot = resolve(__dirname, '..'); const distDir = join(projectRoot, 'dist', 'quick-commitlint'); +const isWindows = process.platform === 'win32'; const projectManifest = JSON.parse(readFileSync(join(projectRoot, 'package.json'), 'utf8')); const manifest = JSON.parse(readFileSync(join(distDir, 'package.json'), 'utf8')); const expectedVersion = projectManifest.version; @@ -12,41 +15,101 @@ const expectedVersion = projectManifest.version; if (manifest.version !== expectedVersion) { throw new Error(`Packaged version ${manifest.version} does not match ${expectedVersion}.`); } -if (manifest.bin?.['quick-commitlint'] !== 'bin/quick-commitlint') { - throw new Error('Packaged bin does not point directly to the native executable.'); +if (manifest.bin?.['quick-commitlint'] !== 'bin/quick-commitlint.js') { + throw new Error('Packaged bin does not point to the portable launcher.'); +} +if ('os' in manifest || 'cpu' in manifest) { + throw new Error('The cross-platform package must not restrict npm installation by OS or CPU.'); } if (manifest.dependencies && Object.keys(manifest.dependencies).length !== 0) { - throw new Error('The published package has runtime dependencies.'); + throw new Error('The published package has runtime package dependencies.'); +} +if (manifest.engines?.node !== projectManifest.engines.node || 'npm' in manifest.engines) { + throw new Error('The published package must declare only the supported Node.js runtime.'); } -const dryRun = JSON.parse( - execFileSync('npm', ['pack', '--dry-run', '--json'], { cwd: distDir, encoding: 'utf8' }), -); +const dryRun = JSON.parse(runNpm(['pack', '--dry-run', '--json'], distDir).stdout); const files = dryRun[0].files.map((file: { path: string }) => file.path).sort(); -for (const required of ['LICENSE', 'README.md', 'bin/quick-commitlint', 'package.json']) { - if (!files.includes(required)) throw new Error(`Package is missing ${required}.`); +const required = ['LICENSE', 'README.md', 'bin/quick-commitlint.js', 'package.json']; +for (const platform of platforms) { + required.push(`bin/native/${platform.id}/${platform.binary}`); +} +for (const file of required) { + if (!files.includes(file)) throw new Error(`Package is missing ${file}.`); } -const packed = JSON.parse( - execFileSync('npm', ['pack', '--json'], { cwd: distDir, encoding: 'utf8' }), -); +const packed = JSON.parse(runNpm(['pack', '--json'], distDir).stdout); const tarball = join(distDir, packed[0].filename); const installDir = mkdtempSync(join(tmpdir(), 'quick-commitlint-package-')); try { - writeFileSync(join(installDir, 'package.json'), '{"private":true}\n'); + writeFileSync( + join(installDir, 'package.json'), + '{"private":true,"scripts":{"quick-commitlint":"quick-commitlint"}}\n', + ); mkdirSync(join(installDir, 'node_modules'), { recursive: true }); - execFileSync('npm', ['install', '--ignore-scripts', '--no-package-lock', tarball], { - cwd: installDir, - stdio: 'pipe', - }); - const executable = join(installDir, 'node_modules', '.bin', 'quick-commitlint'); - const version = execFileSync(executable, ['--version'], { encoding: 'utf8' }).trim(); - if (version !== `quick-commitlint ${expectedVersion}`) - throw new Error(`Unexpected version: ${version}`); + runNpm(['install', '--ignore-scripts', '--no-package-lock', tarball], installDir); + + const executable = join( + installDir, + 'node_modules', + '.bin', + isWindows ? 'quick-commitlint.cmd' : 'quick-commitlint', + ); + if (!existsSync(executable)) + throw new Error(`npm did not create the executable shim at ${executable}.`); + + const versionResult = runCli(installDir, ['--version']); + if (versionResult.status !== 0) { + throw new Error( + `Packaged --version exited with ${versionResult.status}:\n${formatOutput(versionResult)}`, + ); + } + const version = versionResult.stdout.trim(); + if (version !== `quick-commitlint ${expectedVersion}`) { + throw new Error( + `Unexpected version ${JSON.stringify(version)}:\n${formatOutput(versionResult)}`, + ); + } + + const valid = runCli(installDir, [], 'feat: verify packaged command'); + if (valid.status !== 0) { + throw new Error(`Valid message exited with ${valid.status}:\n${formatOutput(valid)}`); + } + + const invalid = runCli(installDir, [], 'invalid: verify packaged command'); + if (invalid.status !== 1 || !invalid.stderr.includes('[type-enum]')) { + throw new Error(`Invalid message produced an unexpected result:\n${formatOutput(invalid)}`); + } } finally { rmSync(tarball, { force: true }); rmSync(installDir, { recursive: true, force: true }); } -console.log('npm package smoke test passed.'); +console.log('Cross-platform npm package smoke test passed.'); + +function runNpm(args: string[], cwd: string): { stdout: string; stderr: string; status: number } { + const result = spawnSync('npm', args, { cwd, encoding: 'utf8', shell: isWindows }); + if (result.error) throw result.error; + if (result.status !== 0) { + throw new Error(`npm ${args.join(' ')} failed:\n${result.stdout}${result.stderr}`); + } + return { stdout: result.stdout, stderr: result.stderr, status: result.status }; +} + +function runCli(cwd: string, args: string[], input?: string): CommandResult { + const result = spawnSync('npm', ['run', '--silent', 'quick-commitlint', '--', ...args], { + cwd, + encoding: 'utf8', + input, + shell: isWindows, + }); + if (result.error) throw result.error; + return { stdout: result.stdout, stderr: result.stderr, status: result.status }; +} + +function formatOutput(result: CommandResult): string { + return `stdout:\n${result.stdout}\nstderr:\n${result.stderr}`; +} + +type CommandResult = { stdout: string; stderr: string; status: number | null }; diff --git a/src/main.zig b/src/main.zig index 7c2e98f..f2c097a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -16,7 +16,8 @@ const config_limit = 256 * 1024; const config_name = ".quick-commitlint.json"; pub fn main(init: std.process.Init) !void { - var args = init.minimal.args.iterate(); + var args = try init.minimal.args.iterateAllocator(init.gpa); + defer args.deinit(); _ = args.next(); switch (cli.parse(&args)) { diff --git a/yarn.lock b/yarn.lock index 728ba1f..99c827a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2682,23 +2682,11 @@ ansi-escapes@^7.0.0: dependencies: environment "^1.0.0" -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - ansi-regex@^6.2.2: version "6.2.2" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.2.2.tgz#60216eea464d864597ce2832000738a0589650c1" integrity sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg== -ansi-styles@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - ansi-styles@^6.2.1, ansi-styles@^6.2.3: version "6.2.3" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041" @@ -2745,11 +2733,6 @@ axobject-query@4.1.0: resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee" integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ== -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - balanced-match@^4.0.2: version "4.0.4" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-4.0.4.tgz#bfb10662feed8196a2c62e7c68e17720c274179a" @@ -2802,14 +2785,6 @@ boolbase@^1.0.0: resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== -brace-expansion@^1.1.7: - version "1.1.16" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.16.tgz#723d3a30c0558c225abc9fc479a73e14e26c3c2f" - integrity sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - brace-expansion@^5.0.5: version "5.0.7" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.7.tgz#1b0e46965b479dad65af737b4a02790a05498337" @@ -2939,15 +2914,6 @@ cli-width@^4.1.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - cliui@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/cliui/-/cliui-9.0.1.tgz#6f7890f386f6f1f79953adc1f78dec46fcc2d291" @@ -2957,28 +2923,11 @@ cliui@^9.0.1: strip-ansi "^7.1.0" wrap-ansi "^9.0.0" -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - commander@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - content-disposition@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-1.1.0.tgz#f3db789c752d45564cc7e9e1e0b31790d4a38e17" @@ -3036,24 +2985,6 @@ cookie@^0.7.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7" integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== -copyfiles@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.4.1.tgz#d2dcff60aaad1015f09d0b66e7f0f1c5cd3c5da5" - integrity sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg== - dependencies: - glob "^7.0.5" - minimatch "^3.0.3" - mkdirp "^1.0.4" - noms "0.0.0" - through2 "^2.0.1" - untildify "^4.0.0" - yargs "^16.1.0" - -core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - cors@^2.8.5: version "2.8.6" resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.6.tgz#ff5dd69bd95e547503820d29aba4f8faf8dfec96" @@ -3211,11 +3142,6 @@ emoji-regex@^10.3.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.6.0.tgz#bf3d6e8f7f8fd22a65d9703475bc0147357a6b0d" integrity sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A== -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - encodeurl@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" @@ -3647,11 +3573,6 @@ fs-minipass@^3.0.0: dependencies: minipass "^7.0.3" -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" @@ -3722,18 +3643,6 @@ glob@^13.0.0, glob@^13.0.3: minipass "^7.1.3" path-scurry "^2.0.2" -glob@^7.0.5: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - global-directory@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/global-directory/-/global-directory-5.0.0.tgz#0f66a94212acd0f81ee838d0a991e88d1c2836cf" @@ -3910,15 +3819,7 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.1, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: +inherits@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -3948,11 +3849,6 @@ is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - is-fullwidth-code-point@^5.0.0, is-fullwidth-code-point@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz#046b2a6d4f6b156b2233d3207d4b5a9783999b98" @@ -3992,16 +3888,6 @@ is-unicode-supported@^2.0.0, is-unicode-supported@^2.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz#09f0ab0de6d3744d48d265ebb98f65d11f2a9b3a" integrity sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ== -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -4367,13 +4253,6 @@ minimatch@^10.0.3, minimatch@^10.1.1, minimatch@^10.2.2, minimatch@^10.2.4: dependencies: brace-expansion "^5.0.5" -minimatch@^3.0.3, minimatch@^3.1.1: - version "3.1.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.5.tgz#580c88f8d5445f2bd6aa8f3cadefa0de79fbd69e" - integrity sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w== - dependencies: - brace-expansion "^1.1.7" - minimist@^1.2.5: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" @@ -4437,11 +4316,6 @@ minizlib@^3.0.1, minizlib@^3.1.0: dependencies: minipass "^7.1.2" -mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - mrmime@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.1.tgz#bc3e87f7987853a54c9850eeb1f1078cd44adddc" @@ -4551,14 +4425,6 @@ node-releases@^2.0.51: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.51.tgz#cdc08433577f5b32ad01694481726e22eeb54aef" integrity sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ== -noms@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859" - integrity sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow== - dependencies: - inherits "^2.0.1" - readable-stream "~1.0.31" - nopt@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-9.0.0.tgz#6bff0836b2964d24508b6b41b5a9a49c4f4a1f96" @@ -4656,7 +4522,7 @@ on-finished@^2.4.1: dependencies: ee-first "1.1.1" -once@^1.3.0, once@^1.4.0: +once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== @@ -4803,11 +4669,6 @@ path-exists@^4.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -4892,11 +4753,6 @@ proc-log@^6.0.0, proc-log@^6.1.0: resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-6.1.0.tgz#18519482a37d5198e231133a70144a50f21f0215" integrity sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ== -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - proxy-addr@^2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -4933,29 +4789,6 @@ raw-body@^3.0.0, raw-body@^3.0.2: iconv-lite "~0.7.0" unpipe "~1.0.0" -readable-stream@~1.0.31: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@~2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" - integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - readdirp@^4.0.1: version "4.1.2" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" @@ -4971,11 +4804,6 @@ reflect-metadata@^0.2.0: resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b" integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q== -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - require-from-string@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" @@ -5122,11 +4950,6 @@ rxjs@7.8.2, rxjs@~7.8.0: dependencies: tslib "^2.1.0" -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -5382,15 +5205,6 @@ stdin-discarder@^0.3.2: resolved "https://registry.yarnpkg.com/stdin-discarder/-/stdin-discarder-0.3.2.tgz#998ab3b9a988661e6036a9bfdc96f43649e8e83e" integrity sha512-eCPu1qRxPVkl5605OTWF8Wz40b4Mf45NY5LQmVPQ599knfs5QhASUm9GbJ5BDMDOXgrnh0wyEdvzmL//YMlw0A== -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^7.0.0, string-width@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.2.0.tgz#b5bb8e2165ce275d4d43476dd2700ad9091db6dc" @@ -5408,25 +5222,6 @@ string-width@^8.1.0, string-width@^8.2.0: get-east-asian-width "^1.5.0" strip-ansi "^7.1.2" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.1.0, strip-ansi@^7.1.2: version "7.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.2.0.tgz#d22a269522836a627af8d04b5c3fd2c7fa3e32e3" @@ -5465,14 +5260,6 @@ tar@^7.4.3, tar@^7.5.4: minizlib "^3.1.0" yallist "^5.0.0" -through2@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - tinybench@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" @@ -5629,11 +5416,6 @@ unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -untildify@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" - integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== - update-browserslist-db@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz#64d76db58713136acbeb4c49114366cc6cc2e80d" @@ -5649,11 +5431,6 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - validate-npm-package-name@^7.0.0: version "7.0.2" resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz#e57c3d721a4c8bbff454a246e7f7da811559ea0d" @@ -5797,15 +5574,6 @@ wrap-ansi@^10.0.0: string-width "^8.2.0" strip-ansi "^7.1.2" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^9.0.0: version "9.0.2" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-9.0.2.tgz#956832dea9494306e6d209eb871643bb873d7c98" @@ -5835,11 +5603,6 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" @@ -5860,11 +5623,6 @@ yallist@^5.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== -yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - yargs-parser@^22.0.0: version "22.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-22.0.0.tgz#87b82094051b0567717346ecd00fd14804b357c8" @@ -5882,19 +5640,6 @@ yargs@18.0.0, yargs@^18.0.0: y18n "^5.0.5" yargs-parser "^22.0.0" -yargs@^16.1.0: - version "16.2.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.2.tgz#c56731dca0d2788ae0866dd3c83907d6bab85f7d" - integrity sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"