Skip to content

Commit

Permalink
back to initial api
Browse files Browse the repository at this point in the history
  • Loading branch information
leonid-shutov committed Nov 24, 2023
1 parent f20281a commit 38f36ef
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 35 deletions.
22 changes: 22 additions & 0 deletions lib/strategies/from-keys.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"use strict";

/** @param {string[]} keys */
const fromKeys = (keys) => {
class MetaClass {
#privateFields;

constructor(argsObj) {
this.#privateFields = argsObj;

for (const field of keys) {
Object.defineProperty(MetaClass.prototype, field, {
get: () => this.#privateFields[field],
});
}
}
}

return { metaClass: MetaClass, metaData: { keys: [...keys] } };
};

module.exports = { fromKeys };
19 changes: 19 additions & 0 deletions lib/strategies/from-zod-schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use strict";

/**
* @typedef {import('zod').ZodRawShape} ZodRawShape
* @typedef {import('zod').ZodObject<ZodRawShape>} TZodSchema
*/

const { fromKeys } = require("./from-keys");

/** @param {TZodSchema} schema */
const fromZodSchema = (schema) => {
const keys = Object.keys(schema.shape);

const { metaClass } = fromKeys(keys);

return { metaClass, metaData: { keys: [...keys] } };
};

module.exports = { fromZodSchema };
4 changes: 4 additions & 0 deletions lib/strategies/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
...require("./from-keys"),
...require("./from-zod-schema"),
};
20 changes: 11 additions & 9 deletions meta-class.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { ZodObject, ZodRawShape, infer as zinfer } from "zod";

export const MetaClass: {
from: {
keys: <IDefault = never, I extends IDefault = IDefault>(
keys: (keyof I)[]
) => new (argsObj: I) => I;
zodSchema: <T extends ZodRawShape>(
schema: ZodObject<T>
) => new (argsObj: zinfer<typeof schema>) => zinfer<typeof schema>;
};
export type TStrategyOutput<TMetaClass> = { metaClass: TMetaClass; metaData: { keys: string[] } };

export type TMetaClass = {
fromKeys: <IDefault = any, I extends IDefault = IDefault>(
keys: (keyof I)[]
) => TStrategyOutput<new (argsObj: I) => I>;
fromZodSchema: <T extends ZodRawShape>(
schema: ZodObject<T>
) => TStrategyOutput<new (argsObj: zinfer<typeof schema>) => zinfer<typeof schema>>;
};

export const MetaClass: TMetaClass;
30 changes: 5 additions & 25 deletions meta-class.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,10 @@
"use strict";

const fromKeys = (keys) => {
class MetaClass {
#privateFields;
/** @typedef {import('./meta-class').TStrategyOutput<any>} TStrategyOutput */

constructor(argsObj) {
this.#privateFields = argsObj;
const strategies = require("./lib/strategies");

for (const field of keys) {
Object.defineProperty(MetaClass.prototype, field, {
get: () => this.#privateFields[field],
});
}
}
}
/** @type {Record<string, (x: any) => TStrategyOutput>} */
const MetaClass = { ...strategies };

return MetaClass;
};

const fromZodSchema = (schema) => fromKeys(Object.keys(schema.shape));

const MetaClassFactory = {
from: {
keys: fromKeys,
zodSchema: fromZodSchema,
},
};

module.exports = { MetaClass: MetaClassFactory };
module.exports = { MetaClass };
43 changes: 43 additions & 0 deletions meta-class.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const assert = require("node:assert");
const { describe, it } = require("node:test");
const { z } = require("zod");
const { MetaClass } = require("./meta-class");

describe("fromKeys strategy", () => {
const keys = ["name", "age", "color"];
const { metaClass: Cat, metaData } = MetaClass.fromKeys(keys);
const cat = new Cat({ name: "Sanya", age: 3, color: "Orange tabbie" });

it("Meta class is correct", () => {
assert.strictEqual(cat.name, "Sanya");
assert.strictEqual(cat.age, 3);
assert.strictEqual(cat.color, "Orange tabbie");
});

it("Meta data is correct", () => {
assert.deepStrictEqual(metaData.keys, keys);
assert.notStrictEqual(metaData.keys, keys);
});
});

describe("fromZodSchema strategy", () => {
const schema = z.object({
name: z.string(),
age: z.number(),
color: z.string(),
});
const { metaClass: Cat, metaData } = MetaClass.fromZodSchema(schema);
const cat = new Cat({ name: "Sanya", age: 3, color: "Orange tabbie" });

it("Meta class is correct", () => {
assert.strictEqual(cat.name, "Sanya");
assert.strictEqual(cat.age, 3);
assert.strictEqual(cat.color, "Orange tabbie");
});

const keys = Object.keys(schema.shape);

it("Meta data is correct", () => {
assert.deepStrictEqual(metaData.keys, keys);
});
});
25 changes: 25 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,9 @@
},
"dependencies": {
"zod": "^3.22.4"
},
"devDependencies": {
"@types/assert": "^1.5.10",
"@types/node": "^20.10.0"
}
}
4 changes: 3 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"module": "commonjs",
"noEmit": true,
"strict": true,
"esModuleInterop": true
"esModuleInterop": true,
"checkJs": true,
"noImplicitAny": false
}
}

0 comments on commit 38f36ef

Please sign in to comment.