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

@quanxiaoxiao/datav

v0.7.1

Published

Data transformation utility with type conversion, path access, and schema-driven data transformation

Readme

@quanxiaoxiao/datav

npm version npm license node version

轻量级数据转换工具库,支持 Schema 驱动Field DSL 两种转换模式,提供类型安全的数据提取、转换和组合能力。

核心特性

  • 双模式转换: 支持声明式 Schema 和链式 Field DSL 两种方式
  • 类型安全: 完整的 TypeScript 类型支持,编译时检查
  • 路径访问: 强大的点分隔符路径访问,支持嵌套和数组索引
  • 类型转换: 自动类型转换,处理 string/number/boolean/integer 等
  • 默认值支持: 支持 defaultValue,在数据缺失或为空时提供默认值
  • 错误处理: 完善的错误机制,提供详细的错误信息

安装

npm install @quanxiaoxiao/datav

快速开始

Schema 驱动模式

通过定义 Schema 来描述数据结构:

import { transform } from '@quanxiaoxiao/datav';

const schema = {
  path: '.',
  type: 'object',
  properties: {
    name: { path: '.name', type: 'string' },
    age: { path: '.age', type: 'integer' },
    active: { path: '.active', type: 'boolean' },
  },
};

const result = transform(schema, {
  name: 123,
  age: '30',
  active: 'true',
});
// { name: '123', age: 30, active: true }

默认值 (defaultValue)

当数据缺失或为空时,可以提供默认值:

const schema = {
  path: '.',
  type: 'object',
  properties: {
    name: { path: '.name', type: 'string', defaultValue: 'Anonymous' },
    count: { path: '.count', type: 'number', defaultValue: 0 },
    items: {
      path: '.items',
      type: 'array',
      items: { path: '.', type: 'string' },
      defaultValue: ['default item'],
    },
  },
};

transform(schema, { name: null, count: null, items: [] });
// { name: 'Anonymous', count: 0, items: ['default item'] }

Field DSL 模式

通过链式 API 构建转换规则:

import { compile, toObject, toString, toInteger, toArray } from '@quanxiaoxiao/datav';

const field = toObject({
  name: toString('user.name'),
  age: toInteger('user.age'),
  tags: toArray('user.tags'),
});

const result = compile(field)({
  user: { name: 'Alice', age: '25', tags: [1, 2, 3] },
});
// { name: 'Alice', age: 25, tags: ['1', '2', '3'] }

API 参考

Schema 驱动模式

transform(schema, data)

一次性转换数据:

const schema = {
  path: '.',
  type: 'object',
  properties: {
    id: { path: '.id', type: 'string' },
    items: {
      path: '.items',
      type: 'array',
      items: { path: '.', type: 'integer' },
    },
  },
};

transform(schema, { id: 123, items: ['1', '2', '3'] });
// { id: '123', items: [1, 2, 3] }

createTransform(schema)

创建可复用的转换函数:

const userTransformer = createTransform({
  path: '.',
  type: 'object',
  properties: {
    name: { path: '.name', type: 'string' },
    age: { path: '.age', type: 'integer' },
  },
});

userTransformer({ name: 'Bob', age: '30' }); // { name: 'Bob', age: 30 }
userTransformer({ name: 'Carol', age: '25' }); // { name: 'Carol', age: 25 }

validateExpressSchema(schema)

验证 Schema 格式:

const result = validateExpressSchema({
  path: '.',
  type: 'object',
  properties: {
    name: { path: '.name', type: 'string' },
  },
});
// { valid: true, errors: [] }

Field DSL 模式

基本类型转换

toString(path?)      // 转换为字符串
toNumber(path?)      // 转换为数字
toInteger(path?)     // 转换为整数
toBoolean(path?)     // 转换为布尔值

复合类型

toObject(pathOrFields, fields?)  // 对象类型
toArray(pathOrField, field?)     // 数组类型

compile(field)

将 Field 编译为可执行函数:

const field = toObject({
  name: toString('user.name'),
  age: toInteger('user.age'),
});

const executor = compile(field);
executor({ user: { name: 'Alice', age: '25' } });
// { name: 'Alice', age: 25 }

路径访问

支持点分隔符路径和数组索引:

// 嵌套路径
toString('user.profile.name')

// 数组索引
toString('items.0.name')
toString('matrix.0.1.value')

// 根路径
toString('$')

错误处理

import { DataVError, isDataVError, ERROR_CODES } from '@quanxiaoxiao/datav';

try {
  transform(schema, data);
} catch (error) {
  if (isDataVError(error)) {
    console.log(error.code);      // 错误码
    console.log(error.details);   // 详细错误信息
  }
}

高级用法

嵌套对象转换

const schema = {
  path: '.',
  type: 'object',
  properties: {
    user: {
      path: '.user',
      type: 'object',
      properties: {
        id: { path: '.id', type: 'integer' },
        name: { path: '.name', type: 'string' },
        address: {
          path: '.address',
          type: 'object',
          properties: {
            city: { path: '.city', type: 'string' },
            zipCode: { path: '.zip', type: 'integer' },
          },
        },
      },
    },
  },
};

transform(schema, {
  user: {
    id: '42',
    name: 'Alice',
    address: { city: 'New York', zip: '10001' },
  },
});
// { user: { id: 42, name: 'Alice', address: { city: 'New York', zip: 10001 } } }

数组转换

const schema = {
  path: '.users',
  type: 'array',
  items: {
    path: '.',
    type: 'object',
    properties: {
      id: { path: '.id', type: 'integer' },
      name: { path: '.name', type: 'string' },
    },
  },
};

transform(schema, {
  users: [
    { id: '1', name: 'A' },
    { id: '2', name: 'B' },
  ],
});
// [{ id: 1, name: 'A' }, { id: 2, name: 'B' }]

自定义 Resolver

通过 resolve 字段添加自定义转换逻辑:

const schema = {
  path: '.',
  type: 'object',
  properties: {
    amount: {
      path: '.amount',
      type: 'number',
      resolve: (value) => (value as number) * 100,
    },
  },
};

transform(schema, { amount: 10 });
// { amount: 1000 }

类型定义

type SchemaType = 'string' | 'number' | 'boolean' | 'integer' | 'object' | 'array';

interface SchemaExpress {
  path: string;
  type: SchemaType;
  resolve?: (value: unknown, context: { data: unknown; rootData: unknown; path: string }) => unknown;
  defaultValue?: string | number | boolean | Record<string, unknown> | unknown[];
  properties?: Record<string, SchemaExpress>;
  items?: SchemaExpress;
}

默认值 (defaultValue)

Schema 支持 defaultValue 字段,当原始数据缺失、为空或为 null 时,将使用默认值:

// primitive 类型
const schema1 = {
  path: '.name',
  type: 'string',
  defaultValue: 'Unknown',
};

// array 类型 - 空数组时使用默认值
const schema2 = {
  path: '.tags',
  type: 'array',
  items: { path: '.', type: 'string' },
  defaultValue: ['untagged'],
};

// object 类型 - null 时使用默认值
const schema3 = {
  path: '.config',
  type: 'object',
  properties: { theme: { path: 'theme', type: 'string' } },
  defaultValue: { theme: 'light' },
};

// 嵌套结构中的 defaultValue
const schema4 = {
  path: '.',
  type: 'object',
  properties: {
    user: {
      path: '.user',
      type: 'object',
      properties: {
        name: { path: '.name', type: 'string', defaultValue: 'Guest' },
      },
    },
  },
};

transform(schema4, { user: { name: null } });
// { user: { name: 'Guest' } }

许可证

MIT