Initial commit - full huishou project

This commit is contained in:
jiapengyu
2026-07-27 14:07:26 +08:00
commit 60790ad1b3
39127 changed files with 5989265 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 - UnJS
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.
+450
View File
@@ -0,0 +1,450 @@
# unimport
[![npm version][npm-version-src]][npm-version-href]
[![npm downloads][npm-downloads-src]][npm-downloads-href]
[![Codecov][codecov-src]][codecov-href]
> Unified utils for auto importing APIs in modules, used in [nuxt](https://github.com/nuxt/nuxt) and [unplugin-auto-import](https://github.com/antfu/unplugin-auto-import)
## Features
- Auto import register APIs for Vite, Webpack or esbuild powered by [unplugin](https://github.com/unjs/unplugin)
- TypeScript declaration file generation
- Auto import for custom APIs defined under specific directories
- Auto import for Vue template
## Install
```sh
# npm
npm install unimport
# yarn
yarn add unimport
# pnpm
pnpm install unimport
```
## Usage
### Plugin Usage
Powered by [unplugin](https://github.com/unjs/unplugin), `unimport` provides a plugin interface for bundlers.
#### Vite / Rollup
```ts
// vite.config.js / rollup.config.js
import Unimport from 'unimport/unplugin'
export default {
plugins: [
Unimport.vite({ /* plugin options */ })
]
}
```
#### Webpack
```ts
// webpack.config.js
import Unimport from 'unimport/unplugin'
module.exports = {
plugins: [
Unimport.webpack({ /* plugin options */ })
]
}
```
### Programmatic Usage
<!-- eslint-skip -->
```js
// ESM
import { createUnimport } from 'unimport'
// CommonJS
const { createUnimport } = require('unimport')
```
```js
const { injectImports } = createUnimport({
imports: [{ name: 'fooBar', from: 'test-id' }]
})
// { code: "import { fooBar } from 'test-id';console.log(fooBar())" }
console.log(injectImports('console.log(fooBar())'))
```
## Configurations
### Imports Item
###### Named import
```ts
imports: [
{ name: 'ref', from: 'vue' },
{ name: 'useState', as: 'useSignal', from: 'react' },
]
```
Will be injected as:
```ts
import { useState as useSignal } from 'react'
import { ref } from 'vue'
```
###### Default import
```ts
imports: [
{ name: 'default', as: '_', from: 'lodash' }
]
```
Will be injected as:
```ts
import _ from 'lodash'
```
###### Namespace import
```ts
imports: [
{ name: '*', as: '_', from: 'lodash' }
]
```
Will be injected as:
```ts
import * as _ from 'lodash'
```
###### Export assignment import
This is a special case for libraries authored with [TypeScript's `export =` syntax](https://www.typescriptlang.org/docs/handbook/modules/reference.html#export--and-import--require). You don't need it the most of the time.
```ts
imports: [
{ name: '=', as: 'browser', from: 'webextension-polyfill' }
]
```
Will be injected as:
```ts
import browser from 'webextension-polyfill'
```
And the type declaration will be added as:
```ts
const browser: typeof import('webextension-polyfill')
```
###### Custom Presets
Presets are provided as a shorthand for declaring imports from the same package:
```ts
presets: [
{
from: 'vue',
imports: [
'ref',
'reactive',
// ...
]
}
]
```
Will be equivalent as:
```ts
imports: [
{ name: 'ref', from: 'vue' },
{ name: 'reactive', from: 'vue' },
// ...
]
```
###### Built-in Presets
`unimport` also provides some builtin presets for common libraries:
```ts
presets: [
'vue',
'pinia',
'vue-i18n',
// ...
]
```
You can check out [`src/presets`](./src/presets/) for all the options available or refer to the type declaration.
###### Exports Auto Scan
Since `unimport` v0.7.0, we also support auto scanning the examples from a local installed package, for example:
```ts
presets: [
{
package: 'h3',
ignore: ['isStream', /^[A-Z]/, /^[a-z]*$/, r => r.length > 8]
}
]
```
This will be expanded into:
```ts
imports: [
{
from: 'h3',
name: 'appendHeader',
},
{
from: 'h3',
name: 'appendHeaders',
},
{
from: 'h3',
name: 'appendResponseHeader',
},
// ...
]
```
The `ignore` option is used to filter out the exports, it can be a string, regex or a function that returns a boolean.
By default, the result is strongly cached by the version of the package. You can disable this by setting `cache: false`.
### Type Declarations
```ts
Unimport.vite({
dts: true // or a path to generated file
})
```
### Directory Auto Import
```ts
Unimport.vite({
dirs: [
'./composables/*',
]
})
```
Scan for modules under `./composables` and auto-import the named exports.
#### Nested Directories
```ts
Unimport.vite({
dirs: [
'./composables/**/*',
{
glob: './composables/nested/**/*',
types: false // disable scan the type declarations
}
]
})
```
Named exports for modules under `./composables/**/*` will be registered for auto imports, and filter out the types in `./composables/nested/**/*`.
#### Directory Scan Options
You can also provide custom options for directory scan, for example:
```ts
Unimport.vite({
dirsScanOptions: {
filePatterns: ['*.ts'], // optional, default `['*.{ts,js,mjs,cjs,mts,cts}']`, glob patterns for matching files
fileFilter: file => file.endsWith('.ts'), // optional, default `() => true`, filter files
types: true, // optional, default `true`, enable/disable scan the type declarations
cwd: process.cwd(), // optional, default `process.cwd()`, custom cwd for directory scan
},
dirs: [
'./composables/**/*',
{
glob: './composables/nested/**/*',
types: false
}
]
})
```
### Opt-out Auto Import
You can opt-out auto-import for specific modules by adding a comment:
```ts
// @unimport-disable
```
It can be customized by setting `commentsDisable`:
```ts
Unimport.vite({
commentsDisable: [
'@unimport-disable',
'@custom-imports-disable',
]
})
```
### Acorn Parser
By default, `unimport` uses RegExp to detect unimport entries. In some cases, RegExp might not be able to detect all the entries (false positive & false negative).
We introduced a new AST-based parser powered by [acorn](https://github.com/acornjs/acorn), providing a more accurate result. The limitation is when using Acorn, it assumes all input code are valid and vanilla JavaScript code.
```ts
Unimport.vite({
parser: 'acorn'
})
```
### Vue Template Auto Import
In Vue's template, the usage of API is in a different context than plain modules. Thus some custom transformations are required. To enable it, set `addons.vueTemplate` to `true`:
```ts
Unimport.vite({
addons: {
vueTemplate: true
}
})
```
#### Caveats
When auto-import a ref, inline operations won't be auto-unwrapped.
```ts
export const counter = ref(0)
```
```html
<template>
<!-- this is ok -->
<div>{{ counter }}</div>
<!-- counter here is a ref, this won't work, volar will throw -->
<div>{{ counter + 1 }}</div>
<!-- use this instead -->
<div>{{ counter.value + 1 }}</div>
</template>
```
We recommend using [Volar](https://github.com/johnsoncodehk/volar) for type checking, which will help you to identify the misusage.
### Vue Directives Auto Import and TypeScript Declaration Generation
In Vue's template, the usage of directives is in a different context than plain modules. Thus some custom transformations are required. To enable it, set `addons.vueDirectives` to `true`:
```ts
Unimport.vite({
addons: {
vueDirectives: true
}
})
```
#### Library Authors
When including directives in your presets, you should:
- provide the corresponding imports with `meta.vueDirective` set to `true`, otherwise, `unimport` will not be able to detect your directives.
- use named exports for your directives, or use default export and use `as` in the Import.
- set `dtsDisabled` to `true` if you provide a type declaration for your directives.
```ts
import type { InlinePreset } from 'unimport'
import { defineUnimportPreset } from 'unimport'
export const composables = defineUnimportPreset({
from: 'my-unimport-library/composables',
/* imports and other options */
})
export const directives = defineUnimportPreset({
from: 'my-unimport-library/directives',
// disable dts generation globally
dtsEnabled: false,
// you can declare the vue directive globally
meta: {
vueDirective: true
},
imports: [{
name: 'ClickOutside',
// disable dts generation per import
dtsEnabled: false,
// you can declare the vue directive per import
meta: {
vueDirective: true
}
}, {
name: 'default',
// you should declare `as` for default exports
as: 'Focus'
}]
})
```
#### Using Directory Scan and Local Directives
If you add a directory scan for your local directives in the project, you need to:
- provide `isDirective` in the `vueDirectives`: `unimport` will use it to detect them (will never be called for imports with `meta.vueDirective` set to `true`).
- use always named exports for your directives.
```ts
Unimport.vite({
dirs: ['./directives/**'],
addons: {
vueDirectives: {
isDirective: (normalizedImportFrom, _importEntry) => {
return normalizedImportFrom.includes('/directives/')
}
}
}
})
```
## 💻 Development
- Clone this repository
- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable` (use `npm i -g corepack` for Node.js < 16.10)
- Install dependencies using `pnpm install`
- Run interactive tests using `pnpm dev`
## License
Made with 💛
Published under [MIT License](./LICENSE).
<!-- Badges -->
[npm-version-src]: https://img.shields.io/npm/v/unimport?style=flat-square
[npm-version-href]: https://npmjs.com/package/unimport
[npm-downloads-src]: https://img.shields.io/npm/dm/unimport?style=flat-square
[npm-downloads-href]: https://npmjs.com/package/unimport
[github-actions-src]: https://img.shields.io/github/workflow/status/unjs/unimport/ci/main?style=flat-square
[github-actions-href]: https://github.com/unjs/unimport/actions?query=workflow%3Aci
[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/unimport/main?style=flat-square
[codecov-href]: https://codecov.io/gh/unjs/unimport
+2
View File
@@ -0,0 +1,2 @@
// redirect for TypeScript to pick it up
export * from './dist/addons'
+15
View File
@@ -0,0 +1,15 @@
'use strict';
const vueDirectives = require('./shared/unimport.MMUMmZ45.cjs');
require('node:path');
require('node:process');
require('pathe');
require('scule');
require('magic-string');
require('mlly');
require('strip-literal');
exports.vueDirectivesAddon = vueDirectives.vueDirectivesAddon;
exports.vueTemplateAddon = vueDirectives.vueTemplateAddon;
+8
View File
@@ -0,0 +1,8 @@
import { n as AddonVueDirectivesOptions, r as Addon } from './shared/unimport.CaVRR9SH.cjs';
export { v as vueTemplateAddon } from './shared/unimport.D0oAO1c8.cjs';
import 'magic-string';
import 'mlly';
declare function vueDirectivesAddon(options?: AddonVueDirectivesOptions): Addon;
export { vueDirectivesAddon };
+8
View File
@@ -0,0 +1,8 @@
import { n as AddonVueDirectivesOptions, r as Addon } from './shared/unimport.CaVRR9SH.mjs';
export { v as vueTemplateAddon } from './shared/unimport.CzOA5cgj.mjs';
import 'magic-string';
import 'mlly';
declare function vueDirectivesAddon(options?: AddonVueDirectivesOptions): Addon;
export { vueDirectivesAddon };
+8
View File
@@ -0,0 +1,8 @@
import { n as AddonVueDirectivesOptions, r as Addon } from './shared/unimport.CaVRR9SH.js';
export { v as vueTemplateAddon } from './shared/unimport.BGSZL1Hy.js';
import 'magic-string';
import 'mlly';
declare function vueDirectivesAddon(options?: AddonVueDirectivesOptions): Addon;
export { vueDirectivesAddon };
+8
View File
@@ -0,0 +1,8 @@
export { v as vueDirectivesAddon, a as vueTemplateAddon } from './shared/unimport.0aitavbJ.mjs';
import 'node:path';
import 'node:process';
import 'pathe';
import 'scule';
import 'magic-string';
import 'mlly';
import 'strip-literal';
+234
View File
@@ -0,0 +1,234 @@
'use strict';
const acorn = require('acorn');
const estreeWalker = require('estree-walker');
const vueDirectives = require('../shared/unimport.MMUMmZ45.cjs');
require('node:path');
require('node:process');
require('pathe');
require('scule');
require('magic-string');
require('mlly');
require('strip-literal');
async function detectImportsAcorn(code, ctx, options) {
const s = vueDirectives.getMagicString(code);
const map = await ctx.getImportMap();
let matchedImports = [];
const enableAutoImport = options?.autoImport !== false;
const enableTransformVirtualImports = options?.transformVirtualImports !== false && ctx.options.virtualImports?.length;
if (enableAutoImport || enableTransformVirtualImports) {
const ast = acorn.parse(s.original, {
sourceType: "module",
ecmaVersion: "latest",
locations: true
});
const virtualImports = createVirtualImportsAcronWalker(map, ctx.options.virtualImports);
const scopes = traveseScopes(
ast,
enableTransformVirtualImports ? virtualImports.walk : {}
);
if (enableAutoImport) {
const identifiers = scopes.unmatched;
matchedImports.push(
...Array.from(identifiers).map((name) => {
const item = map.get(name);
if (item && !item.disabled)
return item;
return null;
}).filter(Boolean)
);
for (const addon of ctx.addons)
matchedImports = await addon.matchImports?.call(ctx, identifiers, matchedImports) || matchedImports;
}
virtualImports.ranges.forEach(([start, end]) => {
s.remove(start, end);
});
matchedImports.push(...virtualImports.imports);
}
return {
s,
strippedCode: code.toString(),
matchedImports,
isCJSContext: false,
firstOccurrence: 0
// TODO:
};
}
function traveseScopes(ast, additionalWalk) {
const scopes = [];
let scopeCurrent = undefined;
const scopesStack = [];
function pushScope(node) {
scopeCurrent = {
node,
parent: scopeCurrent,
declarations: /* @__PURE__ */ new Set(),
references: /* @__PURE__ */ new Set()
};
scopes.push(scopeCurrent);
scopesStack.push(scopeCurrent);
}
function popScope(node) {
const scope = scopesStack.pop();
if (scope?.node !== node)
throw new Error("Scope mismatch");
scopeCurrent = scopesStack[scopesStack.length - 1];
}
pushScope(undefined);
estreeWalker.walk(ast, {
enter(node, parent, prop, index) {
additionalWalk?.enter?.call(this, node, parent, prop, index);
switch (node.type) {
// ====== Declaration ======
case "ImportSpecifier":
case "ImportDefaultSpecifier":
case "ImportNamespaceSpecifier":
scopeCurrent.declarations.add(node.local.name);
return;
case "FunctionDeclaration":
case "ClassDeclaration":
if (node.id)
scopeCurrent.declarations.add(node.id.name);
return;
case "VariableDeclarator":
if (node.id.type === "Identifier") {
scopeCurrent.declarations.add(node.id.name);
} else {
estreeWalker.walk(node.id, {
enter(node2) {
if (node2.type === "ObjectPattern") {
node2.properties.forEach((i) => {
if (i.type === "Property" && i.value.type === "Identifier")
scopeCurrent.declarations.add(i.value.name);
else if (i.type === "RestElement" && i.argument.type === "Identifier")
scopeCurrent.declarations.add(i.argument.name);
});
} else if (node2.type === "ArrayPattern") {
node2.elements.forEach((i) => {
if (i?.type === "Identifier")
scopeCurrent.declarations.add(i.name);
if (i?.type === "RestElement" && i.argument.type === "Identifier")
scopeCurrent.declarations.add(i.argument.name);
});
}
}
});
}
return;
// ====== Scope ======
case "BlockStatement":
pushScope(node);
return;
// ====== Reference ======
case "Identifier":
switch (parent?.type) {
case "CallExpression":
if (parent.callee === node || parent.arguments.includes(node))
scopeCurrent.references.add(node.name);
return;
case "MemberExpression":
if (parent.object === node)
scopeCurrent.references.add(node.name);
return;
case "VariableDeclarator":
if (parent.init === node)
scopeCurrent.references.add(node.name);
return;
case "SpreadElement":
if (parent.argument === node)
scopeCurrent.references.add(node.name);
return;
case "ClassDeclaration":
if (parent.superClass === node)
scopeCurrent.references.add(node.name);
return;
case "Property":
if (parent.value === node)
scopeCurrent.references.add(node.name);
return;
case "TemplateLiteral":
if (parent.expressions.includes(node))
scopeCurrent.references.add(node.name);
return;
case "AssignmentExpression":
if (parent.right === node)
scopeCurrent.references.add(node.name);
return;
case "IfStatement":
case "WhileStatement":
case "DoWhileStatement":
if (parent.test === node)
scopeCurrent.references.add(node.name);
return;
case "SwitchStatement":
if (parent.discriminant === node)
scopeCurrent.references.add(node.name);
return;
}
if (parent?.type.includes("Expression"))
scopeCurrent.references.add(node.name);
}
},
leave(node, parent, prop, index) {
additionalWalk?.leave?.call(this, node, parent, prop, index);
switch (node.type) {
case "BlockStatement":
popScope(node);
}
}
});
const unmatched = /* @__PURE__ */ new Set();
for (const scope of scopes) {
for (const name of scope.references) {
let defined = false;
let parent = scope;
while (parent) {
if (parent.declarations.has(name)) {
defined = true;
break;
}
parent = parent?.parent;
}
if (!defined)
unmatched.add(name);
}
}
return {
unmatched,
scopes
};
}
function createVirtualImportsAcronWalker(importMap, virtualImports = []) {
const imports = [];
const ranges = [];
return {
imports,
ranges,
walk: {
enter(node) {
if (node.type === "ImportDeclaration") {
if (virtualImports.includes(node.source.value)) {
ranges.push([node.start, node.end]);
node.specifiers.forEach((i) => {
if (i.type === "ImportSpecifier" && i.imported.type === "Identifier") {
const original = importMap.get(i.imported.name);
if (!original)
throw new Error(`[unimport] failed to find "${i.imported.name}" imported from "${node.source.value}"`);
imports.push({
from: original.from,
name: original.name,
as: i.local.name
});
}
});
}
}
}
}
};
}
exports.createVirtualImportsAcronWalker = createVirtualImportsAcronWalker;
exports.detectImportsAcorn = detectImportsAcorn;
exports.traveseScopes = traveseScopes;
+230
View File
@@ -0,0 +1,230 @@
import { parse } from 'acorn';
import { walk } from 'estree-walker';
import { n as getMagicString } from '../shared/unimport.0aitavbJ.mjs';
import 'node:path';
import 'node:process';
import 'pathe';
import 'scule';
import 'magic-string';
import 'mlly';
import 'strip-literal';
async function detectImportsAcorn(code, ctx, options) {
const s = getMagicString(code);
const map = await ctx.getImportMap();
let matchedImports = [];
const enableAutoImport = options?.autoImport !== false;
const enableTransformVirtualImports = options?.transformVirtualImports !== false && ctx.options.virtualImports?.length;
if (enableAutoImport || enableTransformVirtualImports) {
const ast = parse(s.original, {
sourceType: "module",
ecmaVersion: "latest",
locations: true
});
const virtualImports = createVirtualImportsAcronWalker(map, ctx.options.virtualImports);
const scopes = traveseScopes(
ast,
enableTransformVirtualImports ? virtualImports.walk : {}
);
if (enableAutoImport) {
const identifiers = scopes.unmatched;
matchedImports.push(
...Array.from(identifiers).map((name) => {
const item = map.get(name);
if (item && !item.disabled)
return item;
return null;
}).filter(Boolean)
);
for (const addon of ctx.addons)
matchedImports = await addon.matchImports?.call(ctx, identifiers, matchedImports) || matchedImports;
}
virtualImports.ranges.forEach(([start, end]) => {
s.remove(start, end);
});
matchedImports.push(...virtualImports.imports);
}
return {
s,
strippedCode: code.toString(),
matchedImports,
isCJSContext: false,
firstOccurrence: 0
// TODO:
};
}
function traveseScopes(ast, additionalWalk) {
const scopes = [];
let scopeCurrent = undefined;
const scopesStack = [];
function pushScope(node) {
scopeCurrent = {
node,
parent: scopeCurrent,
declarations: /* @__PURE__ */ new Set(),
references: /* @__PURE__ */ new Set()
};
scopes.push(scopeCurrent);
scopesStack.push(scopeCurrent);
}
function popScope(node) {
const scope = scopesStack.pop();
if (scope?.node !== node)
throw new Error("Scope mismatch");
scopeCurrent = scopesStack[scopesStack.length - 1];
}
pushScope(undefined);
walk(ast, {
enter(node, parent, prop, index) {
additionalWalk?.enter?.call(this, node, parent, prop, index);
switch (node.type) {
// ====== Declaration ======
case "ImportSpecifier":
case "ImportDefaultSpecifier":
case "ImportNamespaceSpecifier":
scopeCurrent.declarations.add(node.local.name);
return;
case "FunctionDeclaration":
case "ClassDeclaration":
if (node.id)
scopeCurrent.declarations.add(node.id.name);
return;
case "VariableDeclarator":
if (node.id.type === "Identifier") {
scopeCurrent.declarations.add(node.id.name);
} else {
walk(node.id, {
enter(node2) {
if (node2.type === "ObjectPattern") {
node2.properties.forEach((i) => {
if (i.type === "Property" && i.value.type === "Identifier")
scopeCurrent.declarations.add(i.value.name);
else if (i.type === "RestElement" && i.argument.type === "Identifier")
scopeCurrent.declarations.add(i.argument.name);
});
} else if (node2.type === "ArrayPattern") {
node2.elements.forEach((i) => {
if (i?.type === "Identifier")
scopeCurrent.declarations.add(i.name);
if (i?.type === "RestElement" && i.argument.type === "Identifier")
scopeCurrent.declarations.add(i.argument.name);
});
}
}
});
}
return;
// ====== Scope ======
case "BlockStatement":
pushScope(node);
return;
// ====== Reference ======
case "Identifier":
switch (parent?.type) {
case "CallExpression":
if (parent.callee === node || parent.arguments.includes(node))
scopeCurrent.references.add(node.name);
return;
case "MemberExpression":
if (parent.object === node)
scopeCurrent.references.add(node.name);
return;
case "VariableDeclarator":
if (parent.init === node)
scopeCurrent.references.add(node.name);
return;
case "SpreadElement":
if (parent.argument === node)
scopeCurrent.references.add(node.name);
return;
case "ClassDeclaration":
if (parent.superClass === node)
scopeCurrent.references.add(node.name);
return;
case "Property":
if (parent.value === node)
scopeCurrent.references.add(node.name);
return;
case "TemplateLiteral":
if (parent.expressions.includes(node))
scopeCurrent.references.add(node.name);
return;
case "AssignmentExpression":
if (parent.right === node)
scopeCurrent.references.add(node.name);
return;
case "IfStatement":
case "WhileStatement":
case "DoWhileStatement":
if (parent.test === node)
scopeCurrent.references.add(node.name);
return;
case "SwitchStatement":
if (parent.discriminant === node)
scopeCurrent.references.add(node.name);
return;
}
if (parent?.type.includes("Expression"))
scopeCurrent.references.add(node.name);
}
},
leave(node, parent, prop, index) {
additionalWalk?.leave?.call(this, node, parent, prop, index);
switch (node.type) {
case "BlockStatement":
popScope(node);
}
}
});
const unmatched = /* @__PURE__ */ new Set();
for (const scope of scopes) {
for (const name of scope.references) {
let defined = false;
let parent = scope;
while (parent) {
if (parent.declarations.has(name)) {
defined = true;
break;
}
parent = parent?.parent;
}
if (!defined)
unmatched.add(name);
}
}
return {
unmatched,
scopes
};
}
function createVirtualImportsAcronWalker(importMap, virtualImports = []) {
const imports = [];
const ranges = [];
return {
imports,
ranges,
walk: {
enter(node) {
if (node.type === "ImportDeclaration") {
if (virtualImports.includes(node.source.value)) {
ranges.push([node.start, node.end]);
node.specifiers.forEach((i) => {
if (i.type === "ImportSpecifier" && i.imported.type === "Identifier") {
const original = importMap.get(i.imported.name);
if (!original)
throw new Error(`[unimport] failed to find "${i.imported.name}" imported from "${node.source.value}"`);
imports.push({
from: original.from,
name: original.name,
as: i.local.name
});
}
});
}
}
}
}
};
}
export { createVirtualImportsAcronWalker, detectImportsAcorn, traveseScopes };
+71
View File
@@ -0,0 +1,71 @@
'use strict';
const context = require('./shared/unimport.D6_N7ILk.cjs');
const vueDirectives = require('./shared/unimport.MMUMmZ45.cjs');
require('mlly');
require('node:fs');
require('node:fs/promises');
require('node:process');
require('node:url');
require('fast-glob');
require('pathe');
require('picomatch');
require('scule');
require('node:os');
require('pkg-types');
require('local-pkg');
require('node:path');
require('magic-string');
require('strip-literal');
async function installGlobalAutoImports(imports, options = {}) {
const {
globalObject = globalThis,
overrides = false
} = options;
imports = Array.isArray(imports) ? imports : await imports.getImports();
await Promise.all(
imports.map(async (i) => {
if (i.disabled || i.type)
return;
const as = i.as || i.name;
if (overrides || !(as in globalObject)) {
const module = await import(i.from);
globalObject[as] = module[i.name];
}
})
);
return globalObject;
}
exports.builtinPresets = context.builtinPresets;
exports.createUnimport = context.createUnimport;
exports.dedupeDtsExports = context.dedupeDtsExports;
exports.normalizeScanDirs = context.normalizeScanDirs;
exports.resolveBuiltinPresets = context.resolveBuiltinPresets;
exports.resolvePreset = context.resolvePreset;
exports.scanDirExports = context.scanDirExports;
exports.scanExports = context.scanExports;
exports.scanFilesFromDir = context.scanFilesFromDir;
exports.version = context.version;
exports.addImportToCode = vueDirectives.addImportToCode;
exports.dedupeImports = vueDirectives.dedupeImports;
exports.defineUnimportPreset = vueDirectives.defineUnimportPreset;
exports.excludeRE = vueDirectives.excludeRE;
exports.getMagicString = vueDirectives.getMagicString;
exports.getString = vueDirectives.getString;
exports.importAsRE = vueDirectives.importAsRE;
exports.matchRE = vueDirectives.matchRE;
exports.normalizeImports = vueDirectives.normalizeImports;
exports.resolveIdAbsolute = vueDirectives.resolveIdAbsolute;
exports.separatorRE = vueDirectives.separatorRE;
exports.stringifyImports = vueDirectives.stringifyImports;
exports.stripCommentsAndStrings = vueDirectives.stripCommentsAndStrings;
exports.stripFileExtension = vueDirectives.stripFileExtension;
exports.toExports = vueDirectives.toExports;
exports.toImports = vueDirectives.toImports;
exports.toTypeDeclarationFile = vueDirectives.toTypeDeclarationFile;
exports.toTypeDeclarationItems = vueDirectives.toTypeDeclarationItems;
exports.toTypeReExports = vueDirectives.toTypeReExports;
exports.vueTemplateAddon = vueDirectives.vueTemplateAddon;
exports.installGlobalAutoImports = installGlobalAutoImports;
+52
View File
@@ -0,0 +1,52 @@
export { v as vueTemplateAddon } from './shared/unimport.D0oAO1c8.cjs';
import { U as UnimportOptions, a as Unimport, I as Import, b as InstallGlobalOptions, S as ScanDir, c as ScanDirExportsOptions, P as Preset, B as BuiltinPresetName, d as InlinePreset, T as TypeDeclarationOptions, M as MagicStringResult } from './shared/unimport.CaVRR9SH.cjs';
export { r as Addon, n as AddonVueDirectivesOptions, A as AddonsOptions, D as DetectImportResult, h as ImportCommon, s as ImportInjectionResult, g as ImportName, p as InjectImportsOptions, l as InjectionUsageRecord, f as ModuleId, j as PackagePreset, o as PathFromResolver, i as PresetImport, q as Thenable, k as UnimportContext, m as UnimportMeta, e as builtinPresets } from './shared/unimport.CaVRR9SH.cjs';
import { StripLiteralOptions } from 'strip-literal';
import MagicString from 'magic-string';
import 'mlly';
const version = "3.14.6";
declare function createUnimport(opts: Partial<UnimportOptions>): Unimport;
declare function installGlobalAutoImports(imports: Import[] | Unimport, options?: InstallGlobalOptions): Promise<any>;
declare function normalizeScanDirs(dirs: (string | ScanDir)[], options?: ScanDirExportsOptions): Required<ScanDir>[];
declare function scanFilesFromDir(dir: ScanDir | ScanDir[], options?: ScanDirExportsOptions): Promise<string[]>;
declare function scanDirExports(dirs: (string | ScanDir)[], options?: ScanDirExportsOptions): Promise<Import[]>;
declare function dedupeDtsExports(exports: Import[]): Import[];
declare function scanExports(filepath: string, includeTypes: boolean, seen?: Set<string>): Promise<Import[]>;
declare function resolvePreset(preset: Preset): Promise<Import[]>;
declare function resolveBuiltinPresets(presets: (BuiltinPresetName | Preset)[]): Promise<Import[]>;
declare const excludeRE: RegExp[];
declare const importAsRE: RegExp;
declare const separatorRE: RegExp;
/**
* | |
* destructing case&ternary non-call inheritance | id |
* ↓ ↓ ↓ ↓ | |
*/
declare const matchRE: RegExp;
declare function stripCommentsAndStrings(code: string, options?: StripLiteralOptions): string;
declare function defineUnimportPreset(preset: InlinePreset): InlinePreset;
declare function stringifyImports(imports: Import[], isCJS?: boolean): string;
declare function dedupeImports(imports: Import[], warn: (msg: string) => void): Import[];
declare function toExports(imports: Import[], fileDir?: string, includeType?: boolean): string;
declare function stripFileExtension(path: string): string;
declare function toTypeDeclarationItems(imports: Import[], options?: TypeDeclarationOptions): string[];
declare function toTypeDeclarationFile(imports: Import[], options?: TypeDeclarationOptions): string;
declare function toTypeReExports(imports: Import[], options?: TypeDeclarationOptions): string;
declare function getString(code: string | MagicString): string;
declare function getMagicString(code: string | MagicString): MagicString;
declare function addImportToCode(code: string | MagicString, imports: Import[], isCJS?: boolean, mergeExisting?: boolean, injectAtLast?: boolean, firstOccurrence?: number, onResolved?: (imports: Import[]) => void | Import[], onStringified?: (str: string, imports: Import[]) => void | string): MagicStringResult;
declare function normalizeImports(imports: Import[]): Import[];
declare function resolveIdAbsolute(id: string, parentId?: string): string;
/**
* @deprecated renamed to `stringifyImports`
*/
declare const toImports: typeof stringifyImports;
export { BuiltinPresetName, Import, InlinePreset, InstallGlobalOptions, MagicStringResult, Preset, ScanDir, ScanDirExportsOptions, TypeDeclarationOptions, Unimport, UnimportOptions, addImportToCode, createUnimport, dedupeDtsExports, dedupeImports, defineUnimportPreset, excludeRE, getMagicString, getString, importAsRE, installGlobalAutoImports, matchRE, normalizeImports, normalizeScanDirs, resolveBuiltinPresets, resolveIdAbsolute, resolvePreset, scanDirExports, scanExports, scanFilesFromDir, separatorRE, stringifyImports, stripCommentsAndStrings, stripFileExtension, toExports, toImports, toTypeDeclarationFile, toTypeDeclarationItems, toTypeReExports, version };
+52
View File
@@ -0,0 +1,52 @@
export { v as vueTemplateAddon } from './shared/unimport.CzOA5cgj.mjs';
import { U as UnimportOptions, a as Unimport, I as Import, b as InstallGlobalOptions, S as ScanDir, c as ScanDirExportsOptions, P as Preset, B as BuiltinPresetName, d as InlinePreset, T as TypeDeclarationOptions, M as MagicStringResult } from './shared/unimport.CaVRR9SH.mjs';
export { r as Addon, n as AddonVueDirectivesOptions, A as AddonsOptions, D as DetectImportResult, h as ImportCommon, s as ImportInjectionResult, g as ImportName, p as InjectImportsOptions, l as InjectionUsageRecord, f as ModuleId, j as PackagePreset, o as PathFromResolver, i as PresetImport, q as Thenable, k as UnimportContext, m as UnimportMeta, e as builtinPresets } from './shared/unimport.CaVRR9SH.mjs';
import { StripLiteralOptions } from 'strip-literal';
import MagicString from 'magic-string';
import 'mlly';
const version = "3.14.6";
declare function createUnimport(opts: Partial<UnimportOptions>): Unimport;
declare function installGlobalAutoImports(imports: Import[] | Unimport, options?: InstallGlobalOptions): Promise<any>;
declare function normalizeScanDirs(dirs: (string | ScanDir)[], options?: ScanDirExportsOptions): Required<ScanDir>[];
declare function scanFilesFromDir(dir: ScanDir | ScanDir[], options?: ScanDirExportsOptions): Promise<string[]>;
declare function scanDirExports(dirs: (string | ScanDir)[], options?: ScanDirExportsOptions): Promise<Import[]>;
declare function dedupeDtsExports(exports: Import[]): Import[];
declare function scanExports(filepath: string, includeTypes: boolean, seen?: Set<string>): Promise<Import[]>;
declare function resolvePreset(preset: Preset): Promise<Import[]>;
declare function resolveBuiltinPresets(presets: (BuiltinPresetName | Preset)[]): Promise<Import[]>;
declare const excludeRE: RegExp[];
declare const importAsRE: RegExp;
declare const separatorRE: RegExp;
/**
* | |
* destructing case&ternary non-call inheritance | id |
* ↓ ↓ ↓ ↓ | |
*/
declare const matchRE: RegExp;
declare function stripCommentsAndStrings(code: string, options?: StripLiteralOptions): string;
declare function defineUnimportPreset(preset: InlinePreset): InlinePreset;
declare function stringifyImports(imports: Import[], isCJS?: boolean): string;
declare function dedupeImports(imports: Import[], warn: (msg: string) => void): Import[];
declare function toExports(imports: Import[], fileDir?: string, includeType?: boolean): string;
declare function stripFileExtension(path: string): string;
declare function toTypeDeclarationItems(imports: Import[], options?: TypeDeclarationOptions): string[];
declare function toTypeDeclarationFile(imports: Import[], options?: TypeDeclarationOptions): string;
declare function toTypeReExports(imports: Import[], options?: TypeDeclarationOptions): string;
declare function getString(code: string | MagicString): string;
declare function getMagicString(code: string | MagicString): MagicString;
declare function addImportToCode(code: string | MagicString, imports: Import[], isCJS?: boolean, mergeExisting?: boolean, injectAtLast?: boolean, firstOccurrence?: number, onResolved?: (imports: Import[]) => void | Import[], onStringified?: (str: string, imports: Import[]) => void | string): MagicStringResult;
declare function normalizeImports(imports: Import[]): Import[];
declare function resolveIdAbsolute(id: string, parentId?: string): string;
/**
* @deprecated renamed to `stringifyImports`
*/
declare const toImports: typeof stringifyImports;
export { BuiltinPresetName, Import, InlinePreset, InstallGlobalOptions, MagicStringResult, Preset, ScanDir, ScanDirExportsOptions, TypeDeclarationOptions, Unimport, UnimportOptions, addImportToCode, createUnimport, dedupeDtsExports, dedupeImports, defineUnimportPreset, excludeRE, getMagicString, getString, importAsRE, installGlobalAutoImports, matchRE, normalizeImports, normalizeScanDirs, resolveBuiltinPresets, resolveIdAbsolute, resolvePreset, scanDirExports, scanExports, scanFilesFromDir, separatorRE, stringifyImports, stripCommentsAndStrings, stripFileExtension, toExports, toImports, toTypeDeclarationFile, toTypeDeclarationItems, toTypeReExports, version };
+52
View File
@@ -0,0 +1,52 @@
export { v as vueTemplateAddon } from './shared/unimport.BGSZL1Hy.js';
import { U as UnimportOptions, a as Unimport, I as Import, b as InstallGlobalOptions, S as ScanDir, c as ScanDirExportsOptions, P as Preset, B as BuiltinPresetName, d as InlinePreset, T as TypeDeclarationOptions, M as MagicStringResult } from './shared/unimport.CaVRR9SH.js';
export { r as Addon, n as AddonVueDirectivesOptions, A as AddonsOptions, D as DetectImportResult, h as ImportCommon, s as ImportInjectionResult, g as ImportName, p as InjectImportsOptions, l as InjectionUsageRecord, f as ModuleId, j as PackagePreset, o as PathFromResolver, i as PresetImport, q as Thenable, k as UnimportContext, m as UnimportMeta, e as builtinPresets } from './shared/unimport.CaVRR9SH.js';
import { StripLiteralOptions } from 'strip-literal';
import MagicString from 'magic-string';
import 'mlly';
const version = "3.14.6";
declare function createUnimport(opts: Partial<UnimportOptions>): Unimport;
declare function installGlobalAutoImports(imports: Import[] | Unimport, options?: InstallGlobalOptions): Promise<any>;
declare function normalizeScanDirs(dirs: (string | ScanDir)[], options?: ScanDirExportsOptions): Required<ScanDir>[];
declare function scanFilesFromDir(dir: ScanDir | ScanDir[], options?: ScanDirExportsOptions): Promise<string[]>;
declare function scanDirExports(dirs: (string | ScanDir)[], options?: ScanDirExportsOptions): Promise<Import[]>;
declare function dedupeDtsExports(exports: Import[]): Import[];
declare function scanExports(filepath: string, includeTypes: boolean, seen?: Set<string>): Promise<Import[]>;
declare function resolvePreset(preset: Preset): Promise<Import[]>;
declare function resolveBuiltinPresets(presets: (BuiltinPresetName | Preset)[]): Promise<Import[]>;
declare const excludeRE: RegExp[];
declare const importAsRE: RegExp;
declare const separatorRE: RegExp;
/**
* | |
* destructing case&ternary non-call inheritance | id |
* ↓ ↓ ↓ ↓ | |
*/
declare const matchRE: RegExp;
declare function stripCommentsAndStrings(code: string, options?: StripLiteralOptions): string;
declare function defineUnimportPreset(preset: InlinePreset): InlinePreset;
declare function stringifyImports(imports: Import[], isCJS?: boolean): string;
declare function dedupeImports(imports: Import[], warn: (msg: string) => void): Import[];
declare function toExports(imports: Import[], fileDir?: string, includeType?: boolean): string;
declare function stripFileExtension(path: string): string;
declare function toTypeDeclarationItems(imports: Import[], options?: TypeDeclarationOptions): string[];
declare function toTypeDeclarationFile(imports: Import[], options?: TypeDeclarationOptions): string;
declare function toTypeReExports(imports: Import[], options?: TypeDeclarationOptions): string;
declare function getString(code: string | MagicString): string;
declare function getMagicString(code: string | MagicString): MagicString;
declare function addImportToCode(code: string | MagicString, imports: Import[], isCJS?: boolean, mergeExisting?: boolean, injectAtLast?: boolean, firstOccurrence?: number, onResolved?: (imports: Import[]) => void | Import[], onStringified?: (str: string, imports: Import[]) => void | string): MagicStringResult;
declare function normalizeImports(imports: Import[]): Import[];
declare function resolveIdAbsolute(id: string, parentId?: string): string;
/**
* @deprecated renamed to `stringifyImports`
*/
declare const toImports: typeof stringifyImports;
export { BuiltinPresetName, Import, InlinePreset, InstallGlobalOptions, MagicStringResult, Preset, ScanDir, ScanDirExportsOptions, TypeDeclarationOptions, Unimport, UnimportOptions, addImportToCode, createUnimport, dedupeDtsExports, dedupeImports, defineUnimportPreset, excludeRE, getMagicString, getString, importAsRE, installGlobalAutoImports, matchRE, normalizeImports, normalizeScanDirs, resolveBuiltinPresets, resolveIdAbsolute, resolvePreset, scanDirExports, scanExports, scanFilesFromDir, separatorRE, stringifyImports, stripCommentsAndStrings, stripFileExtension, toExports, toImports, toTypeDeclarationFile, toTypeDeclarationItems, toTypeReExports, version };
+39
View File
@@ -0,0 +1,39 @@
export { b as builtinPresets, c as createUnimport, e as dedupeDtsExports, n as normalizeScanDirs, r as resolveBuiltinPresets, a as resolvePreset, d as scanDirExports, f as scanExports, s as scanFilesFromDir, v as version } from './shared/unimport.Ww9aF1N_.mjs';
export { o as addImportToCode, f as dedupeImports, d as defineUnimportPreset, e as excludeRE, n as getMagicString, l as getString, i as importAsRE, m as matchRE, p as normalizeImports, r as resolveIdAbsolute, s as separatorRE, c as stringifyImports, b as stripCommentsAndStrings, g as stripFileExtension, t as toExports, q as toImports, j as toTypeDeclarationFile, h as toTypeDeclarationItems, k as toTypeReExports, a as vueTemplateAddon } from './shared/unimport.0aitavbJ.mjs';
import 'mlly';
import 'node:fs';
import 'node:fs/promises';
import 'node:process';
import 'node:url';
import 'fast-glob';
import 'pathe';
import 'picomatch';
import 'scule';
import 'node:os';
import 'pkg-types';
import 'local-pkg';
import 'node:path';
import 'magic-string';
import 'strip-literal';
async function installGlobalAutoImports(imports, options = {}) {
const {
globalObject = globalThis,
overrides = false
} = options;
imports = Array.isArray(imports) ? imports : await imports.getImports();
await Promise.all(
imports.map(async (i) => {
if (i.disabled || i.type)
return;
const as = i.as || i.name;
if (overrides || !(as in globalObject)) {
const module = await import(i.from);
globalObject[as] = module[i.name];
}
})
);
return globalObject;
}
export { installGlobalAutoImports };
+546
View File
@@ -0,0 +1,546 @@
import { basename } from 'node:path';
import process from 'node:process';
import { isAbsolute, relative, resolve } from 'pathe';
import { camelCase, kebabCase } from 'scule';
import MagicString from 'magic-string';
import { resolvePathSync, findStaticImports, parseStaticImport } from 'mlly';
import { stripLiteral } from 'strip-literal';
const excludeRE = [
// imported/exported from other module
/\b(import|export)\b([\w$*{},\s]+?)\bfrom\s*["']/g,
// defined as function
/\bfunction\s*([\w$]+)\s*\(/g,
// defined as class
/\bclass\s*([\w$]+)\s*\{/g,
// defined as local variable
// eslint-disable-next-line regexp/no-super-linear-backtracking
/\b(?:const|let|var)\s+?(\[.*?\]|\{.*?\}|.+?)\s*?[=;\n]/gs
];
const importAsRE = /^.*\sas\s+/;
const separatorRE = /[,[\]{}\n]|\b(?:import|export)\b/g;
const matchRE = /(^|\.\.\.|(?:\bcase|\?)\s+|[^\w$/)]|\bextends\s+)([\w$]+)\s*(?=[.()[\]}:;?+\-*&|`<>,\n]|\b(?:instanceof|in)\b|$|(?<=extends\s+\w+)\s+\{)/g;
const regexRE = /\/\S*?(?<!\\)(?<!\[[^\]]*)\/[gimsuy]*/g;
function stripCommentsAndStrings(code, options) {
return stripLiteral(code, options).replace(regexRE, 'new RegExp("")');
}
function defineUnimportPreset(preset) {
return preset;
}
const safePropertyName = /^[a-z$_][\w$]*$/i;
function stringifyWith(withValues) {
let withDefs = "";
for (let entries = Object.entries(withValues), l = entries.length, i = 0; i < l; i++) {
const [prop, value] = entries[i];
withDefs += safePropertyName.test(prop) ? prop : JSON.stringify(prop);
withDefs += `: ${JSON.stringify(String(value))}`;
if (i + 1 !== l)
withDefs += ", ";
}
return `{ ${withDefs} }`;
}
function stringifyImports(imports, isCJS = false) {
const map = toImportModuleMap(imports);
return Object.entries(map).flatMap(([name, importSet]) => {
const entries = [];
const imports2 = Array.from(importSet).filter((i) => {
if (!i.name || i.as === "") {
let importStr;
if (isCJS) {
importStr = `require('${name}');`;
} else {
importStr = `import '${name}'`;
if (i.with)
importStr += ` with ${stringifyWith(i.with)}`;
importStr += ";";
}
entries.push(importStr);
return false;
} else if (i.name === "default" || i.name === "=") {
let importStr;
if (isCJS) {
importStr = i.name === "=" ? `const ${i.as} = require('${name}');` : `const { default: ${i.as} } = require('${name}');`;
} else {
importStr = `import ${i.as} from '${name}'`;
if (i.with)
importStr += ` with ${stringifyWith(i.with)}`;
importStr += ";";
}
entries.push(importStr);
return false;
} else if (i.name === "*") {
let importStr;
if (isCJS) {
importStr = `const ${i.as} = require('${name}');`;
} else {
importStr = `import * as ${i.as} from '${name}'`;
if (i.with)
importStr += ` with ${stringifyWith(i.with)}`;
importStr += ";";
}
entries.push(importStr);
return false;
} else if (!isCJS && i.with) {
entries.push(`import { ${stringifyImportAlias(i)} } from '${name}' with ${stringifyWith(i.with)};`);
return false;
}
return true;
});
if (imports2.length) {
const importsAs = imports2.map((i) => stringifyImportAlias(i, isCJS));
entries.push(
isCJS ? `const { ${importsAs.join(", ")} } = require('${name}');` : `import { ${importsAs.join(", ")} } from '${name}';`
);
}
return entries;
}).join("\n");
}
function dedupeImports(imports, warn) {
const map = /* @__PURE__ */ new Map();
const indexToRemove = /* @__PURE__ */ new Set();
imports.filter((i) => !i.disabled).forEach((i, idx) => {
if (i.declarationType === "enum" || i.declarationType === "class")
return;
const name = i.as ?? i.name;
if (!map.has(name)) {
map.set(name, idx);
return;
}
const other = imports[map.get(name)];
if (other.from === i.from) {
indexToRemove.add(idx);
return;
}
const diff = (other.priority || 1) - (i.priority || 1);
if (diff === 0)
warn(`Duplicated imports "${name}", the one from "${other.from}" has been ignored and "${i.from}" is used`);
if (diff <= 0) {
indexToRemove.add(map.get(name));
map.set(name, idx);
} else {
indexToRemove.add(idx);
}
});
return imports.filter((_, idx) => !indexToRemove.has(idx));
}
function toExports(imports, fileDir, includeType = false) {
const map = toImportModuleMap(imports, includeType);
return Object.entries(map).flatMap(([name, imports2]) => {
if (isFilePath(name))
name = name.replace(/\.[a-z]+$/i, "");
if (fileDir && isAbsolute(name)) {
name = relative(fileDir, name);
if (!name.match(/^[./]/))
name = `./${name}`;
}
const entries = [];
const filtered = Array.from(imports2).filter((i) => {
if (i.name === "*") {
entries.push(`export * as ${i.as} from '${name}';`);
return false;
}
return true;
});
if (filtered.length)
entries.push(`export { ${filtered.map((i) => stringifyImportAlias(i, false)).join(", ")} } from '${name}';`);
return entries;
}).join("\n");
}
function stripFileExtension(path) {
return path.replace(/\.[a-z]+$/i, "");
}
function toTypeDeclarationItems(imports, options) {
return imports.map((i) => {
const from = options?.resolvePath?.(i) || stripFileExtension(i.typeFrom || i.from);
let typeDef = "";
if (i.with)
typeDef += `import('${from}', { with: ${stringifyWith(i.with)} })`;
else
typeDef += `import('${from}')`;
if (i.name !== "*" && i.name !== "=")
typeDef += `['${i.name}']`;
return `const ${i.as}: typeof ${typeDef}`;
}).sort();
}
function toTypeDeclarationFile(imports, options) {
const items = toTypeDeclarationItems(imports, options);
const {
exportHelper = true
} = options || {};
let declaration = "";
if (exportHelper)
declaration += "export {}\n";
declaration += `declare global {
${items.map((i) => ` ${i}`).join("\n")}
}`;
return declaration;
}
function makeTypeModulesMap(imports, resolvePath) {
const modulesMap = /* @__PURE__ */ new Map();
const resolveImportFrom = typeof resolvePath === "function" ? (i) => {
return resolvePath(i) || stripFileExtension(i.typeFrom || i.from);
} : (i) => stripFileExtension(i.typeFrom || i.from);
for (const import_ of imports) {
const from = resolveImportFrom(import_);
let module = modulesMap.get(from);
if (!module) {
module = { typeImports: /* @__PURE__ */ new Set(), starTypeImport: undefined };
modulesMap.set(from, module);
}
if (import_.name === "*") {
if (import_.as)
module.starTypeImport = import_;
} else {
module.typeImports.add(import_);
}
}
return modulesMap;
}
function toTypeReExports(imports, options) {
const importsMap = makeTypeModulesMap(imports, options?.resolvePath);
const code = Array.from(importsMap).flatMap(([from, module]) => {
from = from.replace(/\.d\.([cm]?)ts$/i, ".$1js");
const { starTypeImport, typeImports } = module;
const strings = [];
if (typeImports.size) {
const typeImportNames = Array.from(typeImports).map(({ name, as }) => {
if (as && as !== name)
return `${name} as ${as}`;
return name;
});
strings.push(
"// @ts-ignore",
`export type { ${typeImportNames.join(", ")} } from '${from}'`
);
}
if (starTypeImport) {
strings.push(
"// @ts-ignore",
`export type * as ${starTypeImport.as} from '${from}'`
);
}
if (strings.length) {
strings.push(
// This is a workaround for a TypeScript issue where type-only re-exports are not properly initialized.
`import('${from}')`
);
}
return strings;
});
return `// for type re-export
declare global {
${code.map((i) => ` ${i}`).join("\n")}
}`;
}
function stringifyImportAlias(item, isCJS = false) {
return item.as === undefined || item.name === item.as ? item.name : isCJS ? `${item.name}: ${item.as}` : `${item.name} as ${item.as}`;
}
function toImportModuleMap(imports, includeType = false) {
const map = {};
for (const _import of imports) {
if (_import.type && !includeType)
continue;
if (!map[_import.from])
map[_import.from] = /* @__PURE__ */ new Set();
map[_import.from].add(_import);
}
return map;
}
function getString(code) {
if (typeof code === "string")
return code;
return code.toString();
}
function getMagicString(code) {
if (typeof code === "string")
return new MagicString(code);
return code;
}
function addImportToCode(code, imports, isCJS = false, mergeExisting = false, injectAtLast = false, firstOccurrence = Number.POSITIVE_INFINITY, onResolved, onStringified) {
let newImports = [];
const s = getMagicString(code);
let _staticImports;
const strippedCode = stripCommentsAndStrings(s.original);
function findStaticImportsLazy() {
if (!_staticImports) {
_staticImports = findStaticImports(s.original).filter((i) => Boolean(strippedCode.slice(i.start, i.end).trim())).map((i) => parseStaticImport(i));
}
return _staticImports;
}
function hasShebang() {
const shebangRegex = /^#!.+/;
return shebangRegex.test(s.original);
}
if (mergeExisting && !isCJS) {
const existingImports = findStaticImportsLazy();
const map = /* @__PURE__ */ new Map();
imports.forEach((i) => {
const target = existingImports.find((e) => e.specifier === i.from && e.imports.startsWith("{"));
if (!target)
return newImports.push(i);
if (!map.has(target))
map.set(target, []);
map.get(target).push(i);
});
for (const [target, items] of map.entries()) {
const strings = items.map((i) => `${stringifyImportAlias(i)}, `);
const importLength = target.code.match(/^\s*import\s*\{/)?.[0]?.length;
if (importLength)
s.appendLeft(target.start + importLength, ` ${strings.join("").trim()}`);
}
} else {
newImports = imports;
}
newImports = onResolved?.(newImports) ?? newImports;
let newEntries = stringifyImports(newImports, isCJS);
newEntries = onStringified?.(newEntries, newImports) ?? newEntries;
if (newEntries) {
const insertionIndex = injectAtLast ? findStaticImportsLazy().reverse().find((i) => i.end <= firstOccurrence)?.end ?? 0 : 0;
if (insertionIndex > 0)
s.appendRight(insertionIndex, `
${newEntries}
`);
else if (hasShebang())
s.appendLeft(s.original.indexOf("\n") + 1, `
${newEntries}
`);
else
s.prepend(`${newEntries}
`);
}
return {
s,
get code() {
return s.toString();
}
};
}
function normalizeImports(imports) {
for (const _import of imports)
_import.as = _import.as ?? _import.name;
return imports;
}
function resolveIdAbsolute(id, parentId) {
return resolvePathSync(id, {
url: parentId
});
}
function isFilePath(path) {
return path.startsWith(".") || isAbsolute(path) || path.includes("://");
}
const toImports = stringifyImports;
const contextRE$1 = /\b_ctx\.([$\w]+)\b/g;
const UNREF_KEY = "__unimport_unref_";
const VUE_TEMPLATE_NAME = "unimport:vue-template";
function vueTemplateAddon() {
const self = {
name: VUE_TEMPLATE_NAME,
async transform(s, id) {
if (!s.original.includes("_ctx.") || s.original.includes(UNREF_KEY))
return s;
const matches = Array.from(s.original.matchAll(contextRE$1));
const imports = await this.getImports();
let targets = [];
for (const match of matches) {
const name = match[1];
const item = imports.find((i) => i.as === name);
if (!item)
continue;
const start = match.index;
const end = start + match[0].length;
const tempName = `__unimport_${name}`;
s.overwrite(start, end, `(${JSON.stringify(name)} in _ctx ? _ctx.${name} : ${UNREF_KEY}(${tempName}))`);
if (!targets.find((i) => i.as === tempName)) {
targets.push({
...item,
as: tempName
});
}
}
if (targets.length) {
targets.push({
name: "unref",
from: "vue",
as: UNREF_KEY
});
for (const addon of this.addons) {
if (addon === self)
continue;
targets = await addon.injectImportsResolved?.call(this, targets, s, id) ?? targets;
}
let injection = stringifyImports(targets);
for (const addon of this.addons) {
if (addon === self)
continue;
injection = await addon.injectImportsStringified?.call(this, injection, targets, s, id) ?? injection;
}
s.prepend(injection);
}
return s;
},
async declaration(dts, options) {
const imports = await this.getImports();
const items = imports.map((i) => {
if (i.type || i.dtsDisabled)
return "";
const from = options?.resolvePath?.(i) || i.from;
return `readonly ${i.as}: UnwrapRef<typeof import('${from}')${i.name !== "*" ? `['${i.name}']` : ""}>`;
}).filter(Boolean).sort();
const extendItems = items.map((i) => ` ${i}`).join("\n");
return `${dts}
// for vue template auto import
import { UnwrapRef } from 'vue'
declare module 'vue' {
interface ComponentCustomProperties {
${extendItems}
}
}`;
}
};
return self;
}
const contextRE = /resolveDirective as _resolveDirective/;
const contextText = `${contextRE.source}, `;
const directiveRE = /(?:var|const) (\w+) = _resolveDirective\("([\w.-]+)"\);?\s*/g;
const VUE_DIRECTIVES_NAME = "unimport:vue-directives";
function vueDirectivesAddon(options = {}) {
function isDirective(importEntry) {
let isDirective2 = importEntry.meta?.vueDirective === true;
if (isDirective2) {
return true;
}
isDirective2 = options.isDirective?.(normalizePath(process.cwd(), importEntry.from), importEntry) ?? false;
if (isDirective2) {
importEntry.meta ??= {};
importEntry.meta.vueDirective = true;
}
return isDirective2;
}
const self = {
name: VUE_DIRECTIVES_NAME,
async transform(s, id) {
if (!s.original.match(contextRE))
return s;
const matches = Array.from(s.original.matchAll(directiveRE)).sort((a, b) => b.index - a.index);
if (!matches.length)
return s;
let targets = [];
for await (const [
begin,
end,
importEntry
] of findDirectives(
isDirective,
matches,
this.getImports()
)) {
s.overwrite(begin, end, "");
targets.push(importEntry);
}
if (!targets.length)
return s;
s.replace(contextText, "");
for (const addon of this.addons) {
if (addon === self)
continue;
targets = await addon.injectImportsResolved?.call(this, targets, s, id) ?? targets;
}
let injection = stringifyImports(targets);
for (const addon of this.addons) {
if (addon === self)
continue;
injection = await addon.injectImportsStringified?.call(this, injection, targets, s, id) ?? injection;
}
s.prepend(injection);
return s;
},
async declaration(dts, options2) {
const directivesMap = await this.getImports().then((imports) => {
return imports.filter(isDirective).reduce((acc, i) => {
if (i.type || i.dtsDisabled)
return acc;
let name;
if (i.name === "default" && (i.as === "default" || !i.as)) {
const file = basename(i.from);
const idx = file.indexOf(".");
name = idx > -1 ? file.slice(0, idx) : file;
} else {
name = i.as ?? i.name;
}
name = name[0] === "v" ? camelCase(name) : camelCase(`v-${name}`);
if (!acc.has(name)) {
acc.set(name, i);
}
return acc;
}, /* @__PURE__ */ new Map());
});
if (!directivesMap.size)
return dts;
const directives = Array.from(directivesMap.entries()).map(([name, i]) => ` ${name}: typeof import('${options2?.resolvePath?.(i) || i.from}')['${i.name}']`).sort().join("\n");
return `${dts}
// for vue directives auto import
declare module 'vue' {
interface ComponentCustomProperties {
${directives}
}
interface GlobalDirectives {
${directives}
}
}`;
}
};
return self;
}
function resolvePath(cwd, path) {
return path[0] === "." ? resolve(cwd, path) : path;
}
function normalizePath(cwd, path) {
return resolvePath(cwd, path).replace(/\\/g, "/");
}
async function* findDirectives(isDirective, regexArray, importsPromise) {
const imports = (await importsPromise).filter(isDirective);
if (!imports.length)
return;
const symbols = regexArray.reduce((acc, regex) => {
const [all, symbol, resolveDirectiveName] = regex;
if (acc.has(symbol))
return acc;
acc.set(symbol, [
regex.index,
regex.index + all.length,
kebabCase(resolveDirectiveName)
]);
return acc;
}, /* @__PURE__ */ new Map());
for (const [symbol, data] of symbols.entries()) {
yield* findDirective(imports, symbol, data);
}
}
function* findDirective(imports, symbol, [begin, end, importName]) {
let resolvedName;
for (const i of imports) {
if (i.name === "default" && (i.as === "default" || !i.as)) {
const file = basename(i.from);
const idx = file.indexOf(".");
resolvedName = kebabCase(idx > -1 ? file.slice(0, idx) : file);
} else {
resolvedName = kebabCase(i.as ?? i.name);
}
if (resolvedName[0] === "v") {
resolvedName = resolvedName.slice(resolvedName[1] === "-" ? 2 : 1);
}
if (resolvedName === importName) {
yield [
begin,
end,
{ ...i, name: i.name, as: symbol }
];
return;
}
}
}
export { VUE_TEMPLATE_NAME as V, vueTemplateAddon as a, stripCommentsAndStrings as b, stringifyImports as c, defineUnimportPreset as d, excludeRE as e, dedupeImports as f, stripFileExtension as g, toTypeDeclarationItems as h, importAsRE as i, toTypeDeclarationFile as j, toTypeReExports as k, getString as l, matchRE as m, getMagicString as n, addImportToCode as o, normalizeImports as p, toImports as q, resolveIdAbsolute as r, separatorRE as s, toExports as t, VUE_DIRECTIVES_NAME as u, vueDirectivesAddon as v };
+5
View File
@@ -0,0 +1,5 @@
import { r as Addon } from './unimport.CaVRR9SH.js';
declare function vueTemplateAddon(): Addon;
export { vueTemplateAddon as v };
+400
View File
@@ -0,0 +1,400 @@
import MagicString from 'magic-string';
import { ESMExport } from 'mlly';
declare const builtinPresets: {
'@vue/composition-api': InlinePreset;
'@vueuse/core': () => Preset;
'@vueuse/head': InlinePreset;
pinia: InlinePreset;
preact: InlinePreset;
quasar: InlinePreset;
react: InlinePreset;
'react-router': InlinePreset;
'react-router-dom': InlinePreset;
svelte: InlinePreset;
'svelte/animate': InlinePreset;
'svelte/easing': InlinePreset;
'svelte/motion': InlinePreset;
'svelte/store': InlinePreset;
'svelte/transition': InlinePreset;
'vee-validate': InlinePreset;
vitepress: InlinePreset;
'vue-demi': InlinePreset;
'vue-i18n': InlinePreset;
'vue-router': InlinePreset;
'vue-router-composables': InlinePreset;
vue: InlinePreset;
'vue/macros': InlinePreset;
vuex: InlinePreset;
vitest: InlinePreset;
'uni-app': InlinePreset;
'solid-js': InlinePreset;
'solid-app-router': InlinePreset;
rxjs: InlinePreset;
'date-fns': InlinePreset;
};
type BuiltinPresetName = keyof typeof builtinPresets;
type ModuleId = string;
type ImportName = string;
interface ImportCommon {
/** Module specifier to import from */
from: ModuleId;
/**
* Priority of the import, if multiple imports have the same name, the one with the highest priority will be used
* @default 1
*/
priority?: number;
/** If this import is disabled */
disabled?: boolean;
/** Won't output import in declaration file if true */
dtsDisabled?: boolean;
/** Import declaration type like const / var / enum */
declarationType?: ESMExport['declarationType'];
/**
* Metadata of the import
*/
meta?: {
/** Short description of the import */
description?: string;
/** URL to the documentation */
docsUrl?: string;
/** Additional metadata */
[key: string]: any;
};
/**
* If this import is a pure type import
*/
type?: boolean;
/**
* Using this as the from when generating type declarations
*/
typeFrom?: ModuleId;
}
interface Import extends ImportCommon {
/** Import name to be detected */
name: ImportName;
/** Import as this name */
as?: ImportName;
/**
* With properties
*
* Ignored for CJS imports.
*/
with?: Record<string, string>;
}
type PresetImport = Omit<Import, 'from'> | ImportName | [name: ImportName, as?: ImportName, from?: ModuleId];
interface InlinePreset extends ImportCommon {
imports: (PresetImport | InlinePreset)[];
}
/**
* Auto extract exports from a package for auto import
*/
interface PackagePreset {
/**
* Name of the package
*/
package: string;
/**
* Path of the importer
* @default process.cwd()
*/
url?: string;
/**
* RegExp, string, or custom function to exclude names of the extracted imports
*/
ignore?: (string | RegExp | ((name: string) => boolean))[];
/**
* Use local cache if exits
* @default true
*/
cache?: boolean;
}
type Preset = InlinePreset | PackagePreset;
interface UnimportContext {
readonly version: string;
options: Partial<UnimportOptions>;
staticImports: Import[];
dynamicImports: Import[];
addons: Addon[];
getImports: () => Promise<Import[]>;
getImportMap: () => Promise<Map<string, Import>>;
getMetadata: () => UnimportMeta | undefined;
modifyDynamicImports: (fn: (imports: Import[]) => Thenable<void | Import[]>) => Promise<void>;
clearDynamicImports: () => void;
replaceImports: (imports: UnimportOptions['imports']) => Promise<Import[]>;
invalidate: () => void;
resolveId: (id: string, parentId?: string) => Thenable<string | null | undefined | void>;
}
interface DetectImportResult {
s: MagicString;
strippedCode: string;
isCJSContext: boolean;
matchedImports: Import[];
firstOccurrence: number;
}
interface Unimport {
readonly version: string;
init: () => Promise<void>;
clearDynamicImports: UnimportContext['clearDynamicImports'];
getImportMap: UnimportContext['getImportMap'];
getImports: UnimportContext['getImports'];
getInternalContext: () => UnimportContext;
getMetadata: UnimportContext['getMetadata'];
modifyDynamicImports: UnimportContext['modifyDynamicImports'];
generateTypeDeclarations: (options?: TypeDeclarationOptions) => Promise<string>;
/**
* Get un-imported usages from code
*/
detectImports: (code: string | MagicString) => Promise<DetectImportResult>;
/**
* Insert missing imports statements to code
*/
injectImports: (code: string | MagicString, id?: string, options?: InjectImportsOptions) => Promise<ImportInjectionResult>;
scanImportsFromDir: (dir?: (string | ScanDir)[], options?: ScanDirExportsOptions) => Promise<Import[]>;
scanImportsFromFile: (file: string, includeTypes?: boolean) => Promise<Import[]>;
/**
* @deprecated
*/
toExports: (filepath?: string, includeTypes?: boolean) => Promise<string>;
}
interface InjectionUsageRecord {
import: Import;
count: number;
moduleIds: string[];
}
interface UnimportMeta {
injectionUsage: Record<string, InjectionUsageRecord>;
}
interface AddonsOptions {
addons?: Addon[];
/**
* Enable auto import inside for Vue's <template>
*
* @default false
*/
vueTemplate?: boolean;
/**
* Enable auto import directives for Vue's SFC.
*
* Library authors should include `meta.vueDirective: true` in the import metadata.
*
* When using a local directives folder, provide the `isDirective`
* callback to check if the import is a Vue directive.
*/
vueDirectives?: true | AddonVueDirectivesOptions;
}
interface AddonVueDirectivesOptions {
/**
* Checks if the import is a Vue directive.
*
* **NOTES**:
* - imports from a library should include `meta.vueDirective: true`.
* - this callback is only invoked for local directives (only when meta.vueDirective is not set).
*
* @param from The path of the import normalized.
* @param importEntry The import entry.
*/
isDirective?: (from: string, importEntry: Import) => boolean;
}
interface UnimportOptions extends Pick<InjectImportsOptions, 'injectAtEnd' | 'mergeExisting' | 'parser'> {
/**
* Auto import items
*/
imports: Import[];
/**
* Auto import preset
*/
presets: (Preset | BuiltinPresetName)[];
/**
* Custom warning function
* @default console.warn
*/
warn: (msg: string) => void;
/**
* Custom debug log function
* @default console.log
*/
debugLog: (msg: string) => void;
/**
* Unimport Addons.
* To use built-in addons, use:
* ```js
* addons: {
* addons: [<custom-addons-here>] // if you want to use also custom addons
* vueTemplate: true,
* vueDirectives: [<the-directives-here>]
* }
* ```
*
* Built-in addons:
* - vueDirectives: enable auto import directives for Vue's SFC
* - vueTemplate: enable auto import inside for Vue's <template>
*
* @default {}
*/
addons: AddonsOptions | Addon[];
/**
* Name of virtual modules that exposed all the registed auto-imports
* @default []
*/
virtualImports: string[];
/**
* Directories to scan for auto import
* @default []
*/
dirs?: (string | ScanDir)[];
/**
* Options for scanning directories for auto import
*/
dirsScanOptions?: ScanDirExportsOptions;
/**
* Custom resolver to auto import id
*/
resolveId?: (id: string, importee?: string) => Thenable<string | void>;
/**
* Custom magic comments to be opt-out for auto import, per file/module
*
* @default ['@unimport-disable', '@imports-disable']
*/
commentsDisable?: string[];
/**
* Custom magic comments to debug auto import, printed to console
*
* @default ['@unimport-debug', '@imports-debug']
*/
commentsDebug?: string[];
/**
* Collect meta data for each auto import. Accessible via `ctx.meta`
*/
collectMeta?: boolean;
}
type PathFromResolver = (_import: Import) => string | undefined;
interface ScanDirExportsOptions {
/**
* Glob patterns for matching files
*
* @default ['*.{ts,js,mjs,cjs,mts,cts}']
*/
filePatterns?: string[];
/**
* Custom function to filter scanned files
*/
fileFilter?: (file: string) => boolean;
/**
* Register type exports
*
* @default true
*/
types?: boolean;
/**
* Current working directory
*
* @default process.cwd()
*/
cwd?: string;
}
interface ScanDir {
/**
* Path pattern of the directory
*/
glob: string;
/**
* Register type exports
*
* @default true
*/
types?: boolean;
}
interface TypeDeclarationOptions {
/**
* Custom resolver for path of the import
*/
resolvePath?: PathFromResolver;
/**
* Append `export {}` to the end of the file
*
* @default true
*/
exportHelper?: boolean;
/**
* Auto-import for type exports
*
* @default true
*/
typeReExports?: boolean;
}
interface InjectImportsOptions {
/**
* Merge the existing imports
*
* @default false
*/
mergeExisting?: boolean;
/**
* If the module should be auto imported
*
* @default true
*/
autoImport?: boolean;
/**
* If the module should be transformed for virtual modules.
* Only available when `virtualImports` is set.
*
* @default true
*/
transformVirtualImports?: boolean;
/**
* Parser to use for parsing the code
*
* Note that `acorn` only takes valid JS Code, should usually only be used after transformationa and transpilation
*
* @default 'regex'
*/
parser?: 'acorn' | 'regex';
/**
* Inject the imports at the end of other imports
*
* @default false
*/
injectAtEnd?: boolean;
}
type Thenable<T> = Promise<T> | T;
interface Addon {
name?: string;
transform?: (this: UnimportContext, code: MagicString, id: string | undefined) => Thenable<MagicString>;
declaration?: (this: UnimportContext, dts: string, options: TypeDeclarationOptions) => Thenable<string>;
matchImports?: (this: UnimportContext, identifiers: Set<string>, matched: Import[]) => Thenable<Import[] | void>;
/**
* Extend or modify the imports list before injecting
*/
extendImports?: (this: UnimportContext, imports: Import[]) => Import[] | void;
/**
* Resolve imports before injecting
*/
injectImportsResolved?: (this: UnimportContext, imports: Import[], code: MagicString, id?: string) => Import[] | void;
/**
* Modify the injection code before injecting
*/
injectImportsStringified?: (this: UnimportContext, injection: string, imports: Import[], code: MagicString, id?: string) => string | void;
}
interface InstallGlobalOptions {
/**
* @default globalThis
*/
globalObject?: any;
/**
* Overrides the existing property
* @default false
*/
overrides?: boolean;
}
interface MagicStringResult {
s: MagicString;
code: string;
}
interface ImportInjectionResult extends MagicStringResult {
imports: Import[];
}
export { type AddonsOptions as A, type BuiltinPresetName as B, type DetectImportResult as D, type Import as I, type MagicStringResult as M, type Preset as P, type ScanDir as S, type TypeDeclarationOptions as T, type UnimportOptions as U, type Unimport as a, type InstallGlobalOptions as b, type ScanDirExportsOptions as c, type InlinePreset as d, builtinPresets as e, type ModuleId as f, type ImportName as g, type ImportCommon as h, type PresetImport as i, type PackagePreset as j, type UnimportContext as k, type InjectionUsageRecord as l, type UnimportMeta as m, type AddonVueDirectivesOptions as n, type PathFromResolver as o, type InjectImportsOptions as p, type Thenable as q, type Addon as r, type ImportInjectionResult as s };
+400
View File
@@ -0,0 +1,400 @@
import MagicString from 'magic-string';
import { ESMExport } from 'mlly';
declare const builtinPresets: {
'@vue/composition-api': InlinePreset;
'@vueuse/core': () => Preset;
'@vueuse/head': InlinePreset;
pinia: InlinePreset;
preact: InlinePreset;
quasar: InlinePreset;
react: InlinePreset;
'react-router': InlinePreset;
'react-router-dom': InlinePreset;
svelte: InlinePreset;
'svelte/animate': InlinePreset;
'svelte/easing': InlinePreset;
'svelte/motion': InlinePreset;
'svelte/store': InlinePreset;
'svelte/transition': InlinePreset;
'vee-validate': InlinePreset;
vitepress: InlinePreset;
'vue-demi': InlinePreset;
'vue-i18n': InlinePreset;
'vue-router': InlinePreset;
'vue-router-composables': InlinePreset;
vue: InlinePreset;
'vue/macros': InlinePreset;
vuex: InlinePreset;
vitest: InlinePreset;
'uni-app': InlinePreset;
'solid-js': InlinePreset;
'solid-app-router': InlinePreset;
rxjs: InlinePreset;
'date-fns': InlinePreset;
};
type BuiltinPresetName = keyof typeof builtinPresets;
type ModuleId = string;
type ImportName = string;
interface ImportCommon {
/** Module specifier to import from */
from: ModuleId;
/**
* Priority of the import, if multiple imports have the same name, the one with the highest priority will be used
* @default 1
*/
priority?: number;
/** If this import is disabled */
disabled?: boolean;
/** Won't output import in declaration file if true */
dtsDisabled?: boolean;
/** Import declaration type like const / var / enum */
declarationType?: ESMExport['declarationType'];
/**
* Metadata of the import
*/
meta?: {
/** Short description of the import */
description?: string;
/** URL to the documentation */
docsUrl?: string;
/** Additional metadata */
[key: string]: any;
};
/**
* If this import is a pure type import
*/
type?: boolean;
/**
* Using this as the from when generating type declarations
*/
typeFrom?: ModuleId;
}
interface Import extends ImportCommon {
/** Import name to be detected */
name: ImportName;
/** Import as this name */
as?: ImportName;
/**
* With properties
*
* Ignored for CJS imports.
*/
with?: Record<string, string>;
}
type PresetImport = Omit<Import, 'from'> | ImportName | [name: ImportName, as?: ImportName, from?: ModuleId];
interface InlinePreset extends ImportCommon {
imports: (PresetImport | InlinePreset)[];
}
/**
* Auto extract exports from a package for auto import
*/
interface PackagePreset {
/**
* Name of the package
*/
package: string;
/**
* Path of the importer
* @default process.cwd()
*/
url?: string;
/**
* RegExp, string, or custom function to exclude names of the extracted imports
*/
ignore?: (string | RegExp | ((name: string) => boolean))[];
/**
* Use local cache if exits
* @default true
*/
cache?: boolean;
}
type Preset = InlinePreset | PackagePreset;
interface UnimportContext {
readonly version: string;
options: Partial<UnimportOptions>;
staticImports: Import[];
dynamicImports: Import[];
addons: Addon[];
getImports: () => Promise<Import[]>;
getImportMap: () => Promise<Map<string, Import>>;
getMetadata: () => UnimportMeta | undefined;
modifyDynamicImports: (fn: (imports: Import[]) => Thenable<void | Import[]>) => Promise<void>;
clearDynamicImports: () => void;
replaceImports: (imports: UnimportOptions['imports']) => Promise<Import[]>;
invalidate: () => void;
resolveId: (id: string, parentId?: string) => Thenable<string | null | undefined | void>;
}
interface DetectImportResult {
s: MagicString;
strippedCode: string;
isCJSContext: boolean;
matchedImports: Import[];
firstOccurrence: number;
}
interface Unimport {
readonly version: string;
init: () => Promise<void>;
clearDynamicImports: UnimportContext['clearDynamicImports'];
getImportMap: UnimportContext['getImportMap'];
getImports: UnimportContext['getImports'];
getInternalContext: () => UnimportContext;
getMetadata: UnimportContext['getMetadata'];
modifyDynamicImports: UnimportContext['modifyDynamicImports'];
generateTypeDeclarations: (options?: TypeDeclarationOptions) => Promise<string>;
/**
* Get un-imported usages from code
*/
detectImports: (code: string | MagicString) => Promise<DetectImportResult>;
/**
* Insert missing imports statements to code
*/
injectImports: (code: string | MagicString, id?: string, options?: InjectImportsOptions) => Promise<ImportInjectionResult>;
scanImportsFromDir: (dir?: (string | ScanDir)[], options?: ScanDirExportsOptions) => Promise<Import[]>;
scanImportsFromFile: (file: string, includeTypes?: boolean) => Promise<Import[]>;
/**
* @deprecated
*/
toExports: (filepath?: string, includeTypes?: boolean) => Promise<string>;
}
interface InjectionUsageRecord {
import: Import;
count: number;
moduleIds: string[];
}
interface UnimportMeta {
injectionUsage: Record<string, InjectionUsageRecord>;
}
interface AddonsOptions {
addons?: Addon[];
/**
* Enable auto import inside for Vue's <template>
*
* @default false
*/
vueTemplate?: boolean;
/**
* Enable auto import directives for Vue's SFC.
*
* Library authors should include `meta.vueDirective: true` in the import metadata.
*
* When using a local directives folder, provide the `isDirective`
* callback to check if the import is a Vue directive.
*/
vueDirectives?: true | AddonVueDirectivesOptions;
}
interface AddonVueDirectivesOptions {
/**
* Checks if the import is a Vue directive.
*
* **NOTES**:
* - imports from a library should include `meta.vueDirective: true`.
* - this callback is only invoked for local directives (only when meta.vueDirective is not set).
*
* @param from The path of the import normalized.
* @param importEntry The import entry.
*/
isDirective?: (from: string, importEntry: Import) => boolean;
}
interface UnimportOptions extends Pick<InjectImportsOptions, 'injectAtEnd' | 'mergeExisting' | 'parser'> {
/**
* Auto import items
*/
imports: Import[];
/**
* Auto import preset
*/
presets: (Preset | BuiltinPresetName)[];
/**
* Custom warning function
* @default console.warn
*/
warn: (msg: string) => void;
/**
* Custom debug log function
* @default console.log
*/
debugLog: (msg: string) => void;
/**
* Unimport Addons.
* To use built-in addons, use:
* ```js
* addons: {
* addons: [<custom-addons-here>] // if you want to use also custom addons
* vueTemplate: true,
* vueDirectives: [<the-directives-here>]
* }
* ```
*
* Built-in addons:
* - vueDirectives: enable auto import directives for Vue's SFC
* - vueTemplate: enable auto import inside for Vue's <template>
*
* @default {}
*/
addons: AddonsOptions | Addon[];
/**
* Name of virtual modules that exposed all the registed auto-imports
* @default []
*/
virtualImports: string[];
/**
* Directories to scan for auto import
* @default []
*/
dirs?: (string | ScanDir)[];
/**
* Options for scanning directories for auto import
*/
dirsScanOptions?: ScanDirExportsOptions;
/**
* Custom resolver to auto import id
*/
resolveId?: (id: string, importee?: string) => Thenable<string | void>;
/**
* Custom magic comments to be opt-out for auto import, per file/module
*
* @default ['@unimport-disable', '@imports-disable']
*/
commentsDisable?: string[];
/**
* Custom magic comments to debug auto import, printed to console
*
* @default ['@unimport-debug', '@imports-debug']
*/
commentsDebug?: string[];
/**
* Collect meta data for each auto import. Accessible via `ctx.meta`
*/
collectMeta?: boolean;
}
type PathFromResolver = (_import: Import) => string | undefined;
interface ScanDirExportsOptions {
/**
* Glob patterns for matching files
*
* @default ['*.{ts,js,mjs,cjs,mts,cts}']
*/
filePatterns?: string[];
/**
* Custom function to filter scanned files
*/
fileFilter?: (file: string) => boolean;
/**
* Register type exports
*
* @default true
*/
types?: boolean;
/**
* Current working directory
*
* @default process.cwd()
*/
cwd?: string;
}
interface ScanDir {
/**
* Path pattern of the directory
*/
glob: string;
/**
* Register type exports
*
* @default true
*/
types?: boolean;
}
interface TypeDeclarationOptions {
/**
* Custom resolver for path of the import
*/
resolvePath?: PathFromResolver;
/**
* Append `export {}` to the end of the file
*
* @default true
*/
exportHelper?: boolean;
/**
* Auto-import for type exports
*
* @default true
*/
typeReExports?: boolean;
}
interface InjectImportsOptions {
/**
* Merge the existing imports
*
* @default false
*/
mergeExisting?: boolean;
/**
* If the module should be auto imported
*
* @default true
*/
autoImport?: boolean;
/**
* If the module should be transformed for virtual modules.
* Only available when `virtualImports` is set.
*
* @default true
*/
transformVirtualImports?: boolean;
/**
* Parser to use for parsing the code
*
* Note that `acorn` only takes valid JS Code, should usually only be used after transformationa and transpilation
*
* @default 'regex'
*/
parser?: 'acorn' | 'regex';
/**
* Inject the imports at the end of other imports
*
* @default false
*/
injectAtEnd?: boolean;
}
type Thenable<T> = Promise<T> | T;
interface Addon {
name?: string;
transform?: (this: UnimportContext, code: MagicString, id: string | undefined) => Thenable<MagicString>;
declaration?: (this: UnimportContext, dts: string, options: TypeDeclarationOptions) => Thenable<string>;
matchImports?: (this: UnimportContext, identifiers: Set<string>, matched: Import[]) => Thenable<Import[] | void>;
/**
* Extend or modify the imports list before injecting
*/
extendImports?: (this: UnimportContext, imports: Import[]) => Import[] | void;
/**
* Resolve imports before injecting
*/
injectImportsResolved?: (this: UnimportContext, imports: Import[], code: MagicString, id?: string) => Import[] | void;
/**
* Modify the injection code before injecting
*/
injectImportsStringified?: (this: UnimportContext, injection: string, imports: Import[], code: MagicString, id?: string) => string | void;
}
interface InstallGlobalOptions {
/**
* @default globalThis
*/
globalObject?: any;
/**
* Overrides the existing property
* @default false
*/
overrides?: boolean;
}
interface MagicStringResult {
s: MagicString;
code: string;
}
interface ImportInjectionResult extends MagicStringResult {
imports: Import[];
}
export { type AddonsOptions as A, type BuiltinPresetName as B, type DetectImportResult as D, type Import as I, type MagicStringResult as M, type Preset as P, type ScanDir as S, type TypeDeclarationOptions as T, type UnimportOptions as U, type Unimport as a, type InstallGlobalOptions as b, type ScanDirExportsOptions as c, type InlinePreset as d, builtinPresets as e, type ModuleId as f, type ImportName as g, type ImportCommon as h, type PresetImport as i, type PackagePreset as j, type UnimportContext as k, type InjectionUsageRecord as l, type UnimportMeta as m, type AddonVueDirectivesOptions as n, type PathFromResolver as o, type InjectImportsOptions as p, type Thenable as q, type Addon as r, type ImportInjectionResult as s };
+400
View File
@@ -0,0 +1,400 @@
import MagicString from 'magic-string';
import { ESMExport } from 'mlly';
declare const builtinPresets: {
'@vue/composition-api': InlinePreset;
'@vueuse/core': () => Preset;
'@vueuse/head': InlinePreset;
pinia: InlinePreset;
preact: InlinePreset;
quasar: InlinePreset;
react: InlinePreset;
'react-router': InlinePreset;
'react-router-dom': InlinePreset;
svelte: InlinePreset;
'svelte/animate': InlinePreset;
'svelte/easing': InlinePreset;
'svelte/motion': InlinePreset;
'svelte/store': InlinePreset;
'svelte/transition': InlinePreset;
'vee-validate': InlinePreset;
vitepress: InlinePreset;
'vue-demi': InlinePreset;
'vue-i18n': InlinePreset;
'vue-router': InlinePreset;
'vue-router-composables': InlinePreset;
vue: InlinePreset;
'vue/macros': InlinePreset;
vuex: InlinePreset;
vitest: InlinePreset;
'uni-app': InlinePreset;
'solid-js': InlinePreset;
'solid-app-router': InlinePreset;
rxjs: InlinePreset;
'date-fns': InlinePreset;
};
type BuiltinPresetName = keyof typeof builtinPresets;
type ModuleId = string;
type ImportName = string;
interface ImportCommon {
/** Module specifier to import from */
from: ModuleId;
/**
* Priority of the import, if multiple imports have the same name, the one with the highest priority will be used
* @default 1
*/
priority?: number;
/** If this import is disabled */
disabled?: boolean;
/** Won't output import in declaration file if true */
dtsDisabled?: boolean;
/** Import declaration type like const / var / enum */
declarationType?: ESMExport['declarationType'];
/**
* Metadata of the import
*/
meta?: {
/** Short description of the import */
description?: string;
/** URL to the documentation */
docsUrl?: string;
/** Additional metadata */
[key: string]: any;
};
/**
* If this import is a pure type import
*/
type?: boolean;
/**
* Using this as the from when generating type declarations
*/
typeFrom?: ModuleId;
}
interface Import extends ImportCommon {
/** Import name to be detected */
name: ImportName;
/** Import as this name */
as?: ImportName;
/**
* With properties
*
* Ignored for CJS imports.
*/
with?: Record<string, string>;
}
type PresetImport = Omit<Import, 'from'> | ImportName | [name: ImportName, as?: ImportName, from?: ModuleId];
interface InlinePreset extends ImportCommon {
imports: (PresetImport | InlinePreset)[];
}
/**
* Auto extract exports from a package for auto import
*/
interface PackagePreset {
/**
* Name of the package
*/
package: string;
/**
* Path of the importer
* @default process.cwd()
*/
url?: string;
/**
* RegExp, string, or custom function to exclude names of the extracted imports
*/
ignore?: (string | RegExp | ((name: string) => boolean))[];
/**
* Use local cache if exits
* @default true
*/
cache?: boolean;
}
type Preset = InlinePreset | PackagePreset;
interface UnimportContext {
readonly version: string;
options: Partial<UnimportOptions>;
staticImports: Import[];
dynamicImports: Import[];
addons: Addon[];
getImports: () => Promise<Import[]>;
getImportMap: () => Promise<Map<string, Import>>;
getMetadata: () => UnimportMeta | undefined;
modifyDynamicImports: (fn: (imports: Import[]) => Thenable<void | Import[]>) => Promise<void>;
clearDynamicImports: () => void;
replaceImports: (imports: UnimportOptions['imports']) => Promise<Import[]>;
invalidate: () => void;
resolveId: (id: string, parentId?: string) => Thenable<string | null | undefined | void>;
}
interface DetectImportResult {
s: MagicString;
strippedCode: string;
isCJSContext: boolean;
matchedImports: Import[];
firstOccurrence: number;
}
interface Unimport {
readonly version: string;
init: () => Promise<void>;
clearDynamicImports: UnimportContext['clearDynamicImports'];
getImportMap: UnimportContext['getImportMap'];
getImports: UnimportContext['getImports'];
getInternalContext: () => UnimportContext;
getMetadata: UnimportContext['getMetadata'];
modifyDynamicImports: UnimportContext['modifyDynamicImports'];
generateTypeDeclarations: (options?: TypeDeclarationOptions) => Promise<string>;
/**
* Get un-imported usages from code
*/
detectImports: (code: string | MagicString) => Promise<DetectImportResult>;
/**
* Insert missing imports statements to code
*/
injectImports: (code: string | MagicString, id?: string, options?: InjectImportsOptions) => Promise<ImportInjectionResult>;
scanImportsFromDir: (dir?: (string | ScanDir)[], options?: ScanDirExportsOptions) => Promise<Import[]>;
scanImportsFromFile: (file: string, includeTypes?: boolean) => Promise<Import[]>;
/**
* @deprecated
*/
toExports: (filepath?: string, includeTypes?: boolean) => Promise<string>;
}
interface InjectionUsageRecord {
import: Import;
count: number;
moduleIds: string[];
}
interface UnimportMeta {
injectionUsage: Record<string, InjectionUsageRecord>;
}
interface AddonsOptions {
addons?: Addon[];
/**
* Enable auto import inside for Vue's <template>
*
* @default false
*/
vueTemplate?: boolean;
/**
* Enable auto import directives for Vue's SFC.
*
* Library authors should include `meta.vueDirective: true` in the import metadata.
*
* When using a local directives folder, provide the `isDirective`
* callback to check if the import is a Vue directive.
*/
vueDirectives?: true | AddonVueDirectivesOptions;
}
interface AddonVueDirectivesOptions {
/**
* Checks if the import is a Vue directive.
*
* **NOTES**:
* - imports from a library should include `meta.vueDirective: true`.
* - this callback is only invoked for local directives (only when meta.vueDirective is not set).
*
* @param from The path of the import normalized.
* @param importEntry The import entry.
*/
isDirective?: (from: string, importEntry: Import) => boolean;
}
interface UnimportOptions extends Pick<InjectImportsOptions, 'injectAtEnd' | 'mergeExisting' | 'parser'> {
/**
* Auto import items
*/
imports: Import[];
/**
* Auto import preset
*/
presets: (Preset | BuiltinPresetName)[];
/**
* Custom warning function
* @default console.warn
*/
warn: (msg: string) => void;
/**
* Custom debug log function
* @default console.log
*/
debugLog: (msg: string) => void;
/**
* Unimport Addons.
* To use built-in addons, use:
* ```js
* addons: {
* addons: [<custom-addons-here>] // if you want to use also custom addons
* vueTemplate: true,
* vueDirectives: [<the-directives-here>]
* }
* ```
*
* Built-in addons:
* - vueDirectives: enable auto import directives for Vue's SFC
* - vueTemplate: enable auto import inside for Vue's <template>
*
* @default {}
*/
addons: AddonsOptions | Addon[];
/**
* Name of virtual modules that exposed all the registed auto-imports
* @default []
*/
virtualImports: string[];
/**
* Directories to scan for auto import
* @default []
*/
dirs?: (string | ScanDir)[];
/**
* Options for scanning directories for auto import
*/
dirsScanOptions?: ScanDirExportsOptions;
/**
* Custom resolver to auto import id
*/
resolveId?: (id: string, importee?: string) => Thenable<string | void>;
/**
* Custom magic comments to be opt-out for auto import, per file/module
*
* @default ['@unimport-disable', '@imports-disable']
*/
commentsDisable?: string[];
/**
* Custom magic comments to debug auto import, printed to console
*
* @default ['@unimport-debug', '@imports-debug']
*/
commentsDebug?: string[];
/**
* Collect meta data for each auto import. Accessible via `ctx.meta`
*/
collectMeta?: boolean;
}
type PathFromResolver = (_import: Import) => string | undefined;
interface ScanDirExportsOptions {
/**
* Glob patterns for matching files
*
* @default ['*.{ts,js,mjs,cjs,mts,cts}']
*/
filePatterns?: string[];
/**
* Custom function to filter scanned files
*/
fileFilter?: (file: string) => boolean;
/**
* Register type exports
*
* @default true
*/
types?: boolean;
/**
* Current working directory
*
* @default process.cwd()
*/
cwd?: string;
}
interface ScanDir {
/**
* Path pattern of the directory
*/
glob: string;
/**
* Register type exports
*
* @default true
*/
types?: boolean;
}
interface TypeDeclarationOptions {
/**
* Custom resolver for path of the import
*/
resolvePath?: PathFromResolver;
/**
* Append `export {}` to the end of the file
*
* @default true
*/
exportHelper?: boolean;
/**
* Auto-import for type exports
*
* @default true
*/
typeReExports?: boolean;
}
interface InjectImportsOptions {
/**
* Merge the existing imports
*
* @default false
*/
mergeExisting?: boolean;
/**
* If the module should be auto imported
*
* @default true
*/
autoImport?: boolean;
/**
* If the module should be transformed for virtual modules.
* Only available when `virtualImports` is set.
*
* @default true
*/
transformVirtualImports?: boolean;
/**
* Parser to use for parsing the code
*
* Note that `acorn` only takes valid JS Code, should usually only be used after transformationa and transpilation
*
* @default 'regex'
*/
parser?: 'acorn' | 'regex';
/**
* Inject the imports at the end of other imports
*
* @default false
*/
injectAtEnd?: boolean;
}
type Thenable<T> = Promise<T> | T;
interface Addon {
name?: string;
transform?: (this: UnimportContext, code: MagicString, id: string | undefined) => Thenable<MagicString>;
declaration?: (this: UnimportContext, dts: string, options: TypeDeclarationOptions) => Thenable<string>;
matchImports?: (this: UnimportContext, identifiers: Set<string>, matched: Import[]) => Thenable<Import[] | void>;
/**
* Extend or modify the imports list before injecting
*/
extendImports?: (this: UnimportContext, imports: Import[]) => Import[] | void;
/**
* Resolve imports before injecting
*/
injectImportsResolved?: (this: UnimportContext, imports: Import[], code: MagicString, id?: string) => Import[] | void;
/**
* Modify the injection code before injecting
*/
injectImportsStringified?: (this: UnimportContext, injection: string, imports: Import[], code: MagicString, id?: string) => string | void;
}
interface InstallGlobalOptions {
/**
* @default globalThis
*/
globalObject?: any;
/**
* Overrides the existing property
* @default false
*/
overrides?: boolean;
}
interface MagicStringResult {
s: MagicString;
code: string;
}
interface ImportInjectionResult extends MagicStringResult {
imports: Import[];
}
export { type AddonsOptions as A, type BuiltinPresetName as B, type DetectImportResult as D, type Import as I, type MagicStringResult as M, type Preset as P, type ScanDir as S, type TypeDeclarationOptions as T, type UnimportOptions as U, type Unimport as a, type InstallGlobalOptions as b, type ScanDirExportsOptions as c, type InlinePreset as d, builtinPresets as e, type ModuleId as f, type ImportName as g, type ImportCommon as h, type PresetImport as i, type PackagePreset as j, type UnimportContext as k, type InjectionUsageRecord as l, type UnimportMeta as m, type AddonVueDirectivesOptions as n, type PathFromResolver as o, type InjectImportsOptions as p, type Thenable as q, type Addon as r, type ImportInjectionResult as s };
+5
View File
@@ -0,0 +1,5 @@
import { r as Addon } from './unimport.CaVRR9SH.mjs';
declare function vueTemplateAddon(): Addon;
export { vueTemplateAddon as v };
+5
View File
@@ -0,0 +1,5 @@
import { r as Addon } from './unimport.CaVRR9SH.cjs';
declare function vueTemplateAddon(): Addon;
export { vueTemplateAddon as v };
File diff suppressed because it is too large Load Diff
+575
View File
@@ -0,0 +1,575 @@
'use strict';
const node_path = require('node:path');
const process = require('node:process');
const pathe = require('pathe');
const scule = require('scule');
const MagicString = require('magic-string');
const mlly = require('mlly');
const stripLiteral = require('strip-literal');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const process__default = /*#__PURE__*/_interopDefaultCompat(process);
const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
const excludeRE = [
// imported/exported from other module
/\b(import|export)\b([\w$*{},\s]+?)\bfrom\s*["']/g,
// defined as function
/\bfunction\s*([\w$]+)\s*\(/g,
// defined as class
/\bclass\s*([\w$]+)\s*\{/g,
// defined as local variable
// eslint-disable-next-line regexp/no-super-linear-backtracking
/\b(?:const|let|var)\s+?(\[.*?\]|\{.*?\}|.+?)\s*?[=;\n]/gs
];
const importAsRE = /^.*\sas\s+/;
const separatorRE = /[,[\]{}\n]|\b(?:import|export)\b/g;
const matchRE = /(^|\.\.\.|(?:\bcase|\?)\s+|[^\w$/)]|\bextends\s+)([\w$]+)\s*(?=[.()[\]}:;?+\-*&|`<>,\n]|\b(?:instanceof|in)\b|$|(?<=extends\s+\w+)\s+\{)/g;
const regexRE = /\/\S*?(?<!\\)(?<!\[[^\]]*)\/[gimsuy]*/g;
function stripCommentsAndStrings(code, options) {
return stripLiteral.stripLiteral(code, options).replace(regexRE, 'new RegExp("")');
}
function defineUnimportPreset(preset) {
return preset;
}
const safePropertyName = /^[a-z$_][\w$]*$/i;
function stringifyWith(withValues) {
let withDefs = "";
for (let entries = Object.entries(withValues), l = entries.length, i = 0; i < l; i++) {
const [prop, value] = entries[i];
withDefs += safePropertyName.test(prop) ? prop : JSON.stringify(prop);
withDefs += `: ${JSON.stringify(String(value))}`;
if (i + 1 !== l)
withDefs += ", ";
}
return `{ ${withDefs} }`;
}
function stringifyImports(imports, isCJS = false) {
const map = toImportModuleMap(imports);
return Object.entries(map).flatMap(([name, importSet]) => {
const entries = [];
const imports2 = Array.from(importSet).filter((i) => {
if (!i.name || i.as === "") {
let importStr;
if (isCJS) {
importStr = `require('${name}');`;
} else {
importStr = `import '${name}'`;
if (i.with)
importStr += ` with ${stringifyWith(i.with)}`;
importStr += ";";
}
entries.push(importStr);
return false;
} else if (i.name === "default" || i.name === "=") {
let importStr;
if (isCJS) {
importStr = i.name === "=" ? `const ${i.as} = require('${name}');` : `const { default: ${i.as} } = require('${name}');`;
} else {
importStr = `import ${i.as} from '${name}'`;
if (i.with)
importStr += ` with ${stringifyWith(i.with)}`;
importStr += ";";
}
entries.push(importStr);
return false;
} else if (i.name === "*") {
let importStr;
if (isCJS) {
importStr = `const ${i.as} = require('${name}');`;
} else {
importStr = `import * as ${i.as} from '${name}'`;
if (i.with)
importStr += ` with ${stringifyWith(i.with)}`;
importStr += ";";
}
entries.push(importStr);
return false;
} else if (!isCJS && i.with) {
entries.push(`import { ${stringifyImportAlias(i)} } from '${name}' with ${stringifyWith(i.with)};`);
return false;
}
return true;
});
if (imports2.length) {
const importsAs = imports2.map((i) => stringifyImportAlias(i, isCJS));
entries.push(
isCJS ? `const { ${importsAs.join(", ")} } = require('${name}');` : `import { ${importsAs.join(", ")} } from '${name}';`
);
}
return entries;
}).join("\n");
}
function dedupeImports(imports, warn) {
const map = /* @__PURE__ */ new Map();
const indexToRemove = /* @__PURE__ */ new Set();
imports.filter((i) => !i.disabled).forEach((i, idx) => {
if (i.declarationType === "enum" || i.declarationType === "class")
return;
const name = i.as ?? i.name;
if (!map.has(name)) {
map.set(name, idx);
return;
}
const other = imports[map.get(name)];
if (other.from === i.from) {
indexToRemove.add(idx);
return;
}
const diff = (other.priority || 1) - (i.priority || 1);
if (diff === 0)
warn(`Duplicated imports "${name}", the one from "${other.from}" has been ignored and "${i.from}" is used`);
if (diff <= 0) {
indexToRemove.add(map.get(name));
map.set(name, idx);
} else {
indexToRemove.add(idx);
}
});
return imports.filter((_, idx) => !indexToRemove.has(idx));
}
function toExports(imports, fileDir, includeType = false) {
const map = toImportModuleMap(imports, includeType);
return Object.entries(map).flatMap(([name, imports2]) => {
if (isFilePath(name))
name = name.replace(/\.[a-z]+$/i, "");
if (fileDir && pathe.isAbsolute(name)) {
name = pathe.relative(fileDir, name);
if (!name.match(/^[./]/))
name = `./${name}`;
}
const entries = [];
const filtered = Array.from(imports2).filter((i) => {
if (i.name === "*") {
entries.push(`export * as ${i.as} from '${name}';`);
return false;
}
return true;
});
if (filtered.length)
entries.push(`export { ${filtered.map((i) => stringifyImportAlias(i, false)).join(", ")} } from '${name}';`);
return entries;
}).join("\n");
}
function stripFileExtension(path) {
return path.replace(/\.[a-z]+$/i, "");
}
function toTypeDeclarationItems(imports, options) {
return imports.map((i) => {
const from = options?.resolvePath?.(i) || stripFileExtension(i.typeFrom || i.from);
let typeDef = "";
if (i.with)
typeDef += `import('${from}', { with: ${stringifyWith(i.with)} })`;
else
typeDef += `import('${from}')`;
if (i.name !== "*" && i.name !== "=")
typeDef += `['${i.name}']`;
return `const ${i.as}: typeof ${typeDef}`;
}).sort();
}
function toTypeDeclarationFile(imports, options) {
const items = toTypeDeclarationItems(imports, options);
const {
exportHelper = true
} = options || {};
let declaration = "";
if (exportHelper)
declaration += "export {}\n";
declaration += `declare global {
${items.map((i) => ` ${i}`).join("\n")}
}`;
return declaration;
}
function makeTypeModulesMap(imports, resolvePath) {
const modulesMap = /* @__PURE__ */ new Map();
const resolveImportFrom = typeof resolvePath === "function" ? (i) => {
return resolvePath(i) || stripFileExtension(i.typeFrom || i.from);
} : (i) => stripFileExtension(i.typeFrom || i.from);
for (const import_ of imports) {
const from = resolveImportFrom(import_);
let module = modulesMap.get(from);
if (!module) {
module = { typeImports: /* @__PURE__ */ new Set(), starTypeImport: undefined };
modulesMap.set(from, module);
}
if (import_.name === "*") {
if (import_.as)
module.starTypeImport = import_;
} else {
module.typeImports.add(import_);
}
}
return modulesMap;
}
function toTypeReExports(imports, options) {
const importsMap = makeTypeModulesMap(imports, options?.resolvePath);
const code = Array.from(importsMap).flatMap(([from, module]) => {
from = from.replace(/\.d\.([cm]?)ts$/i, ".$1js");
const { starTypeImport, typeImports } = module;
const strings = [];
if (typeImports.size) {
const typeImportNames = Array.from(typeImports).map(({ name, as }) => {
if (as && as !== name)
return `${name} as ${as}`;
return name;
});
strings.push(
"// @ts-ignore",
`export type { ${typeImportNames.join(", ")} } from '${from}'`
);
}
if (starTypeImport) {
strings.push(
"// @ts-ignore",
`export type * as ${starTypeImport.as} from '${from}'`
);
}
if (strings.length) {
strings.push(
// This is a workaround for a TypeScript issue where type-only re-exports are not properly initialized.
`import('${from}')`
);
}
return strings;
});
return `// for type re-export
declare global {
${code.map((i) => ` ${i}`).join("\n")}
}`;
}
function stringifyImportAlias(item, isCJS = false) {
return item.as === undefined || item.name === item.as ? item.name : isCJS ? `${item.name}: ${item.as}` : `${item.name} as ${item.as}`;
}
function toImportModuleMap(imports, includeType = false) {
const map = {};
for (const _import of imports) {
if (_import.type && !includeType)
continue;
if (!map[_import.from])
map[_import.from] = /* @__PURE__ */ new Set();
map[_import.from].add(_import);
}
return map;
}
function getString(code) {
if (typeof code === "string")
return code;
return code.toString();
}
function getMagicString(code) {
if (typeof code === "string")
return new MagicString__default(code);
return code;
}
function addImportToCode(code, imports, isCJS = false, mergeExisting = false, injectAtLast = false, firstOccurrence = Number.POSITIVE_INFINITY, onResolved, onStringified) {
let newImports = [];
const s = getMagicString(code);
let _staticImports;
const strippedCode = stripCommentsAndStrings(s.original);
function findStaticImportsLazy() {
if (!_staticImports) {
_staticImports = mlly.findStaticImports(s.original).filter((i) => Boolean(strippedCode.slice(i.start, i.end).trim())).map((i) => mlly.parseStaticImport(i));
}
return _staticImports;
}
function hasShebang() {
const shebangRegex = /^#!.+/;
return shebangRegex.test(s.original);
}
if (mergeExisting && !isCJS) {
const existingImports = findStaticImportsLazy();
const map = /* @__PURE__ */ new Map();
imports.forEach((i) => {
const target = existingImports.find((e) => e.specifier === i.from && e.imports.startsWith("{"));
if (!target)
return newImports.push(i);
if (!map.has(target))
map.set(target, []);
map.get(target).push(i);
});
for (const [target, items] of map.entries()) {
const strings = items.map((i) => `${stringifyImportAlias(i)}, `);
const importLength = target.code.match(/^\s*import\s*\{/)?.[0]?.length;
if (importLength)
s.appendLeft(target.start + importLength, ` ${strings.join("").trim()}`);
}
} else {
newImports = imports;
}
newImports = onResolved?.(newImports) ?? newImports;
let newEntries = stringifyImports(newImports, isCJS);
newEntries = onStringified?.(newEntries, newImports) ?? newEntries;
if (newEntries) {
const insertionIndex = injectAtLast ? findStaticImportsLazy().reverse().find((i) => i.end <= firstOccurrence)?.end ?? 0 : 0;
if (insertionIndex > 0)
s.appendRight(insertionIndex, `
${newEntries}
`);
else if (hasShebang())
s.appendLeft(s.original.indexOf("\n") + 1, `
${newEntries}
`);
else
s.prepend(`${newEntries}
`);
}
return {
s,
get code() {
return s.toString();
}
};
}
function normalizeImports(imports) {
for (const _import of imports)
_import.as = _import.as ?? _import.name;
return imports;
}
function resolveIdAbsolute(id, parentId) {
return mlly.resolvePathSync(id, {
url: parentId
});
}
function isFilePath(path) {
return path.startsWith(".") || pathe.isAbsolute(path) || path.includes("://");
}
const toImports = stringifyImports;
const contextRE$1 = /\b_ctx\.([$\w]+)\b/g;
const UNREF_KEY = "__unimport_unref_";
const VUE_TEMPLATE_NAME = "unimport:vue-template";
function vueTemplateAddon() {
const self = {
name: VUE_TEMPLATE_NAME,
async transform(s, id) {
if (!s.original.includes("_ctx.") || s.original.includes(UNREF_KEY))
return s;
const matches = Array.from(s.original.matchAll(contextRE$1));
const imports = await this.getImports();
let targets = [];
for (const match of matches) {
const name = match[1];
const item = imports.find((i) => i.as === name);
if (!item)
continue;
const start = match.index;
const end = start + match[0].length;
const tempName = `__unimport_${name}`;
s.overwrite(start, end, `(${JSON.stringify(name)} in _ctx ? _ctx.${name} : ${UNREF_KEY}(${tempName}))`);
if (!targets.find((i) => i.as === tempName)) {
targets.push({
...item,
as: tempName
});
}
}
if (targets.length) {
targets.push({
name: "unref",
from: "vue",
as: UNREF_KEY
});
for (const addon of this.addons) {
if (addon === self)
continue;
targets = await addon.injectImportsResolved?.call(this, targets, s, id) ?? targets;
}
let injection = stringifyImports(targets);
for (const addon of this.addons) {
if (addon === self)
continue;
injection = await addon.injectImportsStringified?.call(this, injection, targets, s, id) ?? injection;
}
s.prepend(injection);
}
return s;
},
async declaration(dts, options) {
const imports = await this.getImports();
const items = imports.map((i) => {
if (i.type || i.dtsDisabled)
return "";
const from = options?.resolvePath?.(i) || i.from;
return `readonly ${i.as}: UnwrapRef<typeof import('${from}')${i.name !== "*" ? `['${i.name}']` : ""}>`;
}).filter(Boolean).sort();
const extendItems = items.map((i) => ` ${i}`).join("\n");
return `${dts}
// for vue template auto import
import { UnwrapRef } from 'vue'
declare module 'vue' {
interface ComponentCustomProperties {
${extendItems}
}
}`;
}
};
return self;
}
const contextRE = /resolveDirective as _resolveDirective/;
const contextText = `${contextRE.source}, `;
const directiveRE = /(?:var|const) (\w+) = _resolveDirective\("([\w.-]+)"\);?\s*/g;
const VUE_DIRECTIVES_NAME = "unimport:vue-directives";
function vueDirectivesAddon(options = {}) {
function isDirective(importEntry) {
let isDirective2 = importEntry.meta?.vueDirective === true;
if (isDirective2) {
return true;
}
isDirective2 = options.isDirective?.(normalizePath(process__default.cwd(), importEntry.from), importEntry) ?? false;
if (isDirective2) {
importEntry.meta ??= {};
importEntry.meta.vueDirective = true;
}
return isDirective2;
}
const self = {
name: VUE_DIRECTIVES_NAME,
async transform(s, id) {
if (!s.original.match(contextRE))
return s;
const matches = Array.from(s.original.matchAll(directiveRE)).sort((a, b) => b.index - a.index);
if (!matches.length)
return s;
let targets = [];
for await (const [
begin,
end,
importEntry
] of findDirectives(
isDirective,
matches,
this.getImports()
)) {
s.overwrite(begin, end, "");
targets.push(importEntry);
}
if (!targets.length)
return s;
s.replace(contextText, "");
for (const addon of this.addons) {
if (addon === self)
continue;
targets = await addon.injectImportsResolved?.call(this, targets, s, id) ?? targets;
}
let injection = stringifyImports(targets);
for (const addon of this.addons) {
if (addon === self)
continue;
injection = await addon.injectImportsStringified?.call(this, injection, targets, s, id) ?? injection;
}
s.prepend(injection);
return s;
},
async declaration(dts, options2) {
const directivesMap = await this.getImports().then((imports) => {
return imports.filter(isDirective).reduce((acc, i) => {
if (i.type || i.dtsDisabled)
return acc;
let name;
if (i.name === "default" && (i.as === "default" || !i.as)) {
const file = node_path.basename(i.from);
const idx = file.indexOf(".");
name = idx > -1 ? file.slice(0, idx) : file;
} else {
name = i.as ?? i.name;
}
name = name[0] === "v" ? scule.camelCase(name) : scule.camelCase(`v-${name}`);
if (!acc.has(name)) {
acc.set(name, i);
}
return acc;
}, /* @__PURE__ */ new Map());
});
if (!directivesMap.size)
return dts;
const directives = Array.from(directivesMap.entries()).map(([name, i]) => ` ${name}: typeof import('${options2?.resolvePath?.(i) || i.from}')['${i.name}']`).sort().join("\n");
return `${dts}
// for vue directives auto import
declare module 'vue' {
interface ComponentCustomProperties {
${directives}
}
interface GlobalDirectives {
${directives}
}
}`;
}
};
return self;
}
function resolvePath(cwd, path) {
return path[0] === "." ? pathe.resolve(cwd, path) : path;
}
function normalizePath(cwd, path) {
return resolvePath(cwd, path).replace(/\\/g, "/");
}
async function* findDirectives(isDirective, regexArray, importsPromise) {
const imports = (await importsPromise).filter(isDirective);
if (!imports.length)
return;
const symbols = regexArray.reduce((acc, regex) => {
const [all, symbol, resolveDirectiveName] = regex;
if (acc.has(symbol))
return acc;
acc.set(symbol, [
regex.index,
regex.index + all.length,
scule.kebabCase(resolveDirectiveName)
]);
return acc;
}, /* @__PURE__ */ new Map());
for (const [symbol, data] of symbols.entries()) {
yield* findDirective(imports, symbol, data);
}
}
function* findDirective(imports, symbol, [begin, end, importName]) {
let resolvedName;
for (const i of imports) {
if (i.name === "default" && (i.as === "default" || !i.as)) {
const file = node_path.basename(i.from);
const idx = file.indexOf(".");
resolvedName = scule.kebabCase(idx > -1 ? file.slice(0, idx) : file);
} else {
resolvedName = scule.kebabCase(i.as ?? i.name);
}
if (resolvedName[0] === "v") {
resolvedName = resolvedName.slice(resolvedName[1] === "-" ? 2 : 1);
}
if (resolvedName === importName) {
yield [
begin,
end,
{ ...i, name: i.name, as: symbol }
];
return;
}
}
}
exports.VUE_DIRECTIVES_NAME = VUE_DIRECTIVES_NAME;
exports.VUE_TEMPLATE_NAME = VUE_TEMPLATE_NAME;
exports.addImportToCode = addImportToCode;
exports.dedupeImports = dedupeImports;
exports.defineUnimportPreset = defineUnimportPreset;
exports.excludeRE = excludeRE;
exports.getMagicString = getMagicString;
exports.getString = getString;
exports.importAsRE = importAsRE;
exports.matchRE = matchRE;
exports.normalizeImports = normalizeImports;
exports.resolveIdAbsolute = resolveIdAbsolute;
exports.separatorRE = separatorRE;
exports.stringifyImports = stringifyImports;
exports.stripCommentsAndStrings = stripCommentsAndStrings;
exports.stripFileExtension = stripFileExtension;
exports.toExports = toExports;
exports.toImports = toImports;
exports.toTypeDeclarationFile = toTypeDeclarationFile;
exports.toTypeDeclarationItems = toTypeDeclarationItems;
exports.toTypeReExports = toTypeReExports;
exports.vueDirectivesAddon = vueDirectivesAddon;
exports.vueTemplateAddon = vueTemplateAddon;
File diff suppressed because it is too large Load Diff
+72
View File
@@ -0,0 +1,72 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const node_fs = require('node:fs');
const pluginutils = require('@rollup/pluginutils');
const MagicString = require('magic-string');
const unplugin$1 = require('unplugin');
const context = require('./shared/unimport.D6_N7ILk.cjs');
require('./shared/unimport.MMUMmZ45.cjs');
require('node:path');
require('node:process');
require('pathe');
require('scule');
require('mlly');
require('strip-literal');
require('node:fs/promises');
require('node:url');
require('fast-glob');
require('picomatch');
require('node:os');
require('pkg-types');
require('local-pkg');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
const defaultIncludes = [/\.[jt]sx?$/, /\.vue$/, /\.vue\?vue/, /\.svelte$/];
const defaultExcludes = [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/];
function toArray(x) {
return x == null ? [] : Array.isArray(x) ? x : [x];
}
const unplugin = unplugin$1.createUnplugin((options = {}) => {
const ctx = context.createUnimport(options);
const filter = pluginutils.createFilter(
toArray(options.include || []).length ? options.include : defaultIncludes,
options.exclude || defaultExcludes
);
const dts = options.dts === true ? "unimport.d.ts" : options.dts;
const {
autoImport = true
} = options;
return {
name: "unimport",
enforce: "post",
transformInclude(id) {
return filter(id);
},
async transform(code, id) {
const s = new MagicString__default(code);
await ctx.injectImports(s, id, {
autoImport
});
if (!s.hasChanged())
return;
return {
code: s.toString(),
map: s.generateMap()
};
},
async buildStart() {
await ctx.init();
if (dts)
return node_fs.promises.writeFile(dts, await ctx.generateTypeDeclarations(), "utf-8");
}
};
});
exports.default = unplugin;
exports.defaultExcludes = defaultExcludes;
exports.defaultIncludes = defaultIncludes;
+23
View File
@@ -0,0 +1,23 @@
import * as unplugin from 'unplugin';
import { FilterPattern } from '@rollup/pluginutils';
import { U as UnimportOptions } from './shared/unimport.CaVRR9SH.cjs';
import 'magic-string';
import 'mlly';
interface UnimportPluginOptions extends UnimportOptions {
include: FilterPattern;
exclude: FilterPattern;
dts: boolean | string;
/**
* Enable implicit auto import.
* Generate global TypeScript definitions.
*
* @default true
*/
autoImport?: boolean;
}
declare const defaultIncludes: RegExp[];
declare const defaultExcludes: RegExp[];
declare const _default: unplugin.UnpluginInstance<Partial<UnimportPluginOptions>, boolean>;
export { type UnimportPluginOptions, _default as default, defaultExcludes, defaultIncludes };
+23
View File
@@ -0,0 +1,23 @@
import * as unplugin from 'unplugin';
import { FilterPattern } from '@rollup/pluginutils';
import { U as UnimportOptions } from './shared/unimport.CaVRR9SH.mjs';
import 'magic-string';
import 'mlly';
interface UnimportPluginOptions extends UnimportOptions {
include: FilterPattern;
exclude: FilterPattern;
dts: boolean | string;
/**
* Enable implicit auto import.
* Generate global TypeScript definitions.
*
* @default true
*/
autoImport?: boolean;
}
declare const defaultIncludes: RegExp[];
declare const defaultExcludes: RegExp[];
declare const _default: unplugin.UnpluginInstance<Partial<UnimportPluginOptions>, boolean>;
export { type UnimportPluginOptions, _default as default, defaultExcludes, defaultIncludes };
+23
View File
@@ -0,0 +1,23 @@
import * as unplugin from 'unplugin';
import { FilterPattern } from '@rollup/pluginutils';
import { U as UnimportOptions } from './shared/unimport.CaVRR9SH.js';
import 'magic-string';
import 'mlly';
interface UnimportPluginOptions extends UnimportOptions {
include: FilterPattern;
exclude: FilterPattern;
dts: boolean | string;
/**
* Enable implicit auto import.
* Generate global TypeScript definitions.
*
* @default true
*/
autoImport?: boolean;
}
declare const defaultIncludes: RegExp[];
declare const defaultExcludes: RegExp[];
declare const _default: unplugin.UnpluginInstance<Partial<UnimportPluginOptions>, boolean>;
export { type UnimportPluginOptions, _default as default, defaultExcludes, defaultIncludes };
+62
View File
@@ -0,0 +1,62 @@
import { promises } from 'node:fs';
import { createFilter } from '@rollup/pluginutils';
import MagicString from 'magic-string';
import { createUnplugin } from 'unplugin';
import { c as createUnimport } from './shared/unimport.Ww9aF1N_.mjs';
import './shared/unimport.0aitavbJ.mjs';
import 'node:path';
import 'node:process';
import 'pathe';
import 'scule';
import 'mlly';
import 'strip-literal';
import 'node:fs/promises';
import 'node:url';
import 'fast-glob';
import 'picomatch';
import 'node:os';
import 'pkg-types';
import 'local-pkg';
const defaultIncludes = [/\.[jt]sx?$/, /\.vue$/, /\.vue\?vue/, /\.svelte$/];
const defaultExcludes = [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/];
function toArray(x) {
return x == null ? [] : Array.isArray(x) ? x : [x];
}
const unplugin = createUnplugin((options = {}) => {
const ctx = createUnimport(options);
const filter = createFilter(
toArray(options.include || []).length ? options.include : defaultIncludes,
options.exclude || defaultExcludes
);
const dts = options.dts === true ? "unimport.d.ts" : options.dts;
const {
autoImport = true
} = options;
return {
name: "unimport",
enforce: "post",
transformInclude(id) {
return filter(id);
},
async transform(code, id) {
const s = new MagicString(code);
await ctx.injectImports(s, id, {
autoImport
});
if (!s.hasChanged())
return;
return {
code: s.toString(),
map: s.generateMap()
};
},
async buildStart() {
await ctx.init();
if (dts)
return promises.writeFile(dts, await ctx.generateTypeDeclarations(), "utf-8");
}
};
});
export { unplugin as default, defaultExcludes, defaultIncludes };
+27
View File
@@ -0,0 +1,27 @@
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.
## Third-Party Licenses
This software includes bundled third-party dependencies. The licenses and
copyright notices for these dependencies are available in
`dist/THIRD-PARTY-LICENSES.md` within the distributed package.
+191
View File
@@ -0,0 +1,191 @@
# confbox
<!-- automd:badges color=yellow bundlephobia packagephobia -->
[![npm version](https://img.shields.io/npm/v/confbox?color=yellow)](https://npmjs.com/package/confbox)
[![npm downloads](https://img.shields.io/npm/dm/confbox?color=yellow)](https://npm.chart.dev/confbox)
[![bundle size](https://img.shields.io/bundlephobia/minzip/confbox?color=yellow)](https://bundlephobia.com/package/confbox)
[![install size](https://badgen.net/packagephobia/install/confbox?color=yellow)](https://packagephobia.com/result?p=confbox)
<!-- /automd -->
Parsing and serialization utils for [YAML](https://yaml.org/) ([js-yaml](https://github.com/nodeca/js-yaml)), [TOML](https://toml.io/) ([smol-toml](https://github.com/squirrelchat/smol-toml)), [JSONC](https://github.com/microsoft/node-jsonc-parser) ([jsonc-parser](https://github.com/microsoft/node-jsonc-parser)), [JSON5](https://json5.org/) ([json5](https://github.com/json5/json5)), [INI](https://en.wikipedia.org/wiki/INI_file) ([ini](https://www.npmjs.com/package/ini)) and [JSON](https://www.json.org/json-en.html).
✨ Zero dependency and tree-shakable
✨ Types exported out of the box
✨ Preserves code style (indentation and whitespace)
> [!TIP]
> Use [unjs/c12](https://github.com/unjs/c12) for a full featured configuration loader!
## Usage
Install package:
<!-- automd:pm-i no-version -->
```sh
# ✨ Auto-detect
npx nypm install confbox
# npm
npm install confbox
# yarn
yarn add confbox
# pnpm
pnpm add confbox
# bun
bun install confbox
# deno
deno install npm:confbox
```
<!-- /automd -->
Import:
<!-- automd:jsimport cdn src="./src/index.ts" -->
**ESM** (Node.js, Bun, Deno)
```js
import {
parseJSON5,
stringifyJSON5,
parseJSONC,
stringifyJSONC,
parseYAML,
stringifyYAML,
parseJSON,
stringifyJSON,
parseTOML,
stringifyTOML,
parseINI,
stringifyINI,
} from "confbox";
```
**CDN** (Deno and Browsers)
```js
import {
parseJSON5,
stringifyJSON5,
parseJSONC,
stringifyJSONC,
parseYAML,
stringifyYAML,
parseJSON,
stringifyJSON,
parseTOML,
stringifyTOML,
parseINI,
stringifyINI,
} from "https://esm.sh/confbox";
```
<!-- /automd -->
<!-- automd:jsdocs src="./src/index" -->
### `parseINI(text, options?)`
Converts an [INI](https://www.ini.org/ini-en.html) string into an object.
**Note:** Style and indentation are not preserved currently.
### `parseJSON(text, options?)`
Converts a [JSON](https://www.json.org/json-en.html) string into an object.
Indentation status is auto-detected and preserved when stringifying back using `stringifyJSON`
### `parseJSON5(text, options?)`
Converts a [JSON5](https://json5.org/) string into an object.
### `parseJSONC(text, options?)`
Converts a [JSONC](https://github.com/microsoft/node-jsonc-parser) string into an object.
### `parseTOML(text)`
Converts a [TOML](https://toml.io/) string into an object.
### `parseYAML(text, options?)`
Converts a [YAML](https://yaml.org/) string into an object.
### `stringifyINI(value, options?)`
Converts a JavaScript value to an [INI](https://www.ini.org/ini-en.html) string.
**Note:** Style and indentation are not preserved currently.
### `stringifyJSON(value, options?)`
Converts a JavaScript value to a [JSON](https://www.json.org/json-en.html) string.
Indentation status is auto detected and preserved when using value from parseJSON.
### `stringifyJSON5(value, options?)`
Converts a JavaScript value to a [JSON5](https://json5.org/) string.
### `stringifyJSONC(value, options?)`
Converts a JavaScript value to a [JSONC](https://github.com/microsoft/node-jsonc-parser) string.
### `stringifyTOML(value)`
Converts a JavaScript value to a [TOML](https://toml.io/) string.
### `stringifyYAML(value, options?)`
Converts a JavaScript value to a [YAML](https://yaml.org/) string.
<!-- /automd -->
<!-- automd:fetch url="gh:unjs/.github/main/snippets/readme-contrib-node-pnpm.md" -->
## Contribution
<details>
<summary>Local development</summary>
- 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 tests using `pnpm dev` or `pnpm test`
</details>
<!-- /automd -->
## License
<!-- automd:contributors license=MIT author=pi0 -->
Published under the [MIT](https://github.com/unjs/confbox/blob/main/LICENSE) license.
Made by [@pi0](https://github.com/pi0) and [community](https://github.com/unjs/confbox/graphs/contributors) 💛
<br><br>
<a href="https://github.com/unjs/confbox/graphs/contributors">
<img src="https://contrib.rocks/image?repo=unjs/confbox" />
</a>
<!-- /automd -->
<!-- automd:with-automd -->
---
_🤖 auto updated with [automd](https://automd.unjs.io)_
<!-- /automd -->
+171
View File
@@ -0,0 +1,171 @@
# Licenses of Bundled Dependencies
The published artifact additionally contains code with the following licenses:
BSD-3-Clause, ISC, MIT
# Bundled Dependencies
## detect-indent
License: MIT
By: Sindre Sorhus
Repository: https://github.com/sindresorhus/detect-indent
> MIT License
>
> Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
>
> 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.
---------------------------------------
## ini
License: ISC
By: GitHub Inc.
Repository: https://github.com/npm/ini
> The ISC License
>
> Copyright (c) Isaac Z. Schlueter and Contributors
>
> Permission to use, copy, modify, and/or distribute this software for any
> purpose with or without fee is hereby granted, provided that the above
> copyright notice and this permission notice appear in all copies.
>
> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
---------------------------------------
## js-yaml
License: MIT
By: Vladimir Zapparov, Aleksey V Zapparov, Vitaly Puzrin, Martin Grenfell
Repository: https://github.com/nodeca/js-yaml
> (The MIT License)
>
> Copyright (C) 2011-2015 by Vitaly Puzrin
>
> 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.
---------------------------------------
## json5
License: MIT
By: Aseem Kishore, Max Nanasy, Andrew Eisenberg, Jordan Tucker
Repository: https://github.com/json5/json5
> MIT License
>
> Copyright (c) 2012-2018 Aseem Kishore, and [others].
>
> 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.
>
> [others]: https://github.com/json5/json5/contributors
---------------------------------------
## jsonc-parser
License: MIT
By: Microsoft Corporation
Repository: https://github.com/microsoft/node-jsonc-parser
> The MIT License (MIT)
>
> Copyright (c) Microsoft
>
> 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.
---------------------------------------
## smol-toml
License: BSD-3-Clause
By: Cynthia
Repository: https://github.com/squirrelchat/smol-toml
> Copyright (c) Squirrel Chat et al., All rights reserved.
>
> Redistribution and use in source and binary forms, with or without
> modification, are permitted provided that the following conditions are met:
>
> 1. Redistributions of source code must retain the above copyright notice, this
> list of conditions and the following disclaimer.
> 2. Redistributions in binary form must reproduce the above copyright notice,
> this list of conditions and the following disclaimer in the
> documentation and/or other materials provided with the distribution.
> 3. Neither the name of the copyright holder nor the names of its contributors
> may be used to endorse or promote products derived from this software without
> specific prior written permission.
>
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
> ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
> WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
> OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+25
View File
@@ -0,0 +1,25 @@
//#region src/_format.d.ts
interface FormatOptions {
/**
* A String or Number object that's used to insert white space into the output JSON string for readability purposes.
*
* When provided, identation won't be auto detected anymore.
*/
indent?: string | number;
/**
* Set to `false` to skip indentation preservation.
*/
preserveIndentation?: boolean;
/**
* Set to `false` to skip whitespace preservation.
*/
preserveWhitespace?: boolean;
/**
* The number of characters to sample from the start of the text.
*
* Default: 1024
*/
sampleSize?: number;
}
//#endregion
export { FormatOptions as t };
+1
View File
@@ -0,0 +1 @@
import{t as e}from"./libs/detect-indent.mjs";const t=Symbol.for(`__confbox_fmt__`),n=/^(\s+)/,r=/(\s+)$/;function i(e,t={}){return{sample:t.indent===void 0&&t.preserveIndentation!==!1&&e.slice(0,t?.sampleSize||1024),whiteSpace:t.preserveWhitespace===!1?void 0:{start:n.exec(e)?.[0]||``,end:r.exec(e)?.[0]||``}}}function a(e,n,r){!n||typeof n!=`object`||Object.defineProperty(n,t,{enumerable:!1,configurable:!0,writable:!0,value:i(e,r)})}function o(n,r){if(!n||typeof n!=`object`||!(t in n))return{indent:r?.indent??2,whitespace:{start:``,end:``}};let i=n[t];return{indent:r?.indent||e(i.sample||``).indent,whitespace:i.whiteSpace||{start:``,end:``}}}export{a as n,o as t};
+1
View File
@@ -0,0 +1 @@
import{n as e,t}from"./_format.mjs";function n(t,n){let r=JSON.parse(t,n?.reviver);return e(t,r,n),r}function r(e,n){let r=t(e,n),i=JSON.stringify(e,n?.replacer,r.indent);return r.whitespace.start+i+r.whitespace.end}export{r as n,n as t};
@@ -0,0 +1 @@
const e=/^(?:( )+|\t+)/,t=`space`;function n(e,n,r){return e&&n===t&&r===1}function r(r,a){let o=new Map,s=0,c,l;for(let u of r.split(/\n/g)){if(!u)continue;let r=u.match(e);if(r===null)s=0,c=``;else{let e=r[0].length,u=r[1]?t:`tab`;if(n(a,u,e))continue;u!==c&&(s=0),c=u;let d=1,f=0,p=e-s;if(s=e,p===0)d=0,f=1;else{let e=Math.abs(p);if(n(a,u,e))continue;l=i(u,e)}let m=o.get(l);o.set(l,m===void 0?[1,0]:[m[0]+d,m[1]+f])}}return o}function i(e,n){return(e===t?`s`:`t`)+String(n)}function a(e){return{type:e[0]===`s`?t:`tab`,amount:Number(e.slice(1))}}function o(e){let t,n=0,r=0;for(let[i,[a,o]]of e)(a>n||a===n&&o>r)&&(n=a,r=o,t=i);return t}function s(e,n){return(e===t?` `:` `).repeat(n)}function c(e){if(typeof e!=`string`)throw TypeError(`Expected a string`);let t=r(e,!0);t.size===0&&(t=r(e,!1));let n=o(t),i,c=0,l=``;return n!==void 0&&({type:i,amount:c}=a(n),l=s(i,c)),{amount:c,type:i,indent:l}}export{c as t};
+3
View File
@@ -0,0 +1,3 @@
import{t as e}from"../rolldown-runtime.mjs";var t=e(((e,t)=>{let{hasOwnProperty:n}=Object.prototype,r=(e,t={})=>{typeof t==`string`&&(t={section:t}),t.align=t.align===!0,t.newline=t.newline===!0,t.sort=t.sort===!0,t.whitespace=t.whitespace===!0||t.align===!0,t.platform=t.platform||typeof process<`u`&&process.platform,t.bracketedArray=t.bracketedArray!==!1;let n=t.platform===`win32`?`\r
`:`
`,a=t.whitespace?` = `:`=`,o=[],c=t.sort?Object.keys(e).sort():Object.keys(e),l=0;t.align&&(l=s(c.filter(t=>e[t]===null||Array.isArray(e[t])||typeof e[t]!=`object`).map(t=>Array.isArray(e[t])?`${t}[]`:t).concat([``]).reduce((e,t)=>s(e).length>=s(t).length?e:t)).length);let u=``,d=t.bracketedArray?`[]`:``;for(let t of c){let r=e[t];if(r&&Array.isArray(r))for(let e of r)u+=s(`${t}${d}`).padEnd(l,` `)+a+s(e)+n;else r&&typeof r==`object`?o.push(t):u+=s(t).padEnd(l,` `)+a+s(r)+n}t.section&&u.length&&(u=`[`+s(t.section)+`]`+(t.newline?n+n:n)+u);for(let a of o){let o=i(a,`.`).join(`\\.`),s=(t.section?t.section+`.`:``)+o,c=r(e[a],{...t,section:s});u.length&&c.length&&(u+=n),u+=c}return u};function i(e,t){var n=0,r=0,i=0,a=[];do if(i=e.indexOf(t,n),i!==-1){if(n=i+t.length,i>0&&e[i-1]===`\\`)continue;a.push(e.slice(r,i)),r=i+t.length}while(i!==-1);return a.push(e.slice(r)),a}let a=(e,t={})=>{t.bracketedArray=t.bracketedArray!==!1;let r=Object.create(null),a=r,o=null,s=/^\[([^\]]*)\]\s*$|^([^=]+)(=(.*))?$/i,l=e.split(/[\r\n]+/g),u={};for(let e of l){if(!e||e.match(/^\s*[;#]/)||e.match(/^\s*$/))continue;let i=e.match(s);if(!i)continue;if(i[1]!==void 0){if(o=c(i[1]),o===`__proto__`){a=Object.create(null);continue}a=r[o]=r[o]||Object.create(null);continue}let l=c(i[2]),d;t.bracketedArray?d=l.length>2&&l.slice(-2)===`[]`:(u[l]=(u?.[l]||0)+1,d=u[l]>1);let f=d&&l.endsWith(`[]`)?l.slice(0,-2):l;if(f===`__proto__`)continue;let p=i[3]?c(i[4]):!0,m=p===`true`||p===`false`||p===`null`?JSON.parse(p):p;d&&(n.call(a,f)?Array.isArray(a[f])||(a[f]=[a[f]]):a[f]=[]),Array.isArray(a[f])?a[f].push(m):a[f]=m}let d=[];for(let e of Object.keys(r)){if(!n.call(r,e)||typeof r[e]!=`object`||Array.isArray(r[e]))continue;let t=i(e,`.`);a=r;let o=t.pop(),s=o.replace(/\\\./g,`.`);for(let e of t)e!==`__proto__`&&((!n.call(a,e)||typeof a[e]!=`object`)&&(a[e]=Object.create(null)),a=a[e]);a===r&&s===o||(a[s]=r[e],d.push(e))}for(let e of d)delete r[e];return r},o=e=>e.startsWith(`"`)&&e.endsWith(`"`)||e.startsWith(`'`)&&e.endsWith(`'`),s=e=>typeof e!=`string`||e.match(/[=\r\n]/)||e.match(/^\[/)||e.length>1&&o(e)||e!==e.trim()?JSON.stringify(e):e.split(`;`).join(`\\;`).split(`#`).join(`\\#`),c=e=>{if(e=(e||``).trim(),o(e)){e.charAt(0)===`'`&&(e=e.slice(1,-1));try{e=JSON.parse(e)}catch{}}else{let t=!1,n=``;for(let r=0,i=e.length;r<i;r++){let i=e.charAt(r);if(t)`\\;#`.indexOf(i)===-1?n+=`\\`+i:n+=i,t=!1;else if(`;#`.indexOf(i)!==-1)break;else i===`\\`?t=!0:n+=i}return t&&(n+=`\\`),n.trim()}return e};t.exports={parse:a,decode:a,stringify:r,encode:r,safe:s,unsafe:c}}));export{t};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,249 @@
/*!
* Copyright (c) Squirrel Chat et al., All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
function e(e,t){let n=e.slice(0,t).split(/\r\n|\n|\r/g);return[n.length,n.pop().length+1]}function t(e,t,n){let r=e.split(/\r\n|\n|\r/g),i=``,a=(Math.log10(t+1)|0)+1;for(let e=t-1;e<=t+1;e++){let o=r[e-1];o&&(i+=e.toString().padEnd(a,` `),i+=`: `,i+=o,i+=`
`,e===t&&(i+=` `.repeat(a+n+2),i+=`^
`))}return i}var n=class extends Error{line;column;codeblock;constructor(n,r){let[i,a]=e(r.toml,r.ptr),o=t(r.toml,i,a);super(`Invalid TOML document: ${n}\n\n${o}`,r),this.line=i,this.column=a,this.codeblock=o}};
/*!
* Copyright (c) Squirrel Chat et al., All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
function r(e,t){let n=0;for(;e[t-++n]===`\\`;);return--n&&n%2}function i(e,t=0,n=e.length){let r=e.indexOf(`
`,t);return e[r-1]===`\r`&&r--,r<=n?r:-1}function a(e,t){for(let r=t;r<e.length;r++){let i=e[r];if(i===`
`)return r;if(i===`\r`&&e[r+1]===`
`)return r+1;if(i<` `&&i!==` `||i===``)throw new n(`control characters are not allowed in comments`,{toml:e,ptr:t})}return e.length}function o(e,t,n,r){let i;for(;(i=e[t])===` `||i===` `||!n&&(i===`
`||i===`\r`&&e[t+1]===`
`);)t++;return r||i!==`#`?t:o(e,a(e,t),n)}function s(e,t,r,a,o=!1){if(!a)return t=i(e,t),t<0?e.length:t;for(let n=t;n<e.length;n++){let t=e[n];if(t===`#`)n=i(e,n);else if(t===r)return n+1;else if(t===a||o&&(t===`
`||t===`\r`&&e[n+1]===`
`))return n}throw new n(`cannot find end of structure`,{toml:e,ptr:t})}function c(e,t){let n=e[t],i=n===e[t+1]&&e[t+1]===e[t+2]?e.slice(t,t+3):n;t+=i.length-1;do t=e.indexOf(i,++t);while(t>-1&&n!==`'`&&r(e,t));return t>-1&&(t+=i.length,i.length>1&&(e[t]===n&&t++,e[t]===n&&t++)),t}
/*!
* Copyright (c) Squirrel Chat et al., All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
let l=/^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;var u=class e extends Date{#e=!1;#t=!1;#n=null;constructor(e){let t=!0,n=!0,r=`Z`;if(typeof e==`string`){let i=e.match(l);i?(i[1]||(t=!1,e=`0000-01-01T${e}`),n=!!i[2],n&&e[10]===` `&&(e=e.replace(` `,`T`)),i[2]&&+i[2]>23?e=``:(r=i[3]||null,e=e.toUpperCase(),!r&&n&&(e+=`Z`))):e=``}super(e),isNaN(this.getTime())||(this.#e=t,this.#t=n,this.#n=r)}isDateTime(){return this.#e&&this.#t}isLocal(){return!this.#e||!this.#t||!this.#n}isDate(){return this.#e&&!this.#t}isTime(){return this.#t&&!this.#e}isValid(){return this.#e||this.#t}toISOString(){let e=super.toISOString();if(this.isDate())return e.slice(0,10);if(this.isTime())return e.slice(11,23);if(this.#n===null)return e.slice(0,-1);if(this.#n===`Z`)return e;let t=this.#n.slice(1,3)*60+ +this.#n.slice(4,6);return t=this.#n[0]===`-`?t:-t,new Date(this.getTime()-t*6e4).toISOString().slice(0,-1)+this.#n}static wrapAsOffsetDateTime(t,n=`Z`){let r=new e(t);return r.#n=n,r}static wrapAsLocalDateTime(t){let n=new e(t);return n.#n=null,n}static wrapAsLocalDate(t){let n=new e(t);return n.#t=!1,n.#n=null,n}static wrapAsLocalTime(t){let n=new e(t);return n.#e=!1,n.#n=null,n}};
/*!
* Copyright (c) Squirrel Chat et al., All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
let d=/^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/,f=/^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/,p=/^[+-]?0[0-9_]/,m=/^[0-9a-f]{2,8}$/i,h={b:`\b`,t:` `,n:`
`,f:`\f`,r:`\r`,e:`\x1B`,'"':`"`,"\\":`\\`};function g(e,t=0,r=e.length){let i=e[t]===`'`,a=e[t++]===e[t]&&e[t]===e[t+1];a&&(r-=2,e[t+=2]===`\r`&&t++,e[t]===`
`&&t++);let s=0,c,l=``,u=t;for(;t<r-1;){let r=e[t++];if(r===`
`||r===`\r`&&e[t]===`
`){if(!a)throw new n(`newlines are not allowed in strings`,{toml:e,ptr:t-1})}else if(r<` `&&r!==` `||r===``)throw new n(`control characters are not allowed in strings`,{toml:e,ptr:t-1});if(c){if(c=!1,r===`x`||r===`u`||r===`U`){let i=e.slice(t,t+=r===`x`?2:r===`u`?4:8);if(!m.test(i))throw new n(`invalid unicode escape`,{toml:e,ptr:s});try{l+=String.fromCodePoint(parseInt(i,16))}catch{throw new n(`invalid unicode escape`,{toml:e,ptr:s})}}else if(a&&(r===`
`||r===` `||r===` `||r===`\r`)){if(t=o(e,t-1,!0),e[t]!==`
`&&e[t]!==`\r`)throw new n(`invalid escape: only line-ending whitespace may be escaped`,{toml:e,ptr:s});t=o(e,t)}else if(r in h)l+=h[r];else throw new n(`unrecognized escape sequence`,{toml:e,ptr:s});u=t}else !i&&r===`\\`&&(s=t-1,c=!0,l+=e.slice(u,s))}return l+e.slice(u,r-1)}function _(e,t,r,i){if(e===`true`)return!0;if(e===`false`)return!1;if(e===`-inf`)return-1/0;if(e===`inf`||e===`+inf`)return 1/0;if(e===`nan`||e===`+nan`||e===`-nan`)return NaN;if(e===`-0`)return i?0n:0;let a=d.test(e);if(a||f.test(e)){if(p.test(e))throw new n(`leading zeroes are not allowed`,{toml:t,ptr:r});e=e.replace(/_/g,``);let o=+e;if(isNaN(o))throw new n(`invalid number`,{toml:t,ptr:r});if(a){if((a=!Number.isSafeInteger(o))&&!i)throw new n(`integer value cannot be represented losslessly`,{toml:t,ptr:r});(a||i===!0)&&(o=BigInt(e))}return o}let o=new u(e);if(!o.isValid())throw new n(`invalid value`,{toml:t,ptr:r});return o}
/*!
* Copyright (c) Squirrel Chat et al., All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
function v(e,t,n){let r=e.slice(t,n),i=r.indexOf(`#`);return i>-1&&(a(e,i),r=r.slice(0,i)),[r.trimEnd(),i]}function y(e,t,r,i,a){if(i===0)throw new n(`document contains excessively nested structures. aborting.`,{toml:e,ptr:t});let l=e[t];if(l===`[`||l===`{`){let[s,c]=l===`[`?C(e,t,i,a):S(e,t,i,a);if(r){if(c=o(e,c),e[c]===`,`)c++;else if(e[c]!==r)throw new n(`expected comma or end of structure`,{toml:e,ptr:c})}return[s,c]}let u;if(l===`"`||l===`'`){u=c(e,t);let i=g(e,t,u);if(r){if(u=o(e,u),e[u]&&e[u]!==`,`&&e[u]!==r&&e[u]!==`
`&&e[u]!==`\r`)throw new n(`unexpected character encountered`,{toml:e,ptr:u});u+=+(e[u]===`,`)}return[i,u]}u=s(e,t,`,`,r);let d=v(e,t,u-+(e[u-1]===`,`));if(!d[0])throw new n(`incomplete key-value declaration: no value specified`,{toml:e,ptr:t});return r&&d[1]>-1&&(u=o(e,t+d[1]),u+=+(e[u]===`,`)),[_(d[0],e,t,a),u]}
/*!
* Copyright (c) Squirrel Chat et al., All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
let b=/^[a-zA-Z0-9-_]+[ \t]*$/;function x(e,t,r=`=`){let a=t-1,s=[],l=e.indexOf(r,t);if(l<0)throw new n(`incomplete key-value: cannot find end of key`,{toml:e,ptr:t});do{let o=e[t=++a];if(o!==` `&&o!==` `)if(o===`"`||o===`'`){if(o===e[t+1]&&o===e[t+2])throw new n(`multiline strings are not allowed in keys`,{toml:e,ptr:t});let u=c(e,t);if(u<0)throw new n(`unfinished string encountered`,{toml:e,ptr:t});a=e.indexOf(`.`,u);let d=e.slice(u,a<0||a>l?l:a),f=i(d);if(f>-1)throw new n(`newlines are not allowed in keys`,{toml:e,ptr:t+a+f});if(d.trimStart())throw new n(`found extra tokens after the string part`,{toml:e,ptr:u});if(l<u&&(l=e.indexOf(r,u),l<0))throw new n(`incomplete key-value: cannot find end of key`,{toml:e,ptr:t});s.push(g(e,t,u))}else{a=e.indexOf(`.`,t);let r=e.slice(t,a<0||a>l?l:a);if(!b.test(r))throw new n(`only letter, numbers, dashes and underscores are allowed in keys`,{toml:e,ptr:t});s.push(r.trimEnd())}}while(a+1&&a<l);return[s,o(e,l+1,!0,!0)]}function S(e,t,r,i){let o={},s=new Set,c;for(t++;(c=e[t++])!==`}`&&c;)if(c===`,`)throw new n(`expected value, found comma`,{toml:e,ptr:t-1});else if(c===`#`)t=a(e,t);else if(c!==` `&&c!==` `&&c!==`
`&&c!==`\r`){let a,c=o,l=!1,[u,d]=x(e,t-1);for(let r=0;r<u.length;r++){if(r&&(c=l?c[a]:c[a]={}),a=u[r],(l=Object.hasOwn(c,a))&&(typeof c[a]!=`object`||s.has(c[a])))throw new n(`trying to redefine an already defined value`,{toml:e,ptr:t});!l&&a===`__proto__`&&Object.defineProperty(c,a,{enumerable:!0,configurable:!0,writable:!0})}if(l)throw new n(`trying to redefine an already defined value`,{toml:e,ptr:t});let[f,p]=y(e,d,`}`,r-1,i);s.add(f),c[a]=f,t=p}if(!c)throw new n(`unfinished table encountered`,{toml:e,ptr:t});return[o,t]}function C(e,t,r,i){let o=[],s;for(t++;(s=e[t++])!==`]`&&s;)if(s===`,`)throw new n(`expected value, found comma`,{toml:e,ptr:t-1});else if(s===`#`)t=a(e,t);else if(s!==` `&&s!==` `&&s!==`
`&&s!==`\r`){let n=y(e,t-1,`]`,r-1,i);o.push(n[0]),t=n[1]}if(!s)throw new n(`unfinished array encountered`,{toml:e,ptr:t});return[o,t]}
/*!
* Copyright (c) Squirrel Chat et al., All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
function w(e,t,n,r){let i=t,a=n,o,s=!1,c;for(let t=0;t<e.length;t++){if(t){if(i=s?i[o]:i[o]={},a=(c=a[o]).c,r===0&&(c.t===1||c.t===2))return null;if(c.t===2){let e=i.length-1;i=i[e],a=a[e].c}}if(o=e[t],(s=Object.hasOwn(i,o))&&a[o]?.t===0&&a[o]?.d)return null;s||(o===`__proto__`&&(Object.defineProperty(i,o,{enumerable:!0,configurable:!0,writable:!0}),Object.defineProperty(a,o,{enumerable:!0,configurable:!0,writable:!0})),a[o]={t:t<e.length-1&&r===2?3:r,d:!1,i:0,c:{}})}if(c=a[o],c.t!==r&&!(r===1&&c.t===3)||(r===2&&(c.d||(c.d=!0,i[o]=[]),i[o].push(i={}),c.c[c.i++]=c={t:1,d:!1,i:0,c:{}}),c.d))return null;if(c.d=!0,r===1)i=s?i[o]:i[o]={};else if(r===0&&s)return null;return[o,i,c.c]}function T(e,{maxDepth:t=1e3,integersAsBigInt:r}={}){let i={},a={},s=i,c=a;for(let l=o(e,0);l<e.length;){if(e[l]===`[`){let t=e[++l]===`[`,r=x(e,l+=+t,`]`);if(t){if(e[r[1]-1]!==`]`)throw new n(`expected end of table declaration`,{toml:e,ptr:r[1]-1});r[1]++}let o=w(r[0],i,a,t?2:1);if(!o)throw new n(`trying to redefine an already defined table or value`,{toml:e,ptr:l});c=o[2],s=o[1],l=r[1]}else{let i=x(e,l),a=w(i[0],s,c,0);if(!a)throw new n(`trying to redefine an already defined table or value`,{toml:e,ptr:l});let o=y(e,i[1],void 0,t,r);a[1][a[0]]=o[0],l=o[1]}if(l=o(e,l,!0),e[l]&&e[l]!==`
`&&e[l]!==`\r`)throw new n(`each key-value declaration must be followed by an end-of-line`,{toml:e,ptr:l});l=o(e,l)}return i}
/*!
* Copyright (c) Squirrel Chat et al., All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
let E=/^[a-z0-9-_]+$/i;function D(e){let t=typeof e;if(t===`object`){if(Array.isArray(e))return`array`;if(e instanceof Date)return`date`}return t}function O(e){for(let t=0;t<e.length;t++)if(D(e[t])!==`object`)return!1;return e.length!=0}function k(e){return JSON.stringify(e).replace(/\x7f/g,`\\u007f`)}function A(e,t,n,r){if(n===0)throw Error(`Could not stringify the object: maximum object depth exceeded`);if(t===`number`)return isNaN(e)?`nan`:e===1/0?`inf`:e===-1/0?`-inf`:r&&Number.isInteger(e)?e.toFixed(1):e.toString();if(t===`bigint`||t===`boolean`)return e.toString();if(t===`string`)return k(e);if(t===`date`){if(isNaN(e.getTime()))throw TypeError(`cannot serialize invalid date`);return e.toISOString()}if(t===`object`)return j(e,n,r);if(t===`array`)return M(e,n,r)}function j(e,t,n){let r=Object.keys(e);if(r.length===0)return`{}`;let i=`{ `;for(let a=0;a<r.length;a++){let o=r[a];a&&(i+=`, `),i+=E.test(o)?o:k(o),i+=` = `,i+=A(e[o],D(e[o]),t-1,n)}return i+` }`}function M(e,t,n){if(e.length===0)return`[]`;let r=`[ `;for(let i=0;i<e.length;i++){if(i&&(r+=`, `),e[i]===null||e[i]===void 0)throw TypeError(`arrays cannot contain null or undefined values`);r+=A(e[i],D(e[i]),t-1,n)}return r+` ]`}function N(e,t,n,r){if(n===0)throw Error(`Could not stringify the object: maximum object depth exceeded`);let i=``;for(let a=0;a<e.length;a++)i+=`${i&&`
`}[[${t}]]\n`,i+=P(0,e[a],t,n,r);return i}function P(e,t,n,r,i){if(r===0)throw Error(`Could not stringify the object: maximum object depth exceeded`);let a=``,o=``,s=Object.keys(t);for(let e=0;e<s.length;e++){let c=s[e];if(t[c]!==null&&t[c]!==void 0){let e=D(t[c]);if(e===`symbol`||e===`function`)throw TypeError(`cannot serialize values of type '${e}'`);let s=E.test(c)?c:k(c);if(e===`array`&&O(t[c]))o+=(o&&`
`)+N(t[c],n?`${n}.${s}`:s,r-1,i);else if(e===`object`){let e=n?`${n}.${s}`:s;o+=(o&&`
`)+P(e,t[c],e,r-1,i)}else a+=s,a+=` = `,a+=A(t[c],e,r,i),a+=`
`}}return e&&(a||!o)&&(a=a?`[${e}]\n${a}`:`[${e}]`),a&&o?`${a}\n${o}`:a||o}function F(e,{maxDepth:t=1e3,numbersAsFloat:n=!1}={}){if(D(e)!==`object`)throw TypeError(`stringify can only be called with an object`);let r=P(0,e,``,t,n);return r[r.length-1]===`
`?r:r+`
`}export{T as n,F as t};
@@ -0,0 +1 @@
import"node:module";var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,a)=>(a=n==null?{}:e(i(n)),s(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));export{c as n,o as t};
+34
View File
@@ -0,0 +1,34 @@
import { t as FormatOptions } from "./_chunks/_format.mjs";
import { JSON5ParseOptions, JSON5StringifyOptions, parseJSON5, stringifyJSON5 } from "./json5.mjs";
import { JSONCParseError, JSONCParseOptions, parseJSONC, stringifyJSONC } from "./jsonc.mjs";
import { YAMLParseOptions, YAMLStringifyOptions, parseYAML, stringifyYAML } from "./yaml.mjs";
import { parseTOML, stringifyTOML } from "./toml.mjs";
import { INIParseOptions, INIStringifyOptions, parseINI, stringifyINI } from "./ini.mjs";
//#region src/json.d.ts
/**
* Converts a [JSON](https://www.json.org/json-en.html) string into an object.
*
* Indentation status is auto-detected and preserved when stringifying back using `stringifyJSON`
*/
declare function parseJSON<T = unknown>(text: string, options?: JSONParseOptions): T;
/**
* Converts a JavaScript value to a [JSON](https://www.json.org/json-en.html) string.
*
* Indentation status is auto detected and preserved when using value from parseJSON.
*/
declare function stringifyJSON(value: any, options?: JSONStringifyOptions): string;
interface JSONParseOptions extends FormatOptions {
/**
* A function that transforms the results. This function is called for each member of the object.
*/
reviver?: (this: any, key: string, value: any) => any;
}
interface JSONStringifyOptions extends FormatOptions {
/**
* A function that transforms the results. This function is called for each member of the object.
*/
replacer?: (this: any, key: string, value: any) => any;
}
//#endregion
export { type INIParseOptions, type INIStringifyOptions, type JSON5ParseOptions, type JSON5StringifyOptions, type JSONCParseError, type JSONCParseOptions, type JSONParseOptions, type JSONStringifyOptions, type YAMLParseOptions, type YAMLStringifyOptions, parseINI, parseJSON, parseJSON5, parseJSONC, parseTOML, parseYAML, stringifyINI, stringifyJSON, stringifyJSON5, stringifyJSONC, stringifyTOML, stringifyYAML };
+1
View File
@@ -0,0 +1 @@
import"./_chunks/rolldown-runtime.mjs";import"./_chunks/libs/json5.mjs";import{parseJSON5 as e,stringifyJSON5 as t}from"./json5.mjs";import"./_chunks/libs/jsonc-parser.mjs";import{n,t as r}from"./_chunks/json.mjs";import{parseJSONC as i,stringifyJSONC as a}from"./jsonc.mjs";import"./_chunks/libs/js-yaml.mjs";import{parseYAML as o,stringifyYAML as s}from"./yaml.mjs";import{parseTOML as c,stringifyTOML as l}from"./toml.mjs";import"./_chunks/libs/ini.mjs";import{parseINI as u,stringifyINI as d}from"./ini.mjs";export{u as parseINI,r as parseJSON,e as parseJSON5,i as parseJSONC,c as parseTOML,o as parseYAML,d as stringifyINI,n as stringifyJSON,t as stringifyJSON5,a as stringifyJSONC,l as stringifyTOML,s as stringifyYAML};
+62
View File
@@ -0,0 +1,62 @@
//#region src/ini.d.ts
/**
* Converts an [INI](https://www.ini.org/ini-en.html) string into an object.
*
* **Note:** Style and indentation are not preserved currently.
*/
declare function parseINI<T = unknown>(text: string, options?: INIParseOptions): T;
/**
* Converts a JavaScript value to an [INI](https://www.ini.org/ini-en.html) string.
*
* **Note:** Style and indentation are not preserved currently.
*/
declare function stringifyINI(value: any, options?: INIStringifyOptions): string;
interface INIParseOptions {
/**
* Whether to append `[]` to array keys.
*
* Some parsers treat duplicate names by themselves as arrays.
*/
bracketedArray?: boolean;
}
interface INIStringifyOptions {
/**
* Whether to insert spaces before & after `=` character.
* Enabled by default.
*/
whitespace?: boolean;
/**
* Whether to align the `=` character for each section.
*/
align?: boolean;
/**
* Identifier to use for global items
* and to prepend to all other sections.
*/
section?: string;
/**
* Whether to sort all sections & their keys alphabetically.
*/
sort?: boolean;
/**
* Whether to insert a newline after each section header.
*/
newline?: boolean;
/**
* Which platforms line-endings should be used.
*
* win32 -> CR+LF
* other -> LF
*
* Default is the current platform
*/
platform?: string;
/**
* Whether to append `[]` to array keys.
*
* Some parsers treat duplicate names by themselves as arrays
*/
bracketedArray?: boolean;
}
//#endregion
export { INIParseOptions, INIStringifyOptions, parseINI, stringifyINI };
+1
View File
@@ -0,0 +1 @@
import"./_chunks/rolldown-runtime.mjs";import{t as e}from"./_chunks/libs/ini.mjs";var t=e();function n(e,n){return(0,t.parse)(e,n)}function r(e,n){return(0,t.stringify)(e,{whitespace:!0,...n})}export{n as parseINI,r as stringifyINI};
+59
View File
@@ -0,0 +1,59 @@
import { t as FormatOptions } from "./_chunks/_format.mjs";
//#region src/json5.d.ts
/**
* Converts a [JSON5](https://json5.org/) string into an object.
*
* @template T The type of the return value.
* @param text The string to parse as JSON5.
* @param options Parsing options.
* @returns The JavaScript value converted from the JSON5 string.
*/
declare function parseJSON5<T = unknown>(text: string, options?: JSON5ParseOptions): T;
/**
* Converts a JavaScript value to a [JSON5](https://json5.org/) string.
*
* @param value
* @param options
* @returns The JSON string converted from the JavaScript value.
*/
declare function stringifyJSON5(value: any, options?: JSON5StringifyOptions): string;
interface JSON5ParseOptions extends FormatOptions {
/**
* A function that alters the behavior of the parsing process, or an array of
* String and Number objects that serve as a allowlist for selecting/filtering
* the properties of the value object to be included in the resulting
* JavaScript object. If this value is null or not provided, all properties of
* the object are included in the resulting JavaScript object.
*/
reviver?: (this: any, key: string, value: any) => any;
}
interface JSON5StringifyOptions extends FormatOptions {
/**
* A function that alters the behavior of the stringification process, or an
* array of String and Number objects that serve as a allowlist for
* selecting/filtering the properties of the value object to be included in
* the JSON5 string. If this value is null or not provided, all properties
* of the object are included in the resulting JSON5 string.
*/
replacer?: ((this: any, key: string, value: any) => any) | null;
/**
* A String or Number object that's used to insert white space into the
* output JSON5 string for readability purposes. If this is a Number, it
* indicates the number of space characters to use as white space; this
* number is capped at 10 (if it is greater, the value is just 10). Values
* less than 1 indicate that no space should be used. If this is a String,
* the string (or the first 10 characters of the string, if it's longer than
* that) is used as white space. If this parameter is not provided (or is
* null), no white space is used. If white space is used, trailing commas
* will be used in objects and arrays.
*/
space?: string | number | null;
/**
* A String representing the quote character to use when serializing
* strings.
*/
quote?: string | null;
}
//#endregion
export { JSON5ParseOptions, JSON5StringifyOptions, parseJSON5, stringifyJSON5 };
+1
View File
@@ -0,0 +1 @@
import{n as e}from"./_chunks/rolldown-runtime.mjs";import{n as t,t as n}from"./_chunks/_format.mjs";import{n as r,t as i}from"./_chunks/libs/json5.mjs";var a=e(r(),1),o=e(i(),1);function s(e,n){let r=(0,a.default)(e,n?.reviver);return t(e,r,n),r}function c(e,t){let r=n(e,t),i=(0,o.default)(e,t?.replacer,r.indent);return r.whitespace.start+i+r.whitespace.end}export{s as parseJSON5,c as stringifyJSON5};
+41
View File
@@ -0,0 +1,41 @@
import { t as FormatOptions } from "./_chunks/_format.mjs";
//#region src/jsonc.d.ts
/**
*
* Converts a [JSONC](https://github.com/microsoft/node-jsonc-parser) string into an object.
*
* @NOTE On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.
*
* @NOTE Comments and trailing commas are not preserved after parsing.
*
* @template T The type of the return value.
* @param text The string to parse as JSONC.
* @param options Parsing options.
* @returns The JavaScript value converted from the JSONC string.
*/
declare function parseJSONC<T = unknown>(text: string, options?: JSONCParseOptions): T;
/**
* Converts a JavaScript value to a [JSONC](https://github.com/microsoft/node-jsonc-parser) string.
*
* @NOTE Comments and trailing commas are not preserved in the output.
*
* @param value
* @param options
* @returns The JSON string converted from the JavaScript value.
*/
declare function stringifyJSONC(value: any, options?: JSONCStringifyOptions): string;
interface JSONCParseOptions extends FormatOptions {
disallowComments?: boolean;
allowTrailingComma?: boolean;
allowEmptyContent?: boolean;
errors?: JSONCParseError[];
}
interface JSONCStringifyOptions extends FormatOptions {}
interface JSONCParseError {
error: number;
offset: number;
length: number;
}
//#endregion
export { JSONCParseError, JSONCParseOptions, JSONCStringifyOptions, parseJSONC, stringifyJSONC };
+1
View File
@@ -0,0 +1 @@
import{n as e}from"./_chunks/_format.mjs";import{t}from"./_chunks/libs/jsonc-parser.mjs";import{n}from"./_chunks/json.mjs";function r(n,r){let i=t(n,r?.errors,r);return e(n,i,r),i}function i(e,t){return n(e,t)}export{r as parseJSONC,i as stringifyJSONC};
+23
View File
@@ -0,0 +1,23 @@
//#region src/toml.d.ts
/**
* Converts a [TOML](https://toml.io/) string into an object.
*
* @NOTE Comments and indentation is not preserved after parsing.
*
* @template T The type of the return value.
* @param text The TOML string to parse.
* @returns The JavaScript value converted from the TOML string.
*/
declare function parseTOML<T = unknown>(text: string): T;
/**
* Converts a JavaScript value to a [TOML](https://toml.io/) string.
*
* @NOTE Comments and indentation is not preserved in the output.
*
* @param value
* @param options
* @returns The YAML string converted from the JavaScript value.
*/
declare function stringifyTOML(value: any): string;
//#endregion
export { parseTOML, stringifyTOML };
+1
View File
@@ -0,0 +1 @@
import{n as e,t}from"./_chunks/_format.mjs";import{n,t as r}from"./_chunks/libs/smol-toml.mjs";function i(t){let r=n(t);return e(t,r,{preserveIndentation:!1}),r}function a(e){let n=t(e,{preserveIndentation:!1}),i=r(e);return n.whitespace.start+i+n.whitespace.end}export{i as parseTOML,a as stringifyTOML};
+96
View File
@@ -0,0 +1,96 @@
import { t as FormatOptions } from "./_chunks/_format.mjs";
//#region src/yaml.d.ts
/**
* Converts a [YAML](https://yaml.org/) string into an object.
*
* @NOTE This function does **not** understand multi-document sources, it throws exception on those.
*
* @NOTE Comments are not preserved after parsing.
*
* @NOTE This function does **not** support schema-specific tag resolution restrictions.
* So, the JSON schema is not as strictly defined in the YAML specification.
* It allows numbers in any notation, use `Null` and `NULL` as `null`, etc.
* The core schema also has no such restrictions. It allows binary notation for integers.
*
* @template T The type of the return value.
* @param text The YAML string to parse.
* @param options Parsing options.
* @returns The JavaScript value converted from the YAML string.
*/
declare function parseYAML<T = unknown>(text: string, options?: YAMLParseOptions): T;
/**
* Converts a JavaScript value to a [YAML](https://yaml.org/) string.
*
* @NOTE Comments are not preserved in the output.
*
* @param value
* @param options
* @returns The YAML string converted from the JavaScript value.
*/
declare function stringifyYAML(value: any, options?: YAMLStringifyOptions): string;
interface YAMLParseOptions extends FormatOptions {
/** string to be used as a file path in error/warning messages. */
filename?: string | undefined;
/** function to call on warning messages. */
onWarning?(this: null, e: YAMLException): void;
/** specifies a schema to use. */
schema?: any | undefined;
/** compatibility with JSON.parse behaviour. */
json?: boolean | undefined;
/** listener for parse events */
listener?(this: any, eventType: any, state: any): void;
}
interface YAMLStringifyOptions extends FormatOptions {
/** indentation width to use (in spaces). */
indent?: number | undefined;
/** when true, will not add an indentation level to array elements */
noArrayIndent?: boolean | undefined;
/** do not throw on invalid types (like function in the safe schema) and skip pairs and single values with such types. */
skipInvalid?: boolean | undefined;
/** specifies level of nesting, when to switch from block to flow style for collections. -1 means block style everwhere */
flowLevel?: number | undefined;
/** Each tag may have own set of styles. - "tag" => "style" map. */
styles?: {
[x: string]: any;
} | undefined;
/** specifies a schema to use. */
schema?: any | undefined;
/** if true, sort keys when dumping YAML. If a function, use the function to sort the keys. (default: false) */
sortKeys?: boolean | ((a: any, b: any) => number) | undefined;
/** set max line width. (default: 80) */
lineWidth?: number | undefined;
/** if true, don't convert duplicate objects into references (default: false) */
noRefs?: boolean | undefined;
/** if true don't try to be compatible with older yaml versions. Currently: don't quote "yes", "no" and so on, as required for YAML 1.1 (default: false) */
noCompatMode?: boolean | undefined;
/**
* if true flow sequences will be condensed, omitting the space between `key: value` or `a, b`. Eg. `'[a,b]'` or `{a:{b:c}}`.
* Can be useful when using yaml for pretty URL query params as spaces are %-encoded. (default: false).
*/
condenseFlow?: boolean | undefined;
/** strings will be quoted using this quoting style. If you specify single quotes, double quotes will still be used for non-printable characters. (default: `'`) */
quotingType?: "'" | '"' | undefined;
/** if true, all non-key strings will be quoted even if they normally don't need to. (default: false) */
forceQuotes?: boolean | undefined;
/** callback `function (key, value)` called recursively on each key/value in source object (see `replacer` docs for `JSON.stringify`). */
replacer?: ((key: string, value: any) => any) | undefined;
}
interface Mark {
buffer: string;
column: number;
line: number;
name: string;
position: number;
snippet: string;
}
declare class YAMLException extends Error {
constructor(reason?: string, mark?: Mark);
toString(compact?: boolean): string;
name: string;
reason: string;
message: string;
mark: Mark;
}
//#endregion
export { YAMLParseOptions, YAMLStringifyOptions, parseYAML, stringifyYAML };
+1
View File
@@ -0,0 +1 @@
import{n as e,t}from"./_chunks/_format.mjs";import{n,t as r}from"./_chunks/libs/js-yaml.mjs";function i(t,r){let i=n(t,r);return e(t,i,r),i}function a(e,n){let i=t(e,{preserveIndentation:!1}),a=r(e,{indent:typeof i.indent==`string`?i.indent.length:i.indent,...n});return i.whitespace.start+a.trim()+i.whitespace.end}export{i as parseYAML,a as stringifyYAML};
+67
View File
@@ -0,0 +1,67 @@
{
"name": "confbox",
"version": "0.2.4",
"description": "Compact YAML, TOML, JSONC, JSON5 and INI parser and serializer",
"keywords": [
"config",
"ini",
"json5",
"jsonc",
"toml",
"unjs",
"yaml"
],
"license": "MIT",
"repository": "unjs/confbox",
"files": [
"dist"
],
"type": "module",
"sideEffects": false,
"types": "./dist/index.d.mts",
"exports": {
".": "./dist/index.mjs",
"./ini": "./dist/ini.mjs",
"./json5": "./dist/json5.mjs",
"./jsonc": "./dist/jsonc.mjs",
"./toml": "./dist/toml.mjs",
"./yaml": "./dist/yaml.mjs"
},
"scripts": {
"build": "obuild",
"dev": "vitest dev --coverage",
"bench": "pnpm build && node test/bench.mjs",
"lint": "oxlint && oxfmt --check src test",
"lint:fix": "oxlint --fix && oxfmt src test",
"prepack": "pnpm build",
"release": "pnpm test && pnpm build && changelogen --release && npm publish && git push --follow-tags",
"test": "pnpm lint && pnpm test:types && vitest run --coverage",
"test:types": "tsgo --noEmit --skipLibCheck"
},
"devDependencies": {
"@types/ini": "^4.1.1",
"@types/js-yaml": "^4.0.9",
"@types/node": "^25.2.1",
"@typescript/native-preview": "7.0.0-dev.20260206.1",
"@vitest/coverage-v8": "^4.0.18",
"automd": "^0.4.3",
"changelogen": "^0.6.2",
"detect-indent": "^7.0.2",
"ini": "^6.0.0",
"jiti": "^2.6.1",
"js-toml": "^1.0.2",
"js-yaml": "^4.1.1",
"json5": "^2.2.3",
"jsonc-parser": "^3.3.1",
"mitata": "^1.0.34",
"obuild": "^0.4.26",
"oxfmt": "^0.28.0",
"oxlint": "^1.43.0",
"smol-toml": "^1.6.0",
"toml": "^3.0.0",
"typescript": "^5.9.3",
"vitest": "^4.0.18",
"yaml": "^2.8.2"
},
"packageManager": "pnpm@10.28.2"
}
+16
View File
@@ -0,0 +1,16 @@
/**
Escape RegExp special characters.
You can also use this to escape a string that is inserted into the middle of a regex, for example, into a character class.
@example
```
import escapeStringRegexp from 'escape-string-regexp';
const escapedString = escapeStringRegexp('How much $ for a 🦄?');
//=> 'How much \\$ for a 🦄\\?'
new RegExp(escapedString);
```
*/
export default function escapeStringRegexp(string: string): string;
+11
View File
@@ -0,0 +1,11 @@
export default function escapeStringRegexp(string) {
if (typeof string !== 'string') {
throw new TypeError('Expected a string');
}
// Escape characters with special meaning either inside or outside character sets.
// Use a simple backslash escape when its always valid, and a `\xnn` escape when the simpler form would be disallowed by Unicode patterns stricter grammar.
return string
.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
.replace(/-/g, '\\x2d');
}
+9
View File
@@ -0,0 +1,9 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
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.
+40
View File
@@ -0,0 +1,40 @@
{
"name": "escape-string-regexp",
"version": "5.0.0",
"description": "Escape RegExp special characters",
"license": "MIT",
"repository": "sindresorhus/escape-string-regexp",
"funding": "https://github.com/sponsors/sindresorhus",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "https://sindresorhus.com"
},
"type": "module",
"exports": "./index.js",
"engines": {
"node": ">=12"
},
"scripts": {
"test": "xo && ava && tsd"
},
"files": [
"index.js",
"index.d.ts"
],
"keywords": [
"escape",
"regex",
"regexp",
"regular",
"expression",
"string",
"special",
"characters"
],
"devDependencies": {
"ava": "^3.15.0",
"tsd": "^0.14.0",
"xo": "^0.38.2"
}
}
+34
View File
@@ -0,0 +1,34 @@
# escape-string-regexp
> Escape RegExp special characters
## Install
```
$ npm install escape-string-regexp
```
## Usage
```js
import escapeStringRegexp from 'escape-string-regexp';
const escapedString = escapeStringRegexp('How much $ for a 🦄?');
//=> 'How much \\$ for a 🦄\\?'
new RegExp(escapedString);
```
You can also use this to escape a string that is inserted into the middle of a regex, for example, into a character class.
---
<div align="center">
<b>
<a href="https://tidelift.com/subscription/pkg/npm-escape-string-regexp?utm_source=npm-escape-string-regexp&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
</b>
<br>
<sub>
Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
</sub>
</div>
+7
View File
@@ -0,0 +1,7 @@
Copyright (c) 2015-20 [these people](https://github.com/Rich-Harris/estree-walker/graphs/contributors)
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.
+48
View File
@@ -0,0 +1,48 @@
# estree-walker
Simple utility for walking an [ESTree](https://github.com/estree/estree)-compliant AST, such as one generated by [acorn](https://github.com/marijnh/acorn).
## Installation
```bash
npm i estree-walker
```
## Usage
```js
var walk = require('estree-walker').walk;
var acorn = require('acorn');
ast = acorn.parse(sourceCode, options); // https://github.com/acornjs/acorn
walk(ast, {
enter(node, parent, prop, index) {
// some code happens
},
leave(node, parent, prop, index) {
// some code happens
}
});
```
Inside the `enter` function, calling `this.skip()` will prevent the node's children being walked, or the `leave` function (which is optional) being called.
Call `this.replace(new_node)` in either `enter` or `leave` to replace the current node with a new one.
Call `this.remove()` in either `enter` or `leave` to remove the current node.
## Why not use estraverse?
The ESTree spec is evolving to accommodate ES6/7. I've had a couple of experiences where [estraverse](https://github.com/estools/estraverse) was unable to handle an AST generated by recent versions of acorn, because it hard-codes visitor keys.
estree-walker, by contrast, simply enumerates a node's properties to find child nodes (and child lists of nodes), and is therefore resistant to spec changes. It's also much smaller. (The performance, if you're wondering, is basically identical.)
None of which should be taken as criticism of estraverse, which has more features and has been battle-tested in many more situations, and for which I'm very grateful.
## License
MIT
+38
View File
@@ -0,0 +1,38 @@
{
"name": "estree-walker",
"description": "Traverse an ESTree-compliant AST",
"version": "3.0.3",
"private": false,
"author": "Rich Harris",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/Rich-Harris/estree-walker"
},
"type": "module",
"module": "./src/index.js",
"exports": {
"./package.json": "./package.json",
".": {
"types": "./types/index.d.ts",
"import": "./src/index.js"
}
},
"types": "types/index.d.ts",
"scripts": {
"prepublishOnly": "tsc && npm test",
"test": "uvu test"
},
"dependencies": {
"@types/estree": "^1.0.0"
},
"devDependencies": {
"typescript": "^4.9.0",
"uvu": "^0.5.1"
},
"files": [
"src",
"types",
"README.md"
]
}
+152
View File
@@ -0,0 +1,152 @@
import { WalkerBase } from './walker.js';
/**
* @typedef { import('estree').Node} Node
* @typedef { import('./walker.js').WalkerContext} WalkerContext
* @typedef {(
* this: WalkerContext,
* node: Node,
* parent: Node | null,
* key: string | number | symbol | null | undefined,
* index: number | null | undefined
* ) => Promise<void>} AsyncHandler
*/
export class AsyncWalker extends WalkerBase {
/**
*
* @param {AsyncHandler} [enter]
* @param {AsyncHandler} [leave]
*/
constructor(enter, leave) {
super();
/** @type {boolean} */
this.should_skip = false;
/** @type {boolean} */
this.should_remove = false;
/** @type {Node | null} */
this.replacement = null;
/** @type {WalkerContext} */
this.context = {
skip: () => (this.should_skip = true),
remove: () => (this.should_remove = true),
replace: (node) => (this.replacement = node)
};
/** @type {AsyncHandler | undefined} */
this.enter = enter;
/** @type {AsyncHandler | undefined} */
this.leave = leave;
}
/**
* @template {Node} Parent
* @param {Node} node
* @param {Parent | null} parent
* @param {keyof Parent} [prop]
* @param {number | null} [index]
* @returns {Promise<Node | null>}
*/
async visit(node, parent, prop, index) {
if (node) {
if (this.enter) {
const _should_skip = this.should_skip;
const _should_remove = this.should_remove;
const _replacement = this.replacement;
this.should_skip = false;
this.should_remove = false;
this.replacement = null;
await this.enter.call(this.context, node, parent, prop, index);
if (this.replacement) {
node = this.replacement;
this.replace(parent, prop, index, node);
}
if (this.should_remove) {
this.remove(parent, prop, index);
}
const skipped = this.should_skip;
const removed = this.should_remove;
this.should_skip = _should_skip;
this.should_remove = _should_remove;
this.replacement = _replacement;
if (skipped) return node;
if (removed) return null;
}
/** @type {keyof Node} */
let key;
for (key in node) {
/** @type {unknown} */
const value = node[key];
if (value && typeof value === 'object') {
if (Array.isArray(value)) {
const nodes = /** @type {Array<unknown>} */ (value);
for (let i = 0; i < nodes.length; i += 1) {
const item = nodes[i];
if (isNode(item)) {
if (!(await this.visit(item, node, key, i))) {
// removed
i--;
}
}
}
} else if (isNode(value)) {
await this.visit(value, node, key, null);
}
}
}
if (this.leave) {
const _replacement = this.replacement;
const _should_remove = this.should_remove;
this.replacement = null;
this.should_remove = false;
await this.leave.call(this.context, node, parent, prop, index);
if (this.replacement) {
node = this.replacement;
this.replace(parent, prop, index, node);
}
if (this.should_remove) {
this.remove(parent, prop, index);
}
const removed = this.should_remove;
this.replacement = _replacement;
this.should_remove = _should_remove;
if (removed) return null;
}
}
return node;
}
}
/**
* Ducktype a node.
*
* @param {unknown} value
* @returns {value is Node}
*/
function isNode(value) {
return (
value !== null && typeof value === 'object' && 'type' in value && typeof value.type === 'string'
);
}
+34
View File
@@ -0,0 +1,34 @@
import { SyncWalker } from './sync.js';
import { AsyncWalker } from './async.js';
/**
* @typedef {import('estree').Node} Node
* @typedef {import('./sync.js').SyncHandler} SyncHandler
* @typedef {import('./async.js').AsyncHandler} AsyncHandler
*/
/**
* @param {Node} ast
* @param {{
* enter?: SyncHandler
* leave?: SyncHandler
* }} walker
* @returns {Node | null}
*/
export function walk(ast, { enter, leave }) {
const instance = new SyncWalker(enter, leave);
return instance.visit(ast, null);
}
/**
* @param {Node} ast
* @param {{
* enter?: AsyncHandler
* leave?: AsyncHandler
* }} walker
* @returns {Promise<Node | null>}
*/
export async function asyncWalk(ast, { enter, leave }) {
const instance = new AsyncWalker(enter, leave);
return await instance.visit(ast, null);
}
+152
View File
@@ -0,0 +1,152 @@
import { WalkerBase } from './walker.js';
/**
* @typedef { import('estree').Node} Node
* @typedef { import('./walker.js').WalkerContext} WalkerContext
* @typedef {(
* this: WalkerContext,
* node: Node,
* parent: Node | null,
* key: string | number | symbol | null | undefined,
* index: number | null | undefined
* ) => void} SyncHandler
*/
export class SyncWalker extends WalkerBase {
/**
*
* @param {SyncHandler} [enter]
* @param {SyncHandler} [leave]
*/
constructor(enter, leave) {
super();
/** @type {boolean} */
this.should_skip = false;
/** @type {boolean} */
this.should_remove = false;
/** @type {Node | null} */
this.replacement = null;
/** @type {WalkerContext} */
this.context = {
skip: () => (this.should_skip = true),
remove: () => (this.should_remove = true),
replace: (node) => (this.replacement = node)
};
/** @type {SyncHandler | undefined} */
this.enter = enter;
/** @type {SyncHandler | undefined} */
this.leave = leave;
}
/**
* @template {Node} Parent
* @param {Node} node
* @param {Parent | null} parent
* @param {keyof Parent} [prop]
* @param {number | null} [index]
* @returns {Node | null}
*/
visit(node, parent, prop, index) {
if (node) {
if (this.enter) {
const _should_skip = this.should_skip;
const _should_remove = this.should_remove;
const _replacement = this.replacement;
this.should_skip = false;
this.should_remove = false;
this.replacement = null;
this.enter.call(this.context, node, parent, prop, index);
if (this.replacement) {
node = this.replacement;
this.replace(parent, prop, index, node);
}
if (this.should_remove) {
this.remove(parent, prop, index);
}
const skipped = this.should_skip;
const removed = this.should_remove;
this.should_skip = _should_skip;
this.should_remove = _should_remove;
this.replacement = _replacement;
if (skipped) return node;
if (removed) return null;
}
/** @type {keyof Node} */
let key;
for (key in node) {
/** @type {unknown} */
const value = node[key];
if (value && typeof value === 'object') {
if (Array.isArray(value)) {
const nodes = /** @type {Array<unknown>} */ (value);
for (let i = 0; i < nodes.length; i += 1) {
const item = nodes[i];
if (isNode(item)) {
if (!this.visit(item, node, key, i)) {
// removed
i--;
}
}
}
} else if (isNode(value)) {
this.visit(value, node, key, null);
}
}
}
if (this.leave) {
const _replacement = this.replacement;
const _should_remove = this.should_remove;
this.replacement = null;
this.should_remove = false;
this.leave.call(this.context, node, parent, prop, index);
if (this.replacement) {
node = this.replacement;
this.replace(parent, prop, index, node);
}
if (this.should_remove) {
this.remove(parent, prop, index);
}
const removed = this.should_remove;
this.replacement = _replacement;
this.should_remove = _should_remove;
if (removed) return null;
}
}
return node;
}
}
/**
* Ducktype a node.
*
* @param {unknown} value
* @returns {value is Node}
*/
function isNode(value) {
return (
value !== null && typeof value === 'object' && 'type' in value && typeof value.type === 'string'
);
}
+61
View File
@@ -0,0 +1,61 @@
/**
* @typedef { import('estree').Node} Node
* @typedef {{
* skip: () => void;
* remove: () => void;
* replace: (node: Node) => void;
* }} WalkerContext
*/
export class WalkerBase {
constructor() {
/** @type {boolean} */
this.should_skip = false;
/** @type {boolean} */
this.should_remove = false;
/** @type {Node | null} */
this.replacement = null;
/** @type {WalkerContext} */
this.context = {
skip: () => (this.should_skip = true),
remove: () => (this.should_remove = true),
replace: (node) => (this.replacement = node)
};
}
/**
* @template {Node} Parent
* @param {Parent | null | undefined} parent
* @param {keyof Parent | null | undefined} prop
* @param {number | null | undefined} index
* @param {Node} node
*/
replace(parent, prop, index, node) {
if (parent && prop) {
if (index != null) {
/** @type {Array<Node>} */ (parent[prop])[index] = node;
} else {
/** @type {Node} */ (parent[prop]) = node;
}
}
}
/**
* @template {Node} Parent
* @param {Parent | null | undefined} parent
* @param {keyof Parent | null | undefined} prop
* @param {number | null | undefined} index
*/
remove(parent, prop, index) {
if (parent && prop) {
if (index !== null && index !== undefined) {
/** @type {Array<Node>} */ (parent[prop]).splice(index, 1);
} else {
delete parent[prop];
}
}
}
}
+36
View File
@@ -0,0 +1,36 @@
/**
* @typedef { import('estree').Node} Node
* @typedef { import('./walker.js').WalkerContext} WalkerContext
* @typedef {(
* this: WalkerContext,
* node: Node,
* parent: Node | null,
* key: string | number | symbol | null | undefined,
* index: number | null | undefined
* ) => Promise<void>} AsyncHandler
*/
export class AsyncWalker extends WalkerBase {
/**
*
* @param {AsyncHandler} [enter]
* @param {AsyncHandler} [leave]
*/
constructor(enter?: AsyncHandler | undefined, leave?: AsyncHandler | undefined);
/** @type {AsyncHandler | undefined} */
enter: AsyncHandler | undefined;
/** @type {AsyncHandler | undefined} */
leave: AsyncHandler | undefined;
/**
* @template {Node} Parent
* @param {Node} node
* @param {Parent | null} parent
* @param {keyof Parent} [prop]
* @param {number | null} [index]
* @returns {Promise<Node | null>}
*/
visit<Parent extends import("estree").Node>(node: Node, parent: Parent | null, prop?: keyof Parent | undefined, index?: number | null | undefined): Promise<Node | null>;
}
export type Node = import('estree').Node;
export type WalkerContext = import('./walker.js').WalkerContext;
export type AsyncHandler = (this: WalkerContext, node: Node, parent: Node | null, key: string | number | symbol | null | undefined, index: number | null | undefined) => Promise<void>;
import { WalkerBase } from "./walker.js";
+32
View File
@@ -0,0 +1,32 @@
/**
* @typedef {import('estree').Node} Node
* @typedef {import('./sync.js').SyncHandler} SyncHandler
* @typedef {import('./async.js').AsyncHandler} AsyncHandler
*/
/**
* @param {Node} ast
* @param {{
* enter?: SyncHandler
* leave?: SyncHandler
* }} walker
* @returns {Node | null}
*/
export function walk(ast: Node, { enter, leave }: {
enter?: SyncHandler;
leave?: SyncHandler;
}): Node | null;
/**
* @param {Node} ast
* @param {{
* enter?: AsyncHandler
* leave?: AsyncHandler
* }} walker
* @returns {Promise<Node | null>}
*/
export function asyncWalk(ast: Node, { enter, leave }: {
enter?: AsyncHandler;
leave?: AsyncHandler;
}): Promise<Node | null>;
export type Node = import('estree').Node;
export type SyncHandler = import('./sync.js').SyncHandler;
export type AsyncHandler = import('./async.js').AsyncHandler;
+36
View File
@@ -0,0 +1,36 @@
/**
* @typedef { import('estree').Node} Node
* @typedef { import('./walker.js').WalkerContext} WalkerContext
* @typedef {(
* this: WalkerContext,
* node: Node,
* parent: Node | null,
* key: string | number | symbol | null | undefined,
* index: number | null | undefined
* ) => void} SyncHandler
*/
export class SyncWalker extends WalkerBase {
/**
*
* @param {SyncHandler} [enter]
* @param {SyncHandler} [leave]
*/
constructor(enter?: SyncHandler | undefined, leave?: SyncHandler | undefined);
/** @type {SyncHandler | undefined} */
enter: SyncHandler | undefined;
/** @type {SyncHandler | undefined} */
leave: SyncHandler | undefined;
/**
* @template {Node} Parent
* @param {Node} node
* @param {Parent | null} parent
* @param {keyof Parent} [prop]
* @param {number | null} [index]
* @returns {Node | null}
*/
visit<Parent extends import("estree").Node>(node: Node, parent: Parent | null, prop?: keyof Parent | undefined, index?: number | null | undefined): Node | null;
}
export type Node = import('estree').Node;
export type WalkerContext = import('./walker.js').WalkerContext;
export type SyncHandler = (this: WalkerContext, node: Node, parent: Node | null, key: string | number | symbol | null | undefined, index: number | null | undefined) => void;
import { WalkerBase } from "./walker.js";
+39
View File
@@ -0,0 +1,39 @@
/**
* @typedef { import('estree').Node} Node
* @typedef {{
* skip: () => void;
* remove: () => void;
* replace: (node: Node) => void;
* }} WalkerContext
*/
export class WalkerBase {
/** @type {boolean} */
should_skip: boolean;
/** @type {boolean} */
should_remove: boolean;
/** @type {Node | null} */
replacement: Node | null;
/** @type {WalkerContext} */
context: WalkerContext;
/**
* @template {Node} Parent
* @param {Parent | null | undefined} parent
* @param {keyof Parent | null | undefined} prop
* @param {number | null | undefined} index
* @param {Node} node
*/
replace<Parent extends import("estree").Node>(parent: Parent | null | undefined, prop: keyof Parent | null | undefined, index: number | null | undefined, node: Node): void;
/**
* @template {Node} Parent
* @param {Parent | null | undefined} parent
* @param {keyof Parent | null | undefined} prop
* @param {number | null | undefined} index
*/
remove<Parent_1 extends import("estree").Node>(parent: Parent_1 | null | undefined, prop: keyof Parent_1 | null | undefined, index: number | null | undefined): void;
}
export type Node = import('estree').Node;
export type WalkerContext = {
skip: () => void;
remove: () => void;
replace: (node: Node) => void;
};
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Anthony Fu <https://github.com/antfu>
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.
+55
View File
@@ -0,0 +1,55 @@
# local-pkg
[![NPM version](https://img.shields.io/npm/v/local-pkg?color=a1b858&label=)](https://www.npmjs.com/package/local-pkg)
Get information on local packages. Works on both CJS and ESM.
## Install
```bash
npm i local-pkg
```
## Usage
```ts
import {
getPackageInfo,
importModule,
isPackageExists,
resolveModule,
} from 'local-pkg'
isPackageExists('local-pkg') // true
isPackageExists('foo') // false
await getPackageInfo('local-pkg')
/* {
* name: "local-pkg",
* version: "0.1.0",
* rootPath: "/path/to/node_modules/local-pkg",
* packageJson: {
* ...
* }
* }
*/
// similar to `require.resolve` but works also in ESM
resolveModule('local-pkg')
// '/path/to/node_modules/local-pkg/dist/index.cjs'
// similar to `await import()` but works also in CJS
const { importModule } = await importModule('local-pkg')
```
## Sponsors
<p align="center">
<a href="https://cdn.jsdelivr.net/gh/antfu/static/sponsors.svg">
<img src='https://cdn.jsdelivr.net/gh/antfu/static/sponsors.svg'/>
</a>
</p>
## License
[MIT](./LICENSE) License © 2021 [Anthony Fu](https://github.com/antfu)
+190
View File
@@ -0,0 +1,190 @@
'use strict';
const fs = require('node:fs');
const node_module = require('node:module');
const path = require('node:path');
const process = require('node:process');
const fsPromises = require('node:fs/promises');
const node_url = require('node:url');
const mlly = require('mlly');
const macro = require('quansync/macro');
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
const process__default = /*#__PURE__*/_interopDefaultCompat(process);
const fsPromises__default = /*#__PURE__*/_interopDefaultCompat(fsPromises);
const toPath = urlOrPath => urlOrPath instanceof URL ? node_url.fileURLToPath(urlOrPath) : urlOrPath;
async function findUp$1(name, {
cwd = process__default.cwd(),
type = 'file',
stopAt,
} = {}) {
let directory = path__default.resolve(toPath(cwd) ?? '');
const {root} = path__default.parse(directory);
stopAt = path__default.resolve(directory, toPath(stopAt ?? root));
const isAbsoluteName = path__default.isAbsolute(name);
while (directory) {
const filePath = isAbsoluteName ? name : path__default.join(directory, name);
try {
const stats = await fsPromises__default.stat(filePath); // eslint-disable-line no-await-in-loop
if ((type === 'file' && stats.isFile()) || (type === 'directory' && stats.isDirectory())) {
return filePath;
}
} catch {}
if (directory === stopAt || directory === root) {
break;
}
directory = path__default.dirname(directory);
}
}
function findUpSync(name, {
cwd = process__default.cwd(),
type = 'file',
stopAt,
} = {}) {
let directory = path__default.resolve(toPath(cwd) ?? '');
const {root} = path__default.parse(directory);
stopAt = path__default.resolve(directory, toPath(stopAt) ?? root);
const isAbsoluteName = path__default.isAbsolute(name);
while (directory) {
const filePath = isAbsoluteName ? name : path__default.join(directory, name);
try {
const stats = fs__default.statSync(filePath, {throwIfNoEntry: false});
if ((type === 'file' && stats?.isFile()) || (type === 'directory' && stats?.isDirectory())) {
return filePath;
}
} catch {}
if (directory === stopAt || directory === root) {
break;
}
directory = path__default.dirname(directory);
}
}
function _resolve(path$1, options = {}) {
if (options.platform === "auto" || !options.platform)
options.platform = process__default.platform === "win32" ? "win32" : "posix";
if (process__default.versions.pnp) {
const paths = options.paths || [];
if (paths.length === 0)
paths.push(process__default.cwd());
const targetRequire = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
try {
return targetRequire.resolve(path$1, { paths });
} catch {
}
}
const modulePath = mlly.resolvePathSync(path$1, {
url: options.paths
});
if (options.platform === "win32")
return path.win32.normalize(modulePath);
return modulePath;
}
function resolveModule(name, options = {}) {
try {
return _resolve(name, options);
} catch {
return void 0;
}
}
async function importModule(path) {
const i = await import(path);
if (i)
return mlly.interopDefault(i);
return i;
}
function isPackageExists(name, options = {}) {
return !!resolvePackage(name, options);
}
function getPackageJsonPath(name, options = {}) {
const entry = resolvePackage(name, options);
if (!entry)
return;
return searchPackageJSON(entry);
}
const readFile = macro.quansync({
async: (id) => fs__default.promises.readFile(id, "utf8"),
sync: (id) => fs__default.readFileSync(id, "utf8")
});
const getPackageInfo = macro.quansync(function* (name, options = {}) {
const packageJsonPath = getPackageJsonPath(name, options);
if (!packageJsonPath)
return;
const packageJson = JSON.parse(yield readFile(packageJsonPath));
return {
name,
version: packageJson.version,
rootPath: path.dirname(packageJsonPath),
packageJsonPath,
packageJson
};
});
const getPackageInfoSync = getPackageInfo.sync;
function resolvePackage(name, options = {}) {
try {
return _resolve(`${name}/package.json`, options);
} catch {
}
try {
return _resolve(name, options);
} catch (e) {
if (e.code !== "MODULE_NOT_FOUND" && e.code !== "ERR_MODULE_NOT_FOUND")
console.error(e);
return false;
}
}
function searchPackageJSON(dir) {
let packageJsonPath;
while (true) {
if (!dir)
return;
const newDir = path.dirname(dir);
if (newDir === dir)
return;
dir = newDir;
packageJsonPath = path.join(dir, "package.json");
if (fs__default.existsSync(packageJsonPath))
break;
}
return packageJsonPath;
}
const findUp = macro.quansync({
sync: findUpSync,
async: findUp$1
});
const loadPackageJSON = macro.quansync(function* (cwd = process__default.cwd()) {
const path = yield findUp("package.json", { cwd });
if (!path || !fs__default.existsSync(path))
return null;
return JSON.parse(yield readFile(path));
});
const loadPackageJSONSync = loadPackageJSON.sync;
const isPackageListed = macro.quansync(function* (name, cwd) {
const pkg = (yield loadPackageJSON(cwd)) || {};
return name in (pkg.dependencies || {}) || name in (pkg.devDependencies || {});
});
const isPackageListedSync = isPackageListed.sync;
exports.getPackageInfo = getPackageInfo;
exports.getPackageInfoSync = getPackageInfoSync;
exports.importModule = importModule;
exports.isPackageExists = isPackageExists;
exports.isPackageListed = isPackageListed;
exports.isPackageListedSync = isPackageListedSync;
exports.loadPackageJSON = loadPackageJSON;
exports.loadPackageJSONSync = loadPackageJSONSync;
exports.resolveModule = resolveModule;
+42
View File
@@ -0,0 +1,42 @@
import * as quansync_types from 'quansync/types';
import { PackageJson } from 'pkg-types';
interface PackageInfo {
name: string;
rootPath: string;
packageJsonPath: string;
version: string;
packageJson: PackageJson;
}
interface PackageResolvingOptions {
paths?: string[];
/**
* @default 'auto'
* Resolve path as posix or win32
*/
platform?: 'posix' | 'win32' | 'auto';
}
declare function resolveModule(name: string, options?: PackageResolvingOptions): string | undefined;
declare function importModule<T = any>(path: string): Promise<T>;
declare function isPackageExists(name: string, options?: PackageResolvingOptions): boolean;
declare const getPackageInfo: quansync_types.QuansyncFn<{
name: string;
version: string | undefined;
rootPath: string;
packageJsonPath: string;
packageJson: PackageJson;
} | undefined, [name: string, options?: PackageResolvingOptions | undefined]>;
declare const getPackageInfoSync: (name: string, options?: PackageResolvingOptions | undefined) => {
name: string;
version: string | undefined;
rootPath: string;
packageJsonPath: string;
packageJson: PackageJson;
} | undefined;
declare const loadPackageJSON: quansync_types.QuansyncFn<PackageJson | null, [cwd?: Args[0] | undefined]>;
declare const loadPackageJSONSync: (cwd?: Args[0] | undefined) => PackageJson | null;
declare const isPackageListed: quansync_types.QuansyncFn<boolean, [name: string, cwd?: string | undefined]>;
declare const isPackageListedSync: (name: string, cwd?: string | undefined) => boolean;
export { getPackageInfo, getPackageInfoSync, importModule, isPackageExists, isPackageListed, isPackageListedSync, loadPackageJSON, loadPackageJSONSync, resolveModule };
export type { PackageInfo, PackageResolvingOptions };
+42
View File
@@ -0,0 +1,42 @@
import * as quansync_types from 'quansync/types';
import { PackageJson } from 'pkg-types';
interface PackageInfo {
name: string;
rootPath: string;
packageJsonPath: string;
version: string;
packageJson: PackageJson;
}
interface PackageResolvingOptions {
paths?: string[];
/**
* @default 'auto'
* Resolve path as posix or win32
*/
platform?: 'posix' | 'win32' | 'auto';
}
declare function resolveModule(name: string, options?: PackageResolvingOptions): string | undefined;
declare function importModule<T = any>(path: string): Promise<T>;
declare function isPackageExists(name: string, options?: PackageResolvingOptions): boolean;
declare const getPackageInfo: quansync_types.QuansyncFn<{
name: string;
version: string | undefined;
rootPath: string;
packageJsonPath: string;
packageJson: PackageJson;
} | undefined, [name: string, options?: PackageResolvingOptions | undefined]>;
declare const getPackageInfoSync: (name: string, options?: PackageResolvingOptions | undefined) => {
name: string;
version: string | undefined;
rootPath: string;
packageJsonPath: string;
packageJson: PackageJson;
} | undefined;
declare const loadPackageJSON: quansync_types.QuansyncFn<PackageJson | null, [cwd?: Args[0] | undefined]>;
declare const loadPackageJSONSync: (cwd?: Args[0] | undefined) => PackageJson | null;
declare const isPackageListed: quansync_types.QuansyncFn<boolean, [name: string, cwd?: string | undefined]>;
declare const isPackageListedSync: (name: string, cwd?: string | undefined) => boolean;
export { getPackageInfo, getPackageInfoSync, importModule, isPackageExists, isPackageListed, isPackageListedSync, loadPackageJSON, loadPackageJSONSync, resolveModule };
export type { PackageInfo, PackageResolvingOptions };
+42
View File
@@ -0,0 +1,42 @@
import * as quansync_types from 'quansync/types';
import { PackageJson } from 'pkg-types';
interface PackageInfo {
name: string;
rootPath: string;
packageJsonPath: string;
version: string;
packageJson: PackageJson;
}
interface PackageResolvingOptions {
paths?: string[];
/**
* @default 'auto'
* Resolve path as posix or win32
*/
platform?: 'posix' | 'win32' | 'auto';
}
declare function resolveModule(name: string, options?: PackageResolvingOptions): string | undefined;
declare function importModule<T = any>(path: string): Promise<T>;
declare function isPackageExists(name: string, options?: PackageResolvingOptions): boolean;
declare const getPackageInfo: quansync_types.QuansyncFn<{
name: string;
version: string | undefined;
rootPath: string;
packageJsonPath: string;
packageJson: PackageJson;
} | undefined, [name: string, options?: PackageResolvingOptions | undefined]>;
declare const getPackageInfoSync: (name: string, options?: PackageResolvingOptions | undefined) => {
name: string;
version: string | undefined;
rootPath: string;
packageJsonPath: string;
packageJson: PackageJson;
} | undefined;
declare const loadPackageJSON: quansync_types.QuansyncFn<PackageJson | null, [cwd?: Args[0] | undefined]>;
declare const loadPackageJSONSync: (cwd?: Args[0] | undefined) => PackageJson | null;
declare const isPackageListed: quansync_types.QuansyncFn<boolean, [name: string, cwd?: string | undefined]>;
declare const isPackageListedSync: (name: string, cwd?: string | undefined) => boolean;
export { getPackageInfo, getPackageInfoSync, importModule, isPackageExists, isPackageListed, isPackageListedSync, loadPackageJSON, loadPackageJSONSync, resolveModule };
export type { PackageInfo, PackageResolvingOptions };
+172
View File
@@ -0,0 +1,172 @@
import fs from 'node:fs';
import { createRequire } from 'node:module';
import path, { dirname, join, win32 } from 'node:path';
import process from 'node:process';
import fsPromises from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { resolvePathSync, interopDefault } from 'mlly';
import { quansync } from 'quansync/macro';
const toPath = urlOrPath => urlOrPath instanceof URL ? fileURLToPath(urlOrPath) : urlOrPath;
async function findUp$1(name, {
cwd = process.cwd(),
type = 'file',
stopAt,
} = {}) {
let directory = path.resolve(toPath(cwd) ?? '');
const {root} = path.parse(directory);
stopAt = path.resolve(directory, toPath(stopAt ?? root));
const isAbsoluteName = path.isAbsolute(name);
while (directory) {
const filePath = isAbsoluteName ? name : path.join(directory, name);
try {
const stats = await fsPromises.stat(filePath); // eslint-disable-line no-await-in-loop
if ((type === 'file' && stats.isFile()) || (type === 'directory' && stats.isDirectory())) {
return filePath;
}
} catch {}
if (directory === stopAt || directory === root) {
break;
}
directory = path.dirname(directory);
}
}
function findUpSync(name, {
cwd = process.cwd(),
type = 'file',
stopAt,
} = {}) {
let directory = path.resolve(toPath(cwd) ?? '');
const {root} = path.parse(directory);
stopAt = path.resolve(directory, toPath(stopAt) ?? root);
const isAbsoluteName = path.isAbsolute(name);
while (directory) {
const filePath = isAbsoluteName ? name : path.join(directory, name);
try {
const stats = fs.statSync(filePath, {throwIfNoEntry: false});
if ((type === 'file' && stats?.isFile()) || (type === 'directory' && stats?.isDirectory())) {
return filePath;
}
} catch {}
if (directory === stopAt || directory === root) {
break;
}
directory = path.dirname(directory);
}
}
function _resolve(path, options = {}) {
if (options.platform === "auto" || !options.platform)
options.platform = process.platform === "win32" ? "win32" : "posix";
if (process.versions.pnp) {
const paths = options.paths || [];
if (paths.length === 0)
paths.push(process.cwd());
const targetRequire = createRequire(import.meta.url);
try {
return targetRequire.resolve(path, { paths });
} catch {
}
}
const modulePath = resolvePathSync(path, {
url: options.paths
});
if (options.platform === "win32")
return win32.normalize(modulePath);
return modulePath;
}
function resolveModule(name, options = {}) {
try {
return _resolve(name, options);
} catch {
return void 0;
}
}
async function importModule(path) {
const i = await import(path);
if (i)
return interopDefault(i);
return i;
}
function isPackageExists(name, options = {}) {
return !!resolvePackage(name, options);
}
function getPackageJsonPath(name, options = {}) {
const entry = resolvePackage(name, options);
if (!entry)
return;
return searchPackageJSON(entry);
}
const readFile = quansync({
async: (id) => fs.promises.readFile(id, "utf8"),
sync: (id) => fs.readFileSync(id, "utf8")
});
const getPackageInfo = quansync(function* (name, options = {}) {
const packageJsonPath = getPackageJsonPath(name, options);
if (!packageJsonPath)
return;
const packageJson = JSON.parse(yield readFile(packageJsonPath));
return {
name,
version: packageJson.version,
rootPath: dirname(packageJsonPath),
packageJsonPath,
packageJson
};
});
const getPackageInfoSync = getPackageInfo.sync;
function resolvePackage(name, options = {}) {
try {
return _resolve(`${name}/package.json`, options);
} catch {
}
try {
return _resolve(name, options);
} catch (e) {
if (e.code !== "MODULE_NOT_FOUND" && e.code !== "ERR_MODULE_NOT_FOUND")
console.error(e);
return false;
}
}
function searchPackageJSON(dir) {
let packageJsonPath;
while (true) {
if (!dir)
return;
const newDir = dirname(dir);
if (newDir === dir)
return;
dir = newDir;
packageJsonPath = join(dir, "package.json");
if (fs.existsSync(packageJsonPath))
break;
}
return packageJsonPath;
}
const findUp = quansync({
sync: findUpSync,
async: findUp$1
});
const loadPackageJSON = quansync(function* (cwd = process.cwd()) {
const path = yield findUp("package.json", { cwd });
if (!path || !fs.existsSync(path))
return null;
return JSON.parse(yield readFile(path));
});
const loadPackageJSONSync = loadPackageJSON.sync;
const isPackageListed = quansync(function* (name, cwd) {
const pkg = (yield loadPackageJSON(cwd)) || {};
return name in (pkg.dependencies || {}) || name in (pkg.devDependencies || {});
});
const isPackageListedSync = isPackageListed.sync;
export { getPackageInfo, getPackageInfoSync, importModule, isPackageExists, isPackageListed, isPackageListedSync, loadPackageJSON, loadPackageJSONSync, resolveModule };
@@ -0,0 +1,44 @@
MIT License
Copyright (c) Pooya Parsa <pooya@pi0.io> - Daniel Roe <daniel@roe.dev>
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.
--------------------------------------------------------------------------------
Copyright Joyent, Inc. and other Node contributors.
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.
@@ -0,0 +1,342 @@
# pkg-types
<!-- automd:badges color=yellow codecov -->
[![npm version](https://img.shields.io/npm/v/pkg-types?color=yellow)](https://npmjs.com/package/pkg-types)
[![npm downloads](https://img.shields.io/npm/dm/pkg-types?color=yellow)](https://npm.chart.dev/pkg-types)
[![codecov](https://img.shields.io/codecov/c/gh/unjs/pkg-types?color=yellow)](https://codecov.io/gh/unjs/pkg-types)
<!-- /automd -->
Node.js utilities and TypeScript definitions for `package.json`, `tsconfig.json`, and other configuration files.
## Install
<!-- automd:pm-i -->
```sh
# ✨ Auto-detect
npx nypm install pkg-types
# npm
npm install pkg-types
# yarn
yarn add pkg-types
# pnpm
pnpm add pkg-types
# bun
bun install pkg-types
# deno
deno install npm:pkg-types
```
<!-- /automd -->
## Usage
### Package Configuration
#### `readPackage`
Reads any package file format (package.json, package.json5, or package.yaml) with automatic format detection.
```js
import { readPackage } from "pkg-types";
const localPackage = await readPackage();
// or
const pkg = await readPackage("/fully/resolved/path/to/folder");
```
#### `writePackage`
Writes package data with format detection based on file extension.
```js
import { writePackage } from "pkg-types";
await writePackage("path/to/package.json", pkg);
await writePackage("path/to/package.json5", pkg);
await writePackage("path/to/package.yaml", pkg);
```
#### `findPackage`
Finds the nearest package file (package.json, package.json5, or package.yaml).
```js
import { findPackage } from "pkg-types";
const filename = await findPackage();
// or
const filename = await findPackage("/fully/resolved/path/to/folder");
```
#### `readPackageJSON`
```js
import { readPackageJSON } from "pkg-types";
const localPackageJson = await readPackageJSON();
// or
const packageJson = await readPackageJSON("/fully/resolved/path/to/folder");
```
#### `writePackageJSON`
```js
import { writePackageJSON } from "pkg-types";
await writePackageJSON("path/to/package.json", pkg);
```
#### `resolvePackageJSON`
```js
import { resolvePackageJSON } from "pkg-types";
const filename = await resolvePackageJSON();
// or
const packageJson = await resolvePackageJSON("/fully/resolved/path/to/folder");
```
#### `updatePackage`
Reads a package file and passes a proxied PackageJson to a callback (the callback may mutate it in-place or return a new object). The updated package is then written back using the same file format (`.json`/`.json5`/`.yaml`). The proxy auto-creates common map fields (e.g. `scripts`, `dependencies`) when accessed.
```js
import { updatePackage } from "pkg-types";
await updatePackage("path/to/package", (pkg) => {
pkg.version = "1.0.1";
pkg.dependencies.lodash = "^4.17.21";
});
```
#### `sortPackage`
Returns a new PackageJson that reorders known top-level fields according to the convention and alphabetically sorts certain nested maps (like `dependencies`, `devDependencies`, `optionalDependencies`, `peerDependencies` and `scripts`). Unknown top-level keys retain their original relative order. The input object is not mutated.
```js
import { sortPackage } from "pkg-types";
const sorted = sortPackage(pkg);
```
#### `normalizePackage`
Normalizes a `PackageJson` for stable output: sorts top-level fields and dependency maps, and removes dependency fields (`dependencies`, `devDependencies`, `optionalDependencies`, `peerDependencies`) if they are not plain objects. Returns a new normalized object.
```js
import { normalizePackage } from "pkg-types";
const normalized = normalizePackage(pkg);
```
### TypeScript Configuration
#### `readTSConfig`
```js
import { readTSConfig } from "pkg-types";
const tsconfig = await readTSConfig();
// or
const tsconfig2 = await readTSConfig("/fully/resolved/path/to/folder");
```
#### `writeTSConfig`
```js
import { writeTSConfig } from "pkg-types";
await writeTSConfig("path/to/tsconfig.json", tsconfig);
```
#### `resolveTSConfig`
```js
import { resolveTSConfig } from "pkg-types";
const filename = await resolveTSConfig();
// or
const tsconfig = await resolveTSConfig("/fully/resolved/path/to/folder");
```
### File Resolution
#### `findFile`
```js
import { findFile } from "pkg-types";
const filename = await findFile("README.md", {
startingFrom: id,
rootPattern: /^node_modules$/,
test: (filename) => filename.endsWith(".md"),
});
```
#### `findNearestFile`
```js
import { findNearestFile } from "pkg-types";
const filename = await findNearestFile("package.json");
```
#### `findFarthestFile`
```js
import { findFarthestFile } from "pkg-types";
const filename = await findFarthestFile("package.json");
```
#### `resolveLockfile`
Find path to the lock file (`yarn.lock`, `package-lock.json`, `pnpm-lock.yaml`, `npm-shrinkwrap.json`, `bun.lockb`, `bun.lock`, `deno.lock`) or throws an error.
```js
import { resolveLockfile } from "pkg-types";
const lockfile = await resolveLockfile(".");
```
#### `findWorkspaceDir`
Try to detect workspace dir by in order:
1. Farthest workspace file (`pnpm-workspace.yaml`, `lerna.json`, `turbo.json`, `rush.json`, `deno.json`, `deno.jsonc`)
2. Closest `.git/config` file
3. Farthest lockfile
4. Farthest `package.json` file
If fails, throws an error.
```js
import { findWorkspaceDir } from "pkg-types";
const workspaceDir = await findWorkspaceDir(".");
```
### Git Configuration
#### `resolveGitConfig`
Finds closest `.git/config` file.
```js
import { resolveGitConfig } from "pkg-types";
const gitConfig = await resolveGitConfig(".");
```
#### `readGitConfig`
Finds and reads closest `.git/config` file into a JS object.
```js
import { readGitConfig } from "pkg-types";
const gitConfigObj = await readGitConfig(".");
```
#### `writeGitConfig`
Stringifies git config object into INI text format and writes it to a file.
```js
import { writeGitConfig } from "pkg-types";
await writeGitConfig(".git/config", gitConfigObj);
```
#### `parseGitConfig`
Parses a git config file in INI text format into a JavaScript object.
```js
import { parseGitConfig } from "pkg-types";
const gitConfigObj = parseGitConfig(gitConfigINI);
```
#### `stringifyGitConfig`
Stringifies a git config object into a git config file INI text format.
```js
import { stringifyGitConfig } from "pkg-types";
const gitConfigINI = stringifyGitConfig(gitConfigObj);
```
## Types
- **Note:** In order to make types work, you need to install `typescript` as a devDependency.
You can directly use typed interfaces:
```ts
import type { TSConfig, PackageJson, GitConfig } from "pkg-types";
```
### Define Utilities
You can use define utilities for type support and auto-completion when working in plain `.js` files. These functions simply return the input object but provide TypeScript type hints.
#### `definePackageJSON`
Provides type safety and auto-completion for package.json objects.
```js
import { definePackageJSON } from "pkg-types";
const pkg = definePackageJSON({
name: "my-package",
version: "1.0.0",
// TypeScript will provide auto-completion here
});
```
#### `defineTSConfig`
Provides type safety and auto-completion for tsconfig.json objects.
```js
import { defineTSConfig } from "pkg-types";
const tsconfig = defineTSConfig({
compilerOptions: {
target: "ES2020",
// TypeScript will provide auto-completion here
},
});
```
#### `defineGitConfig`
Provides type safety and auto-completion for git config objects.
```js
import { defineGitConfig } from "pkg-types";
const gitConfig = defineGitConfig({
user: {
name: "John Doe",
email: "john@example.com",
},
// TypeScript will provide auto-completion here
});
```
## Alternatives
- [dominikg/tsconfck](https://github.com/dominikg/tsconfck)
## License
<!-- automd:contributors license=MIT author="pi0,danielroe" -->
Published under the [MIT](https://github.com/unjs/pkg-types/blob/main/LICENSE) license.
Made by [@pi0](https://github.com/pi0), [@danielroe](https://github.com/danielroe) and [community](https://github.com/unjs/pkg-types/graphs/contributors) 💛
<br><br>
<a href="https://github.com/unjs/pkg-types/graphs/contributors">
<img src="https://contrib.rocks/image?repo=unjs/pkg-types" />
</a>
<!-- /automd -->
@@ -0,0 +1,563 @@
import { ResolveOptions as ResolveOptions$1 } from "exsolve";
import * as ts from "typescript";
//#region src/resolve/types.d.ts
/**
* Represents the options for resolving paths with additional file finding capabilities.
*/
type ResolveOptions = Omit<FindFileOptions, "startingFrom"> & ResolveOptions$1 & {
/** @deprecated: use `from` */url?: string; /** @deprecated: use `from` */
parent?: string;
};
/**
* Options for reading files with optional caching.
*/
type ReadOptions = {
/**
* Specifies whether the read results should be cached.
* Can be a boolean or a map to hold the cached data.
*/
cache?: boolean | Map<string, Record<string, any>>;
};
interface FindFileOptions {
/**
* The starting directory for the search.
* @default . (same as `process.cwd()`)
*/
startingFrom?: string;
/**
* A pattern to match a path segment above which you don't want to ascend
* @default /^node_modules$/
*/
rootPattern?: RegExp;
/**
* If true, search starts from root level descending into subdirectories
*/
reverse?: boolean;
/**
* A matcher that can evaluate whether the given path is a valid file (for example,
* by testing whether the file path exists).
*
* @default fs.statSync(path).isFile()
*/
test?: (filePath: string) => boolean | undefined | Promise<boolean | undefined>;
}
//#endregion
//#region src/resolve/utils.d.ts
/**
* Asynchronously finds a file by name, starting from the specified directory and traversing up (or down if reverse).
* @param filename - The name of the file to find.
* @param _options - Options to customise the search behaviour.
* @returns a promise that resolves to the path of the file found.
* @throws Will throw an error if the file cannot be found.
*/
declare function findFile(filename: string | string[], _options?: FindFileOptions): Promise<string>;
/**
* Asynchronously finds the next file with the given name, starting in the given directory and moving up.
* Alias for findFile without reversing the search.
* @param filename - The name of the file to find.
* @param options - Options to customise the search behaviour.
* @returns A promise that resolves to the path of the next file found.
*/
declare function findNearestFile(filename: string | string[], options?: FindFileOptions): Promise<string>;
/**
* Asynchronously finds the furthest file with the given name, starting from the root directory and moving downwards.
* This is essentially the reverse of `findNearestFile`.
* @param filename - The name of the file to find.
* @param options - Options to customise the search behaviour, with reverse set to true.
* @returns A promise that resolves to the path of the farthest file found.
*/
declare function findFarthestFile(filename: string | string[], options?: FindFileOptions): Promise<string>;
//#endregion
//#region src/tsconfig/types.d.ts
type StripEnums<T extends Record<string, any>> = { [K in keyof T]: T[K] extends boolean ? T[K] : T[K] extends string ? T[K] : T[K] extends object ? T[K] : T[K] extends Array<any> ? T[K] : T[K] extends undefined ? undefined : any };
interface TSConfig {
compilerOptions?: StripEnums<ts.CompilerOptions>;
exclude?: string[];
compileOnSave?: boolean;
extends?: string | string[];
files?: string[];
include?: string[];
typeAcquisition?: ts.TypeAcquisition;
references?: {
path: string;
}[];
}
//#endregion
//#region src/tsconfig/utils.d.ts
/**
* Defines a TSConfig structure.
* @param tsconfig - The contents of `tsconfig.json` as an object. See {@link TSConfig}.
* @returns the same `tsconfig.json` object.
*/
declare function defineTSConfig(tsconfig: TSConfig): TSConfig;
/**
* Asynchronously reads a `tsconfig.json` file.
* @param id - The path to the `tsconfig.json` file, defaults to the current working directory.
* @param options - The options for resolving and reading the file. See {@link ResolveOptions}.
* @returns a promise resolving to the parsed `tsconfig.json` object.
*/
declare function readTSConfig(id?: string, options?: ResolveOptions & ReadOptions): Promise<TSConfig>;
/**
* Asynchronously writes data to a `tsconfig.json` file.
* @param path - The path to the file where the `tsconfig.json` is written.
* @param tsconfig - The `tsconfig.json` object to write. See {@link TSConfig}.
*/
declare function writeTSConfig(path: string, tsconfig: TSConfig): Promise<void>;
/**
* Resolves the path to the nearest `tsconfig.json` file from a given directory.
* @param id - The base path for the search, defaults to the current working directory.
* @param options - Options to modify the search behaviour. See {@link ResolveOptions}.
* @returns A promise resolving to the path of the nearest `tsconfig.json` file.
*/
declare function resolveTSConfig(id?: string, options?: ResolveOptions): Promise<string>;
//#endregion
//#region src/packagejson/types.d.ts
interface PackageJson {
/**
* The name is what your thing is called.
* Some rules:
* - The name must be less than or equal to 214 characters. This includes the scope for scoped packages.
* - The name cant start with a dot or an underscore.
* - New packages must not have uppercase letters in the name.
* - The name ends up being part of a URL, an argument on the command line, and a folder name. Therefore, the name cant contain any non-URL-safe characters.
*/
name?: string;
/**
* Version must be parseable by `node-semver`, which is bundled with npm as a dependency. (`npm install semver` to use it yourself.)
*/
version?: string;
/**
* Put a description in it. Its a string. This helps people discover your package, as its listed in `npm search`.
*/
description?: string;
/**
* Put keywords in it. Its an array of strings. This helps people discover your package as its listed in `npm search`.
*/
keywords?: string[];
/**
* The url to the project homepage.
*/
homepage?: string;
/**
* The url to your projects issue tracker and / or the email address to which issues should be reported. These are helpful for people who encounter issues with your package.
*/
bugs?: string | {
url?: string;
email?: string;
};
/**
* You should specify a license for your package so that people know how they are permitted to use it, and any restrictions youre placing on it.
*/
license?: string;
/**
* Specify the place where your code lives. This is helpful for people who want to contribute. If the git repo is on GitHub, then the `npm docs` command will be able to find you.
* For GitHub, GitHub gist, Bitbucket, or GitLab repositories you can use the same shortcut syntax you use for npm install:
*/
repository?: string | {
type: string;
url: string;
/**
* If the `package.json` for your package is not in the root directory (for example if it is part of a monorepo), you can specify the directory in which it lives:
*/
directory?: string;
};
/**
* The `scripts` field is a dictionary containing script commands that are run at various times in the lifecycle of your package.
*/
scripts?: PackageJsonScripts;
/**
* If you set `"private": true` in your package.json, then npm will refuse to publish it.
*/
private?: boolean;
/**
* The “author” is one person.
*/
author?: PackageJsonPerson;
/**
* “contributors” is an array of people.
*/
contributors?: PackageJsonPerson[];
/**
* An object containing a URL that provides up-to-date information
* about ways to help fund development of your package,
* a string URL, or an array of objects and string URLs
*/
funding?: PackageJsonFunding | PackageJsonFunding[];
/**
* The optional `files` field is an array of file patterns that describes the entries to be included when your package is installed as a dependency. File patterns follow a similar syntax to `.gitignore`, but reversed: including a file, directory, or glob pattern (`*`, `**\/*`, and such) will make it so that file is included in the tarball when its packed. Omitting the field will make it default to `["*"]`, which means it will include all files.
*/
files?: string[];
/**
* The main field is a module ID that is the primary entry point to your program. That is, if your package is named `foo`, and a user installs it, and then does `require("foo")`, then your main modules exports object will be returned.
* This should be a module ID relative to the root of your package folder.
* For most modules, it makes the most sense to have a main script and often not much else.
*/
main?: string;
/**
* If your module is meant to be used client-side the browser field should be used instead of the main field. This is helpful to hint users that it might rely on primitives that arent available in Node.js modules. (e.g. window)
*/
browser?: string | Record<string, string | false>;
/**
* The `unpkg` field is used to specify the URL to a UMD module for your package. This is used by default in the unpkg.com CDN service.
*/
unpkg?: string;
/**
* A map of command name to local file name. On install, npm will symlink that file into `prefix/bin` for global installs, or `./node_modules/.bin/` for local installs.
*/
bin?: string | Record<string, string>;
/**
* Specify either a single file or an array of filenames to put in place for the `man` program to find.
*/
man?: string | string[];
/**
* Dependencies are specified in a simple object that maps a package name to a version range. The version range is a string which has one or more space-separated descriptors. Dependencies can also be identified with a tarball or git URL.
*/
dependencies?: Record<string, string>;
/**
* If someone is planning on downloading and using your module in their program, then they probably dont want or need to download and build the external test or documentation framework that you use.
* In this case, its best to map these additional items in a `devDependencies` object.
*/
devDependencies?: Record<string, string>;
/**
* If a dependency can be used, but you would like npm to proceed if it cannot be found or fails to install, then you may put it in the `optionalDependencies` object. This is a map of package name to version or url, just like the `dependencies` object. The difference is that build failures do not cause installation to fail.
*/
optionalDependencies?: Record<string, string>;
/**
* In some cases, you want to express the compatibility of your package with a host tool or library, while not necessarily doing a `require` of this host. This is usually referred to as a plugin. Notably, your module may be exposing a specific interface, expected and specified by the host documentation.
*/
peerDependencies?: Record<string, string>;
/**
* TypeScript typings, typically ending by `.d.ts`.
*/
types?: string;
/**
* This field is synonymous with `types`.
*/
typings?: string;
/**
* Non-Standard Node.js alternate entry-point to main.
* An initial implementation for supporting CJS packages (from main), and use module for ESM modules.
*/
module?: string;
/**
* Make main entry-point be loaded as an ESM module, support "export" syntax instead of "require"
*
* Docs:
* - https://nodejs.org/docs/latest-v14.x/api/esm.html#esm_package_json_type_field
*
* @default 'commonjs'
* @since Node.js v14
*/
type?: "module" | "commonjs";
/**
* Alternate and extensible alternative to "main" entry point.
*
* When using `{type: "module"}`, any ESM module file MUST end with `.mjs` extension.
*
* Docs:
* - https://nodejs.org/docs/latest-v14.x/api/esm.html#esm_exports_sugar
*
* @since Node.js v12.7
*/
exports?: PackageJsonExports;
/**
* Docs:
* - https://nodejs.org/api/packages.html#imports
*/
imports?: Record<string, string | Record<string, string>>;
/**
* The field is used to define a set of sub-packages (or workspaces) within a monorepo.
*
* This field is an array of glob patterns or an object with specific configurations for managing
* multiple packages in a single repository.
*/
workspaces?: string[] | {
/**
* Workspace package paths. Glob patterns are supported.
*/
packages?: string[];
/**
* Packages to block from hoisting to the workspace root.
* Uses glob patterns to match module paths in the dependency tree.
*
* Docs:
* - https://classic.yarnpkg.com/blog/2018/02/15/nohoist/
*/
nohoist?: string[];
};
/**
* The field is used to specify different TypeScript declaration files for
* different versions of TypeScript, allowing for version-specific type definitions.
*/
typesVersions?: Record<string, Record<string, string[]>>;
/**
* You can specify which operating systems your module will run on:
* ```json
* {
* "os": ["darwin", "linux"]
* }
* ```
* You can also block instead of allowing operating systems, just prepend the blocked os with a '!':
* ```json
* {
* "os": ["!win32"]
* }
* ```
* The host operating system is determined by `process.platform`
* It is allowed to both block and allow an item, although there isn't any good reason to do this.
*/
os?: string[];
/**
* If your code only runs on certain cpu architectures, you can specify which ones.
* ```json
* {
* "cpu": ["x64", "ia32"]
* }
* ```
* Like the `os` option, you can also block architectures:
* ```json
* {
* "cpu": ["!arm", "!mips"]
* }
* ```
* The host architecture is determined by `process.arch`
*/
cpu?: string[];
/**
* This is a set of config values that will be used at publish-time.
*/
publishConfig?: {
/**
* The registry that will be used if the package is published.
*/
registry?: string;
/**
* The tag that will be used if the package is published.
*/
tag?: string;
/**
* The access level that will be used if the package is published.
*/
access?: "public" | "restricted";
/**
* **pnpm-only**
*
* By default, for portability reasons, no files except those listed in
* the bin field will be marked as executable in the resulting package
* archive. The executableFiles field lets you declare additional fields
* that must have the executable flag (+x) set even if
* they aren't directly accessible through the bin field.
*/
executableFiles?: string[];
/**
* **pnpm-only**
*
* You also can use the field `publishConfig.directory` to customize
* the published subdirectory relative to the current `package.json`.
*
* It is expected to have a modified version of the current package in
* the specified directory (usually using third party build tools).
*/
directory?: string;
/**
* **pnpm-only**
*
* When set to `true`, the project will be symlinked from the
* `publishConfig.directory` location during local development.
* @default true
*/
linkDirectory?: boolean;
} & Pick<PackageJson, "bin" | "main" | "exports" | "types" | "typings" | "module" | "browser" | "unpkg" | "typesVersions" | "os" | "cpu">;
/**
* See: https://nodejs.org/api/packages.html#packagemanager
* This field defines which package manager is expected to be used when working on the current project.
* Should be of the format: `<name>@<version>[#hash]`
*/
packageManager?: string;
[key: string]: any;
}
/**
* See: https://docs.npmjs.com/cli/v11/using-npm/scripts#pre--post-scripts
*/
type PackageJsonScriptWithPreAndPost<S extends string> = S | `${"pre" | "post"}${S}`;
/**
* See: https://docs.npmjs.com/cli/v11/using-npm/scripts#life-cycle-operation-order
*/
type PackageJsonNpmLifeCycleScripts = "dependencies" | "prepublishOnly" | PackageJsonScriptWithPreAndPost<"install" | "pack" | "prepare" | "publish" | "restart" | "start" | "stop" | "test" | "version">;
/**
* See: https://pnpm.io/scripts#lifecycle-scripts
*/
type PackageJsonPnpmLifeCycleScripts = "pnpm:devPreinstall";
type PackageJsonCommonScripts = "build" | "coverage" | "deploy" | "dev" | "format" | "lint" | "preview" | "release" | "typecheck" | "watch";
type PackageJsonScriptName = PackageJsonCommonScripts | PackageJsonNpmLifeCycleScripts | PackageJsonPnpmLifeCycleScripts | (string & {});
type PackageJsonScripts = { [P in PackageJsonScriptName]?: string };
/**
* A “person” is an object with a “name” field and optionally “url” and “email”. Or you can shorten that all into a single string, and npm will parse it for you.
*/
type PackageJsonPerson = string | {
name: string;
email?: string;
url?: string;
};
type PackageJsonFunding = string | {
url: string;
type?: string;
};
type PackageJsonExportKey = "." | "import" | "require" | "types" | "node" | "browser" | "default" | (string & {});
type PackageJsonExportsObject = { [P in PackageJsonExportKey]?: string | PackageJsonExportsObject | Array<string | PackageJsonExportsObject> };
type PackageJsonExports = string | PackageJsonExportsObject | Array<string | PackageJsonExportsObject>;
//#endregion
//#region src/packagejson/utils.d.ts
/**
* Defines a PackageJson structure.
* @param pkg - The `package.json` content as an object. See {@link PackageJson}.
* @returns the same `package.json` object.
*/
declare function definePackageJSON(pkg: PackageJson): PackageJson;
/**
* Finds the nearest package file (package.json, package.json5, or package.yaml).
* @param id - The base path for the search, defaults to the current working directory.
* @param options - Options to modify the search behaviour. See {@link ResolveOptions}.
* @returns A promise resolving to the path of the nearest package file.
*/
declare function findPackage(id?: string, options?: ResolveOptions): Promise<string>;
/**
* Reads any package file format (package.json, package.json5, or package.yaml).
* @param id - The path identifier for the package file, defaults to the current working directory.
* @param options - The options for resolving and reading the file. See {@link ResolveOptions}.
* @returns a promise resolving to the parsed `package.json` object.
*/
declare function readPackage(id?: string, options?: ResolveOptions & ReadOptions): Promise<PackageJson>;
/**
* Writes data to a package file with format detection based on file extension.
* @param path - The path to the file where the package data is written.
* @param pkg - The package object to write. See {@link PackageJson}.
*/
declare function writePackage(path: string, pkg: PackageJson): Promise<void>;
/**
* Asynchronously reads a `package.json` file.
* @param id - The path identifier for the package.json, defaults to the current working directory.
* @param options - The options for resolving and reading the file. See {@link ResolveOptions}.
* @returns a promise resolving to the parsed `package.json` object.
*/
declare function readPackageJSON(id?: string, options?: ResolveOptions & ReadOptions): Promise<PackageJson>;
/**
* Asynchronously writes data to a `package.json` file.
* @param path - The path to the file where the `package.json` is written.
* @param pkg - The `package.json` object to write. See {@link PackageJson}.
*/
declare function writePackageJSON(path: string, pkg: PackageJson): Promise<void>;
/**
* Resolves the path to the nearest `package.json` file from a given directory.
* @param id - The base path for the search, defaults to the current working directory.
* @param options - Options to modify the search behaviour. See {@link ResolveOptions}.
* @returns A promise resolving to the path of the nearest `package.json` file.
*/
declare function resolvePackageJSON(id?: string, options?: ResolveOptions): Promise<string>;
/**
* Resolves the path to the nearest lockfile from a given directory.
* @param id - The base path for the search, defaults to the current working directory.
* @param options - Options to modify the search behaviour. See {@link ResolveOptions}.
* @returns A promise resolving to the path of the nearest lockfile.
*/
declare function resolveLockfile(id?: string, options?: ResolveOptions): Promise<string>;
type WorkspaceTestName = "workspaceFile" | "gitConfig" | "lockFile" | "packageJson";
/**
* Detects the workspace directory based on common project markers.
* Throws an error if the workspace root cannot be detected.
*
* @param id - The base path to search, defaults to the current working directory.
* @param options - Options to modify the search behaviour. See {@link ResolveOptions}.
* @returns a promise resolving to the path of the detected workspace directory.
*/
declare function findWorkspaceDir(id?: string, options?: ResolveOptions & Partial<Record<WorkspaceTestName, boolean | "closest" | "furthest">> & {
tests?: WorkspaceTestName[];
}): Promise<string>;
/**
* Reads a package file, allows a callback to mutate it, and writes back the result while preserving the original file format.
*
* @param id - The path to package.json or directory to locate the package file.
* @param callback - A function that receives the package object (proxied) and may mutate it in-place or return a new object.
* @param options - Options for resolving and reading the file. See {@link ResolveOptions} and {@link ReadOptions}.
* @returns A promise that resolves once the package file has been written.
*/
declare function updatePackage(id: string, callback: (pkg: PackageJson) => PackageJson | void | Promise<PackageJson | void>, options?: ResolveOptions & ReadOptions): Promise<void>;
/**
* Returns a new `PackageJson` with known top-level fields reordered and certain nested maps alphabetically sorted.
*
* Known keys are reordered according to project conventions; unknown keys retain their original relative order.
* Nested maps such as dependency maps and `scripts` are sorted alphabetically by key.
*
* @param pkg - The `package.json` object to sort.
* @returns A new `PackageJson` object with fields and nested maps sorted.
*/
declare function sortPackage(pkg: PackageJson): PackageJson;
/**
* Normalizes a `PackageJson` for stable output by sorting fields and removing invalid dependency declarations.
*
* Sorts top-level fields and dependency objects alphabetically, and removes dependency fields
* (`dependencies`, `devDependencies`, etc.) that are not plain objects.
*
* @param pkg - The `package.json` object to normalize.
* @returns A new normalized `PackageJson` object.
*/
declare function normalizePackage(pkg: PackageJson): PackageJson;
//#endregion
//#region src/gitconfig/types.d.ts
interface GitRemote {
[key: string]: unknown;
name?: string;
url?: string;
fetch?: string;
}
interface GitBranch {
[key: string]: unknown;
remote?: string;
merge?: string;
description?: string;
rebase?: boolean;
}
interface GitCoreConfig {
[key: string]: unknown;
}
interface GitConfigUser {
[key: string]: unknown;
name?: string;
email?: string;
}
interface GitConfig {
[key: string]: unknown;
core?: GitCoreConfig;
user?: GitConfigUser;
remote?: Record<string, GitRemote>;
branch?: Record<string, GitBranch>;
}
//#endregion
//#region src/gitconfig/utils.d.ts
/**
* Defines a git config object.
*/
declare function defineGitConfig(config: GitConfig): GitConfig;
/**
* Finds closest `.git/config` file.
*/
declare function resolveGitConfig(dir: string, opts?: ResolveOptions): Promise<string>;
/**
* Finds and reads closest `.git/config` file into a JS object.
*/
declare function readGitConfig(dir: string, opts?: ResolveOptions): Promise<GitConfig>;
/**
* Stringifies git config object into INI text format and writes it to a file.
*/
declare function writeGitConfig(path: string, config: GitConfig): Promise<void>;
/**
* Parses a git config file in INI text format into a JavaScript object.
*/
declare function parseGitConfig(ini: string): GitConfig;
/**
* Stringifies a git config object into a git config file INI text format.
*/
declare function stringifyGitConfig(config: GitConfig): string;
//#endregion
export { type FindFileOptions, type GitBranch, type GitConfig, type GitConfigUser, type GitCoreConfig, type GitRemote, type PackageJson, type PackageJsonExports, type PackageJsonPerson, type ReadOptions, type ResolveOptions, type TSConfig, defineGitConfig, definePackageJSON, defineTSConfig, findFarthestFile, findFile, findNearestFile, findPackage, findWorkspaceDir, normalizePackage, parseGitConfig, readGitConfig, readPackage, readPackageJSON, readTSConfig, resolveGitConfig, resolveLockfile, resolvePackageJSON, resolveTSConfig, sortPackage, stringifyGitConfig, updatePackage, writeGitConfig, writePackage, writePackageJSON, writeTSConfig };
@@ -0,0 +1,317 @@
import { promises, statSync } from "node:fs";
import { dirname, isAbsolute, join, normalize, resolve } from "pathe";
import { parseJSON, parseJSON5, parseJSONC, parseYAML, stringifyJSON, stringifyJSON5, stringifyJSONC, stringifyYAML } from "confbox";
import { resolveModulePath } from "exsolve";
import { fileURLToPath } from "node:url";
import { readFile, writeFile } from "node:fs/promises";
import { parseINI, stringifyINI } from "confbox/ini";
const defaultFindOptions = {
startingFrom: ".",
rootPattern: /^node_modules$/,
reverse: false,
test: (filePath) => {
try {
if (statSync(filePath).isFile()) return true;
} catch {}
}
};
async function findFile(filename, _options = {}) {
const filenames = Array.isArray(filename) ? filename : [filename];
const options = {
...defaultFindOptions,
..._options
};
const basePath = resolve(options.startingFrom);
const leadingSlash = basePath[0] === "/";
const segments = basePath.split("/").filter(Boolean);
if (filenames.includes(segments.at(-1)) && await options.test(basePath)) return basePath;
if (leadingSlash) segments[0] = "/" + segments[0];
let root = segments.findIndex((r) => r.match(options.rootPattern));
if (root === -1) root = 0;
if (options.reverse) for (let index = root + 1; index <= segments.length; index++) for (const filename of filenames) {
const filePath = join(...segments.slice(0, index), filename);
if (await options.test(filePath)) return filePath;
}
else for (let index = segments.length; index > root; index--) for (const filename of filenames) {
const filePath = join(...segments.slice(0, index), filename);
if (await options.test(filePath)) return filePath;
}
throw new Error(`Cannot find matching ${filename} in ${options.startingFrom} or parent directories`);
}
function findNearestFile(filename, options = {}) {
return findFile(filename, options);
}
function findFarthestFile(filename, options = {}) {
return findFile(filename, {
...options,
reverse: true
});
}
function _resolvePath(id, opts = {}) {
if (id instanceof URL || id.startsWith("file://")) return normalize(fileURLToPath(id));
if (isAbsolute(id)) return normalize(id);
return resolveModulePath(id, {
...opts,
from: opts.from || opts.parent || opts.url
});
}
const FileCache$1 = /* @__PURE__ */ new Map();
function defineTSConfig(tsconfig) {
return tsconfig;
}
async function readTSConfig(id, options = {}) {
const resolvedPath = await resolveTSConfig(id, options);
const cache = options.cache && typeof options.cache !== "boolean" ? options.cache : FileCache$1;
if (options.cache && cache.has(resolvedPath)) return cache.get(resolvedPath);
const parsed = parseJSONC(await promises.readFile(resolvedPath, "utf8"));
cache.set(resolvedPath, parsed);
return parsed;
}
async function writeTSConfig(path, tsconfig) {
await promises.writeFile(path, stringifyJSONC(tsconfig));
}
async function resolveTSConfig(id = process.cwd(), options = {}) {
return findNearestFile("tsconfig.json", {
...options,
startingFrom: _resolvePath(id, options)
});
}
const lockFiles = [
"yarn.lock",
"package-lock.json",
"pnpm-lock.yaml",
"npm-shrinkwrap.json",
"bun.lockb",
"bun.lock",
"deno.lock"
];
const packageFiles = [
"package.json",
"package.json5",
"package.yaml"
];
const workspaceFiles = [
"pnpm-workspace.yaml",
"lerna.json",
"turbo.json",
"rush.json",
"deno.json",
"deno.jsonc"
];
const FileCache = /* @__PURE__ */ new Map();
function definePackageJSON(pkg) {
return pkg;
}
async function findPackage(id = process.cwd(), options = {}) {
return findNearestFile(packageFiles, {
...options,
startingFrom: _resolvePath(id, options)
});
}
async function readPackage(id, options = {}) {
const resolvedPath = await findPackage(id, options);
const cache = options.cache && typeof options.cache !== "boolean" ? options.cache : FileCache;
if (options.cache && cache.has(resolvedPath)) return cache.get(resolvedPath);
const blob = await promises.readFile(resolvedPath, "utf8");
let parsed;
if (resolvedPath.endsWith(".json5")) parsed = parseJSON5(blob);
else if (resolvedPath.endsWith(".yaml")) parsed = parseYAML(blob);
else try {
parsed = parseJSON(blob);
} catch {
parsed = parseJSONC(blob);
}
cache.set(resolvedPath, parsed);
return parsed;
}
async function writePackage(path, pkg) {
let content;
if (path.endsWith(".json5")) content = stringifyJSON5(pkg);
else if (path.endsWith(".yaml")) content = stringifyYAML(pkg);
else content = stringifyJSON(pkg);
await promises.writeFile(path, content);
}
async function readPackageJSON(id, options = {}) {
const resolvedPath = await resolvePackageJSON(id, options);
const cache = options.cache && typeof options.cache !== "boolean" ? options.cache : FileCache;
if (options.cache && cache.has(resolvedPath)) return cache.get(resolvedPath);
const blob = await promises.readFile(resolvedPath, "utf8");
let parsed;
try {
parsed = parseJSON(blob);
} catch {
parsed = parseJSONC(blob);
}
cache.set(resolvedPath, parsed);
return parsed;
}
async function writePackageJSON(path, pkg) {
await promises.writeFile(path, stringifyJSON(pkg));
}
async function resolvePackageJSON(id = process.cwd(), options = {}) {
return findNearestFile("package.json", {
...options,
startingFrom: _resolvePath(id, options)
});
}
async function resolveLockfile(id = process.cwd(), options = {}) {
return findNearestFile(lockFiles, {
...options,
startingFrom: _resolvePath(id, options)
});
}
const workspaceTests = {
workspaceFile: (opts) => findFile(workspaceFiles, opts).then((r) => dirname(r)),
gitConfig: (opts) => findFile(".git/config", opts).then((r) => resolve(r, "../..")),
lockFile: (opts) => findFile(lockFiles, opts).then((r) => dirname(r)),
packageJson: (opts) => findFile(packageFiles, opts).then((r) => dirname(r))
};
async function findWorkspaceDir(id = process.cwd(), options = {}) {
const startingFrom = _resolvePath(id, options);
const tests = options.tests || [
"workspaceFile",
"gitConfig",
"lockFile",
"packageJson"
];
for (const testName of tests) {
const test = workspaceTests[testName];
if (options[testName] === false || !test) continue;
const direction = options[testName] || (testName === "gitConfig" ? "closest" : "furthest");
const detected = await test({
...options,
startingFrom,
reverse: direction === "furthest"
}).catch(() => {});
if (detected) return detected;
}
throw new Error(`Cannot detect workspace root from ${id}`);
}
async function updatePackage(id, callback, options = {}) {
const resolvedPath = await findPackage(id, options);
const pkg = await readPackage(id, options);
await writePackage(resolvedPath, await callback(new Proxy(pkg, { get(target, prop) {
if (typeof prop === "string" && objectKeys.has(prop) && !Object.hasOwn(target, prop)) target[prop] = {};
return Reflect.get(target, prop);
} })) || pkg);
}
function sortPackage(pkg) {
const sorted = {};
const originalKeys = Object.keys(pkg);
const knownKeysPresent = defaultFieldOrder.filter((key) => Object.hasOwn(pkg, key));
for (const key of originalKeys) {
const currentIndex = knownKeysPresent.indexOf(key);
if (currentIndex === -1) {
sorted[key] = pkg[key];
continue;
}
for (let i = 0; i <= currentIndex; i++) {
const knownKey = knownKeysPresent[i];
if (!Object.hasOwn(sorted, knownKey)) sorted[knownKey] = pkg[knownKey];
}
}
for (const key of [...dependencyKeys, "scripts"]) {
const value = sorted[key];
if (isObject(value)) sorted[key] = sortObject(value);
}
return sorted;
}
function normalizePackage(pkg) {
const normalized = sortPackage(pkg);
for (const key of dependencyKeys) {
if (!Object.hasOwn(normalized, key)) continue;
const value = normalized[key];
if (!isObject(value)) delete normalized[key];
}
return normalized;
}
function isObject(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function sortObject(obj) {
return Object.fromEntries(Object.entries(obj).sort(([a], [b]) => a.localeCompare(b)));
}
const dependencyKeys = [
"dependencies",
"devDependencies",
"optionalDependencies",
"peerDependencies"
];
const objectKeys = new Set([
"typesVersions",
"scripts",
"resolutions",
"overrides",
"dependencies",
"devDependencies",
"dependenciesMeta",
"peerDependencies",
"peerDependenciesMeta",
"optionalDependencies",
"engines",
"publishConfig"
]);
const defaultFieldOrder = [
"$schema",
"name",
"version",
"private",
"description",
"keywords",
"homepage",
"bugs",
"repository",
"funding",
"license",
"author",
"sideEffects",
"type",
"imports",
"exports",
"main",
"module",
"browser",
"types",
"typesVersions",
"typings",
"bin",
"man",
"files",
"workspaces",
"scripts",
"resolutions",
"overrides",
"dependencies",
"devDependencies",
"dependenciesMeta",
"peerDependencies",
"peerDependenciesMeta",
"optionalDependencies",
"bundledDependencies",
"bundleDependencies",
"packageManager",
"engines",
"publishConfig"
];
function defineGitConfig(config) {
return config;
}
async function resolveGitConfig(dir, opts) {
return findNearestFile(".git/config", {
...opts,
startingFrom: dir
});
}
async function readGitConfig(dir, opts) {
return parseGitConfig(await readFile(await resolveGitConfig(dir, opts), "utf8"));
}
async function writeGitConfig(path, config) {
await writeFile(path, stringifyGitConfig(config));
}
function parseGitConfig(ini) {
return parseINI(ini.replaceAll(/^\[(\w+) "(.+)"\]$/gm, "[$1.$2]"));
}
function stringifyGitConfig(config) {
return stringifyINI(config).replaceAll(/^\[(\w+)\.(\w+)\]$/gm, "[$1 \"$2\"]");
}
export { defineGitConfig, definePackageJSON, defineTSConfig, findFarthestFile, findFile, findNearestFile, findPackage, findWorkspaceDir, normalizePackage, parseGitConfig, readGitConfig, readPackage, readPackageJSON, readTSConfig, resolveGitConfig, resolveLockfile, resolvePackageJSON, resolveTSConfig, sortPackage, stringifyGitConfig, updatePackage, writeGitConfig, writePackage, writePackageJSON, writeTSConfig };
@@ -0,0 +1,45 @@
{
"name": "pkg-types",
"version": "2.3.1",
"description": "Node.js utilities and TypeScript definitions for `package.json` and `tsconfig.json`",
"license": "MIT",
"repository": "unjs/pkg-types",
"files": [
"dist"
],
"sideEffects": false,
"main": "./dist/index.mjs",
"types": "./dist/index.d.mts",
"exports": {
".": "./dist/index.mjs"
},
"dependencies": {
"confbox": "^0.2.4",
"exsolve": "^1.0.8",
"pathe": "^2.0.3"
},
"devDependencies": {
"@types/node": "^25.2.3",
"@typescript/native-preview": "latest",
"@vitest/coverage-v8": "^4.0.18",
"automd": "^0.4.3",
"changelogen": "^0.6.2",
"eslint-config-unjs": "^0.6.2",
"expect-type": "^1.3.0",
"obuild": "^0.4.27",
"oxfmt": "^0.32.0",
"oxlint": "^1.47.0",
"prettier": "^3.8.1",
"typescript": "^5.9.3",
"vitest": "^4.0.18"
},
"scripts": {
"build": "obuild",
"dev": "vitest --typecheck",
"lint": "oxlint && oxfmt --check .",
"fmt": "automd && oxlint --fix . && oxfmt",
"release": "pnpm test && pnpm build && changelogen --release && npm publish && git push --follow-tags",
"test": "pnpm lint && pnpm typecheck",
"typecheck": "tsgo --noEmit --skipLibCheck"
}
}
+65
View File
@@ -0,0 +1,65 @@
{
"name": "local-pkg",
"type": "module",
"version": "1.1.2",
"description": "Get information on local packages.",
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
"license": "MIT",
"funding": "https://github.com/sponsors/antfu",
"homepage": "https://github.com/antfu-collective/local-pkg#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/antfu-collective/local-pkg.git"
},
"bugs": {
"url": "https://github.com/antfu-collective/local-pkg/issues"
},
"keywords": [
"package"
],
"sideEffects": false,
"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"
],
"engines": {
"node": ">=14"
},
"dependencies": {
"mlly": "^1.7.4",
"pkg-types": "^2.3.0",
"quansync": "^0.2.11"
},
"devDependencies": {
"@antfu/eslint-config": "^5.2.1",
"@antfu/ni": "^25.0.0",
"@antfu/utils": "^9.2.0",
"@types/chai": "^5.2.2",
"@types/node": "^24.3.0",
"bumpp": "^10.2.3",
"chai": "^5.3.1",
"eslint": "^9.33.0",
"esno": "^4.8.0",
"find-up-simple": "^1.0.1",
"typescript": "^5.9.2",
"unbuild": "^3.6.1",
"unplugin-quansync": "^0.4.4",
"vitest": "^3.2.4"
},
"scripts": {
"build": "unbuild",
"lint": "eslint .",
"release": "bumpp",
"typecheck": "tsc --noEmit",
"test": "vitest run && node ./test/cjs.cjs && node ./test/esm.mjs"
}
}
+75
View File
@@ -0,0 +1,75 @@
{
"name": "unimport",
"type": "module",
"version": "3.14.6",
"description": "Unified utils for auto importing APIs in modules",
"license": "MIT",
"repository": "unjs/unimport",
"sideEffects": false,
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
},
"./unplugin": {
"import": "./dist/unplugin.mjs",
"require": "./dist/unplugin.cjs"
},
"./addons": {
"import": "./dist/addons.mjs",
"require": "./dist/addons.cjs"
},
"./*": "./*"
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"*.d.ts",
"dist"
],
"dependencies": {
"@rollup/pluginutils": "^5.1.4",
"acorn": "^8.14.0",
"escape-string-regexp": "^5.0.0",
"estree-walker": "^3.0.3",
"fast-glob": "^3.3.3",
"local-pkg": "^1.0.0",
"magic-string": "^0.30.17",
"mlly": "^1.7.4",
"pathe": "^2.0.1",
"picomatch": "^4.0.2",
"pkg-types": "^1.3.0",
"scule": "^1.3.0",
"strip-literal": "^2.1.1",
"unplugin": "^1.16.1"
},
"devDependencies": {
"@antfu/eslint-config": "^3.14.0",
"@types/estree": "^1.0.6",
"@types/node": "^22.10.6",
"@types/picomatch": "^3.0.1",
"@vitest/coverage-v8": "^2.1.8",
"bumpp": "^9.10.0",
"conventional-changelog-cli": "^5.0.0",
"eslint": "^9.18.0",
"h3": "^1.13.1",
"jquery": "^3.7.1",
"lit": "^3.2.1",
"typescript": "^5.7.3",
"unbuild": "^3.3.1",
"vitest": "^2.1.8",
"vue-tsc": "^2.2.0"
},
"scripts": {
"build": "unbuild",
"dev": "vitest dev",
"lint": "eslint .",
"play": "pnpm -C playground run dev",
"play:build": "pnpm -C playground run build",
"typecheck": "vue-tsc --noEmit",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
"release": "pnpm run test --run && bumpp -x \"pnpm run changelog\" --all && pnpm publish",
"test": "vitest --coverage"
}
}
+3
View File
@@ -0,0 +1,3 @@
// redirect for TypeScript to pick it up
export * from './dist/unplugin'
export { default } from './dist/unplugin'