zod-to-x
Version:
Multi language types generation from Zod schemas.
191 lines (190 loc) • 8.42 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Layer = Layer;
exports.Domain = Domain;
exports.Application = Application;
exports.Infrastructure = Infrastructure;
exports.Presentation = Presentation;
const case_1 = __importDefault(require("case"));
const zod_helpers_1 = require("../lib/zod_helpers");
var EZod2XLayer;
(function (EZod2XLayer) {
EZod2XLayer[EZod2XLayer["DOMAIN"] = 0] = "DOMAIN";
EZod2XLayer[EZod2XLayer["APPLICATION"] = 1] = "APPLICATION";
EZod2XLayer[EZod2XLayer["INFRASTRUCTURE"] = 2] = "INFRASTRUCTURE";
EZod2XLayer[EZod2XLayer["PRESENTATION"] = 3] = "PRESENTATION";
})(EZod2XLayer || (EZod2XLayer = {}));
/**
* A decorator function to create a layered model by extending a class with additional metadata.
* This decorator ensures that each class instance is a singleton and associates metadata with
* transpilerable properties of the class.
*
* @param opt - The metadata options for the layer, of type `IZod2xLayerMetadata`.
*
* @returns A class decorator that extends the target class with the following features:
* - Singleton instance management.
* - Automatic assignment of metadata (`IZod2xMetadata`) to transpilerable properties.
* - Layer-specific metadata association for Zod types.
*
* ### Usage
* Apply this decorator to a class to enable layered modeling and metadata management.
*
* ### Example
* ```typescript
* @Layer({ name: "User", file: "user.ts", index: 0 })
* class ExampleClass {
* // Class implementation
* }
* ```
*
* ### Usage
* It can also be used to create custom layers like Domain, Application or Infrastructure:
* ```typescript
* function Domain(opt: Pick<IZod2xLayerMetadata, "file" | "name">) {
* return Layer({ ...opt, index: EZod2XLayer.DOMAIN });
* }
*
* @Domain({ name: "User", file: "user.ts" })
* class User {
* // Class implementation
* }
* ```
*/
function Layer(opt) {
return function (constructor) {
var _a;
return _a = class extends constructor {
constructor(...args) {
if (constructor.instance) {
return constructor.instance;
}
super(...args);
this.modelName = constructor.name;
this.layerMetadata = opt;
constructor.instance = this;
let metadata;
/**
* Set metadata for each transpilerable property of the class if not already set.
* @param name
* @param zodItem
* @param opt
*/
const setMetadata = (name, zodItem, opt) => {
metadata = zodItem["_zod2x"];
if (metadata === undefined) {
metadata = {
typeName: name,
};
zodItem["_zod2x"] = metadata;
}
else if (!metadata.typeName) {
metadata.typeName = name;
}
if (metadata.layer === undefined) {
// Metadata is set independently because typeName could already exist if
// zod2x was used before.
metadata.layer = opt;
}
if (opt.externalInheritance !== false &&
(metadata.layer.file !== opt.file || name !== metadata.typeName)) {
// Using an existing type. A new type is created that inherits from the
// original type.
zodItem = zod_helpers_1.ZodHelpers.cloneZod(zodItem);
zodItem._zod2x = {
parentLayer: metadata.layer,
aliasOf: metadata.typeName,
layer: opt,
typeName: name,
// Generics associated to parent, but related to current type.
genericTypes: metadata.isGenericChild === false
? metadata.genericTypes
: undefined,
isGenericChild: true,
};
}
return zodItem;
};
const lazyProperties = [];
Object.getOwnPropertyNames(this).forEach((prop) => {
const item = this[prop];
if (zod_helpers_1.ZodHelpers.isTranspilerableZodType(item) ||
zod_helpers_1.ZodHelpers.isTranspilerableAliasedZodType(item, opt.basicTypes === false)) {
this[prop] = setMetadata(case_1.default.pascal(prop), item, opt);
}
else if (zod_helpers_1.ZodHelpers.isZodLazy(item)) {
lazyProperties.push(prop);
}
});
// Process lazy properties after initial pass to ensure proper metadata assignment.
lazyProperties.forEach((i) => {
const lazyItem = this[i]._def.getter();
if (zod_helpers_1.ZodHelpers.isTranspilerableZodType(lazyItem) ||
zod_helpers_1.ZodHelpers.isTranspilerableAliasedZodType(lazyItem, opt.basicTypes === false)) {
this[i] = setMetadata(case_1.default.pascal(i), lazyItem, opt);
}
});
}
},
_a.instance = null,
_a;
};
}
/**
* The Domain layer decorator is typically used to define the core business logic or domain-specific
* rules within the application. It serves as a foundational layer in the layered architecture,
* encapsulating domain-related concerns.
*
* @param opt - An object containing the following properties:
* - `file`: The file path associated with the layer.
* - `name`: The name of the layer.
*
* @returns The configured Domain layer.
*/
function Domain(opt) {
return Layer(Object.assign(Object.assign({}, opt), { index: EZod2XLayer.DOMAIN }));
}
/**
* The Application layer decorator is typically used to represent the application-specific logic
* or configuration in a layered architecture. It serves as a higher-level abstraction
* that interacts with other layers, such as domain or infrastructure layers.
*
* @param opt - An object containing the following properties:
* - `file`: The file associated with the layer.
* - `name`: The name of the layer.
*
* @returns The result of invoking the `Layer` function with the provided options and
* the `APPLICATION` layer index.
*/
function Application(opt) {
return Layer(Object.assign(Object.assign({}, opt), { index: EZod2XLayer.APPLICATION }));
}
/**
* The Infrastructure layer decorator is typically responsible for handling
* low-level technical details such as database access, external APIs,
* file systems, and other system-level operations. It serves as the
* foundation for higher-level layers in the architecture.
*
* @param opt - An object containing metadata for the layer:
* - `file`: The file associated with this layer.
* - `name`: The name of the layer.
*
* @returns A configured Infrastructure layer.
*/
function Infrastructure(opt) {
return Layer(Object.assign(Object.assign({}, opt), { index: EZod2XLayer.INFRASTRUCTURE }));
}
/**
* The Presentation layer decorator is typically used to define the presentation or view-specific
* aspects of the model, such as formatting or display-related metadata.
*
* @param opt - An object containing the following properties:
* - `file`: The file associated with the layer.
* - `name`: The name of the layer.
* @returns The configured Presentation layer.
*/
function Presentation(opt) {
return Layer(Object.assign(Object.assign({}, opt), { index: EZod2XLayer.PRESENTATION }));
}