@stacksjs/validation 0.58.47 → 0.58.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stacksjs/validation",
3
3
  "type": "module",
4
- "version": "0.58.47",
4
+ "version": "0.58.49",
5
5
  "description": "The Stacks Validation ways.",
6
6
  "author": "Chris Breuer",
7
7
  "license": "MIT",
@@ -39,7 +39,8 @@
39
39
  ],
40
40
  "files": [
41
41
  "README.md",
42
- "dist"
42
+ "dist",
43
+ "src"
43
44
  ],
44
45
  "scripts": {
45
46
  "build": "bun --bun build.ts",
@@ -47,8 +48,8 @@
47
48
  "prepublishOnly": "bun --bun run build"
48
49
  },
49
50
  "peerDependencies": {
50
- "@stacksjs/strings": "workspace:*",
51
- "@stacksjs/types": "workspace:*",
51
+ "@stacksjs/strings": "latest",
52
+ "@stacksjs/types": "latest",
52
53
  "@vinejs/vine": "^1.7.1"
53
54
  },
54
55
  "dependencies": {
@@ -57,7 +58,7 @@
57
58
  "@vinejs/vine": "^1.7.1"
58
59
  },
59
60
  "devDependencies": {
60
- "@stacksjs/development": "workspace:*",
61
- "@stacksjs/vite": "workspace:*"
61
+ "@stacksjs/development": "latest",
62
+ "@stacksjs/vite": "latest"
62
63
  }
63
64
  }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './is'
2
+ export * from './rules'
3
+ export * from './validate'
4
+ export * from './types'
package/src/is.ts ADDED
@@ -0,0 +1,111 @@
1
+ import { toString } from '@stacksjs/strings'
2
+ import { getTypeName } from '@stacksjs/types'
3
+
4
+ export function isDef<T = any>(val?: T): val is T {
5
+ return typeof val !== 'undefined'
6
+ }
7
+
8
+ export function isBoolean(val: any): val is boolean {
9
+ return typeof val === 'boolean'
10
+ }
11
+
12
+ export function isFunction<T extends Function>(val: any): val is T {
13
+ return typeof val === 'function'
14
+ }
15
+
16
+ export function isNumber(val: any): val is number {
17
+ return typeof val === 'number'
18
+ }
19
+
20
+ export function isString(val: unknown): val is string {
21
+ return typeof val === 'string'
22
+ }
23
+
24
+ export function isObject(val: any): val is object {
25
+ return toString(val) === '[object Object]'
26
+ }
27
+
28
+ export function isWindow(val: any): boolean {
29
+ return typeof window !== 'undefined' && toString(val) === '[object Window]'
30
+ }
31
+
32
+ export const isBrowser = typeof window !== 'undefined'
33
+
34
+ export const isServer = typeof document === 'undefined' // https://remix.run/docs/en/v1/pages/gotchas#typeof-window-checks
35
+
36
+ export function isMap(val: any): val is Map<any, any> {
37
+ return toString(val) === '[object Map]'
38
+ }
39
+
40
+ export function isSet(val: any): val is Set<any> {
41
+ return toString(val) === '[object Set]'
42
+ }
43
+
44
+ export function isPromise<T = any>(val: any): val is Promise<T> {
45
+ return toString(val) === '[object Promise]'
46
+ }
47
+
48
+ export function isUndefined(v: any) {
49
+ return getTypeName(v) === 'undefined'
50
+ }
51
+
52
+ export function isNull(v: any) {
53
+ return getTypeName(v) === 'null'
54
+ }
55
+
56
+ export function isSymbol(v: any) {
57
+ return getTypeName(v) === 'symbol'
58
+ }
59
+
60
+ export function isDate(v: any) {
61
+ return getTypeName(v) === 'date'
62
+ }
63
+
64
+ export function isRegExp(v: any) {
65
+ return getTypeName(v) === 'regexp'
66
+ }
67
+
68
+ export function isArray(v: any) {
69
+ return getTypeName(v) === 'array'
70
+ }
71
+
72
+ export function isPrimitive(v: any) {
73
+ const type = getTypeName(v)
74
+ return type === 'null' || type === 'undefined' || type === 'string' || type === 'number' || type === 'boolean' || type === 'symbol'
75
+ }
76
+
77
+ export function isInteger(v: any) {
78
+ return isNumber(v) && Number.isInteger(v)
79
+ }
80
+
81
+ export function isFloat(v: any) {
82
+ return isNumber(v) && !Number.isInteger(v)
83
+ }
84
+
85
+ export function isPositive(v: any) {
86
+ return isNumber(v) && v > 0
87
+ }
88
+
89
+ export function isNegative(v: any) {
90
+ return isNumber(v) && v < 0
91
+ }
92
+
93
+ export function isEven(v: any) {
94
+ return isNumber(v) && v % 2 === 0
95
+ }
96
+
97
+ export function isOdd(v: any) {
98
+ return isNumber(v) && v % 2 !== 0
99
+ }
100
+
101
+ export function isEvenOrOdd(v: any) {
102
+ return isNumber(v) && (v % 2 === 0 ? 'even' : 'odd')
103
+ }
104
+
105
+ export function isPositiveOrNegative(v: any) {
106
+ return isNumber(v) && (v > 0 ? 'positive' : 'negative')
107
+ }
108
+
109
+ export function isIntegerOrFloat(v: any) {
110
+ return isNumber(v) && (Number.isInteger(v) ? 'integer' : 'float')
111
+ }
package/src/rules.ts ADDED
@@ -0,0 +1,126 @@
1
+ import { USD } from '@dinero.js/currencies'
2
+ import { dinero as currency } from 'dinero.js'
3
+ import { validator } from './validate'
4
+
5
+ /**
6
+ * Thanks to VineJS for the following types:
7
+ *
8
+ * The context shared with the entire validation pipeline.
9
+ * Each field gets its own context object.
10
+ */
11
+ export interface FieldContext {
12
+ /**
13
+ * Field value
14
+ */
15
+ value: unknown
16
+
17
+ /**
18
+ * The data property is the top-level object under validation.
19
+ */
20
+ data: any
21
+
22
+ /**
23
+ * Shared metadata across the entire validation lifecycle. It can be
24
+ * used to pass data between validation rules
25
+ */
26
+ meta: Record<string, any>
27
+
28
+ /**
29
+ * Mutate the value of field under validation.
30
+ */
31
+ mutate(newValue: any, field: FieldContext): void
32
+
33
+ /**
34
+ * Report error to the error reporter
35
+ */
36
+ report: ErrorReporterContract['report']
37
+
38
+ /**
39
+ * Is this field valid. Default: true
40
+ */
41
+ isValid: boolean
42
+
43
+ /**
44
+ * Is this field has value defined.
45
+ */
46
+ isDefined: boolean
47
+
48
+ /**
49
+ * Wildcard path for the field. The value is a nested
50
+ * pointer to the field under validation.
51
+ *
52
+ * In case of arrays, the `*` wildcard is used.
53
+ */
54
+ wildCardPath: string
55
+
56
+ /**
57
+ * The parent property is the parent of the field. It could be an
58
+ * array or an object.
59
+ */
60
+ parent: any
61
+
62
+ /**
63
+ * Name of the field under validation. In case of an array, the field
64
+ * name will be a number
65
+ */
66
+ name: string | number
67
+
68
+ /**
69
+ * Is this field an array member
70
+ */
71
+ isArrayMember: boolean
72
+ }
73
+
74
+ /**
75
+ * Thanks to VineJS for the following types:
76
+ *
77
+ * The error reporter is used to report errors during the validation
78
+ * process.
79
+ */
80
+ export interface ErrorReporterContract {
81
+ /**
82
+ * A boolean to known if there are one or more
83
+ * errors.
84
+ */
85
+ hasErrors: boolean
86
+
87
+ /**
88
+ * Creates an instance of an exception to throw
89
+ */
90
+ createError(): Error
91
+
92
+ /**
93
+ * Report error for a field
94
+ */
95
+ report(message: string, rule: string, field: FieldContext, args?: Record<string, any>): any
96
+ }
97
+
98
+ export const isMoney = validator.createRule((value: unknown, _, field: FieldContext) => {
99
+ /**
100
+ * Convert string representation of a number to a JavaScript
101
+ * Number data type.
102
+ */
103
+ const numericValue = validator.helpers.asNumber(value)
104
+
105
+ /**
106
+ * Report error, if the value is NaN post-conversion
107
+ */
108
+ if (Number.isNaN(numericValue)) {
109
+ field.report(
110
+ 'The {{ field }} field value must be a number',
111
+ 'money',
112
+ field,
113
+ )
114
+ return
115
+ }
116
+
117
+ /**
118
+ * Create amount type
119
+ */
120
+ const amount = currency({ amount: numericValue, currency: USD })
121
+
122
+ /**
123
+ * Mutate the field's value
124
+ */
125
+ field.mutate(amount, field)
126
+ }) as any
@@ -0,0 +1,7 @@
1
+ export * from './money'
2
+ export {
3
+ VineEnum as ValidationEnum,
4
+ VineBoolean as ValidationBoolean,
5
+ VineNumber as ValidationNumber,
6
+ VineString as ValidationString,
7
+ } from '@vinejs/vine'
@@ -0,0 +1,17 @@
1
+ import type { Money } from '@stacksjs/types'
2
+ import { BaseLiteralType } from '@vinejs/vine'
3
+ import type { FieldOptions, Validation } from '@vinejs/vine/types'
4
+ import { isMoney } from '../rules'
5
+
6
+ export class MoneyValidator extends BaseLiteralType<Money, Money> {
7
+ constructor(options?: FieldOptions, validations?: Validation<any>[]) {
8
+ super(options, validations || [isMoney()])
9
+ }
10
+
11
+ clone() {
12
+ return new MoneyValidator(
13
+ this.cloneOptions(),
14
+ this.cloneValidations(),
15
+ ) as this
16
+ }
17
+ }
@@ -0,0 +1,33 @@
1
+ import v, { Vine as Validator } from '@vinejs/vine'
2
+ import { MoneyValidator } from './types/money'
3
+
4
+ Validator.macro('money', () => {
5
+ return new MoneyValidator()
6
+ })
7
+
8
+ export const validator: Validator = v
9
+ // validator.string().email()
10
+ type SchemaString = string
11
+ type SchemaNumber = number
12
+ type SchemaBoolean = boolean
13
+ type SchemaEnum = string[]
14
+
15
+ export type SchemaType = SchemaString | SchemaNumber | SchemaBoolean | SchemaEnum
16
+
17
+ export const validate = {
18
+ string: (defaultValue: string = ''): SchemaString => defaultValue,
19
+ number: (defaultValue: number = 1): SchemaNumber => defaultValue,
20
+ boolean: (defaultValue: boolean = true): SchemaBoolean => defaultValue,
21
+ enum: (values: string[]): SchemaEnum => values,
22
+ }
23
+
24
+ export const RuleString: Validator['string'] = (...args) => validator.string(...args)
25
+ export const RuleNumber: Validator['number'] = (...args) => validator.number(...args)
26
+ export const RuleBoolean: Validator['boolean'] = (...args) => validator.boolean(...args)
27
+ export const RuleArray: Validator['array'] = (...args) => validator.array(...args)
28
+ export const RuleObject: Validator['object'] = (...args) => validator.object(...args)
29
+ export const RuleAny: Validator['any'] = (...args) => validator.any(...args)
30
+ // const email = () => validator.string().email()
31
+
32
+ export type { Infer } from '@vinejs/vine/types'
33
+ export { VineString, VineBoolean, VineEnum, VineNumber } from '@vinejs/vine'