npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@moneko/utils

v0.3.5

Published

[npm-url]: https://npmjs.org/package/@moneko/utils [install-tag]: https://nodei.co/npm/@moneko/utils.png [version-tag]: https://img.shields.io/npm/v/@moneko/utils/latest.svg?logo=npm [size-tag]: https://packagephobia.com/badge?p=%40moneko%2Futils@latest [

Readme

@moneko/utils

🐾 🐾 🐾 🐾

version install size download x install moneko-o

简介

@moneko/utils 是一个功能丰富的跨平台工具库,提供文件操作、格式转换、证书生成、终端输出、网络工具等多种实用功能。由 Rust 编写,通过 NAPI-RS 暴露给 JavaScript,性能卓越。

安装

npm install @moneko/utils

或使用 pnpm/yarn:

pnpm add @moneko/utils
yarn add @moneko/utils

功能模块

📁 文件操作

基础读写

  • loadFile(filepath: string): Promise<string> - 异步读取文件
  • loadFileSync(filepath: string): string | null - 同步读取文件
  • saveFile(filepath: string, data: string): Promise<boolean> - 异步写入文件
  • saveFileSync(filepath: string, data: string): boolean - 同步写入文件
  • loadFileRaw(filepath: string): Promise<Array<number>> - 异步读取二进制文件
  • saveFileRaw(filepath: string, data: Array<number>): Promise<boolean> - 异步保存二进制数据

文件追加与更新

  • appendToFile(filepath: string, data: string): Promise<boolean> - 异步追加内容到文件末尾
  • appendToFileSync(filepath: string, data: string): boolean - 同步追加内容到文件末尾
  • updateFile(filepath: string, data: string): Promise<boolean> - 异步更新文件内容
  • updateFileSync(filepath: string, data: string): boolean - 同步更新文件内容

文件复制与删除

  • copyFile(source: string, destination: string): Promise<boolean> - 异步复制文件
  • copyFileSync(src: string, dest: string): Promise<boolean> - 同步复制文件
  • removeFile(path: string): boolean - 删除文件
  • fileExists(filepath: string): boolean - 检查文件是否存在

目录操作

  • createDir(dirPath: string): boolean - 创建文件夹(包含必要的父级文件夹)
  • removeDir(path: string): boolean - 删除目录及其所有内容(谨慎使用!)
    • ⚠️ 此函数不遵循符号链接,它只会删除符号链接本身
  • deleteEmptyDirs(dirpath: string): void - 递归删除空目录
  • directoryExists(dirPath: string): boolean - 检查文件夹是否存在
  • scanFolderSync(folderpath: string, condition?: Array<string>): Array<string> - 扫描文件夹
  • renameFiles(dirpath: string, patterns: [string, string]): boolean - 重命名文件夹下的所有文件

文件操作示例:

import { 
  loadFile, 
  saveFile, 
  copyFile, 
  removeFile, 
  createDir, 
  scanFolderSync, 
  renameFiles,
  appendToFile,
  updateFile,
  fileExists,
  directoryExists
} from '@moneko/utils';

// 读取文件
const content = await loadFile('path/to/file.txt');
console.log(content);

// 保存文件
await saveFile('path/to/output.txt', 'Hello World');

// 同步读写
const syncContent = loadFileSync('config.json');
saveFileSync('backup.json', syncContent);

// 读取二进制文件
const buffer = await loadFileRaw('image.png');

// 复制文件
await copyFile('source.txt', 'destination.txt');
copyFileSync('src/file.js', 'dist/file.js');

// 追加内容
await appendToFile('log.txt', 'New log entry\n');
appendToFileSync('output.txt', 'appended text');

// 更新文件
await updateFile('config.json', '{"updated": true}');

// 检查文件/目录
if (fileExists('file.txt')) {
  console.log('File exists');
}

if (!directoryExists('output')) {
  createDir('output');
  createDir('path/to/nested/directory');
}

