initial commit

This commit is contained in:
Zoe
2023-01-03 09:29:04 -06:00
commit 7851137d88
12889 changed files with 2557443 additions and 0 deletions

21
node_modules/unctx/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 - 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.

198
node_modules/unctx/README.md generated vendored Normal file
View File

@@ -0,0 +1,198 @@
# 🍦 unctx
> Composition-api in Vanilla js
[![npm version][npm-v-src]][npm-v-href]
[![npm downloads][npm-dm-src]][npm-dm-href]
[![package phobia][packagephobia-src]][packagephobia-href]
[![bundle phobia][bundlephobia-src]][bundlephobia-href]
[![codecov][codecov-src]][codecov-href]
## What is it?
[Vue.js](https://vuejs.org) introduced an amazing pattern called [Composition API](https://v3.vuejs.org/guide/composition-api-introduction.html) that allows organizing complex logic by splitting it into reusable functions and grouping in logical order. `unctx` allows easily implementing composition api pattern in your javascript libraries without hassle.
## Integration
In your **awesome** library:
```bash
yarn add unctx
# or
npm install unctx
```
```js
import { createContext } from 'unctx'
const ctx = createContext()
export const useAwesome = ctx.use
// ...
ctx.call({ test: 1 }, () => {
// This is similar to vue setup function
// Any function called here, can use `useAwesome` to get { test: 1 }
})
```
User code:
```js
import { useAwesome } from 'awesome-lib'
// ...
function setup() {
const ctx = useAwesome()
}
```
**Note:** when no context is presented `ctx.use` will throw an error. Use `ctx.tryUse` for tolerant usages (return nullable context).
## Using Namespaces
To avoid issues with multiple version of library, `unctx` provides a safe global namespace to access context by key (kept in [`globalThis`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis)). **Important:** Please use a verbose name for key to avoid conflict with other js libraries. Using npm package name is recommended. Using symbols has no effect since it still causes multiple context issue.
```js
import { useContext, getContext } from 'unctx'
const useAwesome = useContext('awesome-lib')
// or
// const awesomeContext = getContext('awesome-lib')
```
You can also create your own internal namespace with `createNamespace` utility for more advanced use cases.
## Singleton Pattern
If you are sure it is safe to use a shared instance (not depending to request), you can also use `ctx.set` and `ctx.unset` for a [singleton pattern](https://en.wikipedia.org/wiki/Singleton_pattern).
**Note:** You cannot combine `set` with `call`. Always use `unset` before replacing instance otherwise you will get `Context conflict` error.
```js
import { createContext } from 'unctx'
const ctx = createContext()
ctx.set(new Awesome())
// Replacing instance without unset
// ctx.set(new Awesome(), true)
export const useAwesome = ctx.use
```
## TypeScript
A generic type exists on all utilities to be set for instance/context type:
```ts
// Return type of useAwesome is Awesome | null
const { use: useAwesome } = createContext<Awesome>()
```
## Async Context
Normally, using context is only possible before first await statement:
```js
async function setup() {
console.log(useAwesome()) // Returns context
await new Promise(resolve => setTimeout(resolve, 1000))
console.log(useAwesome()) // Returns null
}
```
A simple workaround, is caching context before first await and use it directly:
```js
async function setup() {
const ctx = useAwesome()
await new Promise(resolve => setTimeout(resolve, 1000))
console.log(ctx) // We can directly access cached version of ctx
}
```
However, this is not always as easy as making a variable when using nested composables.
Unctx provides a better solution that transforms async to automatically restore context after each await call. This requires using a bundler such as Rollup, Vite or Webpack.
Import and register transform plugin:
```js
import { unctxPlugin } from 'unctx/plugin'
// Rollup
// TODO: Add to rollup configuration
unctxPlugin.rollup()
// Vite
// TODO: Add to vite configuration
unctxPlugin.vite()
// Webpack
// TODO: Add to webpack configuration
unctxPlugin.webpack()
```
Use `ctx.callAsync` instead of `ctx.call`:
```js
await ctx.callAsync('test', setup)
```
Any async function that requires context, should be wrapped with `withAsyncContext`:
```js
import { withAsyncContext } from 'unctx'
const setup = withAsyncContext(async () => {
console.log(useAwesome()) // Returns context
await new Promise(resolve => setTimeout(resolve, 1000))
console.log(useAwesome()) // Still returns context with dark magic!
})
```
## Under the hood
Composition of functions is possible using temporary context injection. When calling `ctx.call(instance, cb)`, `instance` argument will be stored in a temporary variable then `cb` is called. Any function inside `cb`, can then implicitly access instance by using `ctx.use` (or `useAwesome`)
## Pitfalls
**context can be only used before first await**:
Please check Async context section.
**`Context conflict` error**:
In your library, you should only keep one `call()` running at a time (unless calling with same reference for first argument)
For instance this makes an error:
```js
ctx.call({ test: 1 }, () => {
ctx.call({ test: 2 }, () => {
// Throws error!
})
})
```
## License
MIT. Made with 💖
<!-- Refs -->
[npm-v-src]: https://flat.badgen.net/npm/v/unctx/latest
[npm-v-href]: https://npmjs.com/package/unctx
[npm-dm-src]: https://flat.badgen.net/npm/dm/unctx
[npm-dm-href]: https://npmjs.com/package/unctx
[packagephobia-src]: https://flat.badgen.net/packagephobia/install/unctx
[packagephobia-href]: https://packagephobia.now.sh/result?p=unctx
[bundlephobia-src]: https://flat.badgen.net/bundlephobia/min/unctx
[bundlephobia-href]: https://bundlephobia.com/result?p=unctx
[codecov-src]: https://flat.badgen.net/codecov/c/github/unjs/unctx/master
[codecov-href]: https://codecov.io/gh/unjs/unctx

116
node_modules/unctx/dist/index.cjs generated vendored Normal file
View File

@@ -0,0 +1,116 @@
'use strict';
function createContext() {
let currentInstance;
let isSingleton = false;
const checkConflict = (instance) => {
if (currentInstance && currentInstance !== instance) {
throw new Error("Context conflict");
}
};
return {
use: () => {
if (currentInstance === void 0) {
throw new Error("Context is not available");
}
return currentInstance;
},
tryUse: () => {
return currentInstance;
},
set: (instance, replace) => {
if (!replace) {
checkConflict(instance);
}
currentInstance = instance;
isSingleton = true;
},
unset: () => {
currentInstance = void 0;
isSingleton = false;
},
call: (instance, callback) => {
checkConflict(instance);
currentInstance = instance;
try {
return callback();
} finally {
if (!isSingleton) {
currentInstance = void 0;
}
}
},
async callAsync(instance, callback) {
currentInstance = instance;
const onRestore = () => {
currentInstance = instance;
};
const onLeave = () => currentInstance === instance ? onRestore : void 0;
asyncHandlers.add(onLeave);
try {
const r = callback();
if (!isSingleton) {
currentInstance = void 0;
}
return await r;
} finally {
asyncHandlers.delete(onLeave);
}
}
};
}
function createNamespace() {
const contexts = {};
return {
get(key) {
if (!contexts[key]) {
contexts[key] = createContext();
}
contexts[key];
return contexts[key];
}
};
}
const _globalThis = typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : typeof window !== "undefined" ? window : {};
const globalKey = "__unctx__";
const defaultNamespace = _globalThis[globalKey] || (_globalThis[globalKey] = createNamespace());
const getContext = (key) => defaultNamespace.get(key);
const useContext = (key) => getContext(key).use;
const asyncHandlersKey = "__unctx_async_handlers__";
const asyncHandlers = _globalThis[asyncHandlersKey] || (_globalThis[asyncHandlersKey] = /* @__PURE__ */ new Set());
function executeAsync(function_) {
const restores = [];
for (const leaveHandler of asyncHandlers) {
const restore2 = leaveHandler();
if (restore2) {
restores.push(restore2);
}
}
const restore = () => {
for (const restore2 of restores) {
restore2();
}
};
let awaitable = function_();
if (awaitable && typeof awaitable === "object" && "catch" in awaitable) {
awaitable = awaitable.catch((error) => {
restore();
throw error;
});
}
return [awaitable, restore];
}
function withAsyncContext(function_, transformed) {
if (!transformed) {
console.warn("[unctx] `withAsyncContext` needs transformation for async context support in", function_, "\n", function_.toString());
}
return function_;
}
exports.createContext = createContext;
exports.createNamespace = createNamespace;
exports.defaultNamespace = defaultNamespace;
exports.executeAsync = executeAsync;
exports.getContext = getContext;
exports.useContext = useContext;
exports.withAsyncContext = withAsyncContext;

42
node_modules/unctx/dist/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,42 @@
interface UseContext<T> {
/**
* Get the current context. Throws if no context is set.
*/
use: () => T;
/**
* Get the current context. Returns `null` when no context is set.
*/
tryUse: () => T | null;
/**
* Set the context as Singleton Pattern.
*/
set: (instance?: T, replace?: Boolean) => void;
/**
* Clear current context.
*/
unset: () => void;
/**
* Exclude a synchronous function with the provided context.
*/
call: <R>(instance: T, callback: () => R) => R;
/**
* Exclude an asynchronous function with the provided context.
* Requires installing the transform plugin to work properly.
*/
callAsync: <R>(instance: T, callback: () => R | Promise<R>) => Promise<R>;
}
declare function createContext<T = any>(): UseContext<T>;
interface ContextNamespace {
get: <T>(key: string) => UseContext<T>;
}
declare function createNamespace<T = any>(): {
get(key: any): UseContext<T>;
};
declare const defaultNamespace: ContextNamespace;
declare const getContext: <T>(key: string) => UseContext<T>;
declare const useContext: <T>(key: string) => () => T;
type AsyncFunction<T> = () => Promise<T>;
declare function executeAsync<T>(function_: AsyncFunction<T>): [Promise<T>, () => void];
declare function withAsyncContext<T = any>(function_: AsyncFunction<T>, transformed?: boolean): AsyncFunction<T>;
export { ContextNamespace, UseContext, createContext, createNamespace, defaultNamespace, executeAsync, getContext, useContext, withAsyncContext };

108
node_modules/unctx/dist/index.mjs generated vendored Normal file
View File

@@ -0,0 +1,108 @@
function createContext() {
let currentInstance;
let isSingleton = false;
const checkConflict = (instance) => {
if (currentInstance && currentInstance !== instance) {
throw new Error("Context conflict");
}
};
return {
use: () => {
if (currentInstance === void 0) {
throw new Error("Context is not available");
}
return currentInstance;
},
tryUse: () => {
return currentInstance;
},
set: (instance, replace) => {
if (!replace) {
checkConflict(instance);
}
currentInstance = instance;
isSingleton = true;
},
unset: () => {
currentInstance = void 0;
isSingleton = false;
},
call: (instance, callback) => {
checkConflict(instance);
currentInstance = instance;
try {
return callback();
} finally {
if (!isSingleton) {
currentInstance = void 0;
}
}
},
async callAsync(instance, callback) {
currentInstance = instance;
const onRestore = () => {
currentInstance = instance;
};
const onLeave = () => currentInstance === instance ? onRestore : void 0;
asyncHandlers.add(onLeave);
try {
const r = callback();
if (!isSingleton) {
currentInstance = void 0;
}
return await r;
} finally {
asyncHandlers.delete(onLeave);
}
}
};
}
function createNamespace() {
const contexts = {};
return {
get(key) {
if (!contexts[key]) {
contexts[key] = createContext();
}
contexts[key];
return contexts[key];
}
};
}
const _globalThis = typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : typeof window !== "undefined" ? window : {};
const globalKey = "__unctx__";
const defaultNamespace = _globalThis[globalKey] || (_globalThis[globalKey] = createNamespace());
const getContext = (key) => defaultNamespace.get(key);
const useContext = (key) => getContext(key).use;
const asyncHandlersKey = "__unctx_async_handlers__";
const asyncHandlers = _globalThis[asyncHandlersKey] || (_globalThis[asyncHandlersKey] = /* @__PURE__ */ new Set());
function executeAsync(function_) {
const restores = [];
for (const leaveHandler of asyncHandlers) {
const restore2 = leaveHandler();
if (restore2) {
restores.push(restore2);
}
}
const restore = () => {
for (const restore2 of restores) {
restore2();
}
};
let awaitable = function_();
if (awaitable && typeof awaitable === "object" && "catch" in awaitable) {
awaitable = awaitable.catch((error) => {
restore();
throw error;
});
}
return [awaitable, restore];
}
function withAsyncContext(function_, transformed) {
if (!transformed) {
console.warn("[unctx] `withAsyncContext` needs transformation for async context support in", function_, "\n", function_.toString());
}
return function_;
}
export { createContext, createNamespace, defaultNamespace, executeAsync, getContext, useContext, withAsyncContext };

27
node_modules/unctx/dist/plugin.cjs generated vendored Normal file
View File

@@ -0,0 +1,27 @@
'use strict';
const unplugin = require('unplugin');
const transform = require('./transform.cjs');
require('acorn');
require('magic-string');
require('estree-walker');
const unctxPlugin = unplugin.createUnplugin((options = {}) => {
const transformer = transform.createTransformer(options);
return {
name: "unctx:transfrom",
enforce: "post",
transformInclude: options.transformInclude,
transform(code, id) {
const result = transformer.transform(code);
if (result) {
return {
code: result.code,
map: result.magicString.generateMap({ source: id, includeContent: true })
};
}
}
};
});
exports.unctxPlugin = unctxPlugin;

10
node_modules/unctx/dist/plugin.d.ts generated vendored Normal file
View File

@@ -0,0 +1,10 @@
import * as unplugin from 'unplugin';
import { TransformerOptions } from './transform.js';
import 'magic-string';
interface UnctxPluginOptions extends TransformerOptions {
transformInclude?: (id: string) => boolean;
}
declare const unctxPlugin: unplugin.UnpluginInstance<UnctxPluginOptions, false>;
export { UnctxPluginOptions, unctxPlugin };

25
node_modules/unctx/dist/plugin.mjs generated vendored Normal file
View File

@@ -0,0 +1,25 @@
import { createUnplugin } from 'unplugin';
import { createTransformer } from './transform.mjs';
import 'acorn';
import 'magic-string';
import 'estree-walker';
const unctxPlugin = createUnplugin((options = {}) => {
const transformer = createTransformer(options);
return {
name: "unctx:transfrom",
enforce: "post",
transformInclude: options.transformInclude,
transform(code, id) {
const result = transformer.transform(code);
if (result) {
return {
code: result.code,
map: result.magicString.generateMap({ source: id, includeContent: true })
};
}
}
};
});
export { unctxPlugin };

126
node_modules/unctx/dist/transform.cjs generated vendored Normal file
View File

@@ -0,0 +1,126 @@
'use strict';
const acorn = require('acorn');
const MagicString = require('magic-string');
const estreeWalker = require('estree-walker');
function _interopNamespaceDefault(e) {
const n = Object.create(null);
if (e) {
for (const k in e) {
n[k] = e[k];
}
}
n.default = e;
return n;
}
const acorn__namespace = /*#__PURE__*/_interopNamespaceDefault(acorn);
function createTransformer(options = {}) {
options = {
asyncFunctions: ["withAsyncContext"],
helperModule: "unctx",
helperName: "executeAsync",
...options
};
const matchRE = new RegExp(`\\b(${options.asyncFunctions.join("|")})\\(`);
function shouldTransform(code) {
return typeof code === "string" && matchRE.test(code);
}
function transform(code, options_ = {}) {
if (!options_.force && !shouldTransform(code)) {
return;
}
const ast = acorn__namespace.parse(code, {
sourceType: "module",
ecmaVersion: "latest",
locations: true
});
const s = new MagicString(code);
const lines = code.split("\n");
let detected = false;
estreeWalker.walk(ast, {
enter(node) {
if (node.type === "CallExpression") {
const functionName = _getFunctionName(node.callee);
if (options.asyncFunctions.includes(functionName)) {
transformFunctionBody(node);
if (functionName !== "callAsync") {
const lastArgument = node.arguments[node.arguments.length - 1];
if (lastArgument) {
s.appendRight(toIndex(lastArgument.loc.end), ",1");
}
}
}
}
}
});
if (!detected) {
return;
}
s.appendLeft(0, `import { ${options.helperName} as __executeAsync } from "${options.helperModule}";`);
return {
code: s.toString(),
magicString: s
};
function toIndex(pos) {
return lines.slice(0, pos.line - 1).join("\n").length + pos.column + 1;
}
function transformFunctionBody(node) {
for (const function_ of node.arguments) {
if (function_.type !== "ArrowFunctionExpression" && function_.type !== "FunctionExpression") {
continue;
}
if (!function_.async) {
continue;
}
const body = function_.body;
let injectVariable = false;
estreeWalker.walk(body, {
enter(node2, parent) {
if (node2.type === "AwaitExpression") {
detected = true;
injectVariable = true;
injectForNode(node2, parent);
}
if (node2.type === "ArrowFunctionExpression" || node2.type === "FunctionExpression" || node2.type === "FunctionDeclaration") {
return this.skip();
}
}
});
if (injectVariable) {
s.appendLeft(
toIndex(body.loc.start) + 1,
"let __temp, __restore;"
);
}
}
}
function injectForNode(node, parent) {
const body = code.slice(
toIndex(node.argument.loc.start),
toIndex(node.argument.loc.end)
);
const isStatement = parent?.type === "ExpressionStatement";
s.overwrite(
toIndex(node.loc.start),
toIndex(node.loc.end),
isStatement ? `;(([__temp,__restore]=__executeAsync(()=>${body})),await __temp,__restore());` : `(([__temp,__restore]=__executeAsync(()=>${body})),__temp=await __temp,__restore(),__temp)`
);
}
}
return {
transform,
shouldTransform
};
}
function _getFunctionName(node) {
if (node.type === "Identifier") {
return node.name;
} else if (node.type === "MemberExpression") {
return _getFunctionName(node.property);
}
}
exports.createTransformer = createTransformer;

29
node_modules/unctx/dist/transform.d.ts generated vendored Normal file
View File

@@ -0,0 +1,29 @@
import MagicString from 'magic-string';
interface TransformerOptions {
/**
* The function names to be transformed.
*
* @default ['withAsyncContext', 'callAsync']
*/
asyncFunctions?: string[];
/**
* @default 'unctx'
*/
helperModule?: string;
/**
* @default 'executeAsync'
*/
helperName?: string;
}
declare function createTransformer(options?: TransformerOptions): {
transform: (code: string, options_?: {
force?: false;
}) => {
code: string;
magicString: MagicString;
};
shouldTransform: (code: string) => boolean;
};
export { TransformerOptions, createTransformer };

111
node_modules/unctx/dist/transform.mjs generated vendored Normal file
View File

@@ -0,0 +1,111 @@
import * as acorn from 'acorn';
import MagicString from 'magic-string';
import { walk } from 'estree-walker';
function createTransformer(options = {}) {
options = {
asyncFunctions: ["withAsyncContext"],
helperModule: "unctx",
helperName: "executeAsync",
...options
};
const matchRE = new RegExp(`\\b(${options.asyncFunctions.join("|")})\\(`);
function shouldTransform(code) {
return typeof code === "string" && matchRE.test(code);
}
function transform(code, options_ = {}) {
if (!options_.force && !shouldTransform(code)) {
return;
}
const ast = acorn.parse(code, {
sourceType: "module",
ecmaVersion: "latest",
locations: true
});
const s = new MagicString(code);
const lines = code.split("\n");
let detected = false;
walk(ast, {
enter(node) {
if (node.type === "CallExpression") {
const functionName = _getFunctionName(node.callee);
if (options.asyncFunctions.includes(functionName)) {
transformFunctionBody(node);
if (functionName !== "callAsync") {
const lastArgument = node.arguments[node.arguments.length - 1];
if (lastArgument) {
s.appendRight(toIndex(lastArgument.loc.end), ",1");
}
}
}
}
}
});
if (!detected) {
return;
}
s.appendLeft(0, `import { ${options.helperName} as __executeAsync } from "${options.helperModule}";`);
return {
code: s.toString(),
magicString: s
};
function toIndex(pos) {
return lines.slice(0, pos.line - 1).join("\n").length + pos.column + 1;
}
function transformFunctionBody(node) {
for (const function_ of node.arguments) {
if (function_.type !== "ArrowFunctionExpression" && function_.type !== "FunctionExpression") {
continue;
}
if (!function_.async) {
continue;
}
const body = function_.body;
let injectVariable = false;
walk(body, {
enter(node2, parent) {
if (node2.type === "AwaitExpression") {
detected = true;
injectVariable = true;
injectForNode(node2, parent);
}
if (node2.type === "ArrowFunctionExpression" || node2.type === "FunctionExpression" || node2.type === "FunctionDeclaration") {
return this.skip();
}
}
});
if (injectVariable) {
s.appendLeft(
toIndex(body.loc.start) + 1,
"let __temp, __restore;"
);
}
}
}
function injectForNode(node, parent) {
const body = code.slice(
toIndex(node.argument.loc.start),
toIndex(node.argument.loc.end)
);
const isStatement = parent?.type === "ExpressionStatement";
s.overwrite(
toIndex(node.loc.start),
toIndex(node.loc.end),
isStatement ? `;(([__temp,__restore]=__executeAsync(()=>${body})),await __temp,__restore());` : `(([__temp,__restore]=__executeAsync(()=>${body})),__temp=await __temp,__restore(),__temp)`
);
}
}
return {
transform,
shouldTransform
};
}
function _getFunctionName(node) {
if (node.type === "Identifier") {
return node.name;
} else if (node.type === "MemberExpression") {
return _getFunctionName(node.property);
}
}
export { createTransformer };

64
node_modules/unctx/package.json generated vendored Normal file
View File

@@ -0,0 +1,64 @@
{
"name": "unctx",
"version": "2.1.1",
"description": "Composition-api in Vanilla js",
"repository": "unjs/unctx",
"license": "MIT",
"sideEffects": false,
"exports": {
".": {
"require": "./dist/index.cjs",
"import": "./dist/index.mjs",
"types": "./dist/index.d.ts"
},
"./transform": {
"import": "./dist/transform.mjs",
"types": "./dist/transform.d.ts"
},
"./plugin": {
"import": "./dist/plugin.mjs",
"types": "./dist/plugin.d.ts"
}
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"typesVersions": {
"*": {
"*": [
"./dist/*",
"./dist/index.d.ts"
]
}
},
"dependencies": {
"acorn": "^8.8.1",
"estree-walker": "^3.0.1",
"magic-string": "^0.26.7",
"unplugin": "^1.0.0"
},
"devDependencies": {
"@types/estree": "^1.0.0",
"@types/jest": "^29.2.3",
"@types/node": "^18.11.9",
"@vitest/coverage-c8": "^0.25.3",
"eslint": "^8.28.0",
"eslint-config-unjs": "^0.0.2",
"jiti": "^1.16.0",
"standard-version": "^9.5.0",
"typescript": "^4.9.3",
"unbuild": "^1.0.1",
"vitest": "^0.25.3"
},
"packageManager": "pnpm@7.17.1",
"scripts": {
"build": "unbuild",
"dev": "vitest",
"lint": "eslint --ext .ts,.js .",
"release": "pnpm test && standard-version && git push --follow-tags && pnpm publish",
"test": "pnpm lint && vitest run --coverage"
}
}