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

@shushu.pro/adapter

v0.1.0

Published

数据适配器

Readme

@shushu.pro/adapter

简介

adapter是一个简单,高效以声明的方式批量适配处理数据的工具,它能帮你对数据进行各种常见的适配转换,使得转换后的数据结构或者数据格式符合业务要求

adapter可以进行高度灵活的自定义扩展,来满足具体的业务需要,通过扩展生成各种速写指令来达到数据的快速处理,并保持数据处理的一致性和准确性

安装使用

yarn add @shushu.pro/adapter

简单示例

const data = {
    user: '张三',
    sex: 0,
    age: '18',
    books: [
        { name: '水浒传', type: 'm1', price: 50 },
        { name: '西游记', type: 'm2', price: 60 },
        { name: '三国演义', type: 'm3', price: null },
    ],
    address: ['浙江省', '杭州市', '江干区', '火车东站旁'],
}
const nextData = adapter({
    user: 'name',
    sex: { $enum: ['先生', '女士', '保密'] },
    age: Number,
    books: {
        name: true,
        type: { $emap: { m1: '武侠小说', m2: '神话小说', m3: '历史小说' } },
        price: { $default: '未知', $value: (value) => '¥' + value.toFixed(2) },
    },
    address: (value) => value.join(''),
}, data)

// 输出新数据
{
    name: '张三',
    sex: '先生',
    age: 18,
    books: [
        { name: '水浒传', type: '武侠小说', price: '¥50.00' },
        { name: '西游记', type: '神话小说', price: '¥60.00' },
        { name: '三国演义', type: '历史小说', price: '未知' },
    ],
    address: '浙江省杭州市江干区火车东站旁',
}

API指令集

模式指令

  • $strict 适配器严格模式,默认true
  • $clears 清除模式,默认false,清除提交请求参数特别有效

$strict 指令示例

严格模式

严格模式会对字段和适配器进行一一对应,适配器中未声明的字段将自动过滤

const testData = { key1:1, key2:1, key3:1 }
const newData = adapter({
    key1: true
}, testData)

// 输出 newData === { key1:1 }
非严格模式

非严格模式会拷贝所有未在适配器中定义的原始字段

const testData = { key1:1, key2:1, key3:1 }
const newData = adapter({
    $strict: false,
    key1: () => 666
}, testData)

// 输出 newData === { key1:666, key2:1, key3:1 }

$clears 指令示例

$clears指令可以控制过滤符合条件的字段,比如值为nullundefined,空字符串等字段

$clears设置为true时,则默认采用[null, undefined, '']规则进行过滤 当传入的是参数函数,filter(value, key, context),过滤返回值为true的项,参数:value(项的值),key(项的键),context(上下文环境)

const testData = { key1:'', key2:undefined, key3:null, key4:false, key5:555, key6:666,key7:true}

const newData1 = adapter({
    $strict: false,
    $clears: true
}, testData)
// 输出 newData1 === { key4:false, key4:false, key5:555, key6:666, key7:true }

const newData2 = adapter({
    $strict: false,
    $clears: ['null', 555, (val, key)=> val === 666 || key === 'key7']
}) 
// 输出 newData2 === {key1:'', key2:undefined, key4:false}

转换指令

  • $key 字段键名转换,默认不转换
  • $type 数据类型转换,使用JS内置转换规则
  • $enum 数据枚举类型转换
  • $emap 数据映射类型转换
  • $format 数据格式化转换
  • $value 数据值转换
  • $default 数据默认值设置
  • $filter 数组扩展指令

高级指令

  • $increase 数据添加层级
  • $reduce 数据缩减层级

字段衍生

可以将一个字段衍生出多个不同的字段,只要使用数组方式传递,例如:[ { $key:'value1', type:Boolean, }, { $key:'value2', type:Number } ] 将会使用原字段生成2个字段,分别是value1, value2,转换规则调用类型转换

运行上下

所有function类型的适配规则,都有一个上下文环境变量ctx,比如$value(value, ctx)$default(ctx)

const testData = {
    type: 3,
    data: {
        books: [
            {name:'水浒传'},
            {name:'西游记'}
        ]
    }
}

const newData = adapter({
    data:{
        books: {
            name: (value, { row, index, root }){
                // row 返回 项{name:'...'}
                // index 返回 项的下标
                // root 返回 根数据testData
                return `${index}.${value}`
            }
        }
    }
})

// 输出 newData === { data:{ books: [ {name:'0.水浒传'}, {name:'1.西游记'} ] } }

API方法

调用方法

  • adapter(setting) 初始化一个适配器对象
  • adapter(setting, data) 快速生成并调用适配器处理数据

扩展指令

  • adapter.addFormat(name, value) 添加一个预设format指令,name可以在$format指令中直接使用
  • adapter.addEnum(name, value) 添加一个预设的enumname可以在$enum指令中直接使用
  • adapter.addEmap(name, value) 添加一个预设的emapname可以在$emap指令中直接使用

