@atscript/typescript 0.1.2 → 0.1.3

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/dist/utils.d.ts CHANGED
@@ -3,7 +3,14 @@ interface TError {
3
3
  message: string;
4
4
  details?: TError[];
5
5
  }
6
+ /**
7
+ * A plugin function that can intercept validation.
8
+ *
9
+ * Return `true` to accept the value, `false` to reject it,
10
+ * or `undefined` to fall through to the default validation.
11
+ */
6
12
  type TValidatorPlugin = (ctx: TValidatorPluginContext, def: TAtscriptAnnotatedType, value: any) => boolean | undefined;
13
+ /** Options for configuring {@link Validator} behavior. */
7
14
  interface TValidatorOptions {
8
15
  partial: boolean | 'deep' | ((type: TAtscriptAnnotatedType<TAtscriptTypeObject>, path: string) => boolean);
9
16
  replace?: (type: TAtscriptAnnotatedType, path: string) => TAtscriptAnnotatedType;
@@ -12,16 +19,43 @@ interface TValidatorOptions {
12
19
  errorLimit: number;
13
20
  skipList?: Set<string>;
14
21
  }
22
+ /** Context exposed to {@link TValidatorPlugin} functions. */
15
23
  interface TValidatorPluginContext {
16
24
  opts: Validator<any>['opts'];
17
25
  validateAnnotatedType: Validator<any>['validateAnnotatedType'];
18
26
  error: Validator<any>['error'];
19
27
  path: Validator<any>['path'];
20
28
  }
21
- declare class Validator<T extends TAtscriptAnnotatedTypeConstructor, IT = InstanceType<T>> {
29
+ /**
30
+ * Validates values against an {@link TAtscriptAnnotatedType} definition.
31
+ *
32
+ * `DataType` is automatically inferred from the type definition's phantom generic,
33
+ * enabling the {@link validate} method to act as a type guard.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * // From a generated interface class:
38
+ * const validator = new Validator(MyInterface)
39
+ * if (validator.validate(data, true)) {
40
+ * data // narrowed to MyInterface
41
+ * }
42
+ *
43
+ * // Or use the built-in factory:
44
+ * MyInterface.validator().validate(data)
45
+ * ```
46
+ *
47
+ * @typeParam T - The annotated type definition.
48
+ * @typeParam DataType - The TypeScript type that `validate` narrows to (auto-inferred).
49
+ */
50
+ declare class Validator<T extends TAtscriptAnnotatedType = TAtscriptAnnotatedType, DataType = T extends {
51
+ type: {
52
+ __dataType?: infer D;
53
+ };
54
+ } ? unknown extends D ? T extends new (...args: any[]) => infer I ? I : unknown : D : unknown> {
22
55
  protected readonly def: T;
23
56
  protected opts: TValidatorOptions;
24
57
  constructor(def: T, opts?: Partial<TValidatorOptions>);
58
+ /** Validation errors collected during the last {@link validate} call. */
25
59
  errors: TError[];
26
60
  protected stackErrors: TError[][];
27
61
  protected stackPath: string[];
@@ -31,7 +65,18 @@ declare class Validator<T extends TAtscriptAnnotatedTypeConstructor, IT = Instan
31
65
  protected clear(): void;
32
66
  protected error(message: string, path?: string, details?: TError[]): void;
33
67
  protected throw(): void;
34
- validate<TT = IT>(value: any, safe?: boolean): value is TT;
68
+ /**
69
+ * Validates a value against the type definition.
70
+ *
71
+ * Acts as a TypeScript type guard — when it returns `true`, the value
72
+ * is narrowed to `DataType`.
73
+ *
74
+ * @param value - The value to validate.
75
+ * @param safe - If `true`, returns `false` on failure instead of throwing.
76
+ * @returns `true` if the value matches the type definition.
77
+ * @throws {ValidatorError} When validation fails and `safe` is not `true`.
78
+ */
79
+ validate<TT = DataType>(value: any, safe?: boolean): value is TT;
35
80
  protected validateSafe(def: TAtscriptAnnotatedType, value: any): boolean;
36
81
  protected get path(): string;
37
82
  protected validateAnnotatedType(def: TAtscriptAnnotatedType, value: any): boolean;
@@ -44,23 +89,31 @@ declare class Validator<T extends TAtscriptAnnotatedTypeConstructor, IT = Instan
44
89
  protected validateString(def: TAtscriptAnnotatedType<TAtscriptTypeFinal>, value: string): boolean;
45
90
  protected validateNumber(def: TAtscriptAnnotatedType<TAtscriptTypeFinal>, value: number): boolean;
46
91
  }
92
+ /** Error thrown by {@link Validator.validate} when validation fails. Contains structured error details. */
47
93
  declare class ValidatorError extends Error {
48
94
  readonly errors: TError[];
49
95
  name: string;
50
96
  constructor(errors: TError[]);
51
97
  }
52
98
 
53
- interface TAtscriptTypeComplex {
99
+ /** Type definition for union, intersection, or tuple types. */
100
+ interface TAtscriptTypeComplex<DataType = unknown> {
54
101
  kind: 'union' | 'intersection' | 'tuple';
55
102
  items: TAtscriptAnnotatedType[];
56
103
  tags: Set<AtscriptPrimitiveTags>;
104
+ /** @internal phantom — carries the DataType at the type level, never set at runtime */
105
+ __dataType?: DataType;
57
106
  }
58
- interface TAtscriptTypeArray {
107
+ /** Type definition for array types. */
108
+ interface TAtscriptTypeArray<DataType = unknown[]> {
59
109
  kind: 'array';
60
110
  of: TAtscriptAnnotatedType;
61
111
  tags: Set<AtscriptPrimitiveTags>;
112
+ /** @internal phantom — carries the DataType at the type level, never set at runtime */
113
+ __dataType?: DataType;
62
114
  }
63
- interface TAtscriptTypeObject<K extends string = string> {
115
+ /** Type definition for object types with named and pattern-matched properties. */
116
+ interface TAtscriptTypeObject<K extends string = string, DataType = Record<K, unknown>> {
64
117
  kind: 'object';
65
118
  props: Map<K, TAtscriptAnnotatedType>;
66
119
  propsPatterns: {
@@ -68,8 +121,11 @@ interface TAtscriptTypeObject<K extends string = string> {
68
121
  def: TAtscriptAnnotatedType;
69
122
  }[];
70
123
  tags: Set<AtscriptPrimitiveTags>;
124
+ /** @internal phantom — carries the DataType at the type level, never set at runtime */
125
+ __dataType?: DataType;
71
126
  }
72
- interface TAtscriptTypeFinal {
127
+ /** Type definition for primitive/literal types (string, number, boolean, null, etc.). */
128
+ interface TAtscriptTypeFinal<DataType = unknown> {
73
129
  kind: '';
74
130
  /**
75
131
  * design type
@@ -80,15 +136,34 @@ interface TAtscriptTypeFinal {
80
136
  */
81
137
  value?: string | number | boolean;
82
138
  tags: Set<AtscriptPrimitiveTags>;
139
+ /** @internal phantom — carries the DataType at the type level, never set at runtime */
140
+ __dataType?: DataType;
83
141
  }
84
- type TAtscriptTypeDef = TAtscriptTypeComplex | TAtscriptTypeFinal | TAtscriptTypeArray | TAtscriptTypeObject<string>;
85
- interface TAtscriptAnnotatedType<T = TAtscriptTypeDef> {
142
+ /**
143
+ * Extract DataType from a type def's phantom generic
144
+ */
145
+ type InferDataType<T> = T extends {
146
+ __dataType?: infer D;
147
+ } ? D : unknown;
148
+ /** Union of all possible type definition shapes. */
149
+ type TAtscriptTypeDef<DataType = unknown> = TAtscriptTypeComplex<DataType> | TAtscriptTypeFinal<DataType> | TAtscriptTypeArray<DataType> | TAtscriptTypeObject<string, DataType>;
150
+ /**
151
+ * Core annotated type — wraps a type definition with metadata and a validator factory.
152
+ *
153
+ * Generated `.as` files produce classes/namespaces that conform to this interface.
154
+ * The `DataType` phantom generic carries the TypeScript data shape for type-safe validation.
155
+ *
156
+ * @typeParam T - The underlying type definition (e.g. {@link TAtscriptTypeObject}).
157
+ * @typeParam DataType - The TypeScript type the validated data narrows to (auto-inferred from `T`).
158
+ */
159
+ interface TAtscriptAnnotatedType<T = TAtscriptTypeDef, DataType = InferDataType<T>> {
86
160
  __is_atscript_annotated_type: true;
87
161
  type: T;
88
- validator: <TT extends TAtscriptAnnotatedTypeConstructor>(opts?: Partial<TValidatorOptions>) => Validator<TT>;
162
+ validator: (opts?: Partial<TValidatorOptions>) => Validator;
89
163
  metadata: TMetadataMap<AtscriptMetadata>;
90
164
  optional?: boolean;
91
165
  }
166
+ /** An annotated type that is also a class constructor (i.e. a generated interface class). */
92
167
  type TAtscriptAnnotatedTypeConstructor = TAtscriptAnnotatedType & (new (...args: any[]) => any);
93
168
  /**
94
169
  * Type Guard to check if a type is atscript-annotated
@@ -100,6 +175,25 @@ declare function isAnnotatedType(type: any): type is TAtscriptAnnotatedType;
100
175
  */
101
176
  declare function annotate<K extends keyof AtscriptMetadata>(metadata: TMetadataMap<AtscriptMetadata> | undefined, key: K, value: AtscriptMetadata[K] extends (infer E)[] ? E : AtscriptMetadata[K], asArray?: boolean): void;
102
177
  type TKind = '' | 'array' | 'object' | 'union' | 'intersection' | 'tuple';
178
+ /**
179
+ * Creates a builder handle for constructing a {@link TAtscriptAnnotatedType} at runtime.
180
+ *
181
+ * This is primarily used by generated `.as.js` code. The returned handle provides
182
+ * a fluent API for setting the type definition, metadata, and properties.
183
+ *
184
+ * @example
185
+ * ```ts
186
+ * const handle = defineAnnotatedType('object')
187
+ * .prop('name', defineAnnotatedType().designType('string').$type)
188
+ * .prop('age', defineAnnotatedType().designType('number').$type)
189
+ *
190
+ * handle.$type // the resulting TAtscriptAnnotatedType
191
+ * ```
192
+ *
193
+ * @param _kind - The kind of type to create (e.g. `'object'`, `'array'`, `'union'`). Defaults to `''` (primitive/final).
194
+ * @param base - Optional existing object to augment with annotated type fields.
195
+ * @returns A builder handle for fluent type construction.
196
+ */
103
197
  declare function defineAnnotatedType(_kind?: TKind, base?: any): TAnnotatedTypeHandle;
104
198
  /**
105
199
  * Atscript Metadata Map with typed setters/getters
@@ -108,6 +202,7 @@ interface TMetadataMap<O extends object> extends Map<keyof O, O[keyof O]> {
108
202
  get<K extends keyof O>(key: K): O[K] | undefined;
109
203
  set<K extends keyof O>(key: K, value: O[K]): this;
110
204
  }
205
+ /** Fluent builder handle returned by {@link defineAnnotatedType}. */
111
206
  interface TAnnotatedTypeHandle {
112
207
  $type: TAtscriptAnnotatedType;
113
208
  $def: {
@@ -129,10 +224,177 @@ interface TAnnotatedTypeHandle {
129
224
  }, chain?: string[]): TAnnotatedTypeHandle;
130
225
  annotate(key: keyof AtscriptMetadata, value: any, asArray?: boolean): TAnnotatedTypeHandle;
131
226
  }
227
+ /**
228
+ * Checks whether an annotated type resolves to a primitive (non-object, non-array) shape.
229
+ *
230
+ * Returns `true` for final types and for unions/intersections/tuples
231
+ * whose members are all primitives.
232
+ */
132
233
  declare function isAnnotatedTypeOfPrimitive(t: TAtscriptAnnotatedType): boolean;
133
234
 
235
+ /** A JSON Schema object (draft-compatible). */
134
236
  type TJsonSchema = Record<string, any>;
237
+ /**
238
+ * Builds a JSON Schema from an {@link TAtscriptAnnotatedType}.
239
+ *
240
+ * Translates the atscript type structure and validation metadata
241
+ * (min/max, patterns, integer constraints, etc.) into a standard JSON Schema.
242
+ *
243
+ * @example
244
+ * ```ts
245
+ * import { buildJsonSchema } from '@atscript/typescript'
246
+ *
247
+ * const schema = buildJsonSchema(MyInterface)
248
+ * // { type: 'object', properties: { ... }, required: [...] }
249
+ * ```
250
+ *
251
+ * @param type - The annotated type to convert.
252
+ * @returns A JSON Schema object.
253
+ */
135
254
  declare function buildJsonSchema(type: TAtscriptAnnotatedType): TJsonSchema;
255
+ /**
256
+ * Converts a JSON Schema object into a {@link TAtscriptAnnotatedType}.
257
+ *
258
+ * This is the inverse of {@link buildJsonSchema}. A round-trip
259
+ * `buildJsonSchema(fromJsonSchema(schema))` preserves structure and constraints.
260
+ *
261
+ * Supports the JSON Schema subset produced by `buildJsonSchema` plus
262
+ * common extensions like `oneOf` (treated as union) and `enum` (union of literals).
263
+ *
264
+ * @example
265
+ * ```ts
266
+ * import { fromJsonSchema } from '@atscript/typescript'
267
+ *
268
+ * const type = fromJsonSchema({ type: 'object', properties: { name: { type: 'string' } }, required: ['name'] })
269
+ * type.validator().validate({ name: 'Alice' }) // passes
270
+ * ```
271
+ *
272
+ * @param schema - A JSON Schema object.
273
+ * @returns An annotated type with full validator support.
274
+ */
275
+ declare function fromJsonSchema(schema: TJsonSchema): TAtscriptAnnotatedType;
276
+
277
+ /**
278
+ * Type-safe dispatch over `TAtscriptAnnotatedType` by its `type.kind`.
279
+ *
280
+ * Provides the common `switch (def.type.kind)` pattern used by
281
+ * the validator, JSON-schema builder, and serializer.
282
+ * Each caller supplies its own handlers that control recursion.
283
+ */
284
+ declare function forAnnotatedType<R>(def: TAtscriptAnnotatedType, handlers: {
285
+ final: (def: TAtscriptAnnotatedType<TAtscriptTypeFinal>) => R;
286
+ object: (def: TAtscriptAnnotatedType<TAtscriptTypeObject<string>>) => R;
287
+ array: (def: TAtscriptAnnotatedType<TAtscriptTypeArray>) => R;
288
+ union: (def: TAtscriptAnnotatedType<TAtscriptTypeComplex>) => R;
289
+ intersection: (def: TAtscriptAnnotatedType<TAtscriptTypeComplex>) => R;
290
+ tuple: (def: TAtscriptAnnotatedType<TAtscriptTypeComplex>) => R;
291
+ }): R;
292
+
293
+ /** Current serialization format version. Bumped on breaking changes to the serialized shape. */
294
+ declare const SERIALIZE_VERSION = 1;
295
+ /** Top-level serialized annotated type. JSON-safe representation of a {@link TAtscriptAnnotatedType}. */
296
+ interface TSerializedAnnotatedType extends TSerializedAnnotatedTypeInner {
297
+ /** Format version for forward compatibility */
298
+ $v: number;
299
+ }
300
+ /** Serialized annotated type node (used for nested types within the top-level). */
301
+ interface TSerializedAnnotatedTypeInner {
302
+ type: TSerializedTypeDef;
303
+ metadata: Record<string, unknown>;
304
+ optional?: boolean;
305
+ }
306
+ interface TSerializedTypeFinal {
307
+ kind: '';
308
+ designType: string;
309
+ value?: string | number | boolean;
310
+ tags: string[];
311
+ }
312
+ interface TSerializedTypeObject {
313
+ kind: 'object';
314
+ props: Record<string, TSerializedAnnotatedTypeInner>;
315
+ propsPatterns: {
316
+ pattern: {
317
+ source: string;
318
+ flags: string;
319
+ };
320
+ def: TSerializedAnnotatedTypeInner;
321
+ }[];
322
+ tags: string[];
323
+ }
324
+ interface TSerializedTypeArray {
325
+ kind: 'array';
326
+ of: TSerializedAnnotatedTypeInner;
327
+ tags: string[];
328
+ }
329
+ interface TSerializedTypeComplex {
330
+ kind: 'union' | 'intersection' | 'tuple';
331
+ items: TSerializedAnnotatedTypeInner[];
332
+ tags: string[];
333
+ }
334
+ type TSerializedTypeDef = TSerializedTypeFinal | TSerializedTypeObject | TSerializedTypeArray | TSerializedTypeComplex;
335
+ /** Context passed to {@link TSerializeOptions.processAnnotation} for each annotation entry. */
336
+ interface TProcessAnnotationContext {
337
+ /** Annotation key, e.g. "meta.label" */
338
+ key: string;
339
+ /** Annotation value */
340
+ value: unknown;
341
+ /** Property path to the current node, e.g. ["address", "city"] */
342
+ path: string[];
343
+ /** The `kind` of the current type node */
344
+ kind: '' | 'object' | 'array' | 'union' | 'intersection' | 'tuple';
345
+ }
346
+ /** Options for controlling which annotations are included during serialization. */
347
+ interface TSerializeOptions {
348
+ /** Simple list of annotation keys to strip */
349
+ ignoreAnnotations?: string[];
350
+ /**
351
+ * Advanced per-annotation callback. Called after `ignoreAnnotations` filtering.
352
+ * Return `{ key, value }` to keep (possibly renamed/transformed).
353
+ * Return `undefined` or `void` to strip the annotation.
354
+ */
355
+ processAnnotation?: (ctx: TProcessAnnotationContext) => {
356
+ key: string;
357
+ value: unknown;
358
+ } | undefined | void;
359
+ }
360
+ /**
361
+ * Converts a runtime {@link TAtscriptAnnotatedType} into a plain JSON-safe object.
362
+ *
363
+ * The result can be stored, transmitted over the network, and later
364
+ * restored with {@link deserializeAnnotatedType}.
365
+ *
366
+ * @example
367
+ * ```ts
368
+ * import { serializeAnnotatedType } from '@atscript/typescript'
369
+ *
370
+ * const json = serializeAnnotatedType(MyInterface)
371
+ * // json is a plain object safe for JSON.stringify
372
+ * ```
373
+ *
374
+ * @param type - The annotated type to serialize.
375
+ * @param options - Optional filtering/transformation for annotations.
376
+ * @returns A versioned, JSON-safe representation of the type.
377
+ */
378
+ declare function serializeAnnotatedType(type: TAtscriptAnnotatedType, options?: TSerializeOptions): TSerializedAnnotatedType;
379
+ /**
380
+ * Restores a runtime {@link TAtscriptAnnotatedType} from its serialized form.
381
+ *
382
+ * The returned object is fully functional — it has a working `.validator()` method
383
+ * and can be used with {@link buildJsonSchema} or the {@link Validator} directly.
384
+ *
385
+ * @example
386
+ * ```ts
387
+ * import { deserializeAnnotatedType } from '@atscript/typescript'
388
+ *
389
+ * const type = deserializeAnnotatedType(json)
390
+ * type.validator().validate(someValue) // works
391
+ * ```
392
+ *
393
+ * @param data - A serialized type produced by {@link serializeAnnotatedType}.
394
+ * @returns A live annotated type with validator support.
395
+ * @throws If the serialized version doesn't match {@link SERIALIZE_VERSION}.
396
+ */
397
+ declare function deserializeAnnotatedType(data: TSerializedAnnotatedType): TAtscriptAnnotatedType;
136
398
 
137
- export { Validator, ValidatorError, annotate, buildJsonSchema, defineAnnotatedType, isAnnotatedType, isAnnotatedTypeOfPrimitive };
138
- export type { TAnnotatedTypeHandle, TAtscriptAnnotatedType, TAtscriptAnnotatedTypeConstructor, TAtscriptTypeArray, TAtscriptTypeComplex, TAtscriptTypeDef, TAtscriptTypeFinal, TAtscriptTypeObject, TMetadataMap, TValidatorOptions, TValidatorPlugin, TValidatorPluginContext };
399
+ export { SERIALIZE_VERSION, Validator, ValidatorError, annotate, buildJsonSchema, defineAnnotatedType, deserializeAnnotatedType, forAnnotatedType, fromJsonSchema, isAnnotatedType, isAnnotatedTypeOfPrimitive, serializeAnnotatedType };
400
+ export type { InferDataType, TAnnotatedTypeHandle, TAtscriptAnnotatedType, TAtscriptAnnotatedTypeConstructor, TAtscriptTypeArray, TAtscriptTypeComplex, TAtscriptTypeDef, TAtscriptTypeFinal, TAtscriptTypeObject, TMetadataMap, TProcessAnnotationContext, TSerializeOptions, TSerializedAnnotatedType, TSerializedAnnotatedTypeInner, TSerializedTypeArray, TSerializedTypeComplex, TSerializedTypeDef, TSerializedTypeFinal, TSerializedTypeObject, TValidatorOptions, TValidatorPlugin, TValidatorPluginContext };