zodbridge 0.2.0
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/LICENSE +21 -0
- package/README.md +361 -0
- package/dist/async/index.cjs +146 -0
- package/dist/async/index.cjs.map +1 -0
- package/dist/async/index.d.cts +49 -0
- package/dist/async/index.d.ts +49 -0
- package/dist/async/index.js +65 -0
- package/dist/async/index.js.map +1 -0
- package/dist/chunk-3HB2CM5G.js +213 -0
- package/dist/chunk-3HB2CM5G.js.map +1 -0
- package/dist/chunk-7DUCUUPF.js +274 -0
- package/dist/chunk-7DUCUUPF.js.map +1 -0
- package/dist/chunk-U3W6PGFE.js +241 -0
- package/dist/chunk-U3W6PGFE.js.map +1 -0
- package/dist/context-B0f9mQWu.d.cts +140 -0
- package/dist/context-B0f9mQWu.d.ts +140 -0
- package/dist/index.cjs +786 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +204 -0
- package/dist/index.d.ts +204 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/resolver/index.cjs +250 -0
- package/dist/resolver/index.cjs.map +1 -0
- package/dist/resolver/index.d.cts +101 -0
- package/dist/resolver/index.d.ts +101 -0
- package/dist/resolver/index.js +17 -0
- package/dist/resolver/index.js.map +1 -0
- package/dist/rules-msHkZDR8.d.cts +59 -0
- package/dist/rules-msHkZDR8.d.ts +59 -0
- package/dist/serialize/index.cjs +258 -0
- package/dist/serialize/index.cjs.map +1 -0
- package/dist/serialize/index.d.cts +84 -0
- package/dist/serialize/index.d.ts +84 -0
- package/dist/serialize/index.js +3 -0
- package/dist/serialize/index.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { R as Rule } from '../rules-msHkZDR8.js';
|
|
3
|
+
import { R as ResolverContext } from '../context-B0f9mQWu.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* `forwardAsync` — the async mapping path. Consumes a resolver graph (Phase 4)
|
|
7
|
+
* for `fromResolver` fields, honors a dynamic `select` set so only requested
|
|
8
|
+
* fields (and their resolver deps) do I/O, and validates with Zod
|
|
9
|
+
* `safeParseAsync` (so async `.refine` runs).
|
|
10
|
+
*
|
|
11
|
+
* Zod 4 constraint: `.pick()`/`.partial()` THROW on object schemas containing
|
|
12
|
+
* refinements, which is exactly the async-refined shape this targets. So a
|
|
13
|
+
* partial `select` is validated against a sub-schema built from the RAW
|
|
14
|
+
* `.shape` (`z.object(pickedShape)`), never by calling `.pick()` on the refined
|
|
15
|
+
* wrapper. Field-level refines on selected fields still run; object-level
|
|
16
|
+
* cross-field refines run only on a full select (documented limitation).
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** Thrown when `select` names a key absent from the dest schema. */
|
|
20
|
+
declare class UnknownSelectKeyError extends Error {
|
|
21
|
+
readonly keys: string[];
|
|
22
|
+
constructor(keys: string[]);
|
|
23
|
+
}
|
|
24
|
+
type AnyZodObject = z.ZodObject<any>;
|
|
25
|
+
interface ForwardAsyncMap<S extends AnyZodObject> {
|
|
26
|
+
readonly schema: S;
|
|
27
|
+
readonly rules: Record<string, Rule | undefined>;
|
|
28
|
+
readonly shape: Record<string, z.ZodType>;
|
|
29
|
+
}
|
|
30
|
+
interface ForwardAsyncOptions<Fields, TAdapter> {
|
|
31
|
+
resolver: ResolverContext<Fields, TAdapter>;
|
|
32
|
+
/** Only these dest keys are computed; unselected resolvers never fire. */
|
|
33
|
+
select?: string[];
|
|
34
|
+
/** Opaque extra passed to sync function rules via the source (unused hook). */
|
|
35
|
+
context?: unknown;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Validate and de-duplicate a `select` list against the dest shape.
|
|
39
|
+
* Unknown keys -> typed {@link UnknownSelectKeyError} (never a raw Zod trace).
|
|
40
|
+
*/
|
|
41
|
+
declare function normalizeSelect(select: string[] | undefined, shape: Record<string, z.ZodType>): string[] | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Build a validated DTO asynchronously. `fromResolver` fields pull from the
|
|
44
|
+
* resolver; a resolver throw rejects the whole promise (fail-fast). Returns the
|
|
45
|
+
* full DTO, or a `Partial<Dto>` when `select` is given.
|
|
46
|
+
*/
|
|
47
|
+
declare function forwardAsync<S extends AnyZodObject, Fields, TAdapter>(map: ForwardAsyncMap<S>, source: Record<string, unknown>, options: ForwardAsyncOptions<Fields, TAdapter>): Promise<Partial<z.infer<S>>>;
|
|
48
|
+
|
|
49
|
+
export { type ForwardAsyncOptions, UnknownSelectKeyError, forwardAsync, normalizeSelect };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { applyForwardRule } from '../chunk-3HB2CM5G.js';
|
|
2
|
+
import { isFromResolverRule, setPath } from '../chunk-7DUCUUPF.js';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
|
|
5
|
+
var UnknownSelectKeyError = class extends Error {
|
|
6
|
+
keys;
|
|
7
|
+
constructor(keys) {
|
|
8
|
+
super(
|
|
9
|
+
`forwardAsync select contains key(s) not in the dest schema: ${keys.join(", ")}`
|
|
10
|
+
);
|
|
11
|
+
this.name = "UnknownSelectKeyError";
|
|
12
|
+
this.keys = keys;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
function normalizeSelect(select, shape) {
|
|
16
|
+
if (select === void 0) return void 0;
|
|
17
|
+
const deduped = Array.from(new Set(select));
|
|
18
|
+
const unknown = deduped.filter(
|
|
19
|
+
(k) => !Object.prototype.hasOwnProperty.call(shape, k)
|
|
20
|
+
);
|
|
21
|
+
if (unknown.length > 0) throw new UnknownSelectKeyError(unknown);
|
|
22
|
+
return deduped;
|
|
23
|
+
}
|
|
24
|
+
async function stripField(value, fieldSchema) {
|
|
25
|
+
const result = await fieldSchema.safeParseAsync(value);
|
|
26
|
+
if (!result.success) return value;
|
|
27
|
+
return result.data;
|
|
28
|
+
}
|
|
29
|
+
async function forwardAsync(map, source, options) {
|
|
30
|
+
const { resolver, select } = options;
|
|
31
|
+
const { schema, rules, shape } = map;
|
|
32
|
+
const selected = normalizeSelect(select, shape);
|
|
33
|
+
const targetKeys = selected ?? Object.keys(shape);
|
|
34
|
+
const assembled = {};
|
|
35
|
+
for (const key of targetKeys) {
|
|
36
|
+
const rule = rules[key];
|
|
37
|
+
if (isFromResolverRule(rule)) {
|
|
38
|
+
const field = rule.field;
|
|
39
|
+
const raw = await resolver.resolve(field);
|
|
40
|
+
if (raw !== void 0) {
|
|
41
|
+
const value2 = await stripField(raw, shape[key]);
|
|
42
|
+
setPath(assembled, key, value2);
|
|
43
|
+
}
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const produced = applyForwardRule(rule, key, source);
|
|
47
|
+
const value = produced instanceof Promise ? await produced : produced;
|
|
48
|
+
if (value !== void 0) setPath(assembled, key, value);
|
|
49
|
+
}
|
|
50
|
+
const validator = selected === void 0 ? schema : buildSubSchema(shape, selected);
|
|
51
|
+
const result = await validator.safeParseAsync(assembled);
|
|
52
|
+
if (!result.success) throw result.error;
|
|
53
|
+
return result.data;
|
|
54
|
+
}
|
|
55
|
+
function buildSubSchema(shape, selected) {
|
|
56
|
+
const picked = {};
|
|
57
|
+
for (const key of selected) {
|
|
58
|
+
picked[key] = shape[key];
|
|
59
|
+
}
|
|
60
|
+
return z.object(picked);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { UnknownSelectKeyError, forwardAsync, normalizeSelect };
|
|
64
|
+
//# sourceMappingURL=index.js.map
|
|
65
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/async/forwardAsync.ts"],"names":["value"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * `forwardAsync` — the async mapping path. Consumes a resolver graph (Phase 4)\n * for `fromResolver` fields, honors a dynamic `select` set so only requested\n * fields (and their resolver deps) do I/O, and validates with Zod\n * `safeParseAsync` (so async `.refine` runs).\n *\n * Zod 4 constraint: `.pick()`/`.partial()` THROW on object schemas containing\n * refinements, which is exactly the async-refined shape this targets. So a\n * partial `select` is validated against a sub-schema built from the RAW\n * `.shape` (`z.object(pickedShape)`), never by calling `.pick()` on the refined\n * wrapper. Field-level refines on selected fields still run; object-level\n * cross-field refines run only on a full select (documented limitation).\n */\nimport { z } from \"zod\";\nimport { applyForwardRule } from \"../map/createMap.js\";\nimport {\n type FromResolver,\n type Rule,\n isFromResolverRule,\n setPath,\n} from \"../map/rules.js\";\nimport type { ResolverContext } from \"../resolver/context.js\";\n\n/** Thrown when `select` names a key absent from the dest schema. */\nexport class UnknownSelectKeyError extends Error {\n readonly keys: string[];\n constructor(keys: string[]) {\n super(\n `forwardAsync select contains key(s) not in the dest schema: ${keys.join(\", \")}`,\n );\n this.name = \"UnknownSelectKeyError\";\n this.keys = keys;\n }\n}\n\ntype AnyZodObject = z.ZodObject<any>;\n\ninterface ForwardAsyncMap<S extends AnyZodObject> {\n readonly schema: S;\n readonly rules: Record<string, Rule | undefined>;\n readonly shape: Record<string, z.ZodType>;\n}\n\nexport interface ForwardAsyncOptions<Fields, TAdapter> {\n resolver: ResolverContext<Fields, TAdapter>;\n /** Only these dest keys are computed; unselected resolvers never fire. */\n select?: string[];\n /** Opaque extra passed to sync function rules via the source (unused hook). */\n context?: unknown;\n}\n\n/**\n * Validate and de-duplicate a `select` list against the dest shape.\n * Unknown keys -> typed {@link UnknownSelectKeyError} (never a raw Zod trace).\n */\nexport function normalizeSelect(\n select: string[] | undefined,\n shape: Record<string, z.ZodType>,\n): string[] | undefined {\n if (select === undefined) return undefined;\n const deduped = Array.from(new Set(select));\n const unknown = deduped.filter(\n (k) => !Object.prototype.hasOwnProperty.call(shape, k),\n );\n if (unknown.length > 0) throw new UnknownSelectKeyError(unknown);\n return deduped;\n}\n\n/**\n * Strip a resolver-produced value through its own dest field sub-schema so\n * unknown adapter-row keys (e.g. `passwordHash`) are dropped. NOTE: a field\n * typed `z.any()`/`.passthrough()`/`z.record()` disables this — those leak the\n * value verbatim by design (documented in the README security section).\n */\nasync function stripField(value: unknown, fieldSchema: z.ZodType): Promise<unknown> {\n const result = await fieldSchema.safeParseAsync(value);\n if (!result.success) return value; // let the full validation surface the error\n return result.data;\n}\n\n/**\n * Build a validated DTO asynchronously. `fromResolver` fields pull from the\n * resolver; a resolver throw rejects the whole promise (fail-fast). Returns the\n * full DTO, or a `Partial<Dto>` when `select` is given.\n */\nexport async function forwardAsync<S extends AnyZodObject, Fields, TAdapter>(\n map: ForwardAsyncMap<S>,\n source: Record<string, unknown>,\n options: ForwardAsyncOptions<Fields, TAdapter>,\n): Promise<Partial<z.infer<S>>> {\n const { resolver, select } = options;\n const { schema, rules, shape } = map;\n\n const selected = normalizeSelect(select, shape);\n const targetKeys = selected ?? Object.keys(shape);\n\n // Fields resolve sequentially (await per key). The resolver's promise-cache\n // (Phase 4) makes Promise.all safe too, but sequential keeps resolver\n // invocations non-overlapping and is the documented default.\n const assembled: Record<string, unknown> = {};\n for (const key of targetKeys) {\n const rule = rules[key];\n if (isFromResolverRule(rule as Rule)) {\n const field = (rule as FromResolver).field;\n // A resolver throw propagates out of forwardAsync (fail-fast).\n const raw = await resolver.resolve(field as keyof Fields);\n if (raw !== undefined) {\n // `key` is always a key of `shape` (it came from shape keys or a\n // select list validated against shape), so its field schema exists.\n const value = await stripField(raw, shape[key] as z.ZodType);\n setPath(assembled, key, value);\n }\n continue;\n }\n // Sync/computed rules reuse the Phase 3 primitive; an async function rule\n // returns a promise, which we await.\n const produced = applyForwardRule(rule, key, source);\n const value = produced instanceof Promise ? await produced : produced;\n if (value !== undefined) setPath(assembled, key, value);\n }\n\n // Validate. Full select -> the original schema (all refines run). Partial\n // select -> a sub-schema built from raw .shape (avoids .pick on refined).\n const validator =\n selected === undefined ? schema : buildSubSchema(shape, selected);\n const result = await validator.safeParseAsync(assembled);\n if (!result.success) throw result.error;\n return result.data as Partial<z.infer<S>>;\n}\n\n/**\n * Construct a partial-select validator from the dest schema's raw `.shape`,\n * via `z.object(pickedShape)`. Refined wrappers are never `.pick()`-ed (which\n * throws in Zod 4); object-level cross-field refines are intentionally omitted\n * here and run only on a full select.\n */\nfunction buildSubSchema(\n shape: Record<string, z.ZodType>,\n selected: string[],\n): z.ZodType {\n const picked: Record<string, z.ZodType> = {};\n for (const key of selected) {\n // `selected` was validated against `shape` by normalizeSelect, so each\n // key is present.\n picked[key] = shape[key] as z.ZodType;\n }\n return z.object(picked);\n}\n"]}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { getPath, isStringRule, isPairRule, isDefaultRule, isFnRule, isFromResolverRule, setPath, createResolver } from './chunk-7DUCUUPF.js';
|
|
2
|
+
|
|
3
|
+
// src/map/case-convert.ts
|
|
4
|
+
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
|
|
5
|
+
function splitWords(key) {
|
|
6
|
+
return key.replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Za-z])(\d)/g, "$1 $2").split(/[^A-Za-z0-9]+/).filter((w) => w.length > 0).map((w) => w.toLowerCase());
|
|
7
|
+
}
|
|
8
|
+
function toSnakeKey(key) {
|
|
9
|
+
const words = splitWords(key);
|
|
10
|
+
if (words.length === 0) return key;
|
|
11
|
+
return words.join("_");
|
|
12
|
+
}
|
|
13
|
+
function toCamelKey(key) {
|
|
14
|
+
const words = splitWords(key);
|
|
15
|
+
if (words.length === 0) return key;
|
|
16
|
+
return words.map((word, i) => i === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
17
|
+
}
|
|
18
|
+
function isPlainObject(value) {
|
|
19
|
+
if (value === null || typeof value !== "object") return false;
|
|
20
|
+
const proto = Object.getPrototypeOf(value);
|
|
21
|
+
return proto === Object.prototype || proto === null;
|
|
22
|
+
}
|
|
23
|
+
function convert(value, keyFn) {
|
|
24
|
+
if (Array.isArray(value)) {
|
|
25
|
+
return value.map((item) => convert(item, keyFn));
|
|
26
|
+
}
|
|
27
|
+
if (isPlainObject(value)) {
|
|
28
|
+
const out = {};
|
|
29
|
+
for (const key of Object.keys(value)) {
|
|
30
|
+
const converted = keyFn(key);
|
|
31
|
+
if (FORBIDDEN_KEYS.has(converted)) continue;
|
|
32
|
+
out[converted] = convert(value[key], keyFn);
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
function toSnakeCase(value) {
|
|
39
|
+
return convert(value, toSnakeKey);
|
|
40
|
+
}
|
|
41
|
+
function toCamelCase(value) {
|
|
42
|
+
return convert(value, toCamelKey);
|
|
43
|
+
}
|
|
44
|
+
var capitalize = (word) => word.charAt(0).toUpperCase() + word.slice(1);
|
|
45
|
+
function toKebabKey(key) {
|
|
46
|
+
const words = splitWords(key);
|
|
47
|
+
if (words.length === 0) return key;
|
|
48
|
+
return words.join("-");
|
|
49
|
+
}
|
|
50
|
+
function toPascalKey(key) {
|
|
51
|
+
const words = splitWords(key);
|
|
52
|
+
if (words.length === 0) return key;
|
|
53
|
+
return words.map(capitalize).join("");
|
|
54
|
+
}
|
|
55
|
+
function toConstantKey(key) {
|
|
56
|
+
const words = splitWords(key);
|
|
57
|
+
if (words.length === 0) return key;
|
|
58
|
+
return words.join("_").toUpperCase();
|
|
59
|
+
}
|
|
60
|
+
function toKebabCase(value) {
|
|
61
|
+
return convert(value, toKebabKey);
|
|
62
|
+
}
|
|
63
|
+
function toPascalCase(value) {
|
|
64
|
+
return convert(value, toPascalKey);
|
|
65
|
+
}
|
|
66
|
+
function toConstantCase(value) {
|
|
67
|
+
return convert(value, toConstantKey);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/map/map-ops.ts
|
|
71
|
+
function forwardMany(map, sources) {
|
|
72
|
+
return sources.map((s) => map.forward(s));
|
|
73
|
+
}
|
|
74
|
+
function reverseMany(map, dtos) {
|
|
75
|
+
return dtos.map((d) => map.reverse(d));
|
|
76
|
+
}
|
|
77
|
+
function safeForward(map, source) {
|
|
78
|
+
try {
|
|
79
|
+
return { success: true, data: map.forward(source) };
|
|
80
|
+
} catch (err) {
|
|
81
|
+
if (isZodError(err)) return { success: false, error: err };
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function isZodError(err) {
|
|
86
|
+
return typeof err === "object" && err !== null && err.name === "ZodError" && Array.isArray(err.issues);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/map/createMap.ts
|
|
90
|
+
var OneWayRuleError = class extends Error {
|
|
91
|
+
key;
|
|
92
|
+
constructor(key) {
|
|
93
|
+
super(
|
|
94
|
+
`Cannot reverse dest key "${key}": it is mapped by a one-way function rule. Use a { to, from } pair rule to make it reversible.`
|
|
95
|
+
);
|
|
96
|
+
this.name = "OneWayRuleError";
|
|
97
|
+
this.key = key;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
var MapHasNoResolversError = class extends Error {
|
|
101
|
+
constructor() {
|
|
102
|
+
super(
|
|
103
|
+
"createMap.toResolver requires a resolver graph: pass `createMap(schema, rules, { resolvers })`."
|
|
104
|
+
);
|
|
105
|
+
this.name = "MapHasNoResolversError";
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
var ReverseKeyCollisionError = class extends Error {
|
|
109
|
+
constructor(sourceKey, a, b) {
|
|
110
|
+
super(
|
|
111
|
+
`Reverse-key collision: dest keys "${a}" and "${b}" both map back to source key "${sourceKey}". Disambiguate one of them.`
|
|
112
|
+
);
|
|
113
|
+
this.name = "ReverseKeyCollisionError";
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
function applyForwardRule(rule, destKey, source) {
|
|
117
|
+
if (rule === void 0) {
|
|
118
|
+
return getPath(source, destKey);
|
|
119
|
+
}
|
|
120
|
+
if (isStringRule(rule)) {
|
|
121
|
+
return getPath(source, rule);
|
|
122
|
+
}
|
|
123
|
+
if (isPairRule(rule)) {
|
|
124
|
+
return rule.to(source);
|
|
125
|
+
}
|
|
126
|
+
if (isDefaultRule(rule)) {
|
|
127
|
+
const read = getPath(source, rule.source ?? destKey);
|
|
128
|
+
return read === void 0 ? rule.value : read;
|
|
129
|
+
}
|
|
130
|
+
if (isFnRule(rule)) {
|
|
131
|
+
return rule(source);
|
|
132
|
+
}
|
|
133
|
+
return void 0;
|
|
134
|
+
}
|
|
135
|
+
function createMap(schema, rules = {}, options = {}) {
|
|
136
|
+
const shape = schema.shape;
|
|
137
|
+
const destKeys = Object.keys(shape);
|
|
138
|
+
const mapResolvers = options.resolvers;
|
|
139
|
+
const reverseTargets = /* @__PURE__ */ new Map();
|
|
140
|
+
for (const destKey of Object.keys(rules)) {
|
|
141
|
+
const rule = rules[destKey];
|
|
142
|
+
if (rule !== void 0 && isStringRule(rule)) {
|
|
143
|
+
const existing = reverseTargets.get(rule);
|
|
144
|
+
if (existing) throw new ReverseKeyCollisionError(rule, existing, destKey);
|
|
145
|
+
reverseTargets.set(rule, destKey);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
function forward(source) {
|
|
149
|
+
const out = {};
|
|
150
|
+
for (const destKey of destKeys) {
|
|
151
|
+
const rule = rules[destKey];
|
|
152
|
+
if (isFromResolverRule(rule)) continue;
|
|
153
|
+
const value = applyForwardRule(rule, destKey, source);
|
|
154
|
+
if (value !== void 0) setPath(out, destKey, value);
|
|
155
|
+
}
|
|
156
|
+
return schema.parse(out);
|
|
157
|
+
}
|
|
158
|
+
function reverse(dto) {
|
|
159
|
+
const out = {};
|
|
160
|
+
const dtoObj = dto;
|
|
161
|
+
for (const destKey of Object.keys(rules)) {
|
|
162
|
+
const rule = rules[destKey];
|
|
163
|
+
if (rule === void 0) continue;
|
|
164
|
+
const destValue = getPath(dtoObj, destKey);
|
|
165
|
+
if (isStringRule(rule)) {
|
|
166
|
+
setPath(out, rule, destValue);
|
|
167
|
+
} else if (isPairRule(rule)) {
|
|
168
|
+
setPath(out, destKey, rule.from(destValue));
|
|
169
|
+
} else if (isDefaultRule(rule)) {
|
|
170
|
+
setPath(out, rule.source ?? destKey, destValue);
|
|
171
|
+
} else if (isFromResolverRule(rule)) {
|
|
172
|
+
continue;
|
|
173
|
+
} else {
|
|
174
|
+
throw new OneWayRuleError(destKey);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return out;
|
|
178
|
+
}
|
|
179
|
+
function toResolver(adapter, seed) {
|
|
180
|
+
if (!mapResolvers) {
|
|
181
|
+
throw new MapHasNoResolversError();
|
|
182
|
+
}
|
|
183
|
+
const schemas = {};
|
|
184
|
+
for (const key of Object.keys(shape)) {
|
|
185
|
+
schemas[key] = shape[key];
|
|
186
|
+
}
|
|
187
|
+
return createResolver({
|
|
188
|
+
adapter,
|
|
189
|
+
seed,
|
|
190
|
+
resolvers: mapResolvers,
|
|
191
|
+
schemas
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
const mapper = {
|
|
195
|
+
forward,
|
|
196
|
+
reverse,
|
|
197
|
+
forwardMany: (sources) => forwardMany(mapper, sources),
|
|
198
|
+
reverseMany: (dtos) => reverseMany(mapper, dtos),
|
|
199
|
+
safeForward: (source) => safeForward(mapper, source),
|
|
200
|
+
toSnakeCase,
|
|
201
|
+
toCamelCase,
|
|
202
|
+
toResolver,
|
|
203
|
+
schema,
|
|
204
|
+
rules: Object.freeze({ ...rules }),
|
|
205
|
+
shape,
|
|
206
|
+
resolvers: mapResolvers
|
|
207
|
+
};
|
|
208
|
+
return mapper;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export { MapHasNoResolversError, OneWayRuleError, ReverseKeyCollisionError, applyForwardRule, createMap, forwardMany, reverseMany, safeForward, splitWords, toCamelCase, toCamelKey, toConstantCase, toConstantKey, toKebabCase, toKebabKey, toPascalCase, toPascalKey, toSnakeCase, toSnakeKey };
|
|
212
|
+
//# sourceMappingURL=chunk-3HB2CM5G.js.map
|
|
213
|
+
//# sourceMappingURL=chunk-3HB2CM5G.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/map/case-convert.ts","../src/map/map-ops.ts","../src/map/createMap.ts"],"names":[],"mappings":"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","file":"chunk-3HB2CM5G.js","sourcesContent":["/**\n * Recursive object-key case conversion. `toSnakeCase`/`toCamelCase` re-case ALL\n * property keys of a value to the target case regardless of the input keys'\n * original casing (snake, camel, Pascal, kebab, SCREAMING_SNAKE all normalize).\n *\n * Only KEYS change. Values pass through untouched; recursion descends plain\n * objects and arrays only — Dates, Maps, Sets, class instances, and primitives\n * are returned as-is so their internal data is never reshaped.\n */\n\n/** Keys that would poison `Object.prototype` — never emitted as output keys. */\nconst FORBIDDEN_KEYS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\n\n/**\n * Split an identifier into lowercase word tokens, the casing-neutral form every\n * target case is rebuilt from. Handles delimiters (`_`, `-`, space), camel/Pascal\n * humps, acronym runs (`HTTPServer` -> `http`,`server`), and digit groups.\n */\nexport function splitWords(key: string): string[] {\n return (\n key\n // acronym followed by a word: \"HTTPServer\" -> \"HTTP Server\"\n .replace(/([A-Z]+)([A-Z][a-z])/g, \"$1 $2\")\n // lower/digit followed by upper: \"fooBar\"/\"foo2Bar\" -> \"foo Bar\"\n .replace(/([a-z\\d])([A-Z])/g, \"$1 $2\")\n // letter followed by digit group: \"v2\" -> \"v 2\"\n .replace(/([A-Za-z])(\\d)/g, \"$1 $2\")\n // any non-alphanumeric run is a delimiter\n .split(/[^A-Za-z0-9]+/)\n .filter((w) => w.length > 0)\n .map((w) => w.toLowerCase())\n );\n}\n\n/** Convert a single key to `snake_case`; leave unconvertible keys untouched. */\nexport function toSnakeKey(key: string): string {\n const words = splitWords(key);\n // Nothing tokenizable (e.g. \"$$$\", \"_\") -> leave the key as-is rather than\n // collapsing it to \"\" and losing the property.\n if (words.length === 0) return key;\n return words.join(\"_\");\n}\n\n/** Convert a single key to `camelCase`; leave unconvertible keys untouched. */\nexport function toCamelKey(key: string): string {\n const words = splitWords(key);\n if (words.length === 0) return key;\n return words\n .map((word, i) => (i === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1)))\n .join(\"\");\n}\n\n/** True only for plain objects (own data records), not Date/Map/Set/class instances. */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nfunction convert(value: unknown, keyFn: (key: string) => string): unknown {\n if (Array.isArray(value)) {\n return value.map((item) => convert(item, keyFn));\n }\n if (isPlainObject(value)) {\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(value)) {\n const converted = keyFn(key);\n if (FORBIDDEN_KEYS.has(converted)) continue;\n out[converted] = convert(value[key], keyFn);\n }\n return out;\n }\n // Primitives, Date, Map, Set, class instances: returned unchanged.\n return value;\n}\n\n// --- type-level key re-casing ---\n//\n// These mapped types model the COMMON case — camelCase/PascalCase <-> snake_case\n// on plain identifier keys (`firstName` <-> `first_name`). They intentionally do\n// NOT replicate the full runtime tokenizer: acronym grouping (`HTTPServer`),\n// digit boundaries, kebab/space delimiters, and multiple leading underscores\n// (`__id`) can yield a type that differs from the runtime key. For normal DTO\n// keys the type is exact; for these exotic cases the runtime is authoritative.\n// Values are preserved (only keys change), and Date/Map/Set/array/primitive are\n// passed through untouched.\n\n/** Insert `_` before each interior uppercase letter, then lowercase. */\ntype CamelToSnake<S extends string> = S extends `${infer Head}${infer Tail}`\n ? Head extends Uppercase<Head>\n ? Head extends Lowercase<Head>\n ? `${Head}${CamelToSnake<Tail>}` // digit/symbol: no separator\n : `_${Lowercase<Head>}${CamelToSnake<Tail>}`\n : `${Head}${CamelToSnake<Tail>}`\n : S;\n\n/** Drop a single leading `_` produced when the first letter was uppercase. */\ntype StripLeadingUnderscore<S extends string> = S extends `_${infer Rest}` ? Rest : S;\n\ntype SnakeKey<S extends string> = StripLeadingUnderscore<CamelToSnake<S>>;\n\n/** Collapse `_x` groups into `X` (snake/kebab -> camelCase). */\ntype SnakeToCamel<S extends string> = S extends `${infer Head}_${infer Tail}`\n ? `${Head}${Capitalize<SnakeToCamel<Tail>>}`\n : S extends `${infer Head}-${infer Tail}`\n ? `${Head}${Capitalize<SnakeToCamel<Tail>>}`\n : S;\n\n/** Public type of {@link toSnakeCase}: keys recursively snake_cased. */\nexport type SnakeCased<T> = T extends Array<infer E>\n ? Array<SnakeCased<E>>\n : T extends Date | Map<unknown, unknown> | Set<unknown>\n ? T\n : T extends object\n ? { [K in keyof T as K extends string ? SnakeKey<K> : K]: SnakeCased<T[K]> }\n : T;\n\n/** Public type of {@link toCamelCase}: keys recursively camelCased. */\nexport type CamelCased<T> = T extends Array<infer E>\n ? Array<CamelCased<E>>\n : T extends Date | Map<unknown, unknown> | Set<unknown>\n ? T\n : T extends object\n ? { [K in keyof T as K extends string ? SnakeToCamel<K> : K]: CamelCased<T[K]> }\n : T;\n\n/**\n * Recursively re-case all property keys of `value` to `snake_case`. The return\n * type maps keys for the common identifier case (see {@link SnakeCased}).\n */\nexport function toSnakeCase<T>(value: T): SnakeCased<T> {\n return convert(value, toSnakeKey) as SnakeCased<T>;\n}\n\n/**\n * Recursively re-case all property keys of `value` to `camelCase`. The return\n * type maps keys for the common identifier case (see {@link CamelCased}).\n */\nexport function toCamelCase<T>(value: T): CamelCased<T> {\n return convert(value, toCamelKey) as CamelCased<T>;\n}\n\nconst capitalize = (word: string): string =>\n word.charAt(0).toUpperCase() + word.slice(1);\n\n/** Convert a single key to `kebab-case`; leave unconvertible keys untouched. */\nexport function toKebabKey(key: string): string {\n const words = splitWords(key);\n if (words.length === 0) return key;\n return words.join(\"-\");\n}\n\n/** Convert a single key to `PascalCase`; leave unconvertible keys untouched. */\nexport function toPascalKey(key: string): string {\n const words = splitWords(key);\n if (words.length === 0) return key;\n return words.map(capitalize).join(\"\");\n}\n\n/** Convert a single key to `CONSTANT_CASE`; leave unconvertible keys untouched. */\nexport function toConstantKey(key: string): string {\n const words = splitWords(key);\n if (words.length === 0) return key;\n return words.join(\"_\").toUpperCase();\n}\n\n/** Recursively re-case all property keys of `value` to `kebab-case`. */\nexport function toKebabCase<T = unknown>(value: T): T {\n return convert(value, toKebabKey) as T;\n}\n\n/** Recursively re-case all property keys of `value` to `PascalCase`. */\nexport function toPascalCase<T = unknown>(value: T): T {\n return convert(value, toPascalKey) as T;\n}\n\n/** Recursively re-case all property keys of `value` to `CONSTANT_CASE`. */\nexport function toConstantCase<T = unknown>(value: T): T {\n return convert(value, toConstantKey) as T;\n}\n","/**\n * Composable operations over a {@link TypeMapper}: batch mapping, safe (non-throwing)\n * forward, sub-DTO views (pick/omit), and map composition. Kept out of\n * `createMap.ts` to respect the per-file size budget; `createMap` attaches thin\n * instance wrappers so these are available as both methods and free functions.\n */\nimport type { z } from \"zod\";\n\n/** Minimal mapper shape these ops need (avoids importing the full createMap type cycle). */\nexport interface MappableForward {\n forward(source: Record<string, unknown>): unknown;\n reverse(dto: unknown): Partial<Record<string, unknown>>;\n readonly schema: z.ZodObject<any>;\n}\n\n/** Result of {@link safeForward}: a discriminated success/failure union. */\nexport type SafeResult<T> =\n | { success: true; data: T }\n | { success: false; error: z.ZodError };\n\n/** Forward every item in `sources`, returning the validated DTO array. */\nexport function forwardMany<M extends MappableForward>(\n map: M,\n sources: Array<Record<string, unknown>>,\n): Array<ReturnType<M[\"forward\"]>> {\n return sources.map((s) => map.forward(s)) as Array<ReturnType<M[\"forward\"]>>;\n}\n\n/** Reverse every DTO in `dtos`, returning the mapped-source array. */\nexport function reverseMany<M extends MappableForward>(\n map: M,\n dtos: unknown[],\n): Array<Partial<Record<string, unknown>>> {\n return dtos.map((d) => map.reverse(d));\n}\n\n/**\n * Forward without throwing: returns `{ success: true, data }` or, on a Zod\n * validation failure, `{ success: false, error }`. Non-Zod errors still throw.\n */\nexport function safeForward<M extends MappableForward>(\n map: M,\n source: Record<string, unknown>,\n): SafeResult<ReturnType<M[\"forward\"]>> {\n try {\n return { success: true, data: map.forward(source) as ReturnType<M[\"forward\"]> };\n } catch (err) {\n if (isZodError(err)) return { success: false, error: err };\n throw err;\n }\n}\n\nfunction isZodError(err: unknown): err is z.ZodError {\n return (\n typeof err === \"object\" &&\n err !== null &&\n (err as { name?: string }).name === \"ZodError\" &&\n Array.isArray((err as { issues?: unknown }).issues)\n );\n}\n","/**\n * `createMap(destSchema, rules)` — synchronous, Zod-validated entity -> DTO\n * mapper. The dest Zod schema is the shape source of truth. Simple string\n * renames and `{ to, from }` pairs auto-reverse; computed function rules are\n * one-way unless paired.\n */\nimport type { z } from \"zod\";\nimport { createResolver } from \"../resolver/createResolver.js\";\nimport type { ResolverContext, ResolverRegistry } from \"../resolver/context.js\";\nimport {\n type CamelCased,\n type SnakeCased,\n toCamelCase,\n toSnakeCase,\n} from \"./case-convert.js\";\nimport {\n type SafeResult,\n forwardMany as forwardManyOp,\n reverseMany as reverseManyOp,\n safeForward as safeForwardOp,\n} from \"./map-ops.js\";\nimport {\n type DefaultRule,\n type FromResolver,\n type Rule,\n getPath,\n isDefaultRule,\n isFnRule,\n isFromResolverRule,\n isPairRule,\n isStringRule,\n setPath,\n} from \"./rules.js\";\n\n/**\n * Resolver graph declared on a map: each field of the dest DTO `Dest` may have\n * a resolver typed against `Dest` and the adapter `TAdapter`.\n */\nexport type MapResolvers<Dest = Record<string, unknown>, TAdapter = unknown> =\n ResolverRegistry<Dest, TAdapter>;\n\n/** Options for {@link createMap}, parameterized by the dest DTO and adapter type. */\nexport interface CreateMapOptions<Dest = Record<string, unknown>, TAdapter = unknown> {\n /**\n * Resolver graph for this map's fields, against the map's own dest schema.\n * Enables `map.toResolver(adapter)` and resolver-backed `forwardAsync` without\n * a separate `createResolver` call. Each resolver's output is typed against the\n * DTO field it produces. NOTE: `ctx.adapter` is typed as the concrete adapter\n * only at the `toResolver(adapter)` call site — inside these declarations it is\n * `unknown` (the adapter is not known at `createMap` time); cast it if needed.\n */\n resolvers?: MapResolvers<Dest, TAdapter>;\n}\n\n/** Thrown when `reverse` meets a one-way function rule that has no inverse. */\nexport class OneWayRuleError extends Error {\n readonly key: string;\n constructor(key: string) {\n super(\n `Cannot reverse dest key \"${key}\": it is mapped by a one-way function ` +\n `rule. Use a { to, from } pair rule to make it reversible.`,\n );\n this.name = \"OneWayRuleError\";\n this.key = key;\n }\n}\n\n/** Thrown when `toResolver` is called on a map that declared no resolvers. */\nexport class MapHasNoResolversError extends Error {\n constructor() {\n super(\n \"createMap.toResolver requires a resolver graph: pass \" +\n \"`createMap(schema, rules, { resolvers })`.\",\n );\n this.name = \"MapHasNoResolversError\";\n }\n}\n\n/** Thrown at build time when two rules reverse onto the same source key. */\nexport class ReverseKeyCollisionError extends Error {\n constructor(sourceKey: string, a: string, b: string) {\n super(\n `Reverse-key collision: dest keys \"${a}\" and \"${b}\" both map back to ` +\n `source key \"${sourceKey}\". Disambiguate one of them.`,\n );\n this.name = \"ReverseKeyCollisionError\";\n }\n}\n\ntype AnyZodObject = z.ZodObject<any>;\n\n/** Rule map: each dest key may carry a rule; unmapped keys are copied by name. */\nexport type RuleMap<Dest> = Partial<Record<keyof Dest & string, Rule>>;\n\nexport interface TypeMapper<S extends AnyZodObject, R extends RuleMap<z.infer<S>>> {\n /** Build a validated DTO from a source entity (sync path). */\n forward(source: Record<string, unknown>): z.infer<S>;\n /** Forward every item in a list, returning the validated DTO array. */\n forwardMany(sources: Array<Record<string, unknown>>): Array<z.infer<S>>;\n /** Forward without throwing: `{ success, data }` or `{ success: false, error }`. */\n safeForward(source: Record<string, unknown>): SafeResult<z.infer<S>>;\n /** Invert reversible rules; returns only mapped source fields. */\n reverse(dto: z.infer<S>): Partial<Record<string, unknown>>;\n /** Reverse every DTO in a list. */\n reverseMany(dtos: Array<z.infer<S>>): Array<Partial<Record<string, unknown>>>;\n /**\n * Recursively re-case ALL property keys of `value` to `snake_case`,\n * regardless of their original casing. Keys only; values pass through.\n */\n toSnakeCase<T>(value: T): SnakeCased<T>;\n /**\n * Recursively re-case ALL property keys of `value` to `camelCase`,\n * regardless of their original casing. Keys only; values pass through.\n */\n toCamelCase<T>(value: T): CamelCased<T>;\n /**\n * Build a resolver graph from THIS map's schema fields plus the resolver\n * graph declared in `createMap`'s options. The resolver validates each field's\n * output against the matching dest sub-schema (over-exposure protection).\n * Throws if no `resolvers` were declared on the map.\n */\n toResolver<TAdapter>(\n adapter: TAdapter,\n seed?: Partial<z.infer<S>>,\n ): ResolverContext<z.infer<S>, TAdapter>;\n /** The dest schema (shape source of truth). */\n readonly schema: S;\n /** Configured rules, frozen. */\n readonly rules: R;\n /** Raw `.shape` of the dest object — used by the async path (Phase 5). */\n readonly shape: Record<string, z.ZodType>;\n /** Resolver graph declared on this map (if any), for `toResolver`/forwardAsync. */\n readonly resolvers?: MapResolvers<z.infer<S>>;\n}\n\n/** Apply a single forward rule for `destKey`, returning the mapped value. */\nexport function applyForwardRule(\n rule: Rule | undefined,\n destKey: string,\n source: Record<string, unknown>,\n): unknown {\n if (rule === undefined) {\n // No rule: copy by matching dest key from source (dot-path aware).\n return getPath(source, destKey);\n }\n if (isStringRule(rule)) {\n return getPath(source, rule);\n }\n if (isPairRule(rule)) {\n return rule.to(source);\n }\n if (isDefaultRule(rule)) {\n const read = getPath(source, rule.source ?? destKey);\n return read === undefined ? rule.value : read;\n }\n if (isFnRule(rule)) {\n return rule(source);\n }\n // FromResolver markers are resolved only on the async path; sync forward\n // treats them as absent (the field is filled by forwardAsync).\n return undefined;\n}\n\n/**\n * Build a two-way mapper. The `const` type parameter on `R` preserves bare\n * object-literal rule values (string-literal renames) without the caller\n * writing `as const` (requires TypeScript >= 5.0).\n */\nexport function createMap<\n S extends AnyZodObject,\n const R extends RuleMap<z.infer<S>>,\n>(\n schema: S,\n rules: R = {} as R,\n options: CreateMapOptions<z.infer<S>> = {},\n): TypeMapper<S, R> {\n const shape = schema.shape as Record<string, z.ZodType>;\n const destKeys = Object.keys(shape);\n const mapResolvers = options.resolvers;\n\n // Build-time reverse-collision detection: any two reversible rules whose\n // inverse targets the same source key are a configuration error.\n const reverseTargets = new Map<string, string>();\n for (const destKey of Object.keys(rules) as Array<keyof R & string>) {\n const rule = rules[destKey] as Rule | undefined;\n if (rule !== undefined && isStringRule(rule)) {\n const existing = reverseTargets.get(rule);\n if (existing) throw new ReverseKeyCollisionError(rule, existing, destKey);\n reverseTargets.set(rule, destKey);\n }\n }\n\n function forward(source: Record<string, unknown>): z.infer<S> {\n const out: Record<string, unknown> = {};\n for (const destKey of destKeys) {\n const rule = rules[destKey as keyof R & string] as Rule | undefined;\n if (isFromResolverRule(rule as Rule)) continue; // async-only\n const value = applyForwardRule(rule, destKey, source);\n if (value !== undefined) setPath(out, destKey, value);\n }\n return schema.parse(out) as z.infer<S>;\n }\n\n function reverse(dto: z.infer<S>): Partial<Record<string, unknown>> {\n const out: Record<string, unknown> = {};\n const dtoObj = dto as Record<string, unknown>;\n for (const destKey of Object.keys(rules) as Array<keyof R & string>) {\n const rule = rules[destKey] as Rule | undefined;\n if (rule === undefined) continue;\n const destValue = getPath(dtoObj, destKey);\n if (isStringRule(rule)) {\n setPath(out, rule, destValue);\n } else if (isPairRule(rule)) {\n setPath(out, destKey, rule.from(destValue));\n } else if (isDefaultRule(rule)) {\n // Round-trip the read key; the default itself is forward-only.\n setPath(out, (rule as DefaultRule).source ?? destKey, destValue);\n } else if (isFromResolverRule(rule as Rule)) {\n // Resolver-backed fields have no source inverse; skip.\n continue;\n } else {\n // One-way function rule, no inverse.\n throw new OneWayRuleError(destKey);\n }\n }\n return out;\n }\n\n type Dest = z.infer<S>;\n\n function toResolver<TAdapter>(\n adapter: TAdapter,\n seed?: Partial<Dest>,\n ): ResolverContext<Dest, TAdapter> {\n if (!mapResolvers) {\n throw new MapHasNoResolversError();\n }\n // Per-field schemas from this map's own shape (over-exposure protection).\n const schemas: Record<string, z.ZodType> = {};\n for (const key of Object.keys(shape)) {\n schemas[key] = shape[key] as z.ZodType;\n }\n return createResolver<Dest, TAdapter>({\n adapter,\n seed,\n resolvers: mapResolvers as ResolverRegistry<Dest, TAdapter>,\n schemas: schemas as Record<keyof Dest, z.ZodType>,\n });\n }\n\n const mapper: TypeMapper<S, R> = {\n forward,\n reverse,\n forwardMany: (sources) => forwardManyOp(mapper, sources) as Array<Dest>,\n reverseMany: (dtos) => reverseManyOp(mapper, dtos),\n safeForward: (source) => safeForwardOp(mapper, source) as SafeResult<Dest>,\n toSnakeCase,\n toCamelCase,\n toResolver,\n schema,\n rules: Object.freeze({ ...rules }) as R,\n shape,\n resolvers: mapResolvers,\n };\n return mapper;\n}\n\nexport type { FromResolver };\n"]}
|