// 删除文件和目录
removeFile('temp.txt');
removeDir('path/to/directory'); // 删除目录及其所有内容

// 递归删除空目录
deleteEmptyDirs('lib');

// 扫描文件夹
const files = scanFolderSync('lib', ['.*\\.js$', '.*\\.ts$']);
console.log(files); // ['file1.js', 'file2.ts', ...]

// 重命名文件夹下的所有文件
renameFiles('lib', ['\\.js$', '.mjs']);
// 将所有 .js 文件重命名为 .mjs

🔄 格式转换

YAML 转换

  • parseYaml(filepath: string): Promise<string | null> - 解析 YAML 文件为 JSON 字符串
  • parseYamlSync(filepath: string): string | null - 同步解析 YAML 文件
  • parseYamlString(yamlString: string): Promise<string | null> - 解析 YAML 字符串
  • parseYamlStringSync(yamlString: string): string | null - 同步解析 YAML 字符串
  • jsonToYaml(jsonString: string): Promise<string | null> - 将 JSON 转换为 YAML
  • jsonToYamlSync(jsonString: string): string | null - 同步将 JSON 转换为 YAML

YAML 示例:

import { parseYaml, parseYamlString, jsonToYaml, jsonToYamlSync } from '@moneko/utils';

// 读取并解析 YAML 文件
const config = await parseYaml('config.yml');
const obj = JSON.parse(config);

// 解析 YAML 字符串
const yaml = `
name: example
version: 1.0.0
items:
  - id: 1
    name: item1
`;
const parsed = await parseYamlString(yaml);
console.log(JSON.parse(parsed)); // { name: 'example', version: 1, items: [...] }

// JSON 转 YAML
const json = { name: 'test', version: '1.0.0', tags: ['a', 'b'] };
const yamlOutput = await jsonToYaml(JSON.stringify(json));
console.log(yamlOutput);
// name: test
// version: 1.0.0
// tags:
//   - a
//   - b

// 同步转换
const yamlSync = jsonToYamlSync(JSON.stringify(json));

Plist 转换(iOS/macOS)

  • parsePlist(filepath: string): Promise<string> - 解析 Plist 文件为 JSON 字符串
  • parsePlistString(value: string): Promise<string> - 解析 Plist 字符串为 JSON
  • buildPlist(data: string): Promise<string> - 构建 JSON 字符串为 Plist 格式

Plist 示例:

import { parsePlist, parsePlistString, buildPlist } from '@moneko/utils';

// 解析 Info.plist 文件
const infoPlist = await parsePlist('Info.plist');
const config = JSON.parse(infoPlist);
console.log(config.CFBundleIdentifier);

// 解析 Plist 字符串
const plistStr = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "...">
<plist version="1.0">
<dict>
  <key>Name</key>
  <string>Test</string>
</dict>
</plist>`;

const parsed = await parsePlistString(plistStr);
console.log(JSON.parse(parsed)); // { Name: 'Test' }

// 构建 Plist
const data = JSON.stringify({ Name: 'App', Version: '1.0' });
const plistOutput = await buildPlist(data);
console.log(plistOutput); // XML 格式的 Plist

XML 转换

  • parseXml(filePath: string): string - 将 XML 文件转换为 JSON 字符串
  • parseXmlToJson(xmlContent: string): string - 将 XML 字符串转换为 JSON 字符串
  • buildXml(jsonContent: string): string - 将 JSON 字符串转换为 XML

XML 示例:

import { parseXml, parseXmlToJson, buildXml } from '@moneko/utils';

// 解析 XML 文件
const xmlData = parseXml('data.xml');
const obj = JSON.parse(xmlData);
console.log(obj);

// 解析 XML 字符串
const xml = `<?xml version="1.0"?>
<root>
  <user id="1">
    <name>John</name>
    <email>[email protected]</email>
  </user>