通过传入对象形式的参数来批量添加扩展指令,例如:addEnum({ provinces:['浙江省', '江苏省'], citys: ['杭州', '宁波'] })

使用示例

键名转换 $key

const testData = { key1:1, key2:2, key3:3 }
const newData = adapter({
    key1: 'newKey1', // 使用速写指令进行转换
    key2: { $key: 'newKey2' } // 使用`$key`指令进行转换
    key3: { $key: (value) => 'newKey3'} // 使用函数
}, testData)

// 输出
{ newKey1:1, newKey2:2, newKey3:3 }

数据类型转换 $type

const testData = { toBoolean: 1, toNumber: '12', toString: 12, toDate: 1561750773712, value: 1 }
const newData = adapter({
    toBoolean: Boolean,
    toNumber: Number,
    toString: String, 
    toDate: Date,
    value1: 'type:Boolean',
    value: [ // 衍生字段
        'key:value2 type:Boolean', // 速写指令 
        { $key: 'value3', type:String }, // 对象型指令
    ]
})

// 输出,使用JS内置转换规则
{ toBoolean:true, toNumber:12, toString:'12', toDate: new Date(1561750773712), value1:true, value2:true, value3:'1' }

枚举转换 $enum

const testData = { type:1 }
const newData = adapter({
    type1: 'enmu:中国,美国'
    type: [
        'key:type2 enmu:中国,美国', // 速写指令
        { $key:'type3', $enmu:['中国', '美国'] }
    ],
    
}, testData)

// 输出
{ type1:'美国', type2:'美国', type3:'美国' }

扩展预设枚举转换 adapter.addEnmu(...) + $enum

adapter.addEnum({ // 扩展的枚举,在指令中可以直接使用名字去索引,对于一些公用的枚举进行统一管理维护,使用速写方式快速的对数据进行转换
    country: ['中国', '美国'],
    province: ['北京市', '杭州市']
})

const testData = { country:0, province:1 }
const newData = adapter({
    country: 'enum:country',
    province: {$enum:'province'}
}, testData)

// 输出
{country:'中国', province:'杭州市'}

映射转换 $emap

同枚举转换,区别在于一个是数字类型的参数来查询数组数据,一个是键的方式查询对象的值

扩展格式化指令 adapter.addFormat(...) + $format

格式化指令是一个很强大的设定,你可以定义任意的格式化指令,然后在需要使用的地方使用,一个适配规则可以使用任意多次,任意顺序的格式化指令

 adapter.addFormat('increase', (value, ctx, num = 1) => { // 一个累加器,可以给一个值进行累加操作
    return value + Number(num)
})
adapter.addFormat('toArray', (value, ctx, token = ',') => { // 转换数组
    return value.split(token)
})
adapter.addFormat('toMap', (value, ctx, arr) => { // 转换数组为map
    const map = {}
    arr.forEach(key => {
        map[key] = key
    })
    return map
})

const testData = { value: 1, value2: 2 }
const newData = adapter({
    value: {  // 传递多条指令,就像管道函数一样,前面的结果作为后面的输入
        $format: ['increase:1', 'increase:-2', 'increase:1234', (value) => String(value), 'toArray:'],
    },
    value2: [ // 传递任意多个,任意类型的参数
        { $key: 'nameMap', $format: { name: 'toMap', args:[ ['张三', '李四'] ] } },
        { $key: 'numMap', $format: { name: 'toMap', args:[ [1, 2] ] } },
    ]
}, testData)

// 输出
{ 
    value: ['1', '2', '3', '4'], 
    nameMap: {'张三':'张三', '李四':'李四'},
    numMap: {'1':'1', '2':'2'}
}

$format数组模式下,允许使用{$enum:'enumName'}, {$emap:'emapName'}进行枚举和映射转化,或者{$enum:[...]},{$emap:{...}}

使用值进行转换 $value

const testData = { value: 1, data: { name:'张三' } }
const newData = adapter({
    value: (value, ctx) => value + 'K',
    data: (value,) => value.name
}, testData)

// 输出
{ value: '1K', data: '张三'}

使用默认值

const testData = { 
    list: [
        { name: null, data: null, age: undefined },
        { name: '张三', data: ['中国', '美国'], age:12 }
    ]
}
const newData = adapter({
    list: {
        name: 'default:保密',
        data: { $default:() => ['中国'] },
        age: { $default:16 }
    }
}, testData)

// 输出
{
    list: [
        { name:'保密', data:['中国'], age:16 },
        { name:'张三', data:['中国', '美国'], age:12 }
    ]
}

数组过滤指令 $filter

const data = {
  list: [
    { id: 1, value: 1 },
    { id: 2, value: 2 },
    { id: 3, value: 3 },
    { id: 4, value: 4 },
    { id: 5, value: 5 },
    { id: 6, value: 6 },
  ],
}
const nextData = adapter({
  list: {
    $filter: (value) => value.id % 2 === 0 || value.value === 5,
    id: {
      $key: 'name',
      $type: String,
    },
  },
}, data)

// 输出
{
    list: [
        { name:'2' },
        { name:'4' },
        { name:'5' },
        { name:'6' },
    ]
}

扩展层级 $increase

const testData = { data:{ name:'张三' } }
const newData = adapter({
    data: {
        $key: 'name',
        $value: (value) => value.name,
    },
    $increase:{ // 扩展了data1字段
        $key: 'data1',
        $increase: {
            $key:'data2', // 扩展了data2字段
            data: {
                $key: 'name2',
                 $value: (value) => value.name
            }
        },
        data: {
            $key: 'name1',
            $value: (value) => value.name
        },
    }
}, testData)

// 输出
{
    name: '张三',
    data1: {
        name1: '张三',
        data2: {
            name2: '张三'
        }
    }
}

扩展字段使用当前层级的数据进行扩展,一般用在数据进行模块化拆分的时候使用

缩减字段 $reduce

const testData = {
    data1: {
        data2: {
            name2: '张三'
        }
    }
}
const newData = adapter({
    data1: { // 缩减data1
        $reduce: true,
        data2: {
            $reduce: true,
            name2: 'name'
        }
    }
}, testData)

// 输出 { name:'张三' }

// 缩减层级,一般在去除模块化实现字段扁平化的时候使用,比如前端业务得到的数据是模块化的,提交给网关需要扁平化,则使用此指令方便数据处理

简单的使用示例

import adapter from '@shushu.pro/adapter'

adapter.addFormat('dateDefault', (value, format) => { // 添加预设的格式化规则,后期可以快速调用
    value = new Date(value)
    if (format === 'YYYY') {
        return value.getFullYear()
    }
    return value.getFullYear() + '/' + (value.getMonth() + 1) + '/' + value.getDate()
})

const originData = {
    data1: [
        {
            goodsCode: 'SP10001',
            goodsTitle: '一件神奇的衣服',
            price: 1.2,
            goodsType: 'normal',
            goodsStatus: 1,
            goodsSkuList: [
                {
                    id: 1000,
                    attrs: ['红色', 'XXL'],
                },
                {
                    id: 1001,
                    attrs: ['黑色', 'XXL'],
                },
            ],
            isSale: 1,
            createTime: 1561750763712,
            modifyTime: null,
        },
        {
            goodsCode: 'SP10002',
            goodsTitle: '一条神奇的裤子',
            price: 2.2,
            goodsType: 'virtual',
            goodsStatus: 2,
            goodsSkuList: [
                {
                    id: 1000,
                    attrs: ['红色', 'XXL'],
                },
                {
                    id: 1001,
                    attrs: ['黑色', 'XXL'],
                },
            ],
            isSale: 0,
            createTime: 1561750773712,
            modifyTime: 1561750773712,
        },
    ],
    discardField1: null,
    discardField2: null,
    provinces: '中国,美国,日本',
}

const newData = adapter({
    data1: {
        $key: 'list', // 重命名data1 => list
        goodsCode: 'code', // 重命名goodsCode => code
        goodsTitle: {
            $key: 'title',
            $value: (value) => '标题:' + value, // 进行重命名和数据格式化,可以通过扩展来生成速写指令`key:title #prepend:标题:`
        },
        price: (value) => '¥' + value.toFixed(2), // 进行数据格式
        goodsType: { $emap: { normal: '常规商品', virtual: '虚拟商品' } }, // 进行映射转换,速写指令`emap:normal:常规商品,virtual:虚拟商品`
        goodsStatus: { $enum: [null, '销售中', '已下架', '缺货'] }, // 进行枚举转换,速写指令`enum:,销售中,已下架,缺货`
        goodsSkuList: (value) => value.map(item => item.attrs.join('-')), // 对数组的值直接处理
        isSale: Boolean, // 类型
        createTime: '#dateDefault', // 无参数预设格式化处理
        modifyTime: { $default: '无', $format: 'dateDefault:YYYY' }, // 速写指令`default:无 #dateDefault:YYYY`
    },
    provinces: (value) => value.split(','), // 转换成数组,可以通过扩展生成速写指令`#toArray`
}, originData)

// 输出数据
{
    list: [
        {
            code: 'SP10001',
            title: '标题:一件神奇的衣服',
            price: '¥1.20',
            goodsType: '常规商品',
            goodsStatus: '销售中',
            goodsSkuList: [
                '红色-XXL',
                '黑色-XXL',
            ],
            isSale: true,
            createTime: '2019/6/29',
            modifyTime: '无',
        },
        {
            code: 'SP10002',
            title: '标题:一条神奇的裤子',
            price: '¥2.20',
            goodsType: '虚拟商品',
            goodsStatus: '已下架',
            goodsSkuList: [
                '红色-XXL',
                '黑色-XXL',
            ],
            isSale: false,
            createTime: '2019/6/29',
            modifyTime: 2019,
        },
    ],
    provinces: ['中国', '美国', '日本'],
}

附录