@atscript/typescript 0.1.26 → 0.1.27
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 +50 -0
- package/dist/cli.cjs +4 -4
- package/dist/index.cjs +7 -9
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +5 -9
- package/dist/utils.cjs +1 -1
- package/dist/utils.mjs +1 -1
- package/package.json +5 -5
- package/scripts/setup-skills.js +23 -13
- package/skills/atscript-typescript/SKILL.md +22 -14
- package/skills/atscript-typescript/annotations.md +51 -50
- package/skills/atscript-typescript/codegen.md +14 -10
- package/skills/atscript-typescript/core.md +23 -21
- package/skills/atscript-typescript/runtime.md +66 -54
- package/skills/atscript-typescript/syntax.md +31 -31
- package/skills/atscript-typescript/utilities.md +94 -67
- package/skills/atscript-typescript/validation.md +39 -39
|
@@ -51,18 +51,18 @@ export default defineConfig({
|
|
|
51
51
|
|
|
52
52
|
### `TAtscriptConfig` Fields
|
|
53
53
|
|
|
54
|
-
| Field
|
|
55
|
-
|
|
56
|
-
| `rootDir`
|
|
57
|
-
| `entries`
|
|
58
|
-
| `include`
|
|
59
|
-
| `exclude`
|
|
60
|
-
| `plugins`
|
|
61
|
-
| `primitives`
|
|
62
|
-
| `annotations`
|
|
63
|
-
| `unknownAnnotation` | `'allow' \| 'warn' \| 'error'`
|
|
64
|
-
| `format`
|
|
65
|
-
| `outDir`
|
|
54
|
+
| Field | Type | Description |
|
|
55
|
+
| ------------------- | ---------------------------------- | ---------------------------------------- |
|
|
56
|
+
| `rootDir` | `string` | Root directory for resolving files |
|
|
57
|
+
| `entries` | `string[]` | Entry point globs for `.as` files |
|
|
58
|
+
| `include` | `string[]` | Include globs |
|
|
59
|
+
| `exclude` | `string[]` | Exclude globs |
|
|
60
|
+
| `plugins` | `TAtscriptPlugin[]` | Build plugins (e.g. `tsPlugin()`) |
|
|
61
|
+
| `primitives` | `Record<string, TPrimitiveConfig>` | Custom primitive type definitions |
|
|
62
|
+
| `annotations` | `TAnnotationsTree` | Custom annotation definitions |
|
|
63
|
+
| `unknownAnnotation` | `'allow' \| 'warn' \| 'error'` | Unknown annotation handling |
|
|
64
|
+
| `format` | `string` | Output format (set by CLI or build tool) |
|
|
65
|
+
| `outDir` | `string` | Output directory |
|
|
66
66
|
|
|
67
67
|
## TypeScript Plugin Options
|
|
68
68
|
|
|
@@ -84,7 +84,8 @@ Individual interfaces can override the JSON Schema setting with `@emit.jsonSchem
|
|
|
84
84
|
### `exampleData`
|
|
85
85
|
|
|
86
86
|
Controls whether `toExampleData()` is generated on output classes:
|
|
87
|
-
|
|
87
|
+
|
|
88
|
+
- `false` _(default)_ — method is not rendered in `.js`; `.d.ts` marks it as optional + `@deprecated`
|
|
88
89
|
- `true` — each class gets `static toExampleData()` that calls `createDataFromAnnotatedType(this, { mode: 'example' })`, creating a new example data object on each call (no caching)
|
|
89
90
|
|
|
90
91
|
## Build Tool Integration
|
|
@@ -96,7 +97,7 @@ Controls whether `toExampleData()` is generated on output classes:
|
|
|
96
97
|
import atscript from 'unplugin-atscript/vite'
|
|
97
98
|
|
|
98
99
|
export default {
|
|
99
|
-
plugins: [atscript()]
|
|
100
|
+
plugins: [atscript()],
|
|
100
101
|
}
|
|
101
102
|
```
|
|
102
103
|
|
|
@@ -106,7 +107,7 @@ export default {
|
|
|
106
107
|
// webpack.config.js
|
|
107
108
|
const atscript = require('unplugin-atscript/webpack')
|
|
108
109
|
module.exports = {
|
|
109
|
-
plugins: [atscript()]
|
|
110
|
+
plugins: [atscript()],
|
|
110
111
|
}
|
|
111
112
|
```
|
|
112
113
|
|
|
@@ -136,6 +137,7 @@ npx asc --skipDiag
|
|
|
136
137
|
### Why run `npx asc -f dts`?
|
|
137
138
|
|
|
138
139
|
This generates two things:
|
|
140
|
+
|
|
139
141
|
1. **`*.as.d.ts`** files next to each `.as` file — TypeScript type declarations for all interfaces/types
|
|
140
142
|
2. **`atscript.d.ts`** in the project root — global type declarations for `AtscriptMetadata` and `AtscriptPrimitiveTags`
|
|
141
143
|
|
|
@@ -143,12 +145,12 @@ The `atscript.d.ts` file is **crucial for type safety** — it tells TypeScript
|
|
|
143
145
|
|
|
144
146
|
### CLI Options
|
|
145
147
|
|
|
146
|
-
| Option
|
|
147
|
-
|
|
148
|
-
| `--config <path>` | `-c`
|
|
149
|
-
| `--format <fmt>`
|
|
150
|
-
| `--noEmit`
|
|
151
|
-
| `--skipDiag`
|
|
148
|
+
| Option | Short | Description |
|
|
149
|
+
| ----------------- | ----- | ----------------------------- |
|
|
150
|
+
| `--config <path>` | `-c` | Path to config file |
|
|
151
|
+
| `--format <fmt>` | `-f` | Output format: `dts`, `js` |
|
|
152
|
+
| `--noEmit` | | Only check for errors |
|
|
153
|
+
| `--skipDiag` | | Skip diagnostics, always emit |
|
|
152
154
|
|
|
153
155
|
## Project Structure Example
|
|
154
156
|
|
|
@@ -8,12 +8,12 @@ Every generated interface/type is a `TAtscriptAnnotatedType` — the core runtim
|
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
10
|
interface TAtscriptAnnotatedType<T extends TAtscriptTypeDef = TAtscriptTypeDef> {
|
|
11
|
-
__is_atscript_annotated_type: true
|
|
12
|
-
type: T
|
|
13
|
-
metadata: TMetadataMap<AtscriptMetadata>
|
|
14
|
-
optional?: boolean
|
|
15
|
-
id?: string
|
|
16
|
-
validator(opts?): Validator
|
|
11
|
+
__is_atscript_annotated_type: true // brand for type checking
|
|
12
|
+
type: T // the type definition (shape)
|
|
13
|
+
metadata: TMetadataMap<AtscriptMetadata> // annotation metadata
|
|
14
|
+
optional?: boolean // whether this type is optional
|
|
15
|
+
id?: string // stable type name (set by codegen or .id() builder)
|
|
16
|
+
validator(opts?): Validator // create a validator instance
|
|
17
17
|
}
|
|
18
18
|
```
|
|
19
19
|
|
|
@@ -38,7 +38,7 @@ The `type` field describes the shape. There are 5 kinds:
|
|
|
38
38
|
interface TAtscriptTypeFinal {
|
|
39
39
|
kind: ''
|
|
40
40
|
designType: 'string' | 'number' | 'boolean' | 'undefined' | 'null' | 'any' | 'never' | 'phantom'
|
|
41
|
-
value?: string | number | boolean
|
|
41
|
+
value?: string | number | boolean // for literal types
|
|
42
42
|
tags: Set<AtscriptPrimitiveTags>
|
|
43
43
|
}
|
|
44
44
|
```
|
|
@@ -48,8 +48,8 @@ interface TAtscriptTypeFinal {
|
|
|
48
48
|
```ts
|
|
49
49
|
interface TAtscriptTypeObject<K extends string = string> {
|
|
50
50
|
kind: 'object'
|
|
51
|
-
props: Map<K, TAtscriptAnnotatedType>
|
|
52
|
-
propsPatterns: Array<{ pattern: RegExp; def: TAtscriptAnnotatedType }>
|
|
51
|
+
props: Map<K, TAtscriptAnnotatedType> // named properties
|
|
52
|
+
propsPatterns: Array<{ pattern: RegExp; def: TAtscriptAnnotatedType }> // pattern properties
|
|
53
53
|
tags: Set<AtscriptPrimitiveTags>
|
|
54
54
|
}
|
|
55
55
|
```
|
|
@@ -59,7 +59,7 @@ interface TAtscriptTypeObject<K extends string = string> {
|
|
|
59
59
|
```ts
|
|
60
60
|
interface TAtscriptTypeArray {
|
|
61
61
|
kind: 'array'
|
|
62
|
-
of: TAtscriptAnnotatedType
|
|
62
|
+
of: TAtscriptAnnotatedType // element type
|
|
63
63
|
tags: Set<AtscriptPrimitiveTags>
|
|
64
64
|
}
|
|
65
65
|
```
|
|
@@ -82,12 +82,12 @@ The `metadata` field is a typed `Map<keyof AtscriptMetadata, value>`:
|
|
|
82
82
|
import { User } from './models/user.as'
|
|
83
83
|
|
|
84
84
|
// Read annotations
|
|
85
|
-
const label = User.metadata.get('meta.label')
|
|
86
|
-
const required = User.metadata.get('meta.required')
|
|
87
|
-
const minLen = User.metadata.get('expect.minLength')
|
|
85
|
+
const label = User.metadata.get('meta.label') // string | undefined
|
|
86
|
+
const required = User.metadata.get('meta.required') // { message?: string } | true | undefined
|
|
87
|
+
const minLen = User.metadata.get('expect.minLength') // { length: number; message?: string } | undefined
|
|
88
88
|
|
|
89
89
|
// Check if annotation exists
|
|
90
|
-
User.metadata.has('meta.sensitive')
|
|
90
|
+
User.metadata.has('meta.sensitive') // boolean
|
|
91
91
|
|
|
92
92
|
// Iterate all annotations
|
|
93
93
|
for (const [key, value] of User.metadata.entries()) {
|
|
@@ -104,11 +104,11 @@ Navigate into object properties via `type.props`:
|
|
|
104
104
|
const nameProp = User.type.props.get('name')!
|
|
105
105
|
|
|
106
106
|
// Read that property's metadata
|
|
107
|
-
nameProp.metadata.get('meta.label')
|
|
108
|
-
nameProp.metadata.get('meta.required')
|
|
107
|
+
nameProp.metadata.get('meta.label') // "Full Name"
|
|
108
|
+
nameProp.metadata.get('meta.required') // true or { message: "..." }
|
|
109
109
|
|
|
110
110
|
// Check if optional
|
|
111
|
-
nameProp.optional
|
|
111
|
+
nameProp.optional // boolean | undefined
|
|
112
112
|
```
|
|
113
113
|
|
|
114
114
|
### Nested Properties
|
|
@@ -148,15 +148,15 @@ The `annotate()` function handles array annotations correctly — if `asArray` i
|
|
|
148
148
|
```ts
|
|
149
149
|
function inspect(def: TAtscriptAnnotatedType) {
|
|
150
150
|
switch (def.type.kind) {
|
|
151
|
-
case '':
|
|
151
|
+
case '': // final/primitive
|
|
152
152
|
console.log('Primitive:', def.type.designType)
|
|
153
153
|
break
|
|
154
|
-
case 'object':
|
|
154
|
+
case 'object': // object with props
|
|
155
155
|
for (const [name, prop] of def.type.props) {
|
|
156
156
|
console.log(` ${name}:`, prop.type.kind || prop.type.designType)
|
|
157
157
|
}
|
|
158
158
|
break
|
|
159
|
-
case 'array':
|
|
159
|
+
case 'array': // array
|
|
160
160
|
console.log('Array of:', def.type.of.type.kind)
|
|
161
161
|
break
|
|
162
162
|
case 'union':
|
|
@@ -176,14 +176,28 @@ A type-safe dispatch helper that covers all `kind` values:
|
|
|
176
176
|
import { forAnnotatedType } from '@atscript/typescript/utils'
|
|
177
177
|
|
|
178
178
|
const result = forAnnotatedType(someType, {
|
|
179
|
-
final(d)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
179
|
+
final(d) {
|
|
180
|
+
return `primitive: ${d.type.designType}`
|
|
181
|
+
},
|
|
182
|
+
object(d) {
|
|
183
|
+
return `object with ${d.type.props.size} props`
|
|
184
|
+
},
|
|
185
|
+
array(d) {
|
|
186
|
+
return `array`
|
|
187
|
+
},
|
|
188
|
+
union(d) {
|
|
189
|
+
return `union of ${d.type.items.length}`
|
|
190
|
+
},
|
|
191
|
+
intersection(d) {
|
|
192
|
+
return `intersection of ${d.type.items.length}`
|
|
193
|
+
},
|
|
194
|
+
tuple(d) {
|
|
195
|
+
return `tuple of ${d.type.items.length}`
|
|
196
|
+
},
|
|
185
197
|
// Optional: handle phantom types separately from final
|
|
186
|
-
phantom(d)
|
|
198
|
+
phantom(d) {
|
|
199
|
+
return `phantom`
|
|
200
|
+
},
|
|
187
201
|
})
|
|
188
202
|
```
|
|
189
203
|
|
|
@@ -195,7 +209,7 @@ Each type definition has a `tags` Set containing primitive tags (e.g. `"string"`
|
|
|
195
209
|
|
|
196
210
|
```ts
|
|
197
211
|
const nameProp = User.type.props.get('name')!
|
|
198
|
-
nameProp.type.tags.has('string')
|
|
212
|
+
nameProp.type.tags.has('string') // true
|
|
199
213
|
```
|
|
200
214
|
|
|
201
215
|
Tags come from primitive definitions and their extensions. They're useful for categorizing types at runtime.
|
|
@@ -221,7 +235,7 @@ for (const [name, prop] of User.type.props) {
|
|
|
221
235
|
import { isAnnotatedTypeOfPrimitive } from '@atscript/typescript/utils'
|
|
222
236
|
|
|
223
237
|
// Returns true for final types and unions/intersections/tuples of all primitives
|
|
224
|
-
isAnnotatedTypeOfPrimitive(someType)
|
|
238
|
+
isAnnotatedTypeOfPrimitive(someType) // true if no objects or arrays
|
|
225
239
|
```
|
|
226
240
|
|
|
227
241
|
## Building Types at Runtime
|
|
@@ -238,41 +252,39 @@ const strType = defineAnnotatedType().designType('string').tags('string').$type
|
|
|
238
252
|
const userType = defineAnnotatedType('object')
|
|
239
253
|
.prop('name', defineAnnotatedType().designType('string').$type)
|
|
240
254
|
.prop('age', defineAnnotatedType().designType('number').$type)
|
|
241
|
-
.prop('email', defineAnnotatedType().optional().designType('string').$type)
|
|
242
|
-
.$type
|
|
255
|
+
.prop('email', defineAnnotatedType().optional().designType('string').$type).$type
|
|
243
256
|
|
|
244
257
|
// Array
|
|
245
|
-
const listType = defineAnnotatedType('array')
|
|
246
|
-
|
|
247
|
-
|
|
258
|
+
const listType = defineAnnotatedType('array').of(
|
|
259
|
+
defineAnnotatedType().designType('string').$type
|
|
260
|
+
).$type
|
|
248
261
|
|
|
249
262
|
// Union
|
|
250
263
|
const statusType = defineAnnotatedType('union')
|
|
251
264
|
.item(defineAnnotatedType().designType('string').value('active').$type)
|
|
252
|
-
.item(defineAnnotatedType().designType('string').value('inactive').$type)
|
|
253
|
-
.$type
|
|
265
|
+
.item(defineAnnotatedType().designType('string').value('inactive').$type).$type
|
|
254
266
|
|
|
255
267
|
// With metadata
|
|
256
|
-
const labeledType = defineAnnotatedType()
|
|
268
|
+
const labeledType = defineAnnotatedType()
|
|
269
|
+
.designType('string')
|
|
257
270
|
.annotate('meta.label', 'My Label')
|
|
258
|
-
.annotate('expect.minLength', { length: 3 })
|
|
259
|
-
.$type
|
|
271
|
+
.annotate('expect.minLength', { length: 3 }).$type
|
|
260
272
|
```
|
|
261
273
|
|
|
262
274
|
### `TAnnotatedTypeHandle` Fluent API
|
|
263
275
|
|
|
264
|
-
| Method
|
|
265
|
-
|
|
266
|
-
| `.designType(dt)`
|
|
267
|
-
| `.value(v)`
|
|
268
|
-
| `.tags(...tags)`
|
|
269
|
-
| `.prop(name, type)`
|
|
270
|
-
| `.propPattern(regex, type)`
|
|
271
|
-
| `.of(type)`
|
|
272
|
-
| `.item(type)`
|
|
273
|
-
| `.optional(flag?)`
|
|
274
|
-
| `.annotate(key, value, asArray?)` | Set metadata annotation
|
|
275
|
-
| `.copyMetadata(from, ignore?)`
|
|
276
|
-
| `.id(name)`
|
|
277
|
-
| `.refTo(type, chain?)`
|
|
278
|
-
| `.$type`
|
|
276
|
+
| Method | Description |
|
|
277
|
+
| --------------------------------- | --------------------------------------------------------------------- |
|
|
278
|
+
| `.designType(dt)` | Set primitive design type |
|
|
279
|
+
| `.value(v)` | Set literal value |
|
|
280
|
+
| `.tags(...tags)` | Add primitive tags |
|
|
281
|
+
| `.prop(name, type)` | Add named property (object kind) |
|
|
282
|
+
| `.propPattern(regex, type)` | Add pattern property (object kind) |
|
|
283
|
+
| `.of(type)` | Set element type (array kind) |
|
|
284
|
+
| `.item(type)` | Add item (union/intersection/tuple kind) |
|
|
285
|
+
| `.optional(flag?)` | Mark as optional |
|
|
286
|
+
| `.annotate(key, value, asArray?)` | Set metadata annotation |
|
|
287
|
+
| `.copyMetadata(from, ignore?)` | Copy metadata from another type |
|
|
288
|
+
| `.id(name)` | Set a stable type name (used by `buildJsonSchema` for `$defs`/`$ref`) |
|
|
289
|
+
| `.refTo(type, chain?)` | Reference another annotated type's definition (carries `id`) |
|
|
290
|
+
| `.$type` | Get the final `TAtscriptAnnotatedType` |
|
|
@@ -120,15 +120,15 @@ annotate User {
|
|
|
120
120
|
|
|
121
121
|
### Built-in Primitives
|
|
122
122
|
|
|
123
|
-
| Primitive
|
|
124
|
-
|
|
125
|
-
| `string`
|
|
126
|
-
| `number`
|
|
127
|
-
| `boolean`
|
|
128
|
-
| `null`
|
|
129
|
-
| `void` / `undefined` | No value
|
|
130
|
-
| `never`
|
|
131
|
-
| `phantom`
|
|
123
|
+
| Primitive | Description |
|
|
124
|
+
| -------------------- | --------------------------------------------- |
|
|
125
|
+
| `string` | Text data |
|
|
126
|
+
| `number` | Numeric data |
|
|
127
|
+
| `boolean` | True/false |
|
|
128
|
+
| `null` | Null value |
|
|
129
|
+
| `void` / `undefined` | No value |
|
|
130
|
+
| `never` | Impossible type |
|
|
131
|
+
| `phantom` | Metadata-only type (no runtime/schema impact) |
|
|
132
132
|
|
|
133
133
|
### Primitive Extensions (Subtypes)
|
|
134
134
|
|
|
@@ -153,35 +153,35 @@ interface User {
|
|
|
153
153
|
|
|
154
154
|
#### String Extensions
|
|
155
155
|
|
|
156
|
-
| Extension
|
|
157
|
-
|
|
158
|
-
| `string.email`
|
|
159
|
-
| `string.phone`
|
|
160
|
-
| `string.date`
|
|
161
|
-
| `string.isoDate`
|
|
162
|
-
| `string.uuid`
|
|
163
|
-
| `string.required` | Non-empty (trimmed length >= 1)
|
|
156
|
+
| Extension | Validation |
|
|
157
|
+
| ----------------- | ------------------------------------------- |
|
|
158
|
+
| `string.email` | Email format (`^[^\s@]+@[^\s@]+\.[^\s@]+$`) |
|
|
159
|
+
| `string.phone` | Phone format (`^\+?[0-9\s-]{10,15}$`) |
|
|
160
|
+
| `string.date` | Date string (YYYY-MM-DD, MM/DD/YYYY, etc.) |
|
|
161
|
+
| `string.isoDate` | ISO 8601 date/time |
|
|
162
|
+
| `string.uuid` | UUID v4 format |
|
|
163
|
+
| `string.required` | Non-empty (trimmed length >= 1) |
|
|
164
164
|
|
|
165
165
|
#### Number Extensions
|
|
166
166
|
|
|
167
|
-
| Extension
|
|
168
|
-
|
|
169
|
-
| `number.int`
|
|
170
|
-
| `number.positive`
|
|
171
|
-
| `number.negative`
|
|
172
|
-
| `number.single`
|
|
173
|
-
| `number.double`
|
|
174
|
-
| `number.timestamp`
|
|
175
|
-
| `number.int.positive` | Integer >= 0
|
|
176
|
-
| `number.int.negative` | Integer <= 0
|
|
167
|
+
| Extension | Validation |
|
|
168
|
+
| --------------------- | ---------------------- |
|
|
169
|
+
| `number.int` | Integer (no decimals) |
|
|
170
|
+
| `number.positive` | >= 0 |
|
|
171
|
+
| `number.negative` | <= 0 |
|
|
172
|
+
| `number.single` | Single-precision float |
|
|
173
|
+
| `number.double` | Double-precision float |
|
|
174
|
+
| `number.timestamp` | Integer timestamp |
|
|
175
|
+
| `number.int.positive` | Integer >= 0 |
|
|
176
|
+
| `number.int.negative` | Integer <= 0 |
|
|
177
177
|
|
|
178
178
|
#### Boolean Extensions
|
|
179
179
|
|
|
180
|
-
| Extension
|
|
181
|
-
|
|
180
|
+
| Extension | Validation |
|
|
181
|
+
| ------------------ | -------------- |
|
|
182
182
|
| `boolean.required` | Must be `true` |
|
|
183
|
-
| `boolean.true`
|
|
184
|
-
| `boolean.false`
|
|
183
|
+
| `boolean.true` | Literal true |
|
|
184
|
+
| `boolean.false` | Literal false |
|
|
185
185
|
|
|
186
186
|
## Imports and Exports
|
|
187
187
|
|
|
@@ -9,17 +9,25 @@ All utilities are exported from `@atscript/typescript/utils`:
|
|
|
9
9
|
```ts
|
|
10
10
|
import {
|
|
11
11
|
// Type construction
|
|
12
|
-
defineAnnotatedType,
|
|
12
|
+
defineAnnotatedType,
|
|
13
|
+
annotate,
|
|
13
14
|
// Type checking
|
|
14
|
-
isAnnotatedType,
|
|
15
|
+
isAnnotatedType,
|
|
16
|
+
isAnnotatedTypeOfPrimitive,
|
|
17
|
+
isPhantomType,
|
|
15
18
|
// Type traversal
|
|
16
19
|
forAnnotatedType,
|
|
17
20
|
// Validation
|
|
18
|
-
Validator,
|
|
21
|
+
Validator,
|
|
22
|
+
ValidatorError,
|
|
19
23
|
// JSON Schema
|
|
20
|
-
buildJsonSchema,
|
|
24
|
+
buildJsonSchema,
|
|
25
|
+
fromJsonSchema,
|
|
26
|
+
mergeJsonSchemas,
|
|
21
27
|
// Serialization
|
|
22
|
-
serializeAnnotatedType,
|
|
28
|
+
serializeAnnotatedType,
|
|
29
|
+
deserializeAnnotatedType,
|
|
30
|
+
SERIALIZE_VERSION,
|
|
23
31
|
// Flattening
|
|
24
32
|
flattenAnnotatedType,
|
|
25
33
|
// Data creation
|
|
@@ -41,13 +49,27 @@ Dispatches over `TAtscriptAnnotatedType` by its `type.kind`, providing type-narr
|
|
|
41
49
|
import { forAnnotatedType } from '@atscript/typescript/utils'
|
|
42
50
|
|
|
43
51
|
const description = forAnnotatedType(someType, {
|
|
44
|
-
final(d)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
52
|
+
final(d) {
|
|
53
|
+
return `${d.type.designType}`
|
|
54
|
+
},
|
|
55
|
+
object(d) {
|
|
56
|
+
return `object(${d.type.props.size} props)`
|
|
57
|
+
},
|
|
58
|
+
array(d) {
|
|
59
|
+
return `array`
|
|
60
|
+
},
|
|
61
|
+
union(d) {
|
|
62
|
+
return `union(${d.type.items.length})`
|
|
63
|
+
},
|
|
64
|
+
intersection(d) {
|
|
65
|
+
return `intersection(${d.type.items.length})`
|
|
66
|
+
},
|
|
67
|
+
tuple(d) {
|
|
68
|
+
return `[${d.type.items.length}]`
|
|
69
|
+
},
|
|
70
|
+
phantom(d) {
|
|
71
|
+
return `phantom`
|
|
72
|
+
}, // optional — without it, phantoms go to final
|
|
51
73
|
})
|
|
52
74
|
```
|
|
53
75
|
|
|
@@ -88,6 +110,7 @@ const schema = buildJsonSchema(CatOrDog)
|
|
|
88
110
|
```
|
|
89
111
|
|
|
90
112
|
Key behaviors:
|
|
113
|
+
|
|
91
114
|
- Only **named object types** (with `id`) are extracted to `$defs`. Primitives, unions, arrays stay inline.
|
|
92
115
|
- The **root type** is never extracted — it IS the schema.
|
|
93
116
|
- Same `id` referenced multiple times → one `$defs` entry, all occurrences become `$ref`.
|
|
@@ -96,23 +119,23 @@ Key behaviors:
|
|
|
96
119
|
|
|
97
120
|
### Metadata → JSON Schema Mapping
|
|
98
121
|
|
|
99
|
-
| Annotation
|
|
100
|
-
|
|
101
|
-
| `@expect.minLength` on string | `minLength`
|
|
102
|
-
| `@expect.maxLength` on string | `maxLength`
|
|
103
|
-
| `@expect.minLength` on array
|
|
104
|
-
| `@expect.maxLength` on array
|
|
105
|
-
| `@expect.min`
|
|
106
|
-
| `@expect.max`
|
|
107
|
-
| `@expect.int`
|
|
108
|
-
| `@expect.pattern` (single)
|
|
109
|
-
| `@expect.pattern` (multiple)
|
|
110
|
-
| `@meta.required` on string
|
|
111
|
-
| optional property
|
|
112
|
-
| union
|
|
113
|
-
| intersection
|
|
114
|
-
| tuple
|
|
115
|
-
| phantom
|
|
122
|
+
| Annotation | JSON Schema |
|
|
123
|
+
| ----------------------------- | --------------------------------------------------------------- |
|
|
124
|
+
| `@expect.minLength` on string | `minLength` |
|
|
125
|
+
| `@expect.maxLength` on string | `maxLength` |
|
|
126
|
+
| `@expect.minLength` on array | `minItems` |
|
|
127
|
+
| `@expect.maxLength` on array | `maxItems` |
|
|
128
|
+
| `@expect.min` | `minimum` |
|
|
129
|
+
| `@expect.max` | `maximum` |
|
|
130
|
+
| `@expect.int` | `type: 'integer'` (instead of `'number'`) |
|
|
131
|
+
| `@expect.pattern` (single) | `pattern` |
|
|
132
|
+
| `@expect.pattern` (multiple) | `allOf: [{ pattern }, ...]` |
|
|
133
|
+
| `@meta.required` on string | `minLength: 1` |
|
|
134
|
+
| optional property | not in `required` array |
|
|
135
|
+
| union | `anyOf` (or `oneOf` + `discriminator` for discriminated unions) |
|
|
136
|
+
| intersection | `allOf` |
|
|
137
|
+
| tuple | `items` as array |
|
|
138
|
+
| phantom | empty object `{}` (excluded) |
|
|
116
139
|
|
|
117
140
|
### Discriminated Unions
|
|
118
141
|
|
|
@@ -131,11 +154,11 @@ const type = fromJsonSchema({
|
|
|
131
154
|
name: { type: 'string', minLength: 1 },
|
|
132
155
|
age: { type: 'integer', minimum: 0 },
|
|
133
156
|
},
|
|
134
|
-
required: ['name', 'age']
|
|
157
|
+
required: ['name', 'age'],
|
|
135
158
|
})
|
|
136
159
|
|
|
137
160
|
// The resulting type has a working validator
|
|
138
|
-
type.validator().validate({ name: 'Alice', age: 30 })
|
|
161
|
+
type.validator().validate({ name: 'Alice', age: 30 }) // passes
|
|
139
162
|
```
|
|
140
163
|
|
|
141
164
|
Supports: `type`, `properties`, `required`, `items`, `anyOf`, `oneOf`, `allOf`, `enum`, `const`, `minLength`, `maxLength`, `minimum`, `maximum`, `pattern`, `minItems`, `maxItems`, `$ref`/`$defs`.
|
|
@@ -288,19 +311,19 @@ const custom = createDataFromAnnotatedType(User, {
|
|
|
288
311
|
mode: (prop, path) => {
|
|
289
312
|
if (path === 'name') return 'John Doe'
|
|
290
313
|
if (path === 'age') return 25
|
|
291
|
-
return undefined
|
|
292
|
-
}
|
|
314
|
+
return undefined // fall through to structural default
|
|
315
|
+
},
|
|
293
316
|
})
|
|
294
317
|
```
|
|
295
318
|
|
|
296
319
|
### Modes
|
|
297
320
|
|
|
298
|
-
| Mode
|
|
299
|
-
|
|
300
|
-
| `'empty'` (default) | Structural defaults: `''`, `0`, `false`, `[]`, `{}`. Optional props omitted
|
|
301
|
-
| `'default'`
|
|
302
|
-
| `'example'`
|
|
303
|
-
| `function`
|
|
321
|
+
| Mode | Behavior |
|
|
322
|
+
| ------------------- | -------------------------------------------------------------------------------------------- |
|
|
323
|
+
| `'empty'` (default) | Structural defaults: `''`, `0`, `false`, `[]`, `{}`. Optional props omitted |
|
|
324
|
+
| `'default'` | Uses `@meta.default` annotations. Optional props only included if annotated |
|
|
325
|
+
| `'example'` | Uses `@meta.example` annotations. Optional props always included. Arrays get one sample item |
|
|
326
|
+
| `function` | Custom resolver per field. Return `undefined` to fall through |
|
|
304
327
|
|
|
305
328
|
### Behavior Notes
|
|
306
329
|
|
|
@@ -317,8 +340,8 @@ const custom = createDataFromAnnotatedType(User, {
|
|
|
317
340
|
import { isAnnotatedType } from '@atscript/typescript/utils'
|
|
318
341
|
|
|
319
342
|
if (isAnnotatedType(value)) {
|
|
320
|
-
value.metadata
|
|
321
|
-
value.type
|
|
343
|
+
value.metadata // safe
|
|
344
|
+
value.type // safe
|
|
322
345
|
}
|
|
323
346
|
```
|
|
324
347
|
|
|
@@ -329,10 +352,10 @@ Returns `true` for final types and for unions/intersections/tuples whose all mem
|
|
|
329
352
|
```ts
|
|
330
353
|
import { isAnnotatedTypeOfPrimitive } from '@atscript/typescript/utils'
|
|
331
354
|
|
|
332
|
-
isAnnotatedTypeOfPrimitive(stringType)
|
|
333
|
-
isAnnotatedTypeOfPrimitive(objectType)
|
|
334
|
-
isAnnotatedTypeOfPrimitive(unionOfStringAndNumber)
|
|
335
|
-
isAnnotatedTypeOfPrimitive(unionOfStringAndObject)
|
|
355
|
+
isAnnotatedTypeOfPrimitive(stringType) // true
|
|
356
|
+
isAnnotatedTypeOfPrimitive(objectType) // false
|
|
357
|
+
isAnnotatedTypeOfPrimitive(unionOfStringAndNumber) // true
|
|
358
|
+
isAnnotatedTypeOfPrimitive(unionOfStringAndObject) // false
|
|
336
359
|
```
|
|
337
360
|
|
|
338
361
|
## `isPhantomType(def)` — Check if Phantom
|
|
@@ -340,7 +363,7 @@ isAnnotatedTypeOfPrimitive(unionOfStringAndObject) // false
|
|
|
340
363
|
```ts
|
|
341
364
|
import { isPhantomType } from '@atscript/typescript/utils'
|
|
342
365
|
|
|
343
|
-
isPhantomType(someProperty)
|
|
366
|
+
isPhantomType(someProperty) // true if designType === 'phantom'
|
|
344
367
|
```
|
|
345
368
|
|
|
346
369
|
## `TAtscriptDataType<T>` — Extract DataType from Annotated Type
|
|
@@ -370,8 +393,12 @@ import type { TAtscriptAnnotatedType, TAtscriptDataType } from '@atscript/typesc
|
|
|
370
393
|
|
|
371
394
|
// Generic repository that infers its entity type
|
|
372
395
|
class Repository<T extends TAtscriptAnnotatedType> {
|
|
373
|
-
findOne(id: string): Promise<TAtscriptDataType<T>> {
|
|
374
|
-
|
|
396
|
+
findOne(id: string): Promise<TAtscriptDataType<T>> {
|
|
397
|
+
/* ... */
|
|
398
|
+
}
|
|
399
|
+
insertOne(data: TAtscriptDataType<T>): Promise<void> {
|
|
400
|
+
/* ... */
|
|
401
|
+
}
|
|
375
402
|
}
|
|
376
403
|
|
|
377
404
|
// Usage — DataType is automatically inferred
|
|
@@ -398,25 +425,25 @@ Key types you may need to import:
|
|
|
398
425
|
|
|
399
426
|
```ts
|
|
400
427
|
import type {
|
|
401
|
-
TAtscriptAnnotatedType,
|
|
428
|
+
TAtscriptAnnotatedType, // core annotated type
|
|
402
429
|
TAtscriptAnnotatedTypeConstructor, // annotated type that's also a class
|
|
403
|
-
TAtscriptTypeDef,
|
|
404
|
-
TAtscriptTypeFinal,
|
|
405
|
-
TAtscriptTypeObject,
|
|
406
|
-
TAtscriptTypeArray,
|
|
407
|
-
TAtscriptTypeComplex,
|
|
408
|
-
TMetadataMap,
|
|
409
|
-
TAnnotatedTypeHandle,
|
|
410
|
-
InferDataType,
|
|
411
|
-
TAtscriptDataType,
|
|
412
|
-
TValidatorOptions,
|
|
413
|
-
TValidatorPlugin,
|
|
414
|
-
TValidatorPluginContext,
|
|
415
|
-
TSerializedAnnotatedType,
|
|
416
|
-
TSerializeOptions,
|
|
417
|
-
TFlattenOptions,
|
|
418
|
-
TCreateDataOptions,
|
|
419
|
-
TValueResolver,
|
|
420
|
-
TJsonSchema,
|
|
430
|
+
TAtscriptTypeDef, // union of all type def shapes
|
|
431
|
+
TAtscriptTypeFinal, // primitive/literal type def
|
|
432
|
+
TAtscriptTypeObject, // object type def
|
|
433
|
+
TAtscriptTypeArray, // array type def
|
|
434
|
+
TAtscriptTypeComplex, // union/intersection/tuple type def
|
|
435
|
+
TMetadataMap, // typed metadata map
|
|
436
|
+
TAnnotatedTypeHandle, // fluent builder handle
|
|
437
|
+
InferDataType, // extract DataType from a type def's phantom generic
|
|
438
|
+
TAtscriptDataType, // extract DataType from TAtscriptAnnotatedType
|
|
439
|
+
TValidatorOptions, // validator config
|
|
440
|
+
TValidatorPlugin, // plugin function type
|
|
441
|
+
TValidatorPluginContext, // plugin context
|
|
442
|
+
TSerializedAnnotatedType, // serialized type (top-level)
|
|
443
|
+
TSerializeOptions, // serialization options
|
|
444
|
+
TFlattenOptions, // flatten options
|
|
445
|
+
TCreateDataOptions, // createData options
|
|
446
|
+
TValueResolver, // custom resolver for createData
|
|
447
|
+
TJsonSchema, // JSON Schema object
|
|
421
448
|
} from '@atscript/typescript/utils'
|
|
422
449
|
```
|