borboleta 0.0.1 → 0.0.2
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/README.md +107 -36
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,64 +1,135 @@
|
|
|
1
|
-
# Borboleta
|
|
1
|
+
# Borboleta 🦋
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Convert [JSON Schema](https://json-schema.org/) definitions into [Angular Signal Forms](https://angular.dev/guide/forms/signals/overview) schema functions.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> **Requires Angular 21+** — Signal Forms are experimental. See the [Angular docs](https://angular.dev/guide/forms/signals/validation#the-schema-function) for details.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Why "Borboleta"?
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
ng generate component component-name
|
|
11
|
-
```
|
|
9
|
+
*Borboleta* is Portuguese for **butterfly** — a symbol of transformation. This library transforms JSON Schema definitions into Angular Signal Forms schemas, much like a caterpillar becomes a butterfly. 🦋
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
## Installation
|
|
14
12
|
|
|
15
13
|
```bash
|
|
16
|
-
|
|
14
|
+
npm install borboleta
|
|
17
15
|
```
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
Peer dependencies: `@angular/core`, `@angular/common`, `@angular/forms` (all `^21.2.0`).
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
## Quick start
|
|
22
20
|
|
|
23
|
-
```
|
|
24
|
-
|
|
21
|
+
```typescript
|
|
22
|
+
import { signal } from '@angular/core';
|
|
23
|
+
import { form } from '@angular/forms/signals';
|
|
24
|
+
import { toSignalSchema } from 'borboleta';
|
|
25
|
+
|
|
26
|
+
const jsonSchema = {
|
|
27
|
+
type: 'object',
|
|
28
|
+
required: ['email', 'age'],
|
|
29
|
+
properties: {
|
|
30
|
+
email: { type: 'string', format: 'email' },
|
|
31
|
+
age: { type: 'number', minimum: 18, maximum: 120 },
|
|
32
|
+
role: { type: 'string', enum: ['admin', 'user', 'guest'] },
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const model = signal({ email: '', age: 0, role: '' });
|
|
37
|
+
const myForm = form(model, toSignalSchema(jsonSchema));
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This generates the same validators as writing the schema by hand:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
const myForm = form(model, (s) => {
|
|
44
|
+
required(s.email);
|
|
45
|
+
email(s.email);
|
|
46
|
+
required(s.age);
|
|
47
|
+
min(s.age, 18);
|
|
48
|
+
max(s.age, 120);
|
|
49
|
+
validate(s.role, ({ value }) => {
|
|
50
|
+
const v = value();
|
|
51
|
+
if (v != null && v !== '' && !['admin', 'user', 'guest'].includes(v)) {
|
|
52
|
+
return { kind: 'enum', message: 'Must be one of: admin, user, guest' };
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
});
|
|
56
|
+
});
|
|
25
57
|
```
|
|
26
58
|
|
|
27
|
-
|
|
59
|
+
## Supported JSON Schema keywords
|
|
60
|
+
|
|
61
|
+
| JSON Schema | Signal Forms validator |
|
|
62
|
+
| ----------------------- | ----------------------------- |
|
|
63
|
+
| `required` | `required()` |
|
|
64
|
+
| `enum` | `validate()` (custom) |
|
|
65
|
+
| `minimum` / `maximum` | `min()` / `max()` |
|
|
66
|
+
| `minLength` / `maxLength` | `minLength()` / `maxLength()` |
|
|
67
|
+
| `pattern` | `pattern()` |
|
|
68
|
+
| `format: "email"` | `email()` |
|
|
69
|
+
| Nested `object` | Recursive descent |
|
|
70
|
+
| `items` (array) | `applyEach()` |
|
|
71
|
+
|
|
72
|
+
## Adding custom validators
|
|
73
|
+
|
|
74
|
+
Use `composeSchemas()` to layer custom validators on top of the generated ones:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { form, validate, required } from '@angular/forms/signals';
|
|
78
|
+
import { toSignalSchema, composeSchemas } from 'borboleta';
|
|
79
|
+
|
|
80
|
+
const myForm = form(
|
|
81
|
+
model,
|
|
82
|
+
composeSchemas(
|
|
83
|
+
toSignalSchema(jsonSchema),
|
|
84
|
+
(s) => {
|
|
85
|
+
// Custom: URL must use HTTPS
|
|
86
|
+
validate(s.run.url, ({ value }) => {
|
|
87
|
+
if (!value().startsWith('https://')) {
|
|
88
|
+
return { kind: 'https', message: 'URL must use HTTPS' };
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Custom: conditional required
|
|
94
|
+
required(s.monitor.url, {
|
|
95
|
+
when: ({ valueOf }) => valueOf(s.monitor.isMonitored),
|
|
96
|
+
});
|
|
97
|
+
},
|
|
98
|
+
),
|
|
99
|
+
);
|
|
100
|
+
```
|
|
28
101
|
|
|
29
|
-
|
|
102
|
+
Or just call `toSignalSchema()` inside your own schema function — no utility needed:
|
|
30
103
|
|
|
31
|
-
|
|
104
|
+
```typescript
|
|
105
|
+
const myForm = form(model, (s) => {
|
|
106
|
+
toSignalSchema(jsonSchema)(s);
|
|
107
|
+
validate(s.run.url, /* ... */);
|
|
108
|
+
});
|
|
109
|
+
```
|
|
32
110
|
|
|
33
|
-
|
|
111
|
+
## API
|
|
34
112
|
|
|
35
|
-
|
|
36
|
-
cd dist/borboleta
|
|
37
|
-
```
|
|
113
|
+
### `toSignalSchema<T>(jsonSchema: JsonSchema): SchemaFn<T>`
|
|
38
114
|
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
npm publish
|
|
42
|
-
```
|
|
115
|
+
Converts a JSON Schema object into an Angular Signal Forms `SchemaFn<T>`. Pass the result directly to `form()` or combine it with `composeSchemas()`.
|
|
43
116
|
|
|
44
|
-
|
|
117
|
+
### `composeSchemas<T>(...schemas: SchemaFn<T>[]): SchemaFn<T>`
|
|
45
118
|
|
|
46
|
-
|
|
119
|
+
Combines multiple schema functions into one. Each schema is called in order on the same `SchemaPathTree`, so validators accumulate.
|
|
47
120
|
|
|
48
|
-
|
|
49
|
-
ng test
|
|
50
|
-
```
|
|
121
|
+
### `JsonSchema` (type)
|
|
51
122
|
|
|
52
|
-
|
|
123
|
+
TypeScript interface describing the subset of JSON Schema Draft-07 that Borboleta understands.
|
|
53
124
|
|
|
54
|
-
|
|
125
|
+
## Development
|
|
55
126
|
|
|
56
127
|
```bash
|
|
57
|
-
|
|
128
|
+
npm install # Install dependencies
|
|
129
|
+
npm run build # Build the library (output: dist/borboleta/)
|
|
130
|
+
npm test # Run tests (Vitest)
|
|
58
131
|
```
|
|
59
132
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
## Additional Resources
|
|
133
|
+
## License
|
|
63
134
|
|
|
64
|
-
|
|
135
|
+
[MIT](LICENSE)
|