GithubHelp home page GithubHelp logo

medz / heroicons Goto Github PK

View Code? Open in Web Editor NEW
179.0 25.0 40.0 43 KB

OvO is a Dart-first schema declaration and validation library.

Home Page: https://pub.dev/packages/ovo

License: MIT License

Dart 100.00%
dart flutter json-schema validate runtime-validation schema schema-validator

heroicons's Introduction

✨ OvO ✨

OvO is a Dart-first schema declaration and validation library.

Introduction

OvO is a Dart-first schema declaration and validation library. We use the technical term "Schema" to define any data type, from simple single data (for example: string/int, etc.) to complex nested Map.

OvO is designed to be as user-friendly and developer-friendly as possible, with the goal of eliminating tedious type checking and object deserialization. It is easy to compose complex data structure validation using simple declaration validation.

several important aspects

  • A fun walkthrough of Dart type extensions
  • Simple and chained interface calls
  • Can be used on any Dart platform (Dart, Web, Flutter)

Sponsors

I am very grateful and encouraged for any level of sponsorship, which will help me continue to develop and maintain this project.

Installation

We are more aggressive and use higher versions of Dart stable versions as much as possible.

Install from command line

# Dart project
dart pub add ovo

# Flutter project
flutter pub add ovo

Install from pubspec.yaml

dependencies:
  ovo: latest

Basic Usage

Create a simple string schema:

import 'package:ovo/ovo.dart' as ovo;

// Create a schema for string.
final schema = ovo.String();

// Parsing
await schema.parse('Hello World'); // => 'Hello World'
await schema.parse(123); // => throws OvOException

Creating an JSON schema:

import 'package:ovo/ovo.dart' as ovo;

final schema = ovo.Object({
    'name': ovo.String(),
});

await schema.parse({
    'name': 'John',
}); // => {'name': 'John'}

Types

OvO provides type validation with dependent type parameters, and also built-in some common types. You can declare a type validation by OvO<T>, where T is a type parameter and can be any type.

Let's try to create a String type validation:

import 'package:ovo/ovo.dart' as ovo;

final schema = ovo.OvO<String>();

await schema.parse('Hello World'); // => 'Hello World'
await schema.parse(123); // => throws OvOException

Or, we create a validation of Record type that is not built-in:

import 'package:ovo/ovo.dart' as ovo;

final schema = ovo.OvO<(int, String)>();

await schema.parse((123, 'Hello World')); // => (123, 'Hello World')

Of course, you can also use it to validate a custom class:

import 'package:ovo/ovo.dart' as ovo;

class User {
    final String name;
    final int age;

    User(this.name, this.age);
}

final schema = ovo.OvO<User>();

await schema.parse(User('John', 18)); // => User('John', 18)

Basic type validation depends on the built-in is keyword in Dart, which is fully capable of most type validation. However, if you need more complex type validation, you can use the constructor of OvO<T> to create a custom type validation.

import 'package:ovo/ovo.dart' as ovo;

class User {
    final String name;
    final int age;

    User(this.name, this.age);

    factory User.fromJson(Map<String, dynamic> json) {
        return User(json['name'], json['age']);
    }
}

class MyOvO implements ovo.OvO<User> {
    @override
    Future<User> parse(ovo.Context, dynamic value) {
        if (value is Map<String, dynamic>) {
            return User.fromJson(value);
        }
        throw ovo.OvOException('Invalid value');
    }
}

final schema = ovo.Object({
    'data': MyOvO(),
    'status': ovo.Boolean(),
});

final data = {
    'data': {
        'name': 'John',
        'age': 18,
    },
    'status': true,
};

await schema.parse(data); // => {'data': User('John', 18), 'status': true}

Any

Any type validation can accept a non-null value of any type. It is an alias of OvO<Object>.

Array

Array type validation can accept an iterable value (for example: List, Set, Iterable, etc.). It is not an alias of OvO<Iterable<T>>, but a specific type validation.

Array accepts a parameter of type OvO<T> to validate each element in the array.

import 'package:ovo/ovo.dart' as ovo;

final schema = ovo.Array(ovo.String());

await schema.parse(['Hello', 'World']); // => ['Hello', 'World']
await schema.parse([123, 456]); // => throws OvOException

.min/.max/.size

.min/.max/.size have the same parameters and type signatures, and they all accept a parameter of type int to validate the length of the array.

  • .min validates that the length of the array must be greater than or equal to the specified length.
  • .max validates that the length of the array must be less than or equal to the specified length.
  • .size validates that the length of the array must be equal to the specified length.
ovo.Array(ovo.String()).min(2); // must contain at least 2 elements
ovo.Array(ovo.String()).max(2); // must contain no more than 2 elements
ovo.Array(ovo.String()).size(2); // must contain exactly 2 elements

.unique

.unique validates that the elements in the array must be unique, similar to Set in Dart.

ovo.Array(ovo.String()).unique(); // must contain unique elements

Boolean

Boolean type validation can accept a value of type bool. It is an alias of OvO<bool>.

另外,他还有两个额外的扩展方法:

In addition, it has two additional extension methods:

  • .isTrue - 验证值必须为 true

  • .isFalse - 验证值必须为 false

  • .isTrue - validates that the value must be true.

  • .isFalse - validates that the value must be false.

ovo.Boolean(); // must be a boolean, `true` or `false`
ovo.Boolean().isTrue(); // must be true
ovo.Boolean().isFalse(); // must be false

Of course, you can use OvO<bool> instead of Boolean type validation, but Boolean type validation is more semantic.

Number

Number type validation can accept a value of type num. It is an alias of OvO<num>.

ovo.Number(); // must be a number, `int` or `double`

If you need to validate an integer, you can use the Integer type validation, which is an alias of OvO<int>. To validate a floating-point number, you can use the Double type validation, which is an alias of OvO<double>.

Integer and Double are both subtypes of Number:

ovo.Integer(); // must be an integer, `int`
ovo.Double(); // must be a double, `double`

OvO<num> also contains some additional methods:

ovo.Number().gt(10); // must be greater than 10
ovo.Number().gte(10); // must be greater than or equal to 10
ovo.Number().lt(10); // must be less than 10
ovo.Number().lte(10); // must be less than or equal to 10
ovo.Number().finite(); // must be finite
ovo.Number().negative(); // must be negative

String

String type validation can accept a value of type String. It is an alias of OvO<String>.

ovo.String(); // must be a string, `String`

OvO<String> also contains some additional methods:

// Validations
ovo.String().min(5); // must be at least 5 characters long
ovo.String().max(5); // must be no more than 5 characters long
ovo.String().length(5); // must be exactly 5 characters long
ovo.String().regex(RegExp(r'^[a-z]+$')); // must match the regular expression
ovo.String().contains('abc'); // must contain the substring
ovo.String().isNotEmpty(); // must not be empty
ovo.String().startsWith('abc'); // must start with the substring
ovo.String().endsWith('abc'); // must end with the substring
ovo.String().equals('abc'); // must be equal to the string

// Transformations
ovo.String().trim(); // trim whitespace
ovo.String().toLowerCase(); // convert to lowercase
ovo.String().toUpperCase(); // convert to uppercase

Object

Object type validation can accept a value of type Map. It is an implementation of OvO<Map<String, T>>.

import 'package:ovo/ovo.dart' as ovo;

final user = ovo.Object({
    'name': ovo.String(),
    'age': ovo.Number(),
});

await user.parse({
    'name': 'John',
    'age': 18,
}); // => {'name': 'John', 'age': 18}

await user.parse({
    'name': 'John',
    'age': '18',
}); // => throws OvOException

Of course, if you just want to simply validate a value of type Map<K, T>, you can use OvO<Map<K, T>> instead of Object type validation.

import 'package:ovo/ovo.dart' as ovo;

final user = ovo.OvO<Map<String, dynamic>>();

await user.parse({
    'name': 'John',
    'age': 18,
}); // => {'name': 'John', 'age': 18}

await user.parse({
    'name': 'John',
    'age': '18',
}); // => {'name': 'John', 'age': '18'}

Functional

.nullable

The .nullable method can convert a type validation to a type validation that accepts null.

ovo.String().nullable(); // must be a string or null

.refine

.refine is a method that allows you to customize the validation. It accepts a validation function of FutureOr<bool> Function(T data) to facilitate validation according to the actual situation.

ovo.String().refine(
    (value) => value.length > 5,
    message: 'must be greater than 5',
); // must be a string and length greater than 5

It is worth noting that many of the built-in extension methods are implemented based on the .refine method.

.transform

.transform is a method that allows you to customize the method of converting data types. It works on the principle of Onion Model.

Pre-transformation

Pre-transformation allows you to pre-process the raw data to be parsed, and then hand it over to the next converter, and finally hand it over to the type validator for verification:

final schema = ovo.String().transform(
    (ovo.Context context, dynamic data, Future<T> Function(dynamic data) next) {
        // data convert to string
        return next(data.toString());
    }
);

await schema.parse(123); // => '123'
await schema.parse(#symbol); // => '#symbol'

Post-transformation

Using the next parameter in the callback, you can perform post-transformation of the data after the type validator is verified successfully:

final schema = ovo.String().transform(
    (ovo.Context context, dynamic data, Future<T> Function(dynamic data) next) async {
        final value = await next(data);

        // value convert to int
        return int.parse(value);
    }
);

await schema.parse('123'); // => 123

.withDefault

.withDefault allows a nullable value T? to be replaced with a default value T when the value is null.

final schema = ovo.String().withDefault('Hello World'); // must be a string or null, default value is 'Hello World'

await schema.parse(null); // => 'Hello World'
await schema.parse('Hello'); // => 'Hello'

As you can see, the .withDefault method will automatically attach the .nullable method, so you don't need to call the .nullable method manually.

Compositions

AnyOf (OR)

AnyOf type validation can accept any of the multiple type validations.

ovo.AnyOf([
    ovo.String(),
    ovo.Integer(),
]); // must be a string or an integer

AllOf (AND)

AllOf type validation can accept all types in multiple type validations.

ovo.AllOf([
    ovo.Double(),
    ovo.Integer(),
]); // must be a double and an integer

OneOf (XOR)

OneOf type validation can accept one type in multiple type validations. If multiple validations match, an exception is thrown.

final schema = ovo.OneOf([
    ovo.String().size(5),
    ovo.String().size(10),
]);

await schema.parse('12345'); // => '12345'
await schema.parse('1234567890'); // => '1234567890'
await schema.parse('123456'); // => throws OvOException

Not (NOT)

Not type validation can accept any type validation, but if the specified type validation is matched, an exception is thrown.

final schema = ovo.Not(ovo.String());

await schema.parse(123); // => 123
await schema.parse({'name': 'Seven'}) // => {'name': 'Seven'}
await schema.parse('123'); // => throws OvOException

Const

Const type validation can accept a constant value.

ovo.Const(123); // must be 123

Using Const we can implement string literals in JSON:

final schema = ovo.OneOf([
    ovo.Const('mobile'),
    ovo.Const('web'),
]);

await schema.parse('mobile'); // => 'mobile'
await schema.parse('web'); // => 'web'

Used in conjunction with conversion, we can implement Enum type validation:

enum MyEnum {
    mobile,
    web,
}

final schema = ovo.OneOf(
    MyEnum.values.map((e) => ovo.Const(e.name)),
).transform<MyEnum>(
    (ovo.Context context, dynamic data, Future<T> Function(dynamic data) next) async {
        final value = await next(data);

        return MyEnum.values.firstWhere((e) => e.name == value);
    }
);

await schema.parse('mobile'); // => MyEnum.mobile
await schema.parse('web'); // => MyEnum.web
await schema.parse('desktop'); // => throws OvOException

heroicons's People

Contributors

medz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

heroicons's Issues

强制验证码问题

登录时密码错误5次会出现强制验证码,即使登录成功,下次依然需要验证码,
除非几个小时后,或者更换IP后才行。
我希望通过后台控制强制验证的开关,或者通过修改某个文件关闭强制验证。
谢谢!

win10 下 phpwind 部分JS事件失灵

应该是和系统有关系,我在win7下功能都是正常的。win10下"模块管理"和"个人空间设置"的按键都无法使用。测试浏览器有"360急速浏览器"和"chrome",如果把360切换IE11可以正常访问。
希望下个版本修复一下win10浏览器的兼容性。

必须设置域名建议

现在论坛,必须设置域名,比如我有多个域名。其他域名可以访问到首页,但是点击任意连接就回转到后台设置的域名上。
最好支持不用绑定域名,即可各自域名访问而不跳转域名。

insertTao not found

windeditor 中调用了一个叫 insertTao 的插件,但是并不存在。

customPlugins.push('insertTao');

表情不按照规则排序

在后台添加的表情没有按照文件名进行排序(自带的那个淘公仔也被打乱了),完全被打乱了顺序。强迫症简直不能忍啊!!!
在数据库中,默认的淘公仔是ID跟文件名对应的(即ID1,同时对应1.gif)。
然而,新添加的表情就乱了:ID跟文件名(都是数字123456……这样的)不对应,完全乱了。
这应该是个排序的BUG。。。
在PHPWind 9.0中没有这个问题。

后台功能”全局-积分设置-积分转换“以及”积分充值“错误

这里给出”全局-积分设置-积分转换“的错误信息:

Uncaught error with message 'E_WARNING: Invalid argument supplied for foreach()'
D:\phpStudy\WWW\data\compile\template\credit\admin\credit_exchange.tpl: 57

52: <td>启用</td>
53: <td>操作</td>
54: </tr>
55: </thead>
56: <tbody>
57: <?php foreach ($exchange as $key => $value) { ?>
58: <tr>
59: <td><?php echo htmlspecialchars($value['value1'], ENT_QUOTES, 'UTF-8');?>个<?php echo htmlspecialchars($creditBo->cType[$value['credit1']], ENT_QUOTES, 'UTF-8');?></td>
60: <td>兑换</td>
61: <td><?php echo htmlspecialchars($value['value2'], ENT_QUOTES, 'UTF-8');?>个<?php echo htmlspecialchars($creditBo->cType[$value['credit2']], ENT_QUOTES, 'UTF-8');?></td>
__Stack:

#12 D:\phpStudy\WWW\vendor\medz\windframework\wind\base\AbstractWindFrontController.php (262)
#11 D:\phpStudy\WWW\data\compile\template\credit\admin\credit_exchange.tpl (57) _errorHandle(2,"Invalid argument supplied for foreach()","D:\phpStudy\WWW\data\compile\template\credit\admin\credit_exchan…",57,array( '__tpl' => 'D:\phpStudy\WWW\data\compile/template/credit/admin/credit_exchange.tpl', '__vars' => array( 'loginUser' => NULL, 'creditBo' => NULL, 'exchange' => '', 'currentTabs' => array( 'run' => '', 'strategy' => '', 'recharge' => '', 'exchange' => 'current', 'transfer' => '', 'log' => '', ), ), '__viewer' => NULL, 'loginUser' => NULL, 'creditBo' => NULL, 'exchange' => '', 'currentTabs' => array( 'run' => '', 'strategy' => '', 'recharge' => '', 'exchange' => 'current', 'transfer' => '', 'log' => '', ), ))
#10 D:\phpStudy\WWW\vendor\medz\windframework\wind\viewer\IWindViewerResolver.php (57) include("D:\phpStudy\WWW\data\compile\template\credit\admin\credit_exchan…")
#9 D:\phpStudy\WWW\vendor\medz\windframework\wind\viewer\resolver\WindViewerResolver.php (43) render("D:\phpStudy\WWW\data\compile/template/credit/admin/credit_exchan…",array( 'loginUser' => NULL, 'creditBo' => NULL, 'exchange' => '', 'currentTabs' => array( 'run' => '', 'strategy' => '', 'recharge' => '', 'exchange' => 'current', 'transfer' => '', 'log' => '', ), ),WindViewerResolver)
#8 D:\phpStudy\WWW\vendor\medz\windframework\wind\viewer\WindView.php (152) windFetch()
#7 D:\phpStudy\WWW\vendor\medz\windframework\wind\web\WindDispatcher.php (44) render(false)
#6 D:\phpStudy\WWW\vendor\medz\windframework\wind\web\WindWebApplication.php (32) dispatch(WindForward,WindRouter,false)
#5 D:\phpStudy\WWW\vendor\medz\windframework\wind\base\AbstractWindApplication.php (95) doDispatch(WindForward)
#4 D:\phpStudy\WWW\vendor\medz\windframework\wind\base\AbstractWindFrontController.php (217) run(WindRouter)
#3 D:\phpStudy\WWW\vendor\medz\windframework\wind\web\WindWebFrontController.php (23) run()
#2 D:\phpStudy\WWW\src\Wekit.php (41) run()
#1 D:\phpStudy\WWW\admin.php (11) run("pwadmin",array( 'router' => array( 'config' => array( 'module' => array( 'default-value' => 'default', ), 'routes' => array( 'admin' => array( 'class' => 'LIB:route.PwAdminRoute', 'default' => true, ), ), ), ), ))

附件url格式自定义请求

举例:
假设pw主站域名为www.example.com,

首先将附件分离到独立域名如pics.example.com,如图片
https://pics.example.com/attachment/1702/thread/abc.jpg
pics.example.com指向CDN图床,可实现图片CDN加速。

然后,为了使用CDN提供的水印功能,需要添加参数,如:
https://pics.example.com/attachment/1702/thread/abc.jpg!watermark

此功能目前只能通过修改pw内部文件才可实现,如果单独提出来做成一个功能,可方便站长们轻松实现CDN加速。

功能改进

希望加入wap模板,哪怕是简洁版的也行。

移动端适配请求

1.默认主题对手机浏览器优化,特别是微信浏览器
2.优化手机端注册、登录步骤,增加用户流入率
3.支持手机端使用Android自带浏览器、iOS Safari、Chrome手机浏览器发布帖子时添加图片等多媒体内容
4.优化移动端帖子编译器行为

js css 等对cdn的支持改进

对模板及后台增加cdn加速设置等,方便实现类似七牛等cdn加速。模板是可以调用后台设置的cdn地址

希望把語言全部拆開來讓別人也能為phpwind作翻譯。

我知道 phpwind 原本已經設計 language 的對應了,但有很多地方例如部分檔案是仍留存在 程式碼裡面而非獨立在 src/i18n 資料夾內的,之前嘗試過自己將 zh_cn 改成 zh_tw 在全面改部分語言為正體中文,仍然在論壇上有看到許多簡體字。

例如template內找到的其中幾個模板都沒有歸類放在 src/i18n 在內,但想把 template 的語言歸類放入 src/i18n 但不知道 單純的 html 語法要如何將 「return new PwError('BBS:forum.unite.error.fid.exists.not');」這種i18n語言放入 template。

如果能指點如何將這 template 的 lang 作個 拆開整合在 i18n ,我覺得日後要維護語言更新會比較不會複雜。

PHP7环境开启伪静态情况下出错

涉及文件:src/library/route/PwRoute.php
242行:
if ($route[$k] === $router->$methods[$k]() && $flag === $flags[$k]) {
改为:

	    $method = $methods[$k];
            if ($route[$k] === $router->$method() && $flag === $flags[$k]) {

以上问题仅在PHP7环境出现。供参考。

后台邮件功能优化请求

后台——全局——电子邮件
希望:

  • 添加一个独立的SSL开关,而不是手写ssl://
  • 提供更好的错误主动检测和错误信息提示
  • 电子邮件检测中记住“收件人地址”,避免反复输入浪费时间
  • 为国内常用企业邮箱如腾讯企业邮箱、阿里云企业邮箱等提供默认配置建议

关于本地搜索的相关建议

您好,现有的本地搜索相关插件速度过慢,能否考虑在插件中提供创建索引的选项

  • 帖子搜索
  • 板块搜索
  • 用户搜索

还有更多开发情补充

建议增加后台清理站内消息功能

论坛 站内通知及站内消息,如果运行时间较长,会占用部分数据库资源。
应该增加清理功能

1、后台 手动清理指定类型的 比如:已读消息、站内通知 可以选择消息时间截止日期。
2、定时自动清理指定类型的消息。

望考虑增加。

composer中Wekit引入大小写问题

autoload文件中,引入类的文件名相关语句为:
'Wekit' => $baseDir . '/src/Wekit.php',
实际文件为/src/wekit.php,w为小写,Linux系统会导致引入类文件失败。

使用 clipboard.min.js

zeroClipboard 依赖 Flash 插件,推荐使用 clipboard.min.js 取代。

  • 帖子详情复制按钮使用 clipboard.js 替代

版块权限问题建议

设置访问权限板块,非拥有权限用户组访问后,能提示哪些用户组可以访问,并且有响应的连接方便购买等操作

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.