feature: vor und nachteile

This commit is contained in:
Hikyu
2026-05-31 13:54:31 +02:00
parent 552a947a1c
commit e3dad17446
23270 changed files with 3024794 additions and 200 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) Pooya Parsa <pooya@pi0.io>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+177
View File
@@ -0,0 +1,177 @@
# 📼 nanotar
[![npm version][npm-version-src]][npm-version-href]
[![bundle][bundle-src]][bundle-href]
<!-- [![npm downloads][npm-downloads-src]][npm-downloads-href] -->
<!-- [![Codecov][codecov-src]][codecov-href] -->
Tiny and fast [tar](<https://en.wikipedia.org/wiki/Tar_(computing)>) utils for any JavaScript runtime!
🌳 Tiny (~1KB minified + gzipped with all utils) and tree-shakable!
✨ Written with modern TypeScript and ESM format
✅ Works in any JavaScript runtime Node.js (18+), Bun, Deno, Browsers, and Edge Workers
🌐 Web Standard Compatible
🗜️ Built-in compression and decompression support
## Installation
Install package:
```sh
# npm
npm install nanotar
# yarn
yarn add nanotar
# pnpm
pnpm install nanotar
# bun
bun install nanotar
```
Import:
```js
// ESM
import {
createTar,
createTarGzip,
createTarGzipStream,
parseTar,
parseTarGzip,
} from "nanotar";
// CommonJS
const { createTar } = require("nanotar");
```
## Creating a tar archive
Easily create a new tar archive using the `createTar` utility.
The first argument is an array of files to archive:
- `name` field is required and you can use `/` to specify files within sub-directories.
- `data` field is optional for directories and can be either a [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String), [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) or [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array).
- `attrs` field is optional for file attributes.
The second argument is for archive options. You can use `attrs` to set default attributes for all files (can still be overridden per file).
Possible attributes are:
- `mtime`: Last modification time. The default is `Date.now()`
- `uid`: Owner user id. The default is `1000`
- `gid`: Owner group id. The default is `1000`
- `user`: Owner user name. The default is `""`
- `group`: Owner user group. The default is `""`
- `mode`: file mode (permissions). Default is `664` (`-rw-rw-r--`) for files and `775` (`-rwxrwxr-x`) for directories
**Example:**
```ts
import { createTar } from "nanotar";
const data = createTar(
[
{ name: "README.md", data: "# Hello World!" },
{ name: "test", attrs: { mode: "777", mtime: 0 } },
{ name: "src/index.js", data: "console.log('wow!')" },
],
{ attrs: { user: "js", group: "js" } },
);
// Data is a Uint8Array view you can send or write to a file
```
### Compression
You can optionaly use `createTarGzip` or `createTarGzipStream` to create a compressed tar data stream (returned value is a [`Promise<Uint8Array>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) or [`RedableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) piped to [`CompressionStream`](https://developer.mozilla.org/en-US/docs/Web/API/CompressionStream))
```js
import { createTarGzip, createTarGzipStream } from "nanotar";
createTarGzip([]); // Promise<Uint8Array>
createTarGzipStream([]); // RedableStream
```
## Parsing a tar archive
Easily parse a tar archive using `parseTar` utility.
**Example:**
```ts
import { parseTar } from "nanotar";
// Read tar data from file or other sources into an ArrayBuffer or Uint8Array
const files = parseTar(data);
/**
[
{
"type": "file",
"name": "hello.txt",
"size": 12,
"data": Uint8Array [ ... ],
"text": "Hello World!",
"attrs": {
"gid": 1750,
"group": "",
"mode": "0000664",
"mtime": 1702076997,
"uid": 1750,
"user": "root",
},
},
...
]
*/
```
Parsed files array has two additional properties: `size` file size and `text`, a lazy getter that decodes `data` view as a string.
### Decompression
If input is compressed, you can use `parseTarGzip` utility instead to parse it (it used [`DecompressionStream`](https://developer.mozilla.org/en-US/docs/Web/API/DecompressionStream) internally and return a `Promise<Uint8Array>` value)
```js
import { parseTarGzip } from "nanotar";
parseTarGzip(data); // Promise<Uint8Array>
```
## Development
- Clone this repository
- Install the latest LTS version of [Node.js](https://nodejs.org/en/)
- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`
- Install dependencies using `pnpm install`
- Run interactive tests using `pnpm dev`
## License
Made with 💛
Inspired by [ankitrohatgi/tarballjs](https://github.com/ankitrohatgi/tarballjs)
Published under the [MIT License](./LICENSE).
<!-- Badges -->
[npm-version-src]: https://img.shields.io/npm/v/nanotar?style=flat&colorA=18181B&colorB=F0DB4F
[npm-version-href]: https://npmjs.com/package/nanotar
[npm-downloads-src]: https://img.shields.io/npm/dm/nanotar?style=flat&colorA=18181B&colorB=F0DB4F
[npm-downloads-href]: https://npmjs.com/package/nanotar
[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/nanotar/main?style=flat&colorA=18181B&colorB=F0DB4F
[codecov-href]: https://codecov.io/gh/unjs/nanotar
[bundle-src]: https://img.shields.io/bundlephobia/minzip/nanotar?style=flat&colorA=18181B&colorB=F0DB4F
[bundle-href]: https://bundlephobia.com/result?p=nanotar
+193
View File
@@ -0,0 +1,193 @@
'use strict';
function parseTar(data) {
const buffer = data.buffer || data;
const files = [];
let offset = 0;
while (offset < buffer.byteLength - 512) {
const name = _readString(buffer, offset, 100);
if (name.length === 0) {
break;
}
const mode = _readString(buffer, offset + 100, 8);
const uid = Number.parseInt(_readString(buffer, offset + 108, 8));
const gid = Number.parseInt(_readString(buffer, offset + 116, 8));
const size = _readNumber(buffer, offset + 124, 12);
const mtime = _readNumber(buffer, offset + 136, 12);
const _type = _readNumber(buffer, offset + 156, 1);
const type = _type === 0 ? "file" : _type === 5 ? "directory" : _type;
const user = _readString(buffer, offset + 265, 32);
const group = _readString(buffer, offset + 297, 32);
const data2 = new Uint8Array(buffer, offset + 512, size);
files.push({
name,
type,
size,
data: data2,
get text() {
return new TextDecoder().decode(this.data);
},
attrs: {
mode,
uid,
gid,
mtime,
user,
group
}
});
offset += 512 + 512 * Math.trunc(size / 512);
if (size % 512) {
offset += 512;
}
}
return files;
}
async function parseTarGzip(data, opts = {}) {
const stream = new ReadableStream({
start(controller) {
controller.enqueue(new Uint8Array(data));
controller.close();
}
}).pipeThrough(new DecompressionStream(opts.compression ?? "gzip"));
const decompressedData = await new Response(stream).arrayBuffer();
return parseTar(decompressedData);
}
function _readString(buffer, offset, size) {
const view = new Uint8Array(buffer, offset, size);
const i = view.indexOf(0);
const td = new TextDecoder();
return td.decode(view.slice(0, i));
}
function _readNumber(buffer, offset, size) {
const view = new Uint8Array(buffer, offset, size);
let str = "";
for (let i = 0; i < size; i++) {
str += String.fromCodePoint(view[i]);
}
return Number.parseInt(str, 8);
}
function createTar(files, opts = {}) {
const _files = files.map((file) => {
const data = _normalizeData(file.data);
return {
...file,
data,
size: data?.length || 0
};
});
let tarDataSize = 0;
for (let i = 0; i < files.length; i++) {
const size = _files[i].data?.length ?? 0;
tarDataSize += 512 + 512 * Math.trunc(size / 512);
if (size % 512) {
tarDataSize += 512;
}
}
let bufSize = 10240 * Math.trunc(tarDataSize / 10240);
if (tarDataSize % 10240) {
bufSize += 10240;
}
const buffer = new ArrayBuffer(bufSize);
let offset = 0;
for (const file of _files) {
const isDir = !file.data;
_writeString(buffer, file.name, offset, 100);
const mode = file.attrs?.mode ?? opts.attrs?.mode ?? (isDir ? "775" : "664");
_writeString(buffer, _leftPad(mode, 7), offset + 100, 8);
const uid = file.attrs?.uid ?? opts.attrs?.uid ?? 1e3;
_writeString(buffer, _leftPad(uid.toString(8), 7), offset + 108, 8);
const gid = file.attrs?.gid ?? opts.attrs?.gid ?? 1e3;
_writeString(buffer, _leftPad(gid.toString(8), 7), offset + 116, 8);
_writeString(buffer, _leftPad(file.size.toString(8), 11), offset + 124, 12);
const mtime = file.attrs?.mtime ?? opts.attrs?.mtime ?? Date.now();
_writeString(
buffer,
_leftPad(Math.trunc(mtime / 1e3).toString(8), 11),
offset + 136,
12
);
const type = isDir ? "5" : "0";
_writeString(buffer, type, offset + 156, 1);
_writeString(
buffer,
"ustar",
offset + 257,
6
/* magic string */
);
_writeString(
buffer,
"00",
offset + 263,
2
/* magic version */
);
const user = file.attrs?.user ?? opts.attrs?.user ?? "";
_writeString(buffer, user, offset + 265, 32);
const group = file.attrs?.group ?? opts.attrs?.group ?? "";
_writeString(buffer, group, offset + 297, 32);
_writeString(buffer, " ", offset + 148, 8);
const header = new Uint8Array(buffer, offset, 512);
let chksum = 0;
for (let i = 0; i < 512; i++) {
chksum += header[i];
}
_writeString(buffer, chksum.toString(8), offset + 148, 8);
if (!isDir) {
const destArray = new Uint8Array(buffer, offset + 512, file.size);
for (let byteIdx = 0; byteIdx < file.size; byteIdx++) {
destArray[byteIdx] = file.data[byteIdx];
}
offset += 512 * Math.trunc(file.size / 512);
if (file.size % 512) {
offset += 512;
}
}
offset += 512;
}
return new Uint8Array(buffer);
}
function createTarGzipStream(files, opts = {}) {
const buffer = createTar(files, opts);
return new ReadableStream({
start(controller) {
controller.enqueue(buffer);
controller.close();
}
}).pipeThrough(new CompressionStream(opts.compression ?? "gzip"));
}
async function createTarGzip(files, opts = {}) {
const data = await new Response(createTarGzipStream(files, opts)).arrayBuffer().then((buffer) => new Uint8Array(buffer));
return data;
}
function _writeString(buffer, str, offset, size) {
const strView = new Uint8Array(buffer, offset, size);
const te = new TextEncoder();
const written = te.encodeInto(str, strView).written;
for (let i = written; i < size; i++) {
strView[i] = 0;
}
}
function _leftPad(input, targetLength) {
return String(input).padStart(targetLength, "0");
}
function _normalizeData(data) {
if (data === null || data === void 0) {
return void 0;
}
if (typeof data === "string") {
return new TextEncoder().encode(data);
}
if (data instanceof ArrayBuffer) {
return new Uint8Array(data);
}
return data;
}
exports.createTar = createTar;
exports.createTarGzip = createTarGzip;
exports.createTarGzipStream = createTarGzipStream;
exports.parseTar = parseTar;
exports.parseTarGzip = parseTarGzip;
+63
View File
@@ -0,0 +1,63 @@
type TarFileItem<DataT = Uint8Array> = {
/**
* File name
*/
name: string;
/**
* File data (don't provide for directories)
*/
data?: DataT;
/**
* File attributes
*/
attrs?: TarFileAttrs;
};
interface ParsedTarFileItem extends TarFileItem {
type: "file" | "directory" | number;
size: number;
readonly text: string;
}
interface TarFileAttrs {
/**
* Default: 664 (-rw-rw-r--) for files and 775 (-rwxrwxr-x) for directories and */
mode?: string;
/**
* Default: 1000
*/
uid?: number;
/**
* Default: 1000
*/
gid?: number;
/**
* Default: Date.now()
*/
mtime?: number;
/**
* Default: ""
*/
user?: string;
/**
* Default: ""
*/
group?: string;
}
declare function parseTar(data: ArrayBuffer | Uint8Array): TarFileItem[];
declare function parseTarGzip(data: ArrayBuffer | Uint8Array, opts?: {
compression?: CompressionFormat;
}): Promise<TarFileItem[]>;
interface CreateTarOptions {
attrs?: TarFileAttrs;
}
type TarFileInput = TarFileItem<string | Uint8Array | ArrayBuffer>;
declare function createTar(files: TarFileInput[], opts?: CreateTarOptions): Uint8Array;
declare function createTarGzipStream(files: TarFileInput[], opts?: CreateTarOptions & {
compression?: CompressionFormat;
}): ReadableStream;
declare function createTarGzip(files: TarFileInput[], opts?: CreateTarOptions & {
compression?: CompressionFormat;
}): Promise<Uint8Array>;
export { type CreateTarOptions, type ParsedTarFileItem, type TarFileAttrs, type TarFileInput, type TarFileItem, createTar, createTarGzip, createTarGzipStream, parseTar, parseTarGzip };
+63
View File
@@ -0,0 +1,63 @@
type TarFileItem<DataT = Uint8Array> = {
/**
* File name
*/
name: string;
/**
* File data (don't provide for directories)
*/
data?: DataT;
/**
* File attributes
*/
attrs?: TarFileAttrs;
};
interface ParsedTarFileItem extends TarFileItem {
type: "file" | "directory" | number;
size: number;
readonly text: string;
}
interface TarFileAttrs {
/**
* Default: 664 (-rw-rw-r--) for files and 775 (-rwxrwxr-x) for directories and */
mode?: string;
/**
* Default: 1000
*/
uid?: number;
/**
* Default: 1000
*/
gid?: number;
/**
* Default: Date.now()
*/
mtime?: number;
/**
* Default: ""
*/
user?: string;
/**
* Default: ""
*/
group?: string;
}
declare function parseTar(data: ArrayBuffer | Uint8Array): TarFileItem[];
declare function parseTarGzip(data: ArrayBuffer | Uint8Array, opts?: {
compression?: CompressionFormat;
}): Promise<TarFileItem[]>;
interface CreateTarOptions {
attrs?: TarFileAttrs;
}
type TarFileInput = TarFileItem<string | Uint8Array | ArrayBuffer>;
declare function createTar(files: TarFileInput[], opts?: CreateTarOptions): Uint8Array;
declare function createTarGzipStream(files: TarFileInput[], opts?: CreateTarOptions & {
compression?: CompressionFormat;
}): ReadableStream;
declare function createTarGzip(files: TarFileInput[], opts?: CreateTarOptions & {
compression?: CompressionFormat;
}): Promise<Uint8Array>;
export { type CreateTarOptions, type ParsedTarFileItem, type TarFileAttrs, type TarFileInput, type TarFileItem, createTar, createTarGzip, createTarGzipStream, parseTar, parseTarGzip };
+63
View File
@@ -0,0 +1,63 @@
type TarFileItem<DataT = Uint8Array> = {
/**
* File name
*/
name: string;
/**
* File data (don't provide for directories)
*/
data?: DataT;
/**
* File attributes
*/
attrs?: TarFileAttrs;
};
interface ParsedTarFileItem extends TarFileItem {
type: "file" | "directory" | number;
size: number;
readonly text: string;
}
interface TarFileAttrs {
/**
* Default: 664 (-rw-rw-r--) for files and 775 (-rwxrwxr-x) for directories and */
mode?: string;
/**
* Default: 1000
*/
uid?: number;
/**
* Default: 1000
*/
gid?: number;
/**
* Default: Date.now()
*/
mtime?: number;
/**
* Default: ""
*/
user?: string;
/**
* Default: ""
*/
group?: string;
}
declare function parseTar(data: ArrayBuffer | Uint8Array): TarFileItem[];
declare function parseTarGzip(data: ArrayBuffer | Uint8Array, opts?: {
compression?: CompressionFormat;
}): Promise<TarFileItem[]>;
interface CreateTarOptions {
attrs?: TarFileAttrs;
}
type TarFileInput = TarFileItem<string | Uint8Array | ArrayBuffer>;
declare function createTar(files: TarFileInput[], opts?: CreateTarOptions): Uint8Array;
declare function createTarGzipStream(files: TarFileInput[], opts?: CreateTarOptions & {
compression?: CompressionFormat;
}): ReadableStream;
declare function createTarGzip(files: TarFileInput[], opts?: CreateTarOptions & {
compression?: CompressionFormat;
}): Promise<Uint8Array>;
export { type CreateTarOptions, type ParsedTarFileItem, type TarFileAttrs, type TarFileInput, type TarFileItem, createTar, createTarGzip, createTarGzipStream, parseTar, parseTarGzip };
+187
View File
@@ -0,0 +1,187 @@
function parseTar(data) {
const buffer = data.buffer || data;
const files = [];
let offset = 0;
while (offset < buffer.byteLength - 512) {
const name = _readString(buffer, offset, 100);
if (name.length === 0) {
break;
}
const mode = _readString(buffer, offset + 100, 8);
const uid = Number.parseInt(_readString(buffer, offset + 108, 8));
const gid = Number.parseInt(_readString(buffer, offset + 116, 8));
const size = _readNumber(buffer, offset + 124, 12);
const mtime = _readNumber(buffer, offset + 136, 12);
const _type = _readNumber(buffer, offset + 156, 1);
const type = _type === 0 ? "file" : _type === 5 ? "directory" : _type;
const user = _readString(buffer, offset + 265, 32);
const group = _readString(buffer, offset + 297, 32);
const data2 = new Uint8Array(buffer, offset + 512, size);
files.push({
name,
type,
size,
data: data2,
get text() {
return new TextDecoder().decode(this.data);
},
attrs: {
mode,
uid,
gid,
mtime,
user,
group
}
});
offset += 512 + 512 * Math.trunc(size / 512);
if (size % 512) {
offset += 512;
}
}
return files;
}
async function parseTarGzip(data, opts = {}) {
const stream = new ReadableStream({
start(controller) {
controller.enqueue(new Uint8Array(data));
controller.close();
}
}).pipeThrough(new DecompressionStream(opts.compression ?? "gzip"));
const decompressedData = await new Response(stream).arrayBuffer();
return parseTar(decompressedData);
}
function _readString(buffer, offset, size) {
const view = new Uint8Array(buffer, offset, size);
const i = view.indexOf(0);
const td = new TextDecoder();
return td.decode(view.slice(0, i));
}
function _readNumber(buffer, offset, size) {
const view = new Uint8Array(buffer, offset, size);
let str = "";
for (let i = 0; i < size; i++) {
str += String.fromCodePoint(view[i]);
}
return Number.parseInt(str, 8);
}
function createTar(files, opts = {}) {
const _files = files.map((file) => {
const data = _normalizeData(file.data);
return {
...file,
data,
size: data?.length || 0
};
});
let tarDataSize = 0;
for (let i = 0; i < files.length; i++) {
const size = _files[i].data?.length ?? 0;
tarDataSize += 512 + 512 * Math.trunc(size / 512);
if (size % 512) {
tarDataSize += 512;
}
}
let bufSize = 10240 * Math.trunc(tarDataSize / 10240);
if (tarDataSize % 10240) {
bufSize += 10240;
}
const buffer = new ArrayBuffer(bufSize);
let offset = 0;
for (const file of _files) {
const isDir = !file.data;
_writeString(buffer, file.name, offset, 100);
const mode = file.attrs?.mode ?? opts.attrs?.mode ?? (isDir ? "775" : "664");
_writeString(buffer, _leftPad(mode, 7), offset + 100, 8);
const uid = file.attrs?.uid ?? opts.attrs?.uid ?? 1e3;
_writeString(buffer, _leftPad(uid.toString(8), 7), offset + 108, 8);
const gid = file.attrs?.gid ?? opts.attrs?.gid ?? 1e3;
_writeString(buffer, _leftPad(gid.toString(8), 7), offset + 116, 8);
_writeString(buffer, _leftPad(file.size.toString(8), 11), offset + 124, 12);
const mtime = file.attrs?.mtime ?? opts.attrs?.mtime ?? Date.now();
_writeString(
buffer,
_leftPad(Math.trunc(mtime / 1e3).toString(8), 11),
offset + 136,
12
);
const type = isDir ? "5" : "0";
_writeString(buffer, type, offset + 156, 1);
_writeString(
buffer,
"ustar",
offset + 257,
6
/* magic string */
);
_writeString(
buffer,
"00",
offset + 263,
2
/* magic version */
);
const user = file.attrs?.user ?? opts.attrs?.user ?? "";
_writeString(buffer, user, offset + 265, 32);
const group = file.attrs?.group ?? opts.attrs?.group ?? "";
_writeString(buffer, group, offset + 297, 32);
_writeString(buffer, " ", offset + 148, 8);
const header = new Uint8Array(buffer, offset, 512);
let chksum = 0;
for (let i = 0; i < 512; i++) {
chksum += header[i];
}
_writeString(buffer, chksum.toString(8), offset + 148, 8);
if (!isDir) {
const destArray = new Uint8Array(buffer, offset + 512, file.size);
for (let byteIdx = 0; byteIdx < file.size; byteIdx++) {
destArray[byteIdx] = file.data[byteIdx];
}
offset += 512 * Math.trunc(file.size / 512);
if (file.size % 512) {
offset += 512;
}
}
offset += 512;
}
return new Uint8Array(buffer);
}
function createTarGzipStream(files, opts = {}) {
const buffer = createTar(files, opts);
return new ReadableStream({
start(controller) {
controller.enqueue(buffer);
controller.close();
}
}).pipeThrough(new CompressionStream(opts.compression ?? "gzip"));
}
async function createTarGzip(files, opts = {}) {
const data = await new Response(createTarGzipStream(files, opts)).arrayBuffer().then((buffer) => new Uint8Array(buffer));
return data;
}
function _writeString(buffer, str, offset, size) {
const strView = new Uint8Array(buffer, offset, size);
const te = new TextEncoder();
const written = te.encodeInto(str, strView).written;
for (let i = written; i < size; i++) {
strView[i] = 0;
}
}
function _leftPad(input, targetLength) {
return String(input).padStart(targetLength, "0");
}
function _normalizeData(data) {
if (data === null || data === void 0) {
return void 0;
}
if (typeof data === "string") {
return new TextEncoder().encode(data);
}
if (data instanceof ArrayBuffer) {
return new Uint8Array(data);
}
return data;
}
export { createTar, createTarGzip, createTarGzipStream, parseTar, parseTarGzip };
+46
View File
@@ -0,0 +1,46 @@
{
"name": "nanotar",
"version": "0.1.1",
"description": "Tiny and fast Tar utils for any JavaScript runtime!",
"repository": "unjs/nanotar",
"license": "MIT",
"sideEffects": false,
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "unbuild",
"dev": "vitest dev",
"play": "jiti playground",
"lint": "eslint --cache --ext .ts,.js,.mjs,.cjs . && prettier -c src test",
"lint:fix": "eslint --cache --ext .ts,.js,.mjs,.cjs . --fix && prettier -c src test -w",
"prepack": "pnpm run build",
"release": "pnpm test && changelogen --release && npm publish && git push --follow-tags",
"test": "pnpm lint && pnpm test:types && vitest run --coverage",
"test:types": "tsc --noEmit --skipLibCheck"
},
"devDependencies": {
"@types/node": "^20.10.3",
"@vitest/coverage-v8": "^1.0.1",
"changelogen": "^0.5.5",
"eslint": "^8.55.0",
"eslint-config-unjs": "^0.2.1",
"jiti": "^1.21.0",
"prettier": "^3.1.0",
"typescript": "^5.3.2",
"unbuild": "^2.0.0",
"vitest": "^1.0.1"
},
"packageManager": "pnpm@8.11.0"
}