</root>`;

const json = parseXmlToJson(xml);
console.log(JSON.parse(json));
// {
//   root: {
//     user: {
//       '@id': '1',
//       name: 'John',
//       email: '[email protected]'
//     }
//   }
// }

// JSON 转 XML
const data = { root: { item: 'value', count: 1 } };
const xmlOutput = buildXml(JSON.stringify(data));
console.log(xmlOutput);
// <?xml version="1.0"?>
// <root>
//   <item>value</item>
//   <count>1</count>
// </root>

🗜️ 压缩与编码

  • compression(source: Array<number>, algo?: string, level?: number): Array<number> - 压缩数据(Gzip/Brotli)
    • algo: 压缩算法,默认 gzip,可选 brotli
    • level: 压缩级别,默认使用各算法默认级别
  • compressionByFilepath(filePath: string, algo?: string, level?: number): Array<number> - 按文件路径压缩文件
  • compressImage(imagePath: string, sizeFactor: number, quality: number): void - 压缩图片

压缩示例:

import { compression, compressionByFilepath, compressImage, saveFileRaw } from '@moneko/utils';

// 压缩数据
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const compressed = compression(data, 'gzip', 6);
console.log(`原始大小: ${data.length}, 压缩后: ${compressed.length}`);

// 使用 Brotli 压缩
const brotliCompressed = compression(data, 'brotli', 11);

// 按文件路径压缩
const result = compressionByFilepath('large-file.bin', 'gzip', 9);
saveFileRaw('large-file.bin.gz', result);

// 压缩图片
compressImage('photo.jpg', 0.8, 80);
// sizeFactor: 缩放比例 (0-1),1.0 = 原始大小
// quality: 图片质量 (0-100)

🖨️ 终端输出

彩色文本

  • ink(text: string, color: string, options?: InkOptions): string - 为终端输出创建彩色文本
    • 支持基础颜色: red, green, blue, yellow, cyan, magenta, white, black
    • 支持 RGB 格式: "255,0,0"
    • 支持 ANSI256: "123"
interface InkOptions {
  bg?: string;           // 背景色
  bold?: boolean;        // 粗体
  intense?: boolean;     // 高亮
  italic?: boolean;      // 斜体
  underline?: boolean;   // 下划线
}

输出函数

  • print(text: string, clear?: boolean): void - 输出文本到控制台
  • println(text: string, clear?: boolean): void - 输出文本到控制台并换行
  • termClear(mode?: number): boolean - 清除终端输出
    • mode=0: 从光标位置到屏幕末尾(默认)
    • mode=1: 从屏幕开始到光标位置
    • mode=2: 整个屏幕
    • mode=3: 整个屏幕和滚动缓冲区

进度条与完成信息

  • progressBar(current: number, max: number, options?: ProgressBarOptions): void - 显示进度条
  • completedInfo(duration: number, output: string): void - 显示完成信息
interface ProgressBarOptions {
  name?: string;         // 进度条名称
  msg?: string;          // 显示的消息
  nameColor?: string;    // 名称颜色
  msgColor?: string;     // 消息颜色
  barColor?: string;     // 进度条颜色
  barBgColor?: string;   // 进度条背景颜色
}

终端输出示例:

import { ink, print, println, termClear, progressBar, completedInfo } from '@moneko/utils';

// 彩色输出
console.log(`${ink("错误", "red")} 连接失败`);
console.log(`${ink("成功", "green")} 数据已保存`);
console.log(`${ink("警告", "255,165,0")} 操作需要审批`); // 橙色 RGB
console.log(ink("提示", "39"));                           // ANSI256 深蓝色

// 高级样式
console.log(ink("粗体", "blue", { bold: true }));
console.log(ink("下划线", "cyan", { underline: true }));
console.log(ink("红底白字", "white", { bg: "red", bold: true }));

// 普通输出
print("你好");              // 输出但不换行
println("操作完成");         // 输出并换行
print("加载中...", true);   // 清行后输出(适用于进度条)

// 进度条
for (let i = 0; i <= 100; i++) {
  progressBar(i, 100, {
    name: '下载',
    nameColor: 'cyan',
    barColor: 'green'
  });
}

// 显示完成信息
const startTime = Date.now();
// ... 执行操作 ...
const duration = Date.now() - startTime;
completedInfo(duration, 'build');

// 清除终端
termClear(0);  // 从光标清到末尾
termClear(2);  // 清除整个屏幕
termClear(3);  // 清除屏幕和历史

📊 数据分析与转换

  • analyzeBundleSize(filepath: string, condition?: Array<string>): void - 分析文件体积
  • convert(num: number): string - 大小转换(字节转人类可读格式)

数据分析示例:

import { analyzeBundleSize, convert } from '@moneko/utils';

// 分析打包体积
analyzeBundleSize('dist', ['.*\\.js$', '.*\\.css$']);
// 输出: 
// dist/index.js: 1.2 MB
// dist/style.css: 150 KB
// 总大小: 1.35 MB

// 字节转换
console.log(convert(1024));       // "1.0 KB"
console.log(convert(1048576));    // "1.0 MB"
console.log(convert(1073741824)); // "1.0 GB"
console.log(convert(512));        // "512 B"

🌐 网络与 Hosts

  • getHostsPath(): string - 获取 hosts 文件路径(跨平台)
    • macOS/Linux: /etc/hosts
    • Windows: C:\Windows\System32\drivers\etc\hosts
  • checkHost(ip: string, domain: string): boolean - 检查 hosts 文件中是否存在指定映射
  • addHost(ip: string, domain: string): boolean - 追加 IP 和域名的映射到 hosts 文件

Hosts 示例:

import { getHostsPath, checkHost, addHost } from '@moneko/utils';

const hostsPath = getHostsPath();
console.log(`Hosts 文件路径: ${hostsPath}`);

// 检查是否已存在映射
if (!checkHost('127.0.0.1', 'local.example.com')) {
  // 如果不存在,添加映射
  const success = addHost('127.0.0.1', 'local.example.com');
  if (success) {
    console.log('Hosts 映射添加成功');
  }
}

// 检查其他映射
if (checkHost('192.168.1.1', 'router.local')) {
  console.log('路由器映射已存在');
}

🔐 证书管理

接口定义

interface GenerateCertificateParams {
  // 证书绑定的主域名(支持通配符域名)
  // @example ["local.example.com", "localhost", "127.0.0.1"]
  subjectAltNames?: Array<string>;
  
  // 国家代码(两位大写字母,遵循 ISO 3166 标准)
  // @example "CN" // 中国
  countryName?: string;
  
  // 州/省名称(全称,不包含缩写)
  // @example "Shanghai"
  stateOrProvinceName?: string;
  
  // 城市/地区名称(需为完整行政区划名称)
  // @example "Beijing"
  localityName?: string;
  
  // 组织机构全称(需为合法注册的实体名称)
  // @example "Acme Corporation"
  organizationName?: string;
  
  // 组织机构部门名称(具体业务部门名称)
  // @example "IT Department"
  organizationUnitName?: string;
  
  // 通用名称(通常显示在证书详情中的主体标识)
  // 对于 SSL 证书通常与域名一致
  // @example "local.example.com"
  commonName?: string;
}

interface CertificateResult {
  cert: string;   // 证书内容(PEM 格式)
  key: string;    // 私钥内容(PEM 格式)
}

interface Certificates {
  cert?: string;     // 签名证书
  key?: string;      // 签名证书私钥
  rootCa: string;    // 根证书(PEM 格式)
  rootKey: string;   // 根证书私钥(PEM 格式)
}

证书生成函数

  • generateRootCertificateAuthority(option: GenerateCertificateParams): CertificateResult - 生成根证书
  • generateCertificate(params: GenerateCertificateParams): Certificates - 生成完整证书(包含根证书和签名证书)
  • generateCert(issuer: string, issuerKey: string, subjectAltNames: Array<string>): CertificateResult - 根据颁发者证书生成签名证书
  • normalCertificateAuthority(): CertificateResult - 获取默认的预设根证书

证书示例:

import {
  generateRootCertificateAuthority,
  generateCertificate,
  generateCert,
  normalCertificateAuthority,
  saveFileSync
} from '@moneko/utils';

// 方式1: 一步生成完整证书
const certs = generateCertificate({
  subjectAltNames: ['localhost', '127.0.0.1', '*.example.com'],
  countryName: 'CN',
  stateOrProvinceName: 'Shanghai',
  localityName: 'Shanghai',
  organizationName: 'My Company',
  organizationUnitName: 'IT Department',
  commonName: 'local.example.com'
});

saveFileSync('./certs/root.pem', certs.rootCa);
saveFileSync('./certs/root-key.pem', certs.rootKey);
saveFileSync('./certs/server.pem', certs.cert);
saveFileSync('./certs/server-key.pem', certs.key);

// 方式2: 分步生成(先生成根证书,再生成签名证书)
const rootCA = generateRootCertificateAuthority({
  countryName: 'CN',
  stateOrProvinceName: 'Beijing',
  localityName: 'Beijing',
  organizationName: 'My Root CA',
  commonName: 'My Root CA'
});

saveFileSync('./certs/ca.pem', rootCA.cert);
saveFileSync('./certs/ca-key.pem', rootCA.key);

// 使用根证书签名服务器证书
const serverCert = generateCert(
  rootCA.cert,
  rootCA.key,
  ['localhost', '127.0.0.1', 'api.example.com']
);

saveFileSync('./certs/server.pem', serverCert.cert);
saveFileSync('./certs/server-key.pem', serverCert.key);

// 方式3: 使用预设根证书
const presetCA = normalCertificateAuthority();
const clientCert = generateCert(
  presetCA.cert,
  presetCA.key,
  ['client.example.com']
);

// 用于 Express/Node.js HTTPS 服务器
const https = require('https');
const fs = require('fs');

const options = {
  key: fs.readFileSync('./certs/server-key.pem'),
  cert: fs.readFileSync('./certs/server.pem')
};

https.createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('Hello HTTPS World!');
}).listen(443);

🍎 iOS/macOS 特有功能

  • bundleIpa(bundleDir: string, outputBundleDir: string, ipaType: string): void - 打包 IPA 文件
    • bundleDir: 要打包的文件夹的目录路径
    • outputBundleDir: 输出 IPA 文件的保存路径
    • ipaType: 打包类型(如 app-store, ad-hoc, development)

iOS 打包示例:

import { bundleIpa } from '@moneko/utils';

// 打包生成的 .app 文件为 IPA
bundleIpa(
  './build/Release-iphoneos',
  './output',
  'app-store'
);

// 其他打包类型
bundleIpa('./build/Release-iphoneos', './output', 'ad-hoc');
bundleIpa('./build/Release-iphoneos', './output', 'development');

⚙️ Promise 工具

  • awaitPromise(p: Promise<boolean>): Promise<boolean> - 等待 Promise 执行
import { awaitPromise } from '@moneko/utils';

async function example() {
  const result = await awaitPromise(someAsyncOperation());
  console.log(result);
}

完整示例

示例1:文件处理流程

import {
  fileExists,
  directoryExists,
  createDir,
  saveFile,
  loadFile,
  scanFolderSync,
  ink,
  println
} from '@moneko/utils';

async function processFiles() {
  const sourceDir = './source';
  const outputDir = './processed';
  
  // 创建输出目录
  if (!directoryExists(outputDir)) {
    createDir(outputDir);
    println(`${ink('✓', 'green')} 创建目录成功`);
  }
  
  // 扫描源文件
  const files = scanFolderSync(sourceDir, ['.*\\.txt$']);
  println(`${ink(`找到 ${files.length} 个文件`, 'cyan')}`);
  
  // 处理每个文件
  for (const file of files) {
    try {
      const content = await loadFile(`${sourceDir}/${file}`);
      const processed = content.toUpperCase();
      
      const outputFile = `${outputDir}/${file}`;
      await saveFile(outputFile, processed);
      println(`${ink('✓', 'green')} 处理完成: ${outputFile}`);
    } catch (error) {
      println(`${ink('✗', 'red')} 处理失败: ${file} - ${error.message}`);
    }
  }
  
  println(`${ink('完成!', 'green', { bold: true })}`);
}

processFiles();

示例2:Web 服务器 SSL 证书生成与使用

import {
  generateRootCertificateAuthority,
  generateCert,
  saveFileSync,
  fileExists,
  createDir,
  directoryExists
} from '@moneko/utils';
import https from 'https';
import fs from 'fs';
import express from 'express';

async function setupSSLServer() {
  const certDir = './certs';
  
  // 确保证书目录存在
  if (!directoryExists(certDir)) {
    createDir(certDir);
  }
  
  const rootCertPath = `${certDir}/root.pem`;
  const rootKeyPath = `${certDir}/root-key.pem`;
  const serverCertPath = `${certDir}/server.pem`;
  const serverKeyPath = `${certDir}/server-key.pem`;
  
  let rootCA;
  
  // 检查根证书是否存在
  if (fileExists(rootCertPath)) {
    console.log('使用现有的根证书');
    rootCA = {
      cert: fs.readFileSync(rootCertPath, 'utf-8'),
      key: fs.readFileSync(rootKeyPath, 'utf-8')
    };
  } else {
    // 生成新的根证书
    console.log('生成新的根证书...');
    rootCA = generateRootCertificateAuthority({
      countryName: 'CN',
      stateOrProvinceName: 'Shanghai',
      localityName: 'Shanghai',
      organizationName: 'Example Corp',
      organizationUnitName: 'IT',
      commonName: 'Example Root CA'
    });
    
    saveFileSync(rootCertPath, rootCA.cert);
    saveFileSync(rootKeyPath, rootCA.key);
  }
  
  // 生成服务器证书
  console.log('生成服务器证书...');
  const serverCert = generateCert(
    rootCA.cert,
    rootCA.key,
    ['localhost', '127.0.0.1', '*.example.local']
  );
  
  saveFileSync(serverCertPath, serverCert.cert);
  saveFileSync(serverKeyPath, serverCert.key);
  
  // 创建 HTTPS 服务器
  const app = express();
  
  app.get('/', (req, res) => {
    res.send('Hello HTTPS World!');
  });
  
  const httpsOptions = {
    key: fs.readFileSync(serverKeyPath),
    cert: fs.readFileSync(serverCertPath)
  };
  
  https.createServer(httpsOptions, app).listen(443, () => {
    console.log('HTTPS 服务器运行在 https://localhost');
  });
}

setupSSLServer();

示例3:批量处理和格式转换

import {
  scanFolderSync,
  loadFile,
  saveFile,
  parseXml,
  buildXml,
  jsonToYaml,
  progressBar,
  ink,
  println
} from '@moneko/utils';

async function convertXmlFiles() {
  const inputDir = './data/xml';
  const outputDir = './data/json';
  
  // 扫描所有 XML 文件
  const xmlFiles = scanFolderSync(inputDir, ['.*\\.xml$']);
  
  println(`${ink(`开始转换 ${xmlFiles.length} 个 XML 文件`, 'cyan')}`);
  
  for (let i = 0; i < xmlFiles.length; i++) {
    const xmlFile = xmlFiles[i];
    
    try {
      // 读取 XML 文件
      const xmlContent = await loadFile(`${inputDir}/${xmlFile}`);
      
      // 转换为 JSON
      const jsonContent = parseXml(`${inputDir}/${xmlFile}`);
      
      // 保存 JSON
      const jsonFileName = xmlFile.replace('.xml', '.json');
      await saveFile(`${outputDir}/${jsonFileName}`, jsonContent);
      
      // 转换为 YAML
      const yamlContent = await jsonToYaml(jsonContent);
      const yamlFileName = xmlFile.replace('.xml', '.yaml');
      await saveFile(`${outputDir}/${yamlFileName}`, yamlContent);
      
      // 显示进度
      progressBar(i + 1, xmlFiles.length, {
        name: '转换',
        nameColor: 'cyan',
        barColor: 'green'
      });
    } catch (error) {
      println(`${ink(`✗ 转换失败: ${xmlFile}`, 'red')}`);
    }
  }
  
  println(`${ink('转换完成!', 'green', { bold: true })}`);
}

convertXmlFiles();

示例4:项目构建和文件整理

import {
  scanFolderSync,
  analyzeBundleSize,
  convert,
  renameFiles,
  progressBar,
  completedInfo,
  ink
} from '@moneko/utils';

async function buildProject() {
  const startTime = Date.now();
  
  console.log(ink('开始构建项目...', 'cyan', { bold: true }));
  
  // 扫描输出目录
  const jsFiles = scanFolderSync('dist', ['.*\\.js$']);
  const cssFiles = scanFolderSync('dist', ['.*\\.css$']);
  
  console.log(`${ink('✓', 'green')} 找到 ${jsFiles.length} 个 JS 文件和 ${cssFiles.length} 个 CSS 文件`);
  
  // 分析打包体积
  console.log('\n分析打包体积:');
  analyzeBundleSize('dist', ['.*\\.(js|css|json)$']);
  
  // 重命名文件为 .mjs
  console.log(`\n${ink('重命名文件...', 'cyan')}`);
  renameFiles('dist', ['\\.js$', '.mjs']);
  
  // 显示完成信息
  const duration = Date.now() - startTime;
  completedInfo(duration, '构建');
}

buildProject();

API 速查表

| 功能 | 函数名 | 同步版本 | 异步版本 | |------|--------|---------|---------| | 读取文件 | loadFile | ✅ | ✅ | | 写入文件 | saveFile | ✅ | ✅ | | 追加内容 | appendToFile | ✅ | ✅ | | 更新内容 | updateFile | ✅ | ✅ | | 复制文件 | copyFile | ✅ | ✅ | | 删除文件 | removeFile | ✅ | ✗ | | 创建目录 | createDir | ✅ | ✗ | | 删除目录 | removeDir | ✅ | ✗ | | 扫描目录 | scanFolderSync | ✅ | ✗ | | 解析 YAML | parseYaml | ✅ | ✅ | | 解析 XML | parseXml | ✅ | ✗ | | 解析 Plist | parsePlist | ✗ | ✅ | | 生成证书 | generateCertificate | ✅ | ✗ | | 彩色输出 | ink | ✅ | ✗ | | 进度条 | progressBar | ✅ | ✗ |

性能说明

  • 所有文件操作都是通过 Rust 实现,性能远优于 Node.js 原生 API
  • 大文件操作(>100MB)建议使用二进制接口(loadFileRaw, saveFileRaw)
  • 递归操作(如 removeDir, deleteEmptyDirs)在处理大目录时性能最优

浏览器兼容性

本库为 Node.js 专用,不支持浏览器环境。

常见问题

Q: 如何在 Windows 上修改 hosts 文件?

A: 需要以管理员身份运行 Node.js 进程。

// Windows 上需要管理员权限
import { addHost } from '@moneko/utils';
addHost('127.0.0.1', 'example.local'); // 需要管理员

Q: 证书生成后如何在浏览器中信任?

A:

  • macOS: 打开钥匙串访问,导入根证书,设置为信任
  • Linux: 将根证书复制到 /usr/local/share/ca-certificates/, 运行 update-ca-certificates
  • Windows: 运行 certmgr.msc,导入根证书到"受信任的根证书颁发机构"

Q: 如何处理大文件?

A: 对于大文件(>100MB),建议使用二进制接口:

const buffer = await loadFileRaw('large-file.bin');
// 处理数据
await saveFileRaw('output.bin', buffer);

许可证

MIT