@atscript/typescript 0.1.44 → 0.1.46
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.cjs +71 -18
- package/dist/utils.d.ts +13 -1
- package/dist/utils.mjs +71 -18
- package/package.json +2 -2
- package/skills/atscript-typescript/utilities.md +4 -1
package/dist/utils.cjs
CHANGED
|
@@ -219,7 +219,7 @@ else flatUnion.item(existing);
|
|
|
219
219
|
|
|
220
220
|
//#endregion
|
|
221
221
|
//#region packages/typescript/src/runtime/serialize.ts
|
|
222
|
-
const SERIALIZE_VERSION =
|
|
222
|
+
const SERIALIZE_VERSION = 2;
|
|
223
223
|
function serializeAnnotatedType(type, options) {
|
|
224
224
|
const visited = new Set();
|
|
225
225
|
const result = serializeNode(type, [], options, visited);
|
|
@@ -243,6 +243,17 @@ function serializeNode(def, path, options, visited) {
|
|
|
243
243
|
};
|
|
244
244
|
if (def.optional) result.optional = true;
|
|
245
245
|
if (def.id) result.id = def.id;
|
|
246
|
+
const refDepth = options?.refDepth ?? 0;
|
|
247
|
+
if (refDepth > 0 && def.ref) {
|
|
248
|
+
const refTarget = def.ref.type();
|
|
249
|
+
if (refTarget) result.ref = {
|
|
250
|
+
type: serializeNode(refTarget, [], {
|
|
251
|
+
...options,
|
|
252
|
+
refDepth: refDepth - 1
|
|
253
|
+
}, visited),
|
|
254
|
+
field: def.ref.field
|
|
255
|
+
};
|
|
256
|
+
}
|
|
246
257
|
return result;
|
|
247
258
|
}
|
|
248
259
|
function serializeTypeDef(def, path, options, visited) {
|
|
@@ -332,18 +343,56 @@ function serializeMetadata(metadata, path, kind, options) {
|
|
|
332
343
|
}
|
|
333
344
|
function deserializeAnnotatedType(data) {
|
|
334
345
|
if (data.$v !== SERIALIZE_VERSION) throw new Error(`Unsupported serialized type version: ${data.$v} (expected ${SERIALIZE_VERSION})`);
|
|
335
|
-
|
|
346
|
+
const resolved = new Map();
|
|
347
|
+
return deserializeNode(data, resolved);
|
|
336
348
|
}
|
|
337
|
-
function deserializeNode(data) {
|
|
349
|
+
function deserializeNode(data, resolved) {
|
|
350
|
+
if (data.type.kind === "$ref") {
|
|
351
|
+
const refId = data.type.id;
|
|
352
|
+
return resolved.get(refId) || require_json_schema.createAnnotatedTypeNode({
|
|
353
|
+
kind: "object",
|
|
354
|
+
props: new Map(),
|
|
355
|
+
propsPatterns: [],
|
|
356
|
+
tags: new Set()
|
|
357
|
+
}, new Map(), { id: refId });
|
|
358
|
+
}
|
|
338
359
|
const metadata = new Map(Object.entries(data.metadata));
|
|
339
|
-
|
|
340
|
-
|
|
360
|
+
let result;
|
|
361
|
+
if (data.id) {
|
|
362
|
+
const existing = resolved.get(data.id);
|
|
363
|
+
if (existing) return existing;
|
|
364
|
+
result = require_json_schema.createAnnotatedTypeNode({
|
|
365
|
+
kind: "object",
|
|
366
|
+
props: new Map(),
|
|
367
|
+
propsPatterns: [],
|
|
368
|
+
tags: new Set()
|
|
369
|
+
}, metadata, {
|
|
370
|
+
optional: data.optional || undefined,
|
|
371
|
+
id: data.id
|
|
372
|
+
});
|
|
373
|
+
resolved.set(data.id, result);
|
|
374
|
+
}
|
|
375
|
+
const type = deserializeTypeDef(data.type, resolved);
|
|
376
|
+
let ref;
|
|
377
|
+
if (data.ref) {
|
|
378
|
+
const deserializedRefTarget = deserializeNode(data.ref.type, resolved);
|
|
379
|
+
ref = {
|
|
380
|
+
type: () => deserializedRefTarget,
|
|
381
|
+
field: data.ref.field
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
if (result) {
|
|
385
|
+
result.type = type;
|
|
386
|
+
if (ref) result.ref = ref;
|
|
387
|
+
return result;
|
|
388
|
+
}
|
|
389
|
+
return require_json_schema.createAnnotatedTypeNode(type, metadata, {
|
|
341
390
|
optional: data.optional || undefined,
|
|
342
|
-
id: data.id || undefined
|
|
391
|
+
id: data.id || undefined,
|
|
392
|
+
ref
|
|
343
393
|
});
|
|
344
|
-
return result;
|
|
345
394
|
}
|
|
346
|
-
function deserializeTypeDef(t) {
|
|
395
|
+
function deserializeTypeDef(t, resolved) {
|
|
347
396
|
const tags = "tags" in t ? new Set(t.tags) : new Set();
|
|
348
397
|
switch (t.kind) {
|
|
349
398
|
case "": {
|
|
@@ -357,10 +406,10 @@ function deserializeTypeDef(t) {
|
|
|
357
406
|
}
|
|
358
407
|
case "object": {
|
|
359
408
|
const props = new Map();
|
|
360
|
-
for (const [key, val] of Object.entries(t.props)) props.set(key, deserializeNode(val));
|
|
409
|
+
for (const [key, val] of Object.entries(t.props)) props.set(key, deserializeNode(val, resolved));
|
|
361
410
|
const propsPatterns = t.propsPatterns.map((pp) => ({
|
|
362
411
|
pattern: new RegExp(pp.pattern.source, pp.pattern.flags),
|
|
363
|
-
def: deserializeNode(pp.def)
|
|
412
|
+
def: deserializeNode(pp.def, resolved)
|
|
364
413
|
}));
|
|
365
414
|
return {
|
|
366
415
|
kind: "object",
|
|
@@ -371,22 +420,26 @@ function deserializeTypeDef(t) {
|
|
|
371
420
|
}
|
|
372
421
|
case "array": return {
|
|
373
422
|
kind: "array",
|
|
374
|
-
of: deserializeNode(t.of),
|
|
423
|
+
of: deserializeNode(t.of, resolved),
|
|
375
424
|
tags
|
|
376
425
|
};
|
|
377
426
|
case "union":
|
|
378
427
|
case "intersection":
|
|
379
428
|
case "tuple": return {
|
|
380
429
|
kind: t.kind,
|
|
381
|
-
items: t.items.map((item) => deserializeNode(item)),
|
|
382
|
-
tags
|
|
383
|
-
};
|
|
384
|
-
case "$ref": return {
|
|
385
|
-
kind: "object",
|
|
386
|
-
props: new Map(),
|
|
387
|
-
propsPatterns: [],
|
|
430
|
+
items: t.items.map((item) => deserializeNode(item, resolved)),
|
|
388
431
|
tags
|
|
389
432
|
};
|
|
433
|
+
case "$ref": {
|
|
434
|
+
const existing = resolved.get(t.id);
|
|
435
|
+
if (existing) return existing.type;
|
|
436
|
+
return {
|
|
437
|
+
kind: "object",
|
|
438
|
+
props: new Map(),
|
|
439
|
+
propsPatterns: [],
|
|
440
|
+
tags
|
|
441
|
+
};
|
|
442
|
+
}
|
|
390
443
|
default: throw new Error(`Unknown serialized type kind "${t.kind}"`);
|
|
391
444
|
}
|
|
392
445
|
}
|
package/dist/utils.d.ts
CHANGED
|
@@ -479,7 +479,7 @@ type AtscriptQueryNode = AtscriptQueryComparison | {
|
|
|
479
479
|
};
|
|
480
480
|
|
|
481
481
|
/** Current serialization format version. Bumped on breaking changes to the serialized shape. */
|
|
482
|
-
declare const SERIALIZE_VERSION =
|
|
482
|
+
declare const SERIALIZE_VERSION = 2;
|
|
483
483
|
/** Top-level serialized annotated type. JSON-safe representation of a {@link TAtscriptAnnotatedType}. */
|
|
484
484
|
interface TSerializedAnnotatedType extends TSerializedAnnotatedTypeInner {
|
|
485
485
|
/** Format version for forward compatibility */
|
|
@@ -491,6 +491,11 @@ interface TSerializedAnnotatedTypeInner {
|
|
|
491
491
|
metadata: Record<string, unknown>;
|
|
492
492
|
optional?: boolean;
|
|
493
493
|
id?: string;
|
|
494
|
+
/** FK reference — present when serialized with `refDepth > 0` */
|
|
495
|
+
ref?: {
|
|
496
|
+
type: TSerializedAnnotatedTypeInner;
|
|
497
|
+
field: string;
|
|
498
|
+
};
|
|
494
499
|
}
|
|
495
500
|
interface TSerializedTypeFinal {
|
|
496
501
|
kind: '';
|
|
@@ -549,6 +554,13 @@ interface TSerializeOptions {
|
|
|
549
554
|
key: string;
|
|
550
555
|
value: unknown;
|
|
551
556
|
} | undefined | void;
|
|
557
|
+
/**
|
|
558
|
+
* How many levels of `.ref` (FK references) to expand during serialization.
|
|
559
|
+
* - `0` (default): refs are stripped (backward-compatible)
|
|
560
|
+
* - `1`: immediate refs are serialized, but refs inside referenced types are stripped
|
|
561
|
+
* - `2+`: deeper expansion
|
|
562
|
+
*/
|
|
563
|
+
refDepth?: number;
|
|
552
564
|
}
|
|
553
565
|
/**
|
|
554
566
|
* Converts a runtime {@link TAtscriptAnnotatedType} into a plain JSON-safe object.
|
package/dist/utils.mjs
CHANGED
|
@@ -218,7 +218,7 @@ else flatUnion.item(existing);
|
|
|
218
218
|
|
|
219
219
|
//#endregion
|
|
220
220
|
//#region packages/typescript/src/runtime/serialize.ts
|
|
221
|
-
const SERIALIZE_VERSION =
|
|
221
|
+
const SERIALIZE_VERSION = 2;
|
|
222
222
|
function serializeAnnotatedType(type, options) {
|
|
223
223
|
const visited = new Set();
|
|
224
224
|
const result = serializeNode(type, [], options, visited);
|
|
@@ -242,6 +242,17 @@ function serializeNode(def, path, options, visited) {
|
|
|
242
242
|
};
|
|
243
243
|
if (def.optional) result.optional = true;
|
|
244
244
|
if (def.id) result.id = def.id;
|
|
245
|
+
const refDepth = options?.refDepth ?? 0;
|
|
246
|
+
if (refDepth > 0 && def.ref) {
|
|
247
|
+
const refTarget = def.ref.type();
|
|
248
|
+
if (refTarget) result.ref = {
|
|
249
|
+
type: serializeNode(refTarget, [], {
|
|
250
|
+
...options,
|
|
251
|
+
refDepth: refDepth - 1
|
|
252
|
+
}, visited),
|
|
253
|
+
field: def.ref.field
|
|
254
|
+
};
|
|
255
|
+
}
|
|
245
256
|
return result;
|
|
246
257
|
}
|
|
247
258
|
function serializeTypeDef(def, path, options, visited) {
|
|
@@ -331,18 +342,56 @@ function serializeMetadata(metadata, path, kind, options) {
|
|
|
331
342
|
}
|
|
332
343
|
function deserializeAnnotatedType(data) {
|
|
333
344
|
if (data.$v !== SERIALIZE_VERSION) throw new Error(`Unsupported serialized type version: ${data.$v} (expected ${SERIALIZE_VERSION})`);
|
|
334
|
-
|
|
345
|
+
const resolved = new Map();
|
|
346
|
+
return deserializeNode(data, resolved);
|
|
335
347
|
}
|
|
336
|
-
function deserializeNode(data) {
|
|
348
|
+
function deserializeNode(data, resolved) {
|
|
349
|
+
if (data.type.kind === "$ref") {
|
|
350
|
+
const refId = data.type.id;
|
|
351
|
+
return resolved.get(refId) || createAnnotatedTypeNode({
|
|
352
|
+
kind: "object",
|
|
353
|
+
props: new Map(),
|
|
354
|
+
propsPatterns: [],
|
|
355
|
+
tags: new Set()
|
|
356
|
+
}, new Map(), { id: refId });
|
|
357
|
+
}
|
|
337
358
|
const metadata = new Map(Object.entries(data.metadata));
|
|
338
|
-
|
|
339
|
-
|
|
359
|
+
let result;
|
|
360
|
+
if (data.id) {
|
|
361
|
+
const existing = resolved.get(data.id);
|
|
362
|
+
if (existing) return existing;
|
|
363
|
+
result = createAnnotatedTypeNode({
|
|
364
|
+
kind: "object",
|
|
365
|
+
props: new Map(),
|
|
366
|
+
propsPatterns: [],
|
|
367
|
+
tags: new Set()
|
|
368
|
+
}, metadata, {
|
|
369
|
+
optional: data.optional || undefined,
|
|
370
|
+
id: data.id
|
|
371
|
+
});
|
|
372
|
+
resolved.set(data.id, result);
|
|
373
|
+
}
|
|
374
|
+
const type = deserializeTypeDef(data.type, resolved);
|
|
375
|
+
let ref;
|
|
376
|
+
if (data.ref) {
|
|
377
|
+
const deserializedRefTarget = deserializeNode(data.ref.type, resolved);
|
|
378
|
+
ref = {
|
|
379
|
+
type: () => deserializedRefTarget,
|
|
380
|
+
field: data.ref.field
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
if (result) {
|
|
384
|
+
result.type = type;
|
|
385
|
+
if (ref) result.ref = ref;
|
|
386
|
+
return result;
|
|
387
|
+
}
|
|
388
|
+
return createAnnotatedTypeNode(type, metadata, {
|
|
340
389
|
optional: data.optional || undefined,
|
|
341
|
-
id: data.id || undefined
|
|
390
|
+
id: data.id || undefined,
|
|
391
|
+
ref
|
|
342
392
|
});
|
|
343
|
-
return result;
|
|
344
393
|
}
|
|
345
|
-
function deserializeTypeDef(t) {
|
|
394
|
+
function deserializeTypeDef(t, resolved) {
|
|
346
395
|
const tags = "tags" in t ? new Set(t.tags) : new Set();
|
|
347
396
|
switch (t.kind) {
|
|
348
397
|
case "": {
|
|
@@ -356,10 +405,10 @@ function deserializeTypeDef(t) {
|
|
|
356
405
|
}
|
|
357
406
|
case "object": {
|
|
358
407
|
const props = new Map();
|
|
359
|
-
for (const [key, val] of Object.entries(t.props)) props.set(key, deserializeNode(val));
|
|
408
|
+
for (const [key, val] of Object.entries(t.props)) props.set(key, deserializeNode(val, resolved));
|
|
360
409
|
const propsPatterns = t.propsPatterns.map((pp) => ({
|
|
361
410
|
pattern: new RegExp(pp.pattern.source, pp.pattern.flags),
|
|
362
|
-
def: deserializeNode(pp.def)
|
|
411
|
+
def: deserializeNode(pp.def, resolved)
|
|
363
412
|
}));
|
|
364
413
|
return {
|
|
365
414
|
kind: "object",
|
|
@@ -370,22 +419,26 @@ function deserializeTypeDef(t) {
|
|
|
370
419
|
}
|
|
371
420
|
case "array": return {
|
|
372
421
|
kind: "array",
|
|
373
|
-
of: deserializeNode(t.of),
|
|
422
|
+
of: deserializeNode(t.of, resolved),
|
|
374
423
|
tags
|
|
375
424
|
};
|
|
376
425
|
case "union":
|
|
377
426
|
case "intersection":
|
|
378
427
|
case "tuple": return {
|
|
379
428
|
kind: t.kind,
|
|
380
|
-
items: t.items.map((item) => deserializeNode(item)),
|
|
381
|
-
tags
|
|
382
|
-
};
|
|
383
|
-
case "$ref": return {
|
|
384
|
-
kind: "object",
|
|
385
|
-
props: new Map(),
|
|
386
|
-
propsPatterns: [],
|
|
429
|
+
items: t.items.map((item) => deserializeNode(item, resolved)),
|
|
387
430
|
tags
|
|
388
431
|
};
|
|
432
|
+
case "$ref": {
|
|
433
|
+
const existing = resolved.get(t.id);
|
|
434
|
+
if (existing) return existing.type;
|
|
435
|
+
return {
|
|
436
|
+
kind: "object",
|
|
437
|
+
props: new Map(),
|
|
438
|
+
propsPatterns: [],
|
|
439
|
+
tags
|
|
440
|
+
};
|
|
441
|
+
}
|
|
389
442
|
default: throw new Error(`Unknown serialized type kind "${t.kind}"`);
|
|
390
443
|
}
|
|
391
444
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/typescript",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.46",
|
|
4
4
|
"description": "Atscript: typescript-gen support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"annotations",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
},
|
|
67
67
|
"peerDependencies": {
|
|
68
68
|
"@atscript/db": "^0.1.41",
|
|
69
|
-
"@atscript/core": "^0.1.
|
|
69
|
+
"@atscript/core": "^0.1.46"
|
|
70
70
|
},
|
|
71
71
|
"peerDependenciesMeta": {
|
|
72
72
|
"@atscript/db": {
|
|
@@ -213,6 +213,9 @@ serializeAnnotatedType(User, {
|
|
|
213
213
|
if (ctx.key.startsWith('mongo.')) return undefined
|
|
214
214
|
return { key: ctx.key, value: ctx.value }
|
|
215
215
|
},
|
|
216
|
+
|
|
217
|
+
// Include FK references (0 = strip, 1 = immediate refs, 2+ = deeper)
|
|
218
|
+
refDepth: 1,
|
|
216
219
|
})
|
|
217
220
|
```
|
|
218
221
|
|
|
@@ -236,7 +239,7 @@ Throws if the serialized version doesn't match `SERIALIZE_VERSION`. The `id` fie
|
|
|
236
239
|
|
|
237
240
|
### `SERIALIZE_VERSION`
|
|
238
241
|
|
|
239
|
-
Current serialization format version (currently `
|
|
242
|
+
Current serialization format version (currently `2`). Used for forward compatibility:
|
|
240
243
|
|
|
241
244
|
```ts
|
|
242
245
|
import { SERIALIZE_VERSION } from '@atscript/typescript/utils'
|