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 🙏

© 2025 – Pkg Stats / Ryan Hefner

awlibs

v1.0.17

Published

<p align="center"> <h3 align="center">Awlibs</h3>

Downloads

11

Readme

Table of contents

Quick start

  • Install with npm: npm install awlibs

Status

npm version

What's included

包含 atinterceptor、awlvalidator、formhandler、lazychain、pcurry、promiseajax、cvd 等工具库,下面分别介绍。

Atinterceptor

异步任务拦截器,把一个异步任务抽象成一个请求 -> 响应的过程,对异步任务的返回结果进行归类,方便后续的统一处理,内置异步任务的状态标记(ready/pending),可以防止同一任务的重复执行。

代码示例

const atinterceptor = require('awlibs/atinterceptor');
const asyncTaskTrigger = atinterceptor();

asyncTaskTrigger(() => {
  return [
    fetch() // 异步任务,需要返回一个 Promise 对象
  ];
}, true, 'getList').then((result) => {
});

参数

const asyncTaskTrigger = atinterceptor(asyncTag, configs)
asyncTaskTrigger(getAsyncTaskArray, repeat, tagKey, onAsyncTagChange)

Awlvalidator

轻量级校验器,源码内容不到 200 行,易使用,易扩展。

代码示例

const awlvalidator = require('awlibs/awlvalidator');

const value = 'xxx';

const validator = awlvalidator.validateGetter(
    awlvalidator.ruleGetter('required', {
        errorMsg: '请填写包含 xxx 的字符串'
    }),
    awlvalidator.ruleGetter('xxx', null, (value, params) => {
        value = value.toString();
        if (value.indexOf('xxx') !== -1) {
            return {
                valid: true
            };
        } else {
            return {
                valid: false,
                msg: '不包含 xxx'
            };
        }
    }),
    awlvalidator.ruleGetter('minLength', {
        minLength: 5
    }),
);

const result = validator(value);

参数

awlvalidator.validateGetter(rule1, rule2, ..., ruleN) 接收任意数量的校验规则,生成校验方法。
awlvalidator.ruleGetter(ruleName, params, handler) 生成校验规则。

内置规则比较少,但是提供了一种校验的机制,推荐开发者根据自己的需求定制规则。

Formhandler

使用函数式组合,避免批量 if else 的小工具。

代码示例

const formhandler = require('module/formhandler').default;

const handler = formhandler.dispatch(
    formhandler.register('name', (key, value, params) => {
        return 'My name is ' + value;
    }),

    formhandler.register('age', (key, value, params) => {
        return value + params.base;
    }),
);


const rawName = 'wxl';
const name = handler('name', rawName);


const rawAge = 100;
const age = handler('age', rawAge, {
    base: 20
});

// 'wxl' --> 'My name is wxl.'
// 100   --> 120

参数

formhandler.dispatch(handler1, handler2, ..., handlerN) 组合处理器。
formhandler.register(name, callback) 注册单个处理器。

Lazychain

惰性求值的小工具。

代码示例

const Lazychain = require('module/lazychain').default;

const lc = new Lazychain([1, 2]).tap((target) => {
    return target.concat('xxx');
}).tap((target) => {
    return target.join('*');
}).tap((target) => {
    return target + '__';
})

const ret = lc.force();
// ret = '1*2*xxx__'

参数

new Lacychain(target).tap(handler).tap(handler2) 把处理器添加到待执行的队列。
force 执行函数队列。

Pcurry

针对 Promise 的柯里化工具,预先定义处理器,不需要在每次 Promise 完成后都重复写处理逻辑。

代码示例

const pcurry = require('module/pcurry');

const decorateA = pcurry((promise) => {
    return promise.then((data) => {
        let msg = data + ':handlerA';
        console.log(msg);
        return msg;
    });
});

const decorateAB = decorateA((promise) => {
    return promise.then((data) => {
        let msg = data + ':handlerB';
        console.log(msg);
        return msg;
    });
});


decorateAB(new Promise((resolve) => {
    let msg = 'begin';
    console.log(msg);
    resolve(msg);
})).then((result) => {
});

参数

pcurry(handlerA)(handlerB)(promise)

Promiseajax

基于 Promise 的轻量级 Ajax 库。

代码示例

import { get as ajaxGet, post as ajaxPost } from 'module/promiseajax';

ajaxPost({
    url: '/apis/getList',
    contentType: 'json',
    params: {
        pageNo: 1,
        pageSize: 20
    }
}).then((res) => {
    console.log(res);
});


ajaxGet({
    url: '/apis/getInfo',
}).then((res) => {
    console.log(res);
});

参数

CVD

复杂表单录入场景的分层解决方案,轻量级、跨平台、易扩展。

核心概念

  • 单一数据源:整个表单交互逻辑的状态被存储在一个状态树 store 中。来自服务端的数据无需编写更多的代码情况下被序列化并注入到客户端中,由于单一的状态树,调试变得容易。此外,受益于单一状态树,以前难以实现的“清空/撤销”这类功能也变得轻而易举。
  • State 是只读的:改变 state 需要使用特定的方法 connector、validator、dependency、flow 才可以,类似 Redux 只能通过 Action,下面会介绍各个方法的含义。
  • 分层:把对表单的处理逻辑分成三层 connector(序列化用户输入的数据)、validator(校验序列化后的数据输出校验结果)、dependency(处理表单控件之间的依赖关系),代码解耦、三层任意组合代码灵活。
  • 使用纯函数来执行修改:使用函数式组合的方式,注册逻辑处理器(handler 函数),接收先前的 state 并返回新的 state,注意使用不可变数据更新,类似 Redux 的 Reducer。

代码示例

const CVD = require('awlibs/cvd');
const awlvalidator = require('awlibs/awlvalidator').default;
const Lazychain = require('awlibs/lazychain').default;

/**
 * 注册每一层的 handler 对 store 进行修改
 * 使用不可变数据更新的方式
 */
const connectorHandler = CVD.dispatch(
    CVD.register('name,age', (key, value, params, store) => {
        if (!value) {
            return '';
        } else {
            return 'yoyo_' + value;
        }
    }),

    CVD.register('jobs', (key, value, params, store) => {

        if (Object.prototype.toString.call(value) == '[object Array]') {
            return [
                ...value
            ];
        }

        const checked = params.checked;
        let model = store.model[key].concat();
        const index = model.indexOf(value);

        if (checked && index == -1) {
            model.push(value);
        }

        if (!checked && index != -1) {
            model.splice(index, 1);
        }

        return model;
    }),
);

const validatorHandler = CVD.dispatch(
    CVD.register('name', (key, value) => {
        return awlvalidator.validateGetter(
            awlvalidator.ruleGetter('required', {
                errorMsg: '请填写名称'
            }),
            awlvalidator.ruleGetter('minLength', {
                minLength: 10
            }),
            awlvalidator.ruleGetter('maxLength', {
                maxLength: 30
            })
        )(value);
    }),

    CVD.register('jobs', (key, value) => {
        if (!value || !value.length) {
            return {
                valid: false,
                msg: '请选择工作',
            };
        }
        return {
            valid: true,
            msg: '',
        };
    }),
);

const dependencyHandler = CVD.dispatch(
    CVD.register('jobs', (key, value, params, store) => {
        let desc = {
            ...store.desc,
        };

        desc['name'] = {
            ...desc['name'],
            showCrown: value.indexOf(1) != -1 ? true : false
        };

        return {
            desc,
        };
    }),
);


/**
 * 提供单一数据源 store
 * 必须包含 model 和 desc 两个属性
 * model 是序列化好的数据可以直接提交
 * desc 维护前端路径所需的数据
 */
const cvd = new CVD({
    model: {
        name: '',
        age: '',
        jobs: [],
    },
    desc: {
        name: {
            showCrown: false,
            valid: true,
            msg: ''
        },

        jobs: {
            list: [{id: 1, name: '腾讯'}, {id: 2, name: '阿里'}, {id: 3, name: '百度'} ],
        }
    },
});

/**
 * 初始化 cvd
 * 初始化完成后生成
 * cvd.connector
 * cvd.validator
 * cvd.dependency
 * 以及三者的统一调用 cvd.flow 方法
 * 修改 store 的入口
 */
cvd.init(connectorHandler, validatorHandler, dependencyHandler);



/**
 * 模拟一个 key 为 name 的 input 控件
 * value 为输入内容
 * params 提供自定义信息
 */
let cvdParams = {
    key: 'name',
    value: 'wxl',
    params: {}
};


// 使用 flow 自动调用三层进行逻辑处理
cvd.flow(cvdParams);

// 获取新的 store
let store = cvd.getStore();
console.log(store);

/**
 * 模拟一个 key 为 age 的 input 控件
 */

cvdParams = {
    key: 'age',
    value: '',
};

// 手动调用
// 三层可任意组合,灵活使用
// 这里只调用 connector 和 dependency 两层
// 这里使用了惰性求值(如何使用见上文)非必须
const lc = new Lazychain(cvdParams);

lc.tap((cvdResult) => {
    return cvd.connector({
        ...cvdResult
    });
}).tap((cvResult) => {
    return cvd.dependency({
        ...cvResult,
    });
});
lc.force();


console.log(cvd.getStore());


/**
 * 模拟一个 key 为 jobs 的 checkbox 控件
 */
const jobs = cvd.getStore().desc['jobs'].list;

// 选中了第一项,把要提交后端的 id 注入进来
cvdParams = {
    key: 'jobs',
    value: jobs[0].id,
    params: {
        checked: true
    }
};

cvd.flow(cvdParams);
console.log(cvd.getStore());

// 选中第二项
setTimeout(() => {
    cvdParams = {
        key: 'jobs',
        value: jobs[1].id,
        params: {
            checked: true
        }
    };
    cvd.flow(cvdParams);
    console.log(cvd.getStore());
}, 1000);


// 取消第一项
setTimeout(() => {
    cvdParams = {
        key: 'jobs',
        value: jobs[0].id,
        params: {
            checked: false
        }
    };
    cvd.flow(cvdParams);
    console.log(cvd.getStore());
}, 2000);

以上代码可以直接运行,这里只给出了简单例子,在特别复杂的表单场景有过应用。

Tree

JS 树形数据结构操作库,可以根据嵌套或者扁平的结构,生成一个包含完整父子关系的图形结构;只有数据层,不涉及 UI 部分,可以在前端、Node 使用。

代码示例

const Tree = require('awlibs/tree');

/**
 * 嵌套表示的树形数据源
 * 父节点通过 children 数组引用子节点
 * 只有父 -> 子关系,没有子 -> 父关系
 */
const treeData1 = [
    {
        name: 'L1',
        children: [
            {
                name: 'L2_1',
                children: [ { name: 'L3_1'} ]
            },

            {
                name: 'L2_2',
                children: [ { name: 'L3_1' } ]
            },
        ]
    }
];

// 构造 Tree 实例,参数意义见下文参数列表
const treeIst1 = new Tree({
    type: 'nested',
    idKey: 'id',
    pIdKey: 'pId',
    childrenKey: 'children',
    data: treeData1,
});
// 获取处理后的数据结构,包含完整的父 -> 子、子 -> 父关系
const ret1 = treeIst1.getData();
console.log(ret1);


/**
 * 扁平表示的树形数据源
 * 只有子 -> 父关系,没有父 -> 子关系
 */
var treeData2 = [
    { id: 1, name: 'L1' },
    { id: 2, pId: 1, name: 'L2_1' },
    { id: 3, pId: 2, name: 'L3_1' },

    { id: 4, pId: 1, name: 'L2_2' },
    { id: 5, pId: 4, name: 'L3_1' },

];

const treeIst2 = new Tree({
    type: 'flattened',
    idKey: 'id',
    pIdKey: 'pId',
    childrenKey: 'children',
    data: treeData2,
});
const ret2 = treeIst2.getData();
console.log(ret2);

参数

treeData1 和 treeData2 经过处理会生成相同的数据结构,包含了完整的父子关系,可以是后续的业务逻辑处理更加方便。