@ts-runtypes/core 0.9.1 → 0.9.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.
Files changed (63) hide show
  1. package/dist/cjs/fnHash.d.ts +8 -0
  2. package/dist/cjs/fnHash.js +31 -0
  3. package/dist/cjs/fnHashes.generated.d.ts +130 -0
  4. package/dist/cjs/fnHashes.generated.js +31 -0
  5. package/dist/cjs/formats/string/stringFormats.d.ts +1 -0
  6. package/dist/cjs/index.d.ts +2 -1
  7. package/dist/cjs/index.js +4 -1
  8. package/dist/cjs/mocking/mockStringFormat.js +8 -3
  9. package/dist/cjs/mocking/mockType.js +2 -2
  10. package/dist/cjs/runtypes/classSerializerRegistry.d.ts +1 -1
  11. package/dist/cjs/runtypes/classSerializerRegistry.js +65 -19
  12. package/dist/cjs/runtypes/entryTuple.d.ts +2 -2
  13. package/dist/cjs/runtypes/entryTuple.js +1 -0
  14. package/dist/cjs/runtypes/rtUtils.d.ts +2 -1
  15. package/dist/cjs/runtypes/rtUtils.js +15 -2
  16. package/dist/cjs/runtypes/types.d.ts +1 -0
  17. package/dist/fnHash.d.ts +9 -0
  18. package/dist/fnHash.d.ts.map +1 -0
  19. package/dist/fnHash.js +29 -0
  20. package/dist/fnHash.js.map +1 -0
  21. package/dist/fnHashes.generated.d.ts +131 -0
  22. package/dist/fnHashes.generated.d.ts.map +1 -0
  23. package/dist/fnHashes.generated.js +29 -0
  24. package/dist/fnHashes.generated.js.map +1 -0
  25. package/dist/formats/string/stringFormats.d.ts +1 -0
  26. package/dist/formats/string/stringFormats.d.ts.map +1 -1
  27. package/dist/formats/string/stringFormats.js.map +1 -1
  28. package/dist/index.d.ts +2 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +2 -1
  31. package/dist/index.js.map +1 -1
  32. package/dist/mocking/mockStringFormat.d.ts.map +1 -1
  33. package/dist/mocking/mockStringFormat.js +8 -3
  34. package/dist/mocking/mockStringFormat.js.map +1 -1
  35. package/dist/mocking/mockType.js +2 -2
  36. package/dist/mocking/mockType.js.map +1 -1
  37. package/dist/runtypes/classSerializerRegistry.d.ts +1 -1
  38. package/dist/runtypes/classSerializerRegistry.d.ts.map +1 -1
  39. package/dist/runtypes/classSerializerRegistry.js +65 -19
  40. package/dist/runtypes/classSerializerRegistry.js.map +1 -1
  41. package/dist/runtypes/dataOnly.d.ts.map +1 -1
  42. package/dist/runtypes/entryTuple.d.ts +2 -2
  43. package/dist/runtypes/entryTuple.d.ts.map +1 -1
  44. package/dist/runtypes/entryTuple.js +1 -0
  45. package/dist/runtypes/entryTuple.js.map +1 -1
  46. package/dist/runtypes/rtUtils.d.ts +2 -1
  47. package/dist/runtypes/rtUtils.d.ts.map +1 -1
  48. package/dist/runtypes/rtUtils.js +15 -2
  49. package/dist/runtypes/rtUtils.js.map +1 -1
  50. package/dist/runtypes/types.d.ts +1 -0
  51. package/dist/runtypes/types.d.ts.map +1 -1
  52. package/package.json +2 -2
  53. package/src/fnHash.ts +67 -0
  54. package/src/fnHashes.generated.ts +54 -0
  55. package/src/formats/string/stringFormats.ts +4 -0
  56. package/src/index.ts +23 -4
  57. package/src/mocking/mockStringFormat.ts +17 -5
  58. package/src/mocking/mockType.ts +9 -6
  59. package/src/runtypes/classSerializerRegistry.ts +130 -38
  60. package/src/runtypes/dataOnly.ts +16 -0
  61. package/src/runtypes/entryTuple.ts +1 -0
  62. package/src/runtypes/rtUtils.ts +24 -6
  63. package/src/runtypes/types.ts +6 -0
@@ -0,0 +1,8 @@
1
+ import { FN_HASHES } from './fnHashes.generated.ts';
2
+ export type FnHashKey = keyof typeof FN_HASHES;
3
+ export interface FnHashOptions {
4
+ noLiterals?: boolean;
5
+ noIsArrayCheck?: boolean;
6
+ strategy?: string;
7
+ }
8
+ export declare function getFnHash(fnKey: FnHashKey | (string & {}), options?: FnHashOptions): string;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getFnHash = getFnHash;
4
+ const fnHashes_generated_ts_1 = require("./fnHashes.generated.js");
5
+ function validateVariantToken(options) {
6
+ if (!options)
7
+ return '';
8
+ let suffix = 'N';
9
+ let hit = false;
10
+ for (const [name, letter] of fnHashes_generated_ts_1.VALIDATE_OPTION_LETTERS) {
11
+ if (options[name]) {
12
+ suffix += letter;
13
+ hit = true;
14
+ }
15
+ }
16
+ return hit ? suffix : '';
17
+ }
18
+ function getFnHash(fnKey, options) {
19
+ const entry = fnHashes_generated_ts_1.FN_HASHES[fnKey];
20
+ if (!entry)
21
+ throw new Error(`getFnHash: unknown fnKey ${JSON.stringify(fnKey)}`);
22
+ let token = '';
23
+ if (entry.axis === 'validateOptions')
24
+ token = validateVariantToken(options);
25
+ else if (entry.axis === 'jsonStrategy')
26
+ token = options?.strategy ?? entry.defaultVariant ?? '';
27
+ const hash = entry.variants[token];
28
+ if (hash === undefined)
29
+ throw new Error(`getFnHash: fnKey ${JSON.stringify(fnKey)} has no ${JSON.stringify(token)} variant`);
30
+ return hash;
31
+ }
@@ -0,0 +1,130 @@
1
+ export type FnHashAxis = 'none' | 'validateOptions' | 'jsonStrategy';
2
+ export interface FnHashEntry {
3
+ readonly axis: FnHashAxis;
4
+ readonly defaultVariant?: string;
5
+ readonly variants: Readonly<Record<string, string>>;
6
+ }
7
+ export declare const FN_HASHES: {
8
+ readonly cj: {
9
+ readonly axis: "none";
10
+ readonly variants: {
11
+ readonly '': "xnN";
12
+ };
13
+ };
14
+ readonly cjr: {
15
+ readonly axis: "none";
16
+ readonly variants: {
17
+ readonly '': "Siw";
18
+ };
19
+ };
20
+ readonly fb: {
21
+ readonly axis: "none";
22
+ readonly variants: {
23
+ readonly '': "mY6";
24
+ };
25
+ };
26
+ readonly fmt: {
27
+ readonly axis: "none";
28
+ readonly variants: {
29
+ readonly '': "SS6";
30
+ };
31
+ };
32
+ readonly huk: {
33
+ readonly axis: "none";
34
+ readonly variants: {
35
+ readonly '': "trR";
36
+ };
37
+ };
38
+ readonly jsonDecoder: {
39
+ readonly axis: "jsonStrategy";
40
+ readonly defaultVariant: "strip";
41
+ readonly variants: {
42
+ readonly compact: "MCy";
43
+ readonly preserve: "J5l";
44
+ readonly strip: "fDV";
45
+ };
46
+ };
47
+ readonly jsonEncoder: {
48
+ readonly axis: "jsonStrategy";
49
+ readonly defaultVariant: "clone";
50
+ readonly variants: {
51
+ readonly clone: "wUi";
52
+ readonly compact: "yeS";
53
+ readonly direct: "y0u";
54
+ readonly mutate: "z1L";
55
+ };
56
+ };
57
+ readonly pj: {
58
+ readonly axis: "none";
59
+ readonly variants: {
60
+ readonly '': "tt1";
61
+ };
62
+ };
63
+ readonly pjs: {
64
+ readonly axis: "none";
65
+ readonly variants: {
66
+ readonly '': "oak";
67
+ };
68
+ };
69
+ readonly rj: {
70
+ readonly axis: "none";
71
+ readonly variants: {
72
+ readonly '': "X13";
73
+ };
74
+ };
75
+ readonly sj: {
76
+ readonly axis: "none";
77
+ readonly variants: {
78
+ readonly '': "qm4";
79
+ };
80
+ };
81
+ readonly suk: {
82
+ readonly axis: "none";
83
+ readonly variants: {
84
+ readonly '': "rRP";
85
+ };
86
+ };
87
+ readonly tb: {
88
+ readonly axis: "none";
89
+ readonly variants: {
90
+ readonly '': "plZ";
91
+ };
92
+ };
93
+ readonly uke: {
94
+ readonly axis: "none";
95
+ readonly variants: {
96
+ readonly '': "XFJ";
97
+ };
98
+ };
99
+ readonly uku: {
100
+ readonly axis: "none";
101
+ readonly variants: {
102
+ readonly '': "emC";
103
+ };
104
+ };
105
+ readonly ukuw: {
106
+ readonly axis: "none";
107
+ readonly variants: {
108
+ readonly '': "N3x";
109
+ };
110
+ };
111
+ readonly val: {
112
+ readonly axis: "validateOptions";
113
+ readonly variants: {
114
+ readonly '': "nPZ";
115
+ readonly NA: "WeU";
116
+ readonly NL: "N7J";
117
+ readonly NLA: "GYK";
118
+ };
119
+ };
120
+ readonly verr: {
121
+ readonly axis: "validateOptions";
122
+ readonly variants: {
123
+ readonly '': "pBb";
124
+ readonly NA: "UKg";
125
+ readonly NL: "LD5";
126
+ readonly NLA: "Yk4";
127
+ };
128
+ };
129
+ };
130
+ export declare const VALIDATE_OPTION_LETTERS: readonly [readonly ["noLiterals", "L"], readonly ["noIsArrayCheck", "A"]];
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VALIDATE_OPTION_LETTERS = exports.FN_HASHES = void 0;
4
+ exports.FN_HASHES = {
5
+ cj: { axis: 'none', variants: { '': 'xnN' } },
6
+ cjr: { axis: 'none', variants: { '': 'Siw' } },
7
+ fb: { axis: 'none', variants: { '': 'mY6' } },
8
+ fmt: { axis: 'none', variants: { '': 'SS6' } },
9
+ huk: { axis: 'none', variants: { '': 'trR' } },
10
+ jsonDecoder: { axis: 'jsonStrategy', defaultVariant: 'strip', variants: { compact: 'MCy', preserve: 'J5l', strip: 'fDV' } },
11
+ jsonEncoder: {
12
+ axis: 'jsonStrategy',
13
+ defaultVariant: 'clone',
14
+ variants: { clone: 'wUi', compact: 'yeS', direct: 'y0u', mutate: 'z1L' },
15
+ },
16
+ pj: { axis: 'none', variants: { '': 'tt1' } },
17
+ pjs: { axis: 'none', variants: { '': 'oak' } },
18
+ rj: { axis: 'none', variants: { '': 'X13' } },
19
+ sj: { axis: 'none', variants: { '': 'qm4' } },
20
+ suk: { axis: 'none', variants: { '': 'rRP' } },
21
+ tb: { axis: 'none', variants: { '': 'plZ' } },
22
+ uke: { axis: 'none', variants: { '': 'XFJ' } },
23
+ uku: { axis: 'none', variants: { '': 'emC' } },
24
+ ukuw: { axis: 'none', variants: { '': 'N3x' } },
25
+ val: { axis: 'validateOptions', variants: { '': 'nPZ', NA: 'WeU', NL: 'N7J', NLA: 'GYK' } },
26
+ verr: { axis: 'validateOptions', variants: { '': 'pBb', NA: 'UKg', NL: 'LD5', NLA: 'Yk4' } },
27
+ };
28
+ exports.VALIDATE_OPTION_LETTERS = [
29
+ ['noLiterals', 'L'],
30
+ ['noIsArrayCheck', 'A'],
31
+ ];
@@ -147,6 +147,7 @@ export interface DomainParams {
147
147
  mockSamples?: readonly string[];
148
148
  names?: DomainPartParams;
149
149
  tld?: DomainPartParams;
150
+ allowedValues?: AllowedValuesParam;
150
151
  }
151
152
  export type Domain = TypeFormat<string, 'domain', {
152
153
  pattern: typeof DOMAIN_PATTERN;
@@ -9,6 +9,7 @@ import type { FriendlyText } from './enrich/friendlyText.ts';
9
9
  export type FriendlyType<T> = FriendlyText<T>;
10
10
  export { type MockData, type MockNode } from './enrich/mockData.ts';
11
11
  export { createFriendlyText, createFriendlyTextI18n, resolveLocale, type FriendlyMessage, type FriendlyRenderer, type FriendlyI18nOptions, } from './enrich/createFriendlyText.ts';
12
+ export { getFnHash, type FnHashKey, type FnHashOptions } from './fnHash.ts';
12
13
  export { registerPureFnFactory, type PureFnId } from './runtypes/pureFn.ts';
13
14
  import './runtypes/pure-fns-utils.ts';
14
15
  export { registerClassSerializer, type ClassSerializerHandler, type AnyClass, type SerializableClass, type DeserializeClassFn, } from './runtypes/classSerializerRegistry.ts';
@@ -16,7 +17,7 @@ export { type TypeFormat, type TypeFormatBase, type TypeFormatParams } from './r
16
17
  export { type FormatAnnotation } from './runtypes/formatAnnotation.ts';
17
18
  export { registerMockingFunction, type MockFormatFn } from './mocking/mockRegistry.ts';
18
19
  export { registerFormatPattern, type FormatPattern, type StringPatternArgs } from './runtypes/formatPattern.ts';
19
- export { RunTypeKind, type RunTypeKindValue } from './runTypeKind.ts';
20
+ export { RunTypeKind, type RunTypeKindName, type RunTypeKindValue, RunTypeSubKind, type RunTypeSubKindName, type RunTypeSubKindValue, } from './runTypeKind.ts';
20
21
  export { getRTFunction, type RTFunctionByKey, type RTFunctionKey, createValidate, type ValidateFn, type ValidateOptions, createGetValidationErrors, type GetValidationErrorsFn, type RTValidationError, type TypeFormatError, type RTValidationErrorPathSegment, type RTPathSegment, createHasUnknownKeys, type HasUnknownKeysFn, type HasUnknownKeysOptions, createStripUnknownKeys, type StripUnknownKeysFn, createUnknownKeyErrors, type UnknownKeyErrorsFn, createUnknownKeysToUndefined, type UnknownKeysToUndefinedFn, createFormatTransform, type FormatTransformFn, createJsonEncoder, type JsonEncoderFn, type JsonEncoderOptions, createJsonDecoder, type JsonDecoderFn, type JsonDecoderOptions, type PrepareForJsonFn, type RestoreFromJsonFn, type StringifyJsonFn, } from './createRTFunctions.ts';
21
22
  export { createBinaryEncoder, type BinaryEncoderFn, type BinaryEncoderSizeFn, type BinaryEncoderIntoFn, type BinaryEncoderOptions, createBinarySizer, type BinarySizerFn, createBinaryDecoder, type BinaryDecoderFn, type BinaryDecoderOptions, type ToBinaryFn, type FromBinaryFn, } from './createRTFBinary.ts';
22
23
  export { overrideValidate, overrideGetValidationErrors, overrideHasUnknownKeys, overrideStripUnknownKeys, overrideUnknownKeyErrors, overrideUnknownKeysToUndefined, overrideFormatTransform, overrideBinaryEncoder, overrideBinaryDecoder, overrideJsonEncoder, overrideJsonDecoder, } from './overrideRTFunctions.ts';
package/dist/cjs/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.setSerializationOptions = exports.createDataViewDeserializer = exports.createDataViewSerializer = exports.CircularReferenceError = exports.isRejectCircularRefsEnabled = exports.setRejectCircularRefs = exports.runTypeErrorsToIssues = exports.createStandardSchema = exports.createMockData = exports.overrideJsonDecoder = exports.overrideJsonEncoder = exports.overrideBinaryDecoder = exports.overrideBinaryEncoder = exports.overrideFormatTransform = exports.overrideUnknownKeysToUndefined = exports.overrideUnknownKeyErrors = exports.overrideStripUnknownKeys = exports.overrideHasUnknownKeys = exports.overrideGetValidationErrors = exports.overrideValidate = exports.createBinaryDecoder = exports.createBinarySizer = exports.createBinaryEncoder = exports.createJsonDecoder = exports.createJsonEncoder = exports.createFormatTransform = exports.createUnknownKeysToUndefined = exports.createUnknownKeyErrors = exports.createStripUnknownKeys = exports.createHasUnknownKeys = exports.createGetValidationErrors = exports.createValidate = exports.getRTFunction = exports.RunTypeKind = exports.registerFormatPattern = exports.registerMockingFunction = exports.registerClassSerializer = exports.registerPureFnFactory = exports.resolveLocale = exports.createFriendlyTextI18n = exports.createFriendlyText = exports.getRunType = exports.getRTFnCaches = exports.getRTUtils = exports.getRunTypeId = void 0;
3
+ exports.setSerializationOptions = exports.createDataViewDeserializer = exports.createDataViewSerializer = exports.CircularReferenceError = exports.isRejectCircularRefsEnabled = exports.setRejectCircularRefs = exports.runTypeErrorsToIssues = exports.createStandardSchema = exports.createMockData = exports.overrideJsonDecoder = exports.overrideJsonEncoder = exports.overrideBinaryDecoder = exports.overrideBinaryEncoder = exports.overrideFormatTransform = exports.overrideUnknownKeysToUndefined = exports.overrideUnknownKeyErrors = exports.overrideStripUnknownKeys = exports.overrideHasUnknownKeys = exports.overrideGetValidationErrors = exports.overrideValidate = exports.createBinaryDecoder = exports.createBinarySizer = exports.createBinaryEncoder = exports.createJsonDecoder = exports.createJsonEncoder = exports.createFormatTransform = exports.createUnknownKeysToUndefined = exports.createUnknownKeyErrors = exports.createStripUnknownKeys = exports.createHasUnknownKeys = exports.createGetValidationErrors = exports.createValidate = exports.getRTFunction = exports.RunTypeSubKind = exports.RunTypeKind = exports.registerFormatPattern = exports.registerMockingFunction = exports.registerClassSerializer = exports.registerPureFnFactory = exports.getFnHash = exports.resolveLocale = exports.createFriendlyTextI18n = exports.createFriendlyText = exports.getRunType = exports.getRTFnCaches = exports.getRTUtils = exports.getRunTypeId = void 0;
4
4
  var markers_ts_1 = require("./markers.js");
5
5
  Object.defineProperty(exports, "getRunTypeId", { enumerable: true, get: function () { return markers_ts_1.getRunTypeId; } });
6
6
  var rtUtils_ts_1 = require("./runtypes/rtUtils.js");
@@ -12,6 +12,8 @@ var createFriendlyText_ts_1 = require("./enrich/createFriendlyText.js");
12
12
  Object.defineProperty(exports, "createFriendlyText", { enumerable: true, get: function () { return createFriendlyText_ts_1.createFriendlyText; } });
13
13
  Object.defineProperty(exports, "createFriendlyTextI18n", { enumerable: true, get: function () { return createFriendlyText_ts_1.createFriendlyTextI18n; } });
14
14
  Object.defineProperty(exports, "resolveLocale", { enumerable: true, get: function () { return createFriendlyText_ts_1.resolveLocale; } });
15
+ var fnHash_ts_1 = require("./fnHash.js");
16
+ Object.defineProperty(exports, "getFnHash", { enumerable: true, get: function () { return fnHash_ts_1.getFnHash; } });
15
17
  var pureFn_ts_1 = require("./runtypes/pureFn.js");
16
18
  Object.defineProperty(exports, "registerPureFnFactory", { enumerable: true, get: function () { return pureFn_ts_1.registerPureFnFactory; } });
17
19
  require("./runtypes/pure-fns-utils.js");
@@ -23,6 +25,7 @@ var formatPattern_ts_1 = require("./runtypes/formatPattern.js");
23
25
  Object.defineProperty(exports, "registerFormatPattern", { enumerable: true, get: function () { return formatPattern_ts_1.registerFormatPattern; } });
24
26
  var runTypeKind_ts_1 = require("./runTypeKind.js");
25
27
  Object.defineProperty(exports, "RunTypeKind", { enumerable: true, get: function () { return runTypeKind_ts_1.RunTypeKind; } });
28
+ Object.defineProperty(exports, "RunTypeSubKind", { enumerable: true, get: function () { return runTypeKind_ts_1.RunTypeSubKind; } });
26
29
  var createRTFunctions_ts_1 = require("./createRTFunctions.js");
27
30
  Object.defineProperty(exports, "getRTFunction", { enumerable: true, get: function () { return createRTFunctions_ts_1.getRTFunction; } });
28
31
  Object.defineProperty(exports, "createValidate", { enumerable: true, get: function () { return createRTFunctions_ts_1.createValidate; } });
@@ -44,7 +44,8 @@ function mockStringParams(params) {
44
44
  if (charSet)
45
45
  return randomStringFrom(charSet, Math.max(1, pickMockLength(params)));
46
46
  if (params.pattern !== undefined) {
47
- throw new Error('StringFormat: a `pattern` requires `mockSamples` to mock — none provided.');
47
+ throw new Error('StringFormat: a `pattern` requires `mockSamples` compatible with the length bounds to mock — ' +
48
+ 'none provided, or every sample violates length/minLength/maxLength.');
48
49
  }
49
50
  return randomString(pickMockLength(params));
50
51
  }
@@ -57,7 +58,7 @@ function filterSamplesByLength(samples, params) {
57
58
  return samples;
58
59
  if (params.length === undefined && params.minLength === undefined && params.maxLength === undefined)
59
60
  return samples;
60
- const kept = samples.filter((sample) => {
61
+ return samples.filter((sample) => {
61
62
  if (params.length !== undefined && sample.length !== params.length)
62
63
  return false;
63
64
  if (params.minLength !== undefined && sample.length < params.minLength)
@@ -66,7 +67,6 @@ function filterSamplesByLength(samples, params) {
66
67
  return false;
67
68
  return true;
68
69
  });
69
- return kept.length > 0 ? kept : samples;
70
70
  }
71
71
  function pickSample(samples) {
72
72
  if (!samples || samples.length === 0)
@@ -164,6 +164,11 @@ function randomPort() {
164
164
  return Math.floor(Math.random() * 65536);
165
165
  }
166
166
  function mockDomain(params) {
167
+ if (params.allowedValues) {
168
+ const allowed = pickSample(params.allowedValues.val);
169
+ if (allowed !== undefined)
170
+ return allowed;
171
+ }
167
172
  if (params.names || params.tld) {
168
173
  const name = pickSample(domainPartSamples(params.names)) ?? 'example';
169
174
  const tld = pickSample(domainPartSamples(params.tld)) ?? 'com';
@@ -28,9 +28,9 @@ function mockRunType(runType, options, stack = []) {
28
28
  stack.pop();
29
29
  }
30
30
  }
31
- const FORMAT_TRANSFORM_PREFIX = 'fmt_';
31
+ const FORMAT_TRANSFORM_FAMILY = 'fmt';
32
32
  function lookupFormatTransform(id) {
33
- const entry = (0, rtUtils_ts_1.getRTUtils)().getRT(FORMAT_TRANSFORM_PREFIX + id);
33
+ const entry = (0, rtUtils_ts_1.getRTUtils)().findRTForType(FORMAT_TRANSFORM_FAMILY, id);
34
34
  if (!entry || entry.isNoop || !entry.fn)
35
35
  return undefined;
36
36
  return entry.fn;
@@ -21,7 +21,7 @@ export declare function registerClassSerializer<T>(cls: SerializableClass<T>, ha
21
21
  export declare function registerClassSerializer<T>(cls: AnyClass<T>, handler: ClassSerializerHandler<T> & {
22
22
  deserialize(data: DataOnly<T>): T;
23
23
  }, id?: InjectRunTypeId<T>): void;
24
- export declare function getClassSerializer(typeId: string): ClassSerializerEntry | undefined;
24
+ export declare function getClassSerializer(typeId: string, className?: string): ClassSerializerEntry | undefined;
25
25
  export declare function isClassSerializerRegistered(cls: AnyClass): boolean;
26
26
  export declare function deserializeClass<T>(entry: ClassSerializerEntry<T>, data: DataOnly<T>): T;
27
27
  export declare function unregisterClassSerializer(cls: AnyClass): void;
@@ -8,8 +8,11 @@ exports.deserializeClass = deserializeClass;
8
8
  exports.unregisterClassSerializer = unregisterClassSerializer;
9
9
  exports.clearClassSerializers = clearClassSerializers;
10
10
  const entryTuple_ts_1 = require("./entryTuple.js");
11
+ const rtUtils_ts_1 = require("./rtUtils.js");
11
12
  const classSerializers = new Map();
12
- const classToKey = new Map();
13
+ const classSerializersByName = new Map();
14
+ const classStates = new Map();
15
+ const warnedAmbiguousNames = new Set();
13
16
  let epoch = 0;
14
17
  function classSerializerEpoch() {
15
18
  return epoch;
@@ -23,28 +26,62 @@ function classSerializerKey(id, cls) {
23
26
  return id;
24
27
  throw new Error(`[ts-runtypes] registerClassSerializer(${cls.name || '<anonymous>'}): no type id injected. ` +
25
28
  `The ts-runtypes-devtools plugin must process the registration file so the class's ` +
26
- `type id can be injected (the registry is keyed by type id, not name).`);
29
+ `type id can be injected (the registry is keyed by type id + class name).`);
30
+ }
31
+ function classSerializerName(key, cls) {
32
+ const node = (0, rtUtils_ts_1.getRTUtils)().getRunType(key);
33
+ const typeName = node?.typeName;
34
+ if (typeof typeName === 'string' && typeName.length > 0)
35
+ return typeName;
36
+ return cls.name || undefined;
37
+ }
38
+ function indexByName(name, entry) {
39
+ let entries = classSerializersByName.get(name);
40
+ if (!entries) {
41
+ entries = new Set();
42
+ classSerializersByName.set(name, entries);
43
+ }
44
+ entries.add(entry);
45
+ if (entries.size > 1 && !warnedAmbiguousNames.has(name)) {
46
+ warnedAmbiguousNames.add(name);
47
+ console.warn(`[ts-runtypes] registerClassSerializer: ${entries.size} different classes named "${name}" are registered. ` +
48
+ `The class-name fallback is disabled for "${name}" — only exact-instantiation matches will use the registry ` +
49
+ `(other generic instantiations of these classes fall back to structural decode).`);
50
+ }
27
51
  }
28
52
  function registerClassSerializer(cls, handler, id) {
29
53
  if (typeof cls !== 'function')
30
54
  throw new Error('registerClassSerializer: cls must be a class constructor');
31
55
  const key = classSerializerKey(id, cls);
32
- const prior = classToKey.get(cls);
33
- if (prior && prior !== key)
34
- classSerializers.delete(prior);
35
- classSerializers.set(key, {
36
- cls,
37
- serialize: handler?.serialize,
38
- deserialize: handler?.deserialize,
39
- });
40
- classToKey.set(cls, key);
56
+ let state = classStates.get(cls);
57
+ if (!state) {
58
+ state = { entry: { cls }, keys: new Set() };
59
+ classStates.set(cls, state);
60
+ }
61
+ state.entry.serialize = handler?.serialize;
62
+ state.entry.deserialize = handler?.deserialize;
63
+ state.keys.add(key);
64
+ classSerializers.set(key, state.entry);
65
+ const name = classSerializerName(key, cls);
66
+ if (name && state.name === undefined) {
67
+ state.name = name;
68
+ indexByName(name, state.entry);
69
+ }
41
70
  epoch++;
42
71
  }
43
- function getClassSerializer(typeId) {
44
- return classSerializers.get(typeId);
72
+ function getClassSerializer(typeId, className) {
73
+ const exact = classSerializers.get(typeId);
74
+ if (exact)
75
+ return exact;
76
+ if (!className)
77
+ return undefined;
78
+ const entries = classSerializersByName.get(className);
79
+ if (!entries || entries.size !== 1)
80
+ return undefined;
81
+ return entries.values().next().value;
45
82
  }
46
83
  function isClassSerializerRegistered(cls) {
47
- return classToKey.has(cls);
84
+ return classStates.has(cls);
48
85
  }
49
86
  function deserializeClass(entry, data) {
50
87
  if (entry.deserialize)
@@ -62,15 +99,24 @@ function deserializeClass(entry, data) {
62
99
  }
63
100
  }
64
101
  function unregisterClassSerializer(cls) {
65
- const key = classToKey.get(cls);
66
- if (key === undefined)
102
+ const state = classStates.get(cls);
103
+ if (!state)
67
104
  return;
68
- classSerializers.delete(key);
69
- classToKey.delete(cls);
105
+ for (const key of state.keys)
106
+ classSerializers.delete(key);
107
+ if (state.name !== undefined) {
108
+ const entries = classSerializersByName.get(state.name);
109
+ entries?.delete(state.entry);
110
+ if (entries && entries.size === 0)
111
+ classSerializersByName.delete(state.name);
112
+ }
113
+ classStates.delete(cls);
70
114
  epoch++;
71
115
  }
72
116
  function clearClassSerializers() {
73
117
  classSerializers.clear();
74
- classToKey.clear();
118
+ classSerializersByName.clear();
119
+ classStates.clear();
120
+ warnedAmbiguousNames.clear();
75
121
  epoch++;
76
122
  }
@@ -8,7 +8,7 @@ declare const KIND_RUN_TYPE_FACADE = 5;
8
8
  export declare const FN_HASH_LEN = 3;
9
9
  export type EntryDepsThunk = () => readonly EntryTuple[];
10
10
  export type RunTypeIni = (rtu: RTUtils) => void;
11
- declare const RUN_TYPE_FIELD_KEYS: readonly ["id", "kind", "subKind", "typeName", "name", "literal", "optional", "readonly", "isAbstract", "isStatic", "visibility", "isSafeName", "position", "isCircular", "flags", "description", "defaultVal", "enumVal", "values", "notSupported"];
11
+ declare const RUN_TYPE_FIELD_KEYS: readonly ["id", "kind", "subKind", "typeName", "name", "literal", "optional", "readonly", "isAbstract", "isStatic", "visibility", "isSafeName", "position", "isCircular", "flags", "description", "defaultVal", "enumVal", "values", "notSupported", "nonEnumerable"];
12
12
  export type RunTypeRowRecord = Pick<RunType, (typeof RUN_TYPE_FIELD_KEYS)[number]>;
13
13
  type RunTypeRel = number | string | object;
14
14
  export type RunTypeRelRow = readonly (RunTypeRel | readonly RunTypeRel[] | undefined)[];
@@ -56,7 +56,7 @@ type TupleFrom<R, K extends readonly (keyof R)[]> = {
56
56
  declare const ENTRY_HEAD_KEYS: readonly ["entryKind", "deps", "ini"];
57
57
  type RunTypeRowRequiredKeys = readonly ['id', 'kind'];
58
58
  type RunTypeRowTrimmedKeys = typeof RUN_TYPE_FIELD_KEYS extends readonly [unknown, unknown, ...infer Rest] ? Rest : never;
59
- export declare const RUN_TYPE_TUPLE_KEYS: readonly ["entryKind", "deps", "ini", "id", "kind", "subKind", "typeName", "name", "literal", "optional", "readonly", "isAbstract", "isStatic", "visibility", "isSafeName", "position", "isCircular", "flags", "description", "defaultVal", "enumVal", "values", "notSupported"];
59
+ export declare const RUN_TYPE_TUPLE_KEYS: readonly ["entryKind", "deps", "ini", "id", "kind", "subKind", "typeName", "name", "literal", "optional", "readonly", "isAbstract", "isStatic", "visibility", "isSafeName", "position", "isCircular", "flags", "description", "defaultVal", "enumVal", "values", "notSupported", "nonEnumerable"];
60
60
  export declare const RUN_TYPE_BUNDLE_TUPLE_KEYS: readonly ["entryKind", "deps", "ini", "key", "rows", "rels"];
61
61
  export declare const RUN_TYPE_FACADE_TUPLE_KEYS: readonly ["entryKind", "deps", "ini", "key"];
62
62
  declare const FN_TYPE_REQUIRED_KEYS: readonly ["familyTag", "deps", "ini", "rtFnHash", "typeName", "code"];
@@ -36,6 +36,7 @@ const RUN_TYPE_FIELD_KEYS = [
36
36
  'enumVal',
37
37
  'values',
38
38
  'notSupported',
39
+ 'nonEnumerable',
39
40
  ];
40
41
  const RUN_TYPE_REL_KEYS = [
41
42
  'child',
@@ -8,6 +8,7 @@ declare const rtUtils: {
8
8
  addToRTCache(comp: CompiledTypeFn): void;
9
9
  removeFromRTCache(comp: CompiledTypeFn): void;
10
10
  getRT(rtFnHash: string): InitializedTypeFn | undefined;
11
+ findRTForType(familyTag: string, typeId: string): InitializedTypeFn | undefined;
11
12
  getRTFn(rtFnHash: string): (...args: any[]) => any;
12
13
  hasRTFn(rtFnHash: string): boolean;
13
14
  addPureFn(key: string, compiledFn: CompiledPureFunction): CompiledPureFunction;
@@ -22,7 +23,7 @@ declare const rtUtils: {
22
23
  useRunType(id: string): RunType;
23
24
  hasRunType(id: string): boolean;
24
25
  alwaysThrowFactory(message: string): () => never;
25
- getClassSerializer(typeId: string): ClassSerializerEntry | undefined;
26
+ getClassSerializer(typeId: string, className?: string): ClassSerializerEntry | undefined;
26
27
  csEpoch(): number;
27
28
  deserializeClass<T>(entry: ClassSerializerEntry<T>, data: DataOnly<T>): T;
28
29
  };
@@ -31,6 +31,19 @@ const rtUtils = {
31
31
  materializeRTFn(entry);
32
32
  return entry;
33
33
  },
34
+ findRTForType(familyTag, typeId) {
35
+ const suffix = '_' + typeId;
36
+ for (const key of Object.keys(rtFnsCache)) {
37
+ if (!key.endsWith(suffix))
38
+ continue;
39
+ const entry = rtFnsCache[key];
40
+ if (!entry || entry.familyTag !== familyTag)
41
+ continue;
42
+ materializeRTFn(entry);
43
+ return entry;
44
+ }
45
+ return undefined;
46
+ },
34
47
  getRTFn(rtFnHash) {
35
48
  const entry = rtFnsCache[rtFnHash];
36
49
  if (!entry)
@@ -114,8 +127,8 @@ const rtUtils = {
114
127
  throw new Error(message);
115
128
  };
116
129
  },
117
- getClassSerializer(typeId) {
118
- return (0, classSerializerRegistry_ts_1.getClassSerializer)(typeId);
130
+ getClassSerializer(typeId, className) {
131
+ return (0, classSerializerRegistry_ts_1.getClassSerializer)(typeId, className);
119
132
  },
120
133
  csEpoch() {
121
134
  return (0, classSerializerRegistry_ts_1.classSerializerEpoch)();
@@ -25,6 +25,7 @@ export interface RunType<T = unknown> {
25
25
  literal?: unknown;
26
26
  optional?: unknown;
27
27
  readonly?: unknown;
28
+ nonEnumerable?: boolean;
28
29
  isAbstract?: unknown;
29
30
  isStatic?: unknown;
30
31
  visibility?: unknown;
@@ -0,0 +1,9 @@
1
+ import { FN_HASHES } from './fnHashes.generated.ts';
2
+ export type FnHashKey = keyof typeof FN_HASHES;
3
+ export interface FnHashOptions {
4
+ noLiterals?: boolean;
5
+ noIsArrayCheck?: boolean;
6
+ strategy?: string;
7
+ }
8
+ export declare function getFnHash(fnKey: FnHashKey | (string & {}), options?: FnHashOptions): string;
9
+ //# sourceMappingURL=fnHash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fnHash.d.ts","sourceRoot":"","sources":["../src/fnHash.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAC,SAAS,EAA4C,MAAM,yBAAyB,CAAC;AAK7F,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,SAAS,CAAC;AAO/C,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAuBD,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAS3F"}
package/dist/fnHash.js ADDED
@@ -0,0 +1,29 @@
1
+ import { FN_HASHES, VALIDATE_OPTION_LETTERS } from "./fnHashes.generated.js";
2
+ function validateVariantToken(options) {
3
+ if (!options)
4
+ return '';
5
+ let suffix = 'N';
6
+ let hit = false;
7
+ for (const [name, letter] of VALIDATE_OPTION_LETTERS) {
8
+ if (options[name]) {
9
+ suffix += letter;
10
+ hit = true;
11
+ }
12
+ }
13
+ return hit ? suffix : '';
14
+ }
15
+ export function getFnHash(fnKey, options) {
16
+ const entry = FN_HASHES[fnKey];
17
+ if (!entry)
18
+ throw new Error(`getFnHash: unknown fnKey ${JSON.stringify(fnKey)}`);
19
+ let token = '';
20
+ if (entry.axis === 'validateOptions')
21
+ token = validateVariantToken(options);
22
+ else if (entry.axis === 'jsonStrategy')
23
+ token = options?.strategy ?? entry.defaultVariant ?? '';
24
+ const hash = entry.variants[token];
25
+ if (hash === undefined)
26
+ throw new Error(`getFnHash: fnKey ${JSON.stringify(fnKey)} has no ${JSON.stringify(token)} variant`);
27
+ return hash;
28
+ }
29
+ //# sourceMappingURL=fnHash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fnHash.js","sourceRoot":"","sources":["../src/fnHash.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAC,SAAS,EAAE,uBAAuB,EAAmB,MAAM,yBAAyB,CAAC;AAsB7F,SAAS,oBAAoB,CAAC,OAAkC;IAC9D,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,IAAI,MAAM,GAAG,GAAG,CAAC;IACjB,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,uBAAuB,EAAE,CAAC;QACrD,IAAI,OAAO,CAAC,IAAuC,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,MAAM,CAAC;YACjB,GAAG,GAAG,IAAI,CAAC;QACb,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3B,CAAC;AAMD,MAAM,UAAU,SAAS,CAAC,KAAgC,EAAE,OAAuB;IACjF,MAAM,KAAK,GAAG,SAAS,CAAC,KAAkB,CAA4B,CAAC;IACvE,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACjF,IAAI,KAAK,GAAG,EAAE,CAAC;IACf,IAAI,KAAK,CAAC,IAAI,KAAK,iBAAiB;QAAE,KAAK,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;SACvE,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc;QAAE,KAAK,GAAG,OAAO,EAAE,QAAQ,IAAI,KAAK,CAAC,cAAc,IAAI,EAAE,CAAC;IAChG,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,IAAI,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC7H,OAAO,IAAI,CAAC;AACd,CAAC"}