svelte-reflector 1.1.21 → 1.1.23
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 +518 -518
- package/dist/core/method/generators/MethodApiCallBuilder.js +24 -24
- package/dist/core/method/generators/MethodGenerator.js +35 -35
- package/dist/core/method/generators/MethodPropsBuilder.js +3 -3
- package/dist/core/module/ModuleClassBuilder.js +36 -36
- package/dist/core/module/ModuleConstructorBuilder.js +13 -13
- package/dist/core/module/ModuleFileBuilder.js +24 -24
- package/dist/helpers/input.js +11 -11
- package/dist/interface.js +4 -4
- package/dist/main.js +16 -16
- package/dist/module.js +6 -6
- package/dist/props/array.property.js +4 -4
- package/dist/props/primitive.property.js +2 -2
- package/dist/reflector.js +184 -184
- package/dist/schema.js +13 -13
- package/package.json +39 -39
- package/dist/array.property.d.ts +0 -22
- package/dist/array.property.js +0 -68
- package/dist/constructor.d.ts +0 -2
- package/dist/constructor.js +0 -2
- package/dist/core/Method.d.ts +0 -41
- package/dist/core/Method.js +0 -19
- package/dist/core/MethodApiTypeAnalyzer.d.ts +0 -9
- package/dist/core/MethodApiTypeAnalyzer.js +0 -19
- package/dist/core/MethodBodyAnalyzer.d.ts +0 -11
- package/dist/core/MethodBodyAnalyzer.js +0 -78
- package/dist/core/MethodBuilder.d.ts +0 -11
- package/dist/core/MethodBuilder.js +0 -50
- package/dist/core/MethodEndpointBuilder.d.ts +0 -6
- package/dist/core/MethodEndpointBuilder.js +0 -21
- package/dist/core/MethodRequestAnalyzer.d.ts +0 -16
- package/dist/core/MethodRequestAnalyzer.js +0 -62
- package/dist/core/MethodResponseAnalyzer.d.ts +0 -12
- package/dist/core/MethodResponseAnalyzer.js +0 -96
- package/dist/core/Module.d.ts +0 -16
- package/dist/core/Module.js +0 -14
- package/dist/core/ModuleBuilder.d.ts +0 -11
- package/dist/core/ModuleBuilder.js +0 -45
- package/dist/core/ModuleClassBuilder.d.ts +0 -12
- package/dist/core/ModuleClassBuilder.js +0 -78
- package/dist/core/ModuleConstructorBuilder.d.ts +0 -7
- package/dist/core/ModuleConstructorBuilder.js +0 -20
- package/dist/core/ModuleFileBuilder.d.ts +0 -19
- package/dist/core/ModuleFileBuilder.js +0 -49
- package/dist/core/ModuleFormBuilder.d.ts +0 -13
- package/dist/core/ModuleFormBuilder.js +0 -34
- package/dist/core/ModuleImports.d.ts +0 -16
- package/dist/core/ModuleImports.js +0 -47
- package/dist/core/ModuleMethodProcessor.d.ts +0 -28
- package/dist/core/ModuleMethodProcessor.js +0 -75
- package/dist/core/ModuleParamProcessor.d.ts +0 -24
- package/dist/core/ModuleParamProcessor.js +0 -42
- package/dist/core/ModuleParameterProcessor.d.ts +0 -19
- package/dist/core/ModuleParameterProcessor.js +0 -68
- package/dist/core/ModuleStateBuilder.d.ts +0 -10
- package/dist/core/ModuleStateBuilder.js +0 -21
- package/dist/enum-property.d.ts +0 -17
- package/dist/enum-property.js +0 -29
- package/dist/enum.class.d.ts +0 -10
- package/dist/enum.class.js +0 -15
- package/dist/generators/MethodApiCallBuilder.d.ts +0 -13
- package/dist/generators/MethodApiCallBuilder.js +0 -80
- package/dist/generators/MethodGenerator.d.ts +0 -10
- package/dist/generators/MethodGenerator.js +0 -75
- package/dist/generators/MethodPropsBuilder.d.ts +0 -5
- package/dist/generators/MethodPropsBuilder.js +0 -19
- package/dist/generators/ModuleGenerator.d.ts +0 -16
- package/dist/generators/ModuleGenerator.js +0 -133
- package/dist/generators/QueryBuilderGenerator.d.ts +0 -3
- package/dist/generators/QueryBuilderGenerator.js +0 -26
- package/dist/generators/ReflectorClasses.d.ts +0 -3
- package/dist/generators/ReflectorClasses.js +0 -46
- package/dist/generators/ReflectorFileGenerator.d.ts +0 -8
- package/dist/generators/ReflectorFileGenerator.js +0 -32
- package/dist/generators/ReflectorFunctions.d.ts +0 -3
- package/dist/generators/ReflectorFunctions.js +0 -58
- package/dist/generators/ReflectorTypes.d.ts +0 -3
- package/dist/generators/ReflectorTypes.js +0 -21
- package/dist/generators/index.d.ts +0 -3
- package/dist/generators/index.js +0 -3
- package/dist/helpers.d.ts +0 -6
- package/dist/helpers.js +0 -35
- package/dist/input.d.ts +0 -3
- package/dist/input.js +0 -14
- package/dist/models/ArrayProperty.d.ts +0 -23
- package/dist/models/ArrayProperty.js +0 -62
- package/dist/models/EnumClass.d.ts +0 -10
- package/dist/models/EnumClass.js +0 -15
- package/dist/models/EnumProperty.d.ts +0 -19
- package/dist/models/EnumProperty.js +0 -41
- package/dist/models/ObjectProperty.d.ts +0 -15
- package/dist/models/ObjectProperty.js +0 -25
- package/dist/models/PrimitiveProperty.d.ts +0 -20
- package/dist/models/PrimitiveProperty.js +0 -64
- package/dist/models/Property.d.ts +0 -19
- package/dist/models/Property.js +0 -24
- package/dist/models/PropertyBuilder.d.ts +0 -22
- package/dist/models/PropertyBuilder.js +0 -89
- package/dist/models/index.d.ts +0 -7
- package/dist/models/index.js +0 -7
- package/dist/module.imports.d.ts +0 -2
- package/dist/module.imports.js +0 -2
- package/dist/object.property.d.ts +0 -17
- package/dist/object.property.js +0 -33
- package/dist/primitive-property.d.ts +0 -28
- package/dist/primitive-property.js +0 -102
- package/dist/property.d.ts +0 -1
- package/dist/property.js +0 -116
- package/dist/reflector/controllers/admin/account/admin-account.module.svelte.d.ts +0 -7
- package/dist/reflector/controllers/admin/account/admin-account.module.svelte.js +0 -28
- package/dist/reflector/controllers/admin/account/owner/account-owner.module.svelte.d.ts +0 -15
- package/dist/reflector/controllers/admin/account/owner/account-owner.module.svelte.js +0 -79
- package/dist/reflector/controllers/admin/kyc/config/kyc-config.module.svelte.d.ts +0 -49
- package/dist/reflector/controllers/admin/kyc/config/kyc-config.module.svelte.js +0 -303
- package/dist/reflector/controllers/admin/policy/system/policy-system.module.svelte.d.ts +0 -9
- package/dist/reflector/controllers/admin/policy/system/policy-system.module.svelte.js +0 -36
- package/dist/reflector/controllers/admin/smtp/config/smtp-config.module.svelte.d.ts +0 -19
- package/dist/reflector/controllers/admin/smtp/config/smtp-config.module.svelte.js +0 -82
- package/dist/reflector/controllers/customer/kyc/file-upload/kyc-file-upload.module.svelte.d.ts +0 -37
- package/dist/reflector/controllers/customer/kyc/file-upload/kyc-file-upload.module.svelte.js +0 -228
- package/dist/reflector/controllers/member/account/member-account.module.svelte.d.ts +0 -11
- package/dist/reflector/controllers/member/account/member-account.module.svelte.js +0 -54
- package/dist/reflector/controllers/owner/account/owner-account.module.svelte.d.ts +0 -11
- package/dist/reflector/controllers/owner/account/owner-account.module.svelte.js +0 -54
- package/dist/reflector/controllers/owner/kyc/config/kyc-config.module.svelte.d.ts +0 -49
- package/dist/reflector/controllers/owner/kyc/config/kyc-config.module.svelte.js +0 -303
- package/dist/reflector/controllers/owner/kyc/self/create-or-update/self-create-or-update.module.svelte.d.ts +0 -33
- package/dist/reflector/controllers/owner/kyc/self/create-or-update/self-create-or-update.module.svelte.js +0 -197
- package/dist/reflector/controllers/owner/policy/owner-policy.module.svelte.d.ts +0 -9
- package/dist/reflector/controllers/owner/policy/owner-policy.module.svelte.js +0 -36
- package/dist/reflector/controllers/owner/smtp/config/smtp-config.module.svelte.d.ts +0 -19
- package/dist/reflector/controllers/owner/smtp/config/smtp-config.module.svelte.js +0 -82
- package/dist/reflector/controllers/public/auth/sign-in-firebase/auth-sign-in-firebase.module.svelte.d.ts +0 -29
- package/dist/reflector/controllers/public/auth/sign-in-firebase/auth-sign-in-firebase.module.svelte.js +0 -223
- package/dist/reflector/controllers/public/reset-password/tenant/send-recovery-email/tenant-send-recovery-email.module.svelte.d.ts +0 -13
- package/dist/reflector/controllers/public/reset-password/tenant/send-recovery-email/tenant-send-recovery-email.module.svelte.js +0 -49
- package/dist/reflector/controllers/restricted/account/avatar-file-upload/account-avatar-file-upload.module.svelte.d.ts +0 -19
- package/dist/reflector/controllers/restricted/account/avatar-file-upload/account-avatar-file-upload.module.svelte.js +0 -114
- package/dist/reflector/controllers/restricted/bank/restricted-bank.module.svelte.d.ts +0 -15
- package/dist/reflector/controllers/restricted/bank/restricted-bank.module.svelte.js +0 -78
- package/dist/reflector/controllers/restricted/files/presigned-url/files-presigned-url.module.svelte.d.ts +0 -11
- package/dist/reflector/controllers/restricted/files/presigned-url/files-presigned-url.module.svelte.js +0 -56
- package/dist/reflector/controllers/restricted/notification/restricted-notification.module.svelte.d.ts +0 -9
- package/dist/reflector/controllers/restricted/notification/restricted-notification.module.svelte.js +0 -36
- package/dist/reflector/controllers/restricted/two-factor-auth/status/two-factor-auth-status.module.svelte.d.ts +0 -15
- package/dist/reflector/controllers/restricted/two-factor-auth/status/two-factor-auth-status.module.svelte.js +0 -68
- package/dist/reflector/reflector.types.d.ts +0 -4
- package/dist/reflector/reflector.types.js +0 -4
- package/dist/reflector/schemas.d.ts +0 -357
- package/dist/reflector/schemas.js +0 -1709
- package/dist/request.d.ts +0 -32
- package/dist/request.js +0 -125
- package/dist/utils/EndpointUtils.d.ts +0 -4
- package/dist/utils/EndpointUtils.js +0 -34
- package/dist/utils/EnumUtils.d.ts +0 -2
- package/dist/utils/EnumUtils.js +0 -9
- package/dist/utils/FileUtils.d.ts +0 -3
- package/dist/utils/FileUtils.js +0 -20
- package/dist/utils/NamingUtils.d.ts +0 -4
- package/dist/utils/NamingUtils.js +0 -19
- package/dist/utils/SchemaUtils.d.ts +0 -4
- package/dist/utils/SchemaUtils.js +0 -18
- package/dist/utils/StringUtils.d.ts +0 -5
- package/dist/utils/StringUtils.js +0 -41
- package/dist/utils/ValidatorUtils.d.ts +0 -6
- package/dist/utils/ValidatorUtils.js +0 -70
- package/dist/utils/index.d.ts +0 -7
- package/dist/utils/index.js +0 -7
- package/dist/zodProperty.d.ts +0 -32
- package/dist/zodProperty.js +0 -123
package/README.md
CHANGED
|
@@ -1,518 +1,518 @@
|
|
|
1
|
-
# Svelte Reflector
|
|
2
|
-
|
|
3
|
-
**Turn your OpenAPI into a first-class Svelte 5 DX.**
|
|
4
|
-
|
|
5
|
-
Svelte Reflector is a **developer-experience-first code generator** that converts OpenAPI specs into fully typed, reactive Svelte 5 modules — ready for production, forms included.
|
|
6
|
-
|
|
7
|
-
[](https://www.npmjs.com/package/svelte-reflector)
|
|
8
|
-
[](https://www.npmjs.com/package/svelte-reflector)
|
|
9
|
-
[](https://www.npmjs.com/package/svelte-reflector)
|
|
10
|
-
[](https://www.typescriptlang.org/)
|
|
11
|
-
[](https://svelte.dev/)
|
|
12
|
-
|
|
13
|
-
A TypeScript code generator that creates type-safe Svelte 5 modules from OpenAPI specifications. It transforms your backend's OpenAPI/Swagger docs into fully-typed Svelte stores with built-in form handling, validation, and API integration.
|
|
14
|
-
|
|
15
|
-
## Features
|
|
16
|
-
|
|
17
|
-
- **Automatic Type Generation** - Generates TypeScript interfaces and classes from OpenAPI schemas
|
|
18
|
-
- **Svelte 5 Runes Integration** - Uses `$state` and `$derived` for reactive state management
|
|
19
|
-
- **Form Handling** - Auto-generates form schemas with validation support
|
|
20
|
-
- **Type-Safe API Calls** - Full TypeScript support for all API operations
|
|
21
|
-
- **Query Parameter Sync** - `QueryBuilder` and `EnumQueryBuilder` keep state synced with URL searchParams
|
|
22
|
-
- **Enum Support** - Auto-generates enum types and array enum query builders
|
|
23
|
-
- **OpenAPI/Swagger Compatible** - Works with any backend that exposes OpenAPI specs
|
|
24
|
-
- **Development Mode** - Smart regeneration based on environment
|
|
25
|
-
- **Validation Ready** - Built-in support for custom field validators
|
|
26
|
-
- **Vite Plugin** - Can be used as a Vite plugin for automatic generation on build
|
|
27
|
-
|
|
28
|
-
## Installation
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
npm install svelte-reflector
|
|
32
|
-
# or
|
|
33
|
-
yarn add svelte-reflector
|
|
34
|
-
# or
|
|
35
|
-
pnpm add svelte-reflector
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Quick Start
|
|
39
|
-
|
|
40
|
-
### 1. Configure Environment Variables
|
|
41
|
-
|
|
42
|
-
Create a `.env` file in your project root:
|
|
43
|
-
|
|
44
|
-
```env
|
|
45
|
-
# Required - Your backend URL
|
|
46
|
-
BACKEND_URL=https://api.example.com/
|
|
47
|
-
# or
|
|
48
|
-
PUBLIC_BACKEND=https://api.example.com/
|
|
49
|
-
|
|
50
|
-
# Optional - Environment (defaults to PROD)
|
|
51
|
-
ENVIRONMENT=DEV
|
|
52
|
-
# or
|
|
53
|
-
VITE_ENVIRONMENT=DEV
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### 2. Create Reflector Config (Optional)
|
|
57
|
-
|
|
58
|
-
Create a `src/reflector.config.ts` to define custom validators:
|
|
59
|
-
|
|
60
|
-
```typescript
|
|
61
|
-
export const validators = [
|
|
62
|
-
{
|
|
63
|
-
fields: ["email", "userEmail"],
|
|
64
|
-
validator: "validateEmail",
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
fields: ["phone", "mobile"],
|
|
68
|
-
validator: "validatePhone",
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
fields: ["cpf", "cnpj"],
|
|
72
|
-
validator: "validateDocument",
|
|
73
|
-
},
|
|
74
|
-
];
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### 3. Run the Generator
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
# Manual generation (recommended for DEV environment)
|
|
81
|
-
npx reflect
|
|
82
|
-
|
|
83
|
-
# Or programmatically as a Vite plugin
|
|
84
|
-
import { reflector } from "svelte-reflector";
|
|
85
|
-
await reflector(true); // true = force generation
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### 4. Use Generated Modules
|
|
89
|
-
|
|
90
|
-
The generator creates files in `src/reflector/`:
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
import { UserModule } from "$reflector/controllers/user/user.module.svelte";
|
|
94
|
-
import type { User } from "$reflector/schemas.svelte";
|
|
95
|
-
|
|
96
|
-
// Create module instance
|
|
97
|
-
const userModule = new UserModule();
|
|
98
|
-
|
|
99
|
-
// Access reactive state
|
|
100
|
-
console.log(userModule.loading); // $state<boolean>
|
|
101
|
-
console.log(userModule.list); // $state<User[]>
|
|
102
|
-
|
|
103
|
-
// Call API methods
|
|
104
|
-
await userModule.listAll({
|
|
105
|
-
behavior: {
|
|
106
|
-
onSuccess: (response) => console.log(response),
|
|
107
|
-
onError: (error) => console.error(error),
|
|
108
|
-
},
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// Work with forms
|
|
112
|
-
const userForm = userModule.forms.createUser;
|
|
113
|
-
userForm.name.value = "John Doe";
|
|
114
|
-
userForm.email.value = "john@example.com";
|
|
115
|
-
|
|
116
|
-
// Submit form
|
|
117
|
-
await userModule.createUser();
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
## Generated Structure
|
|
121
|
-
|
|
122
|
-
```
|
|
123
|
-
src/reflector/
|
|
124
|
-
├── controllers/
|
|
125
|
-
│ └── user/
|
|
126
|
-
│ └── user.module.svelte.ts # API module with methods
|
|
127
|
-
├── schemas.svelte.ts # Generated schemas & types
|
|
128
|
-
├── reflector.svelte.ts # Core utilities (build, isFormValid, QueryBuilder, etc.)
|
|
129
|
-
├── fields.ts # Field name constants
|
|
130
|
-
├── enums.ts # Enum type definitions
|
|
131
|
-
├── mocked-params.svelte.ts # Mocked path parameters ($state)
|
|
132
|
-
└── backup.json # Cached OpenAPI spec
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
## Generated Module API
|
|
136
|
-
|
|
137
|
-
Each generated module provides:
|
|
138
|
-
|
|
139
|
-
### State Properties
|
|
140
|
-
|
|
141
|
-
| Property | Type | Description |
|
|
142
|
-
|----------|------|-------------|
|
|
143
|
-
| `loading` | `$state<boolean>` | Request loading state |
|
|
144
|
-
| `list` | `$state<T[]>` | List results (for list endpoints) |
|
|
145
|
-
| `forms` | `$state<Record<string, T>>` | Form instances |
|
|
146
|
-
| `querys` | `Querys` | Query parameter state (QueryBuilder instances) |
|
|
147
|
-
| `headers` | `Headers` | Header state |
|
|
148
|
-
| `paths` | `Paths` | Path parameter state |
|
|
149
|
-
|
|
150
|
-
### Methods
|
|
151
|
-
|
|
152
|
-
```typescript
|
|
153
|
-
// List all items (GET with page parameter)
|
|
154
|
-
async listAll(params?: { behavior?: Behavior }): Promise<T[]>
|
|
155
|
-
|
|
156
|
-
// Get single entity (GET without page parameter)
|
|
157
|
-
async get(params?: { behavior?: Behavior }): Promise<T>
|
|
158
|
-
|
|
159
|
-
// Create/Update (POST/PUT/PATCH)
|
|
160
|
-
async create(params?: { behavior?: Behavior }): Promise<T>
|
|
161
|
-
async update(params?: { behavior?: Behavior }): Promise<T>
|
|
162
|
-
|
|
163
|
-
// Delete (DELETE)
|
|
164
|
-
async delete(params?: { behavior?: Behavior }): Promise<void>
|
|
165
|
-
|
|
166
|
-
// Reset all state
|
|
167
|
-
reset(): void
|
|
168
|
-
|
|
169
|
-
// Clear forms
|
|
170
|
-
clearForms(): void
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
### QueryBuilder
|
|
174
|
-
|
|
175
|
-
Query parameters are wrapped in `QueryBuilder` instances that sync with URL searchParams:
|
|
176
|
-
|
|
177
|
-
```typescript
|
|
178
|
-
// Single value query parameter
|
|
179
|
-
const querys = module.querys;
|
|
180
|
-
querys.status.update("active"); // Updates URL searchParam and internal state
|
|
181
|
-
|
|
182
|
-
// Array enum query parameter
|
|
183
|
-
const enumQuery = module.querys.roles; // EnumQueryBuilder<RoleType>
|
|
184
|
-
enumQuery.selected = "admin";
|
|
185
|
-
enumQuery.add(); // Adds to URL searchParams
|
|
186
|
-
enumQuery.remove(0); // Removes from URL searchParams
|
|
187
|
-
enumQuery.values; // $derived from URL - always in sync
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
## Configuration
|
|
191
|
-
|
|
192
|
-
### Environment Variables
|
|
193
|
-
|
|
194
|
-
| Variable | Required | Description |
|
|
195
|
-
|----------|----------|-------------|
|
|
196
|
-
| `BACKEND_URL` | Yes | Backend API URL |
|
|
197
|
-
| `PUBLIC_BACKEND` | Yes | Alternative to BACKEND_URL |
|
|
198
|
-
| `ENVIRONMENT` | No | DEV/PROD (defaults to PROD) |
|
|
199
|
-
| `VITE_ENVIRONMENT` | No | Vite-specific env var |
|
|
200
|
-
| `NODE_ENV` | No | Node environment |
|
|
201
|
-
|
|
202
|
-
### Behavior Pattern
|
|
203
|
-
|
|
204
|
-
All API methods accept a `Behavior` object for callbacks:
|
|
205
|
-
|
|
206
|
-
```typescript
|
|
207
|
-
interface Behavior<TSuccess, TError> {
|
|
208
|
-
onSuccess?: (value: TSuccess) => Promise<void> | void;
|
|
209
|
-
onError?: (error: TError) => Promise<void> | void;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Usage
|
|
213
|
-
await userModule.createUser({
|
|
214
|
-
behavior: {
|
|
215
|
-
onSuccess: (user) => console.log("Created:", user),
|
|
216
|
-
onError: (err) => console.error("Failed:", err),
|
|
217
|
-
},
|
|
218
|
-
});
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
### Form Validation
|
|
222
|
-
|
|
223
|
-
Forms use `BuildedInput` class with validation:
|
|
224
|
-
|
|
225
|
-
```typescript
|
|
226
|
-
class BuildedInput<T> {
|
|
227
|
-
value: T; // Current value ($state)
|
|
228
|
-
display: T; // Display value ($state)
|
|
229
|
-
required: boolean; // Is field required
|
|
230
|
-
placeholder: T; // Placeholder/example value
|
|
231
|
-
readonly kind: 'builded';
|
|
232
|
-
validator?: (v: T) => string | null; // Validation function
|
|
233
|
-
validate(): string | null; // Run validation
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Check if all form fields are valid
|
|
237
|
-
import { isFormValid } from "$reflector/reflector.svelte";
|
|
238
|
-
|
|
239
|
-
if (isFormValid(userModule.forms.createUser)) {
|
|
240
|
-
await userModule.createUser();
|
|
241
|
-
}
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
## TypeScript Configuration
|
|
245
|
-
|
|
246
|
-
Add path aliases to your `tsconfig.json`:
|
|
247
|
-
|
|
248
|
-
```json
|
|
249
|
-
{
|
|
250
|
-
"compilerOptions": {
|
|
251
|
-
"paths": {
|
|
252
|
-
"$reflector/*": ["./src/reflector/*"],
|
|
253
|
-
"$lib/*": ["./src/lib/*"]
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
For Vite projects, also update `vite.config.ts`:
|
|
260
|
-
|
|
261
|
-
```typescript
|
|
262
|
-
export default defineConfig({
|
|
263
|
-
resolve: {
|
|
264
|
-
alias: {
|
|
265
|
-
$reflector: path.resolve("./src/reflector"),
|
|
266
|
-
$lib: path.resolve("./src/lib"),
|
|
267
|
-
},
|
|
268
|
-
},
|
|
269
|
-
});
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
## Workflow
|
|
273
|
-
|
|
274
|
-
### Development Mode
|
|
275
|
-
|
|
276
|
-
In `ENVIRONMENT=DEV`:
|
|
277
|
-
- Schemas are **NOT** auto-regenerated on build
|
|
278
|
-
- Use `npx reflect` to manually regenerate
|
|
279
|
-
- Faster builds, manual control
|
|
280
|
-
|
|
281
|
-
### Production Mode
|
|
282
|
-
|
|
283
|
-
In `ENVIRONMENT=PROD`:
|
|
284
|
-
- Schemas are auto-regenerated on each build
|
|
285
|
-
- Fresh types from latest OpenAPI spec
|
|
286
|
-
- Fallback to `backup.json` if backend is unavailable
|
|
287
|
-
|
|
288
|
-
## Advanced Usage
|
|
289
|
-
|
|
290
|
-
### Custom Validators
|
|
291
|
-
|
|
292
|
-
Define validators in `src/reflector.config.ts`:
|
|
293
|
-
|
|
294
|
-
```typescript
|
|
295
|
-
export const validators = [
|
|
296
|
-
{
|
|
297
|
-
fields: ["email", "userEmail", "contactEmail"],
|
|
298
|
-
validator: "validateEmail",
|
|
299
|
-
},
|
|
300
|
-
{
|
|
301
|
-
fields: ["phone", "mobile", "whatsapp"],
|
|
302
|
-
validator: "validatePhone",
|
|
303
|
-
},
|
|
304
|
-
{
|
|
305
|
-
fields: ["cpf", "cnpj", "document"],
|
|
306
|
-
validator: "validateDocument",
|
|
307
|
-
},
|
|
308
|
-
{
|
|
309
|
-
fields: ["password", "newPassword"],
|
|
310
|
-
validator: "validatePassword",
|
|
311
|
-
},
|
|
312
|
-
{
|
|
313
|
-
fields: ["birthDate", "startDate", "endDate"],
|
|
314
|
-
validator: "validateDate",
|
|
315
|
-
},
|
|
316
|
-
{
|
|
317
|
-
fields: ["zipcode", "cep"],
|
|
318
|
-
validator: "validateZipcode",
|
|
319
|
-
},
|
|
320
|
-
{
|
|
321
|
-
fields: ["url", "website", "avatarUrl"],
|
|
322
|
-
validator: "validateUrl",
|
|
323
|
-
},
|
|
324
|
-
];
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
Then implement in your app at `$lib/sanitizers/validateFormats.ts`:
|
|
328
|
-
|
|
329
|
-
```typescript
|
|
330
|
-
// Email validation
|
|
331
|
-
export function validateEmail(value: string): string | null {
|
|
332
|
-
if (!value) return null; // Let required handle empty
|
|
333
|
-
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
334
|
-
return emailRegex.test(value) ? null : "Invalid email format";
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// Phone validation
|
|
338
|
-
export function validatePhone(value: string): string | null {
|
|
339
|
-
if (!value) return null;
|
|
340
|
-
const phoneRegex = /^(\+?55\s?)?(\(?\d{2}\)?\s?)?(\d{4,5}-?\d{4})$/;
|
|
341
|
-
return phoneRegex.test(value) ? null : "Invalid phone number";
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// CPF/CNPJ validation (Brazilian documents)
|
|
345
|
-
export function validateDocument(value: string): string | null {
|
|
346
|
-
if (!value) return null;
|
|
347
|
-
const cleaned = value.replace(/\D/g, '');
|
|
348
|
-
|
|
349
|
-
if (cleaned.length === 11) {
|
|
350
|
-
return validateCPF(cleaned) ? null : "Invalid CPF";
|
|
351
|
-
} else if (cleaned.length === 14) {
|
|
352
|
-
return validateCNPJ(cleaned) ? null : "Invalid CNPJ";
|
|
353
|
-
}
|
|
354
|
-
return "Invalid document format";
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
function validateCPF(cpf: string): boolean {
|
|
358
|
-
if (/^(\d)\1{10}$/.test(cpf)) return false;
|
|
359
|
-
|
|
360
|
-
let sum = 0;
|
|
361
|
-
for (let i = 0; i < 9; i++) sum += parseInt(cpf[i]) * (10 - i);
|
|
362
|
-
let rev = 11 - (sum % 11);
|
|
363
|
-
if (rev === 10 || rev === 11) rev = 0;
|
|
364
|
-
if (rev !== parseInt(cpf[9])) return false;
|
|
365
|
-
|
|
366
|
-
sum = 0;
|
|
367
|
-
for (let i = 0; i < 10; i++) sum += parseInt(cpf[i]) * (11 - i);
|
|
368
|
-
rev = 11 - (sum % 11);
|
|
369
|
-
if (rev === 10 || rev === 11) rev = 0;
|
|
370
|
-
return rev === parseInt(cpf[10]);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
function validateCNPJ(cnpj: string): boolean {
|
|
374
|
-
if (/^(\d)\1{13}$/.test(cnpj)) return false;
|
|
375
|
-
|
|
376
|
-
const weights1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
377
|
-
const weights2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
378
|
-
|
|
379
|
-
let sum = 0;
|
|
380
|
-
for (let i = 0; i < 12; i++) sum += parseInt(cnpj[i]) * weights1[i];
|
|
381
|
-
let rev = sum % 11 < 2 ? 0 : 11 - (sum % 11);
|
|
382
|
-
if (rev !== parseInt(cnpj[12])) return false;
|
|
383
|
-
|
|
384
|
-
sum = 0;
|
|
385
|
-
for (let i = 0; i < 13; i++) sum += parseInt(cnpj[i]) * weights2[i];
|
|
386
|
-
rev = sum % 11 < 2 ? 0 : 11 - (sum % 11);
|
|
387
|
-
return rev === parseInt(cnpj[13]);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
// Password strength validation
|
|
391
|
-
export function validatePassword(value: string): string | null {
|
|
392
|
-
if (!value) return null;
|
|
393
|
-
if (value.length < 8) return "Password must be at least 8 characters";
|
|
394
|
-
if (!/[A-Z]/.test(value)) return "Password must contain an uppercase letter";
|
|
395
|
-
if (!/[a-z]/.test(value)) return "Password must contain a lowercase letter";
|
|
396
|
-
if (!/[0-9]/.test(value)) return "Password must contain a number";
|
|
397
|
-
if (!/[!@#$%^&*]/.test(value)) return "Password must contain a special character";
|
|
398
|
-
return null;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// Date validation
|
|
402
|
-
export function validateDate(value: string): string | null {
|
|
403
|
-
if (!value) return null;
|
|
404
|
-
const date = new Date(value);
|
|
405
|
-
if (isNaN(date.getTime())) return "Invalid date";
|
|
406
|
-
if (date > new Date()) return "Date cannot be in the future";
|
|
407
|
-
return null;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// Brazilian ZIP code (CEP) validation
|
|
411
|
-
export function validateZipcode(value: string): string | null {
|
|
412
|
-
if (!value) return null;
|
|
413
|
-
const cepRegex = /^\d{5}-?\d{3}$/;
|
|
414
|
-
return cepRegex.test(value) ? null : "Invalid ZIP code format";
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
// URL validation
|
|
418
|
-
export function validateUrl(value: string): string | null {
|
|
419
|
-
if (!value) return null;
|
|
420
|
-
try {
|
|
421
|
-
new URL(value);
|
|
422
|
-
return null;
|
|
423
|
-
} catch {
|
|
424
|
-
return "Invalid URL format";
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// Min/max length validator factory
|
|
429
|
-
export function minLength(min: number) {
|
|
430
|
-
return (value: string): string | null => {
|
|
431
|
-
if (!value) return null;
|
|
432
|
-
return value.length >= min ? null : `Must be at least ${min} characters`;
|
|
433
|
-
};
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
export function maxLength(max: number) {
|
|
437
|
-
return (value: string): string | null => {
|
|
438
|
-
if (!value) return null;
|
|
439
|
-
return value.length <= max ? null : `Must be at most ${max} characters`;
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
// Number range validator factory
|
|
444
|
-
export function numberRange(min: number, max: number) {
|
|
445
|
-
return (value: number): string | null => {
|
|
446
|
-
if (value === null || value === undefined) return null;
|
|
447
|
-
return value >= min && value <= max ? null : `Must be between ${min} and ${max}`;
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// Required field validator
|
|
452
|
-
export function required(value: string | number | boolean | null): string | null {
|
|
453
|
-
if (value === null || value === undefined || value === '') {
|
|
454
|
-
return "This field is required";
|
|
455
|
-
}
|
|
456
|
-
return null;
|
|
457
|
-
}
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
### Manual Schema Access
|
|
461
|
-
|
|
462
|
-
```typescript
|
|
463
|
-
import { User } from "$reflector/schemas.svelte";
|
|
464
|
-
|
|
465
|
-
// Create instance
|
|
466
|
-
const user = new User({ name: "John", email: "john@example.com" });
|
|
467
|
-
|
|
468
|
-
// Get data bundle
|
|
469
|
-
const data = user.bundle(); // { name: "John", email: "john@example.com" }
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
### Batch Query Updates
|
|
473
|
-
|
|
474
|
-
```typescript
|
|
475
|
-
import { setQueryGroup } from "$reflector/reflector.svelte";
|
|
476
|
-
|
|
477
|
-
// Update multiple query params at once
|
|
478
|
-
setQueryGroup([
|
|
479
|
-
{ key: "page", value: 1 },
|
|
480
|
-
{ key: "status", value: "active" },
|
|
481
|
-
{ key: "roles", value: ["admin", "editor"] }, // Array params supported
|
|
482
|
-
]);
|
|
483
|
-
```
|
|
484
|
-
|
|
485
|
-
## Troubleshooting
|
|
486
|
-
|
|
487
|
-
### "BACKEND_URL vazio" Error
|
|
488
|
-
|
|
489
|
-
Ensure you have set `BACKEND_URL` or `PUBLIC_BACKEND` in your `.env` file.
|
|
490
|
-
|
|
491
|
-
### Schemas Not Updating
|
|
492
|
-
|
|
493
|
-
In DEV mode, run `npx reflect` manually. Check that your backend's OpenAPI spec is accessible at `{BACKEND_URL}openapi.json`.
|
|
494
|
-
|
|
495
|
-
### Type Errors After Generation
|
|
496
|
-
|
|
497
|
-
1. Restart your TypeScript language server
|
|
498
|
-
2. Check path aliases in `tsconfig.json`
|
|
499
|
-
3. Ensure `$reflector/*` alias is configured
|
|
500
|
-
|
|
501
|
-
## License
|
|
502
|
-
|
|
503
|
-
MIT License - see [LICENSE](LICENSE) for details.
|
|
504
|
-
|
|
505
|
-
## Contributing
|
|
506
|
-
|
|
507
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
508
|
-
|
|
509
|
-
## Links
|
|
510
|
-
|
|
511
|
-
- [npm](https://www.npmjs.com/package/svelte-reflector)
|
|
512
|
-
- [GitHub](https://github.com/aleleppy/reflector)
|
|
513
|
-
- [Svelte](https://svelte.dev/)
|
|
514
|
-
- [OpenAPI Specification](https://swagger.io/specification/)
|
|
515
|
-
|
|
516
|
-
---
|
|
517
|
-
|
|
518
|
-
Built with by the Pináculo Digital team.
|
|
1
|
+
# Svelte Reflector
|
|
2
|
+
|
|
3
|
+
**Turn your OpenAPI into a first-class Svelte 5 DX.**
|
|
4
|
+
|
|
5
|
+
Svelte Reflector is a **developer-experience-first code generator** that converts OpenAPI specs into fully typed, reactive Svelte 5 modules — ready for production, forms included.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/svelte-reflector)
|
|
8
|
+
[](https://www.npmjs.com/package/svelte-reflector)
|
|
9
|
+
[](https://www.npmjs.com/package/svelte-reflector)
|
|
10
|
+
[](https://www.typescriptlang.org/)
|
|
11
|
+
[](https://svelte.dev/)
|
|
12
|
+
|
|
13
|
+
A TypeScript code generator that creates type-safe Svelte 5 modules from OpenAPI specifications. It transforms your backend's OpenAPI/Swagger docs into fully-typed Svelte stores with built-in form handling, validation, and API integration.
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- **Automatic Type Generation** - Generates TypeScript interfaces and classes from OpenAPI schemas
|
|
18
|
+
- **Svelte 5 Runes Integration** - Uses `$state` and `$derived` for reactive state management
|
|
19
|
+
- **Form Handling** - Auto-generates form schemas with validation support
|
|
20
|
+
- **Type-Safe API Calls** - Full TypeScript support for all API operations
|
|
21
|
+
- **Query Parameter Sync** - `QueryBuilder` and `EnumQueryBuilder` keep state synced with URL searchParams
|
|
22
|
+
- **Enum Support** - Auto-generates enum types and array enum query builders
|
|
23
|
+
- **OpenAPI/Swagger Compatible** - Works with any backend that exposes OpenAPI specs
|
|
24
|
+
- **Development Mode** - Smart regeneration based on environment
|
|
25
|
+
- **Validation Ready** - Built-in support for custom field validators
|
|
26
|
+
- **Vite Plugin** - Can be used as a Vite plugin for automatic generation on build
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install svelte-reflector
|
|
32
|
+
# or
|
|
33
|
+
yarn add svelte-reflector
|
|
34
|
+
# or
|
|
35
|
+
pnpm add svelte-reflector
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
### 1. Configure Environment Variables
|
|
41
|
+
|
|
42
|
+
Create a `.env` file in your project root:
|
|
43
|
+
|
|
44
|
+
```env
|
|
45
|
+
# Required - Your backend URL
|
|
46
|
+
BACKEND_URL=https://api.example.com/
|
|
47
|
+
# or
|
|
48
|
+
PUBLIC_BACKEND=https://api.example.com/
|
|
49
|
+
|
|
50
|
+
# Optional - Environment (defaults to PROD)
|
|
51
|
+
ENVIRONMENT=DEV
|
|
52
|
+
# or
|
|
53
|
+
VITE_ENVIRONMENT=DEV
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 2. Create Reflector Config (Optional)
|
|
57
|
+
|
|
58
|
+
Create a `src/reflector.config.ts` to define custom validators:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
export const validators = [
|
|
62
|
+
{
|
|
63
|
+
fields: ["email", "userEmail"],
|
|
64
|
+
validator: "validateEmail",
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
fields: ["phone", "mobile"],
|
|
68
|
+
validator: "validatePhone",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
fields: ["cpf", "cnpj"],
|
|
72
|
+
validator: "validateDocument",
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 3. Run the Generator
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Manual generation (recommended for DEV environment)
|
|
81
|
+
npx reflect
|
|
82
|
+
|
|
83
|
+
# Or programmatically as a Vite plugin
|
|
84
|
+
import { reflector } from "svelte-reflector";
|
|
85
|
+
await reflector(true); // true = force generation
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 4. Use Generated Modules
|
|
89
|
+
|
|
90
|
+
The generator creates files in `src/reflector/`:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { UserModule } from "$reflector/controllers/user/user.module.svelte";
|
|
94
|
+
import type { User } from "$reflector/schemas.svelte";
|
|
95
|
+
|
|
96
|
+
// Create module instance
|
|
97
|
+
const userModule = new UserModule();
|
|
98
|
+
|
|
99
|
+
// Access reactive state
|
|
100
|
+
console.log(userModule.loading); // $state<boolean>
|
|
101
|
+
console.log(userModule.list); // $state<User[]>
|
|
102
|
+
|
|
103
|
+
// Call API methods
|
|
104
|
+
await userModule.listAll({
|
|
105
|
+
behavior: {
|
|
106
|
+
onSuccess: (response) => console.log(response),
|
|
107
|
+
onError: (error) => console.error(error),
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Work with forms
|
|
112
|
+
const userForm = userModule.forms.createUser;
|
|
113
|
+
userForm.name.value = "John Doe";
|
|
114
|
+
userForm.email.value = "john@example.com";
|
|
115
|
+
|
|
116
|
+
// Submit form
|
|
117
|
+
await userModule.createUser();
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Generated Structure
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
src/reflector/
|
|
124
|
+
├── controllers/
|
|
125
|
+
│ └── user/
|
|
126
|
+
│ └── user.module.svelte.ts # API module with methods
|
|
127
|
+
├── schemas.svelte.ts # Generated schemas & types
|
|
128
|
+
├── reflector.svelte.ts # Core utilities (build, isFormValid, QueryBuilder, etc.)
|
|
129
|
+
├── fields.ts # Field name constants
|
|
130
|
+
├── enums.ts # Enum type definitions
|
|
131
|
+
├── mocked-params.svelte.ts # Mocked path parameters ($state)
|
|
132
|
+
└── backup.json # Cached OpenAPI spec
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Generated Module API
|
|
136
|
+
|
|
137
|
+
Each generated module provides:
|
|
138
|
+
|
|
139
|
+
### State Properties
|
|
140
|
+
|
|
141
|
+
| Property | Type | Description |
|
|
142
|
+
|----------|------|-------------|
|
|
143
|
+
| `loading` | `$state<boolean>` | Request loading state |
|
|
144
|
+
| `list` | `$state<T[]>` | List results (for list endpoints) |
|
|
145
|
+
| `forms` | `$state<Record<string, T>>` | Form instances |
|
|
146
|
+
| `querys` | `Querys` | Query parameter state (QueryBuilder instances) |
|
|
147
|
+
| `headers` | `Headers` | Header state |
|
|
148
|
+
| `paths` | `Paths` | Path parameter state |
|
|
149
|
+
|
|
150
|
+
### Methods
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// List all items (GET with page parameter)
|
|
154
|
+
async listAll(params?: { behavior?: Behavior }): Promise<T[]>
|
|
155
|
+
|
|
156
|
+
// Get single entity (GET without page parameter)
|
|
157
|
+
async get(params?: { behavior?: Behavior }): Promise<T>
|
|
158
|
+
|
|
159
|
+
// Create/Update (POST/PUT/PATCH)
|
|
160
|
+
async create(params?: { behavior?: Behavior }): Promise<T>
|
|
161
|
+
async update(params?: { behavior?: Behavior }): Promise<T>
|
|
162
|
+
|
|
163
|
+
// Delete (DELETE)
|
|
164
|
+
async delete(params?: { behavior?: Behavior }): Promise<void>
|
|
165
|
+
|
|
166
|
+
// Reset all state
|
|
167
|
+
reset(): void
|
|
168
|
+
|
|
169
|
+
// Clear forms
|
|
170
|
+
clearForms(): void
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### QueryBuilder
|
|
174
|
+
|
|
175
|
+
Query parameters are wrapped in `QueryBuilder` instances that sync with URL searchParams:
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
// Single value query parameter
|
|
179
|
+
const querys = module.querys;
|
|
180
|
+
querys.status.update("active"); // Updates URL searchParam and internal state
|
|
181
|
+
|
|
182
|
+
// Array enum query parameter
|
|
183
|
+
const enumQuery = module.querys.roles; // EnumQueryBuilder<RoleType>
|
|
184
|
+
enumQuery.selected = "admin";
|
|
185
|
+
enumQuery.add(); // Adds to URL searchParams
|
|
186
|
+
enumQuery.remove(0); // Removes from URL searchParams
|
|
187
|
+
enumQuery.values; // $derived from URL - always in sync
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Configuration
|
|
191
|
+
|
|
192
|
+
### Environment Variables
|
|
193
|
+
|
|
194
|
+
| Variable | Required | Description |
|
|
195
|
+
|----------|----------|-------------|
|
|
196
|
+
| `BACKEND_URL` | Yes | Backend API URL |
|
|
197
|
+
| `PUBLIC_BACKEND` | Yes | Alternative to BACKEND_URL |
|
|
198
|
+
| `ENVIRONMENT` | No | DEV/PROD (defaults to PROD) |
|
|
199
|
+
| `VITE_ENVIRONMENT` | No | Vite-specific env var |
|
|
200
|
+
| `NODE_ENV` | No | Node environment |
|
|
201
|
+
|
|
202
|
+
### Behavior Pattern
|
|
203
|
+
|
|
204
|
+
All API methods accept a `Behavior` object for callbacks:
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
interface Behavior<TSuccess, TError> {
|
|
208
|
+
onSuccess?: (value: TSuccess) => Promise<void> | void;
|
|
209
|
+
onError?: (error: TError) => Promise<void> | void;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Usage
|
|
213
|
+
await userModule.createUser({
|
|
214
|
+
behavior: {
|
|
215
|
+
onSuccess: (user) => console.log("Created:", user),
|
|
216
|
+
onError: (err) => console.error("Failed:", err),
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Form Validation
|
|
222
|
+
|
|
223
|
+
Forms use `BuildedInput` class with validation:
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
class BuildedInput<T> {
|
|
227
|
+
value: T; // Current value ($state)
|
|
228
|
+
display: T; // Display value ($state)
|
|
229
|
+
required: boolean; // Is field required
|
|
230
|
+
placeholder: T; // Placeholder/example value
|
|
231
|
+
readonly kind: 'builded';
|
|
232
|
+
validator?: (v: T) => string | null; // Validation function
|
|
233
|
+
validate(): string | null; // Run validation
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Check if all form fields are valid
|
|
237
|
+
import { isFormValid } from "$reflector/reflector.svelte";
|
|
238
|
+
|
|
239
|
+
if (isFormValid(userModule.forms.createUser)) {
|
|
240
|
+
await userModule.createUser();
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## TypeScript Configuration
|
|
245
|
+
|
|
246
|
+
Add path aliases to your `tsconfig.json`:
|
|
247
|
+
|
|
248
|
+
```json
|
|
249
|
+
{
|
|
250
|
+
"compilerOptions": {
|
|
251
|
+
"paths": {
|
|
252
|
+
"$reflector/*": ["./src/reflector/*"],
|
|
253
|
+
"$lib/*": ["./src/lib/*"]
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
For Vite projects, also update `vite.config.ts`:
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
export default defineConfig({
|
|
263
|
+
resolve: {
|
|
264
|
+
alias: {
|
|
265
|
+
$reflector: path.resolve("./src/reflector"),
|
|
266
|
+
$lib: path.resolve("./src/lib"),
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Workflow
|
|
273
|
+
|
|
274
|
+
### Development Mode
|
|
275
|
+
|
|
276
|
+
In `ENVIRONMENT=DEV`:
|
|
277
|
+
- Schemas are **NOT** auto-regenerated on build
|
|
278
|
+
- Use `npx reflect` to manually regenerate
|
|
279
|
+
- Faster builds, manual control
|
|
280
|
+
|
|
281
|
+
### Production Mode
|
|
282
|
+
|
|
283
|
+
In `ENVIRONMENT=PROD`:
|
|
284
|
+
- Schemas are auto-regenerated on each build
|
|
285
|
+
- Fresh types from latest OpenAPI spec
|
|
286
|
+
- Fallback to `backup.json` if backend is unavailable
|
|
287
|
+
|
|
288
|
+
## Advanced Usage
|
|
289
|
+
|
|
290
|
+
### Custom Validators
|
|
291
|
+
|
|
292
|
+
Define validators in `src/reflector.config.ts`:
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
export const validators = [
|
|
296
|
+
{
|
|
297
|
+
fields: ["email", "userEmail", "contactEmail"],
|
|
298
|
+
validator: "validateEmail",
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
fields: ["phone", "mobile", "whatsapp"],
|
|
302
|
+
validator: "validatePhone",
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
fields: ["cpf", "cnpj", "document"],
|
|
306
|
+
validator: "validateDocument",
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
fields: ["password", "newPassword"],
|
|
310
|
+
validator: "validatePassword",
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
fields: ["birthDate", "startDate", "endDate"],
|
|
314
|
+
validator: "validateDate",
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
fields: ["zipcode", "cep"],
|
|
318
|
+
validator: "validateZipcode",
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
fields: ["url", "website", "avatarUrl"],
|
|
322
|
+
validator: "validateUrl",
|
|
323
|
+
},
|
|
324
|
+
];
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Then implement in your app at `$lib/sanitizers/validateFormats.ts`:
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
// Email validation
|
|
331
|
+
export function validateEmail(value: string): string | null {
|
|
332
|
+
if (!value) return null; // Let required handle empty
|
|
333
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
334
|
+
return emailRegex.test(value) ? null : "Invalid email format";
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Phone validation
|
|
338
|
+
export function validatePhone(value: string): string | null {
|
|
339
|
+
if (!value) return null;
|
|
340
|
+
const phoneRegex = /^(\+?55\s?)?(\(?\d{2}\)?\s?)?(\d{4,5}-?\d{4})$/;
|
|
341
|
+
return phoneRegex.test(value) ? null : "Invalid phone number";
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// CPF/CNPJ validation (Brazilian documents)
|
|
345
|
+
export function validateDocument(value: string): string | null {
|
|
346
|
+
if (!value) return null;
|
|
347
|
+
const cleaned = value.replace(/\D/g, '');
|
|
348
|
+
|
|
349
|
+
if (cleaned.length === 11) {
|
|
350
|
+
return validateCPF(cleaned) ? null : "Invalid CPF";
|
|
351
|
+
} else if (cleaned.length === 14) {
|
|
352
|
+
return validateCNPJ(cleaned) ? null : "Invalid CNPJ";
|
|
353
|
+
}
|
|
354
|
+
return "Invalid document format";
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function validateCPF(cpf: string): boolean {
|
|
358
|
+
if (/^(\d)\1{10}$/.test(cpf)) return false;
|
|
359
|
+
|
|
360
|
+
let sum = 0;
|
|
361
|
+
for (let i = 0; i < 9; i++) sum += parseInt(cpf[i]) * (10 - i);
|
|
362
|
+
let rev = 11 - (sum % 11);
|
|
363
|
+
if (rev === 10 || rev === 11) rev = 0;
|
|
364
|
+
if (rev !== parseInt(cpf[9])) return false;
|
|
365
|
+
|
|
366
|
+
sum = 0;
|
|
367
|
+
for (let i = 0; i < 10; i++) sum += parseInt(cpf[i]) * (11 - i);
|
|
368
|
+
rev = 11 - (sum % 11);
|
|
369
|
+
if (rev === 10 || rev === 11) rev = 0;
|
|
370
|
+
return rev === parseInt(cpf[10]);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function validateCNPJ(cnpj: string): boolean {
|
|
374
|
+
if (/^(\d)\1{13}$/.test(cnpj)) return false;
|
|
375
|
+
|
|
376
|
+
const weights1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
377
|
+
const weights2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
378
|
+
|
|
379
|
+
let sum = 0;
|
|
380
|
+
for (let i = 0; i < 12; i++) sum += parseInt(cnpj[i]) * weights1[i];
|
|
381
|
+
let rev = sum % 11 < 2 ? 0 : 11 - (sum % 11);
|
|
382
|
+
if (rev !== parseInt(cnpj[12])) return false;
|
|
383
|
+
|
|
384
|
+
sum = 0;
|
|
385
|
+
for (let i = 0; i < 13; i++) sum += parseInt(cnpj[i]) * weights2[i];
|
|
386
|
+
rev = sum % 11 < 2 ? 0 : 11 - (sum % 11);
|
|
387
|
+
return rev === parseInt(cnpj[13]);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Password strength validation
|
|
391
|
+
export function validatePassword(value: string): string | null {
|
|
392
|
+
if (!value) return null;
|
|
393
|
+
if (value.length < 8) return "Password must be at least 8 characters";
|
|
394
|
+
if (!/[A-Z]/.test(value)) return "Password must contain an uppercase letter";
|
|
395
|
+
if (!/[a-z]/.test(value)) return "Password must contain a lowercase letter";
|
|
396
|
+
if (!/[0-9]/.test(value)) return "Password must contain a number";
|
|
397
|
+
if (!/[!@#$%^&*]/.test(value)) return "Password must contain a special character";
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Date validation
|
|
402
|
+
export function validateDate(value: string): string | null {
|
|
403
|
+
if (!value) return null;
|
|
404
|
+
const date = new Date(value);
|
|
405
|
+
if (isNaN(date.getTime())) return "Invalid date";
|
|
406
|
+
if (date > new Date()) return "Date cannot be in the future";
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Brazilian ZIP code (CEP) validation
|
|
411
|
+
export function validateZipcode(value: string): string | null {
|
|
412
|
+
if (!value) return null;
|
|
413
|
+
const cepRegex = /^\d{5}-?\d{3}$/;
|
|
414
|
+
return cepRegex.test(value) ? null : "Invalid ZIP code format";
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// URL validation
|
|
418
|
+
export function validateUrl(value: string): string | null {
|
|
419
|
+
if (!value) return null;
|
|
420
|
+
try {
|
|
421
|
+
new URL(value);
|
|
422
|
+
return null;
|
|
423
|
+
} catch {
|
|
424
|
+
return "Invalid URL format";
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Min/max length validator factory
|
|
429
|
+
export function minLength(min: number) {
|
|
430
|
+
return (value: string): string | null => {
|
|
431
|
+
if (!value) return null;
|
|
432
|
+
return value.length >= min ? null : `Must be at least ${min} characters`;
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export function maxLength(max: number) {
|
|
437
|
+
return (value: string): string | null => {
|
|
438
|
+
if (!value) return null;
|
|
439
|
+
return value.length <= max ? null : `Must be at most ${max} characters`;
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Number range validator factory
|
|
444
|
+
export function numberRange(min: number, max: number) {
|
|
445
|
+
return (value: number): string | null => {
|
|
446
|
+
if (value === null || value === undefined) return null;
|
|
447
|
+
return value >= min && value <= max ? null : `Must be between ${min} and ${max}`;
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Required field validator
|
|
452
|
+
export function required(value: string | number | boolean | null): string | null {
|
|
453
|
+
if (value === null || value === undefined || value === '') {
|
|
454
|
+
return "This field is required";
|
|
455
|
+
}
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
### Manual Schema Access
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
import { User } from "$reflector/schemas.svelte";
|
|
464
|
+
|
|
465
|
+
// Create instance
|
|
466
|
+
const user = new User({ name: "John", email: "john@example.com" });
|
|
467
|
+
|
|
468
|
+
// Get data bundle
|
|
469
|
+
const data = user.bundle(); // { name: "John", email: "john@example.com" }
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Batch Query Updates
|
|
473
|
+
|
|
474
|
+
```typescript
|
|
475
|
+
import { setQueryGroup } from "$reflector/reflector.svelte";
|
|
476
|
+
|
|
477
|
+
// Update multiple query params at once
|
|
478
|
+
setQueryGroup([
|
|
479
|
+
{ key: "page", value: 1 },
|
|
480
|
+
{ key: "status", value: "active" },
|
|
481
|
+
{ key: "roles", value: ["admin", "editor"] }, // Array params supported
|
|
482
|
+
]);
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
## Troubleshooting
|
|
486
|
+
|
|
487
|
+
### "BACKEND_URL vazio" Error
|
|
488
|
+
|
|
489
|
+
Ensure you have set `BACKEND_URL` or `PUBLIC_BACKEND` in your `.env` file.
|
|
490
|
+
|
|
491
|
+
### Schemas Not Updating
|
|
492
|
+
|
|
493
|
+
In DEV mode, run `npx reflect` manually. Check that your backend's OpenAPI spec is accessible at `{BACKEND_URL}openapi.json`.
|
|
494
|
+
|
|
495
|
+
### Type Errors After Generation
|
|
496
|
+
|
|
497
|
+
1. Restart your TypeScript language server
|
|
498
|
+
2. Check path aliases in `tsconfig.json`
|
|
499
|
+
3. Ensure `$reflector/*` alias is configured
|
|
500
|
+
|
|
501
|
+
## License
|
|
502
|
+
|
|
503
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
504
|
+
|
|
505
|
+
## Contributing
|
|
506
|
+
|
|
507
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
508
|
+
|
|
509
|
+
## Links
|
|
510
|
+
|
|
511
|
+
- [npm](https://www.npmjs.com/package/svelte-reflector)
|
|
512
|
+
- [GitHub](https://github.com/aleleppy/reflector)
|
|
513
|
+
- [Svelte](https://svelte.dev/)
|
|
514
|
+
- [OpenAPI Specification](https://swagger.io/specification/)
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
Built with by the Pináculo Digital team.
|