Skip to content

Commit

Permalink
fix(typedef): prccess json schema for tagged union
Browse files Browse the repository at this point in the history
  • Loading branch information
morlay committed Jan 15, 2024
1 parent 306bad2 commit 2817099
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 203 deletions.
3 changes: 2 additions & 1 deletion nodepkg/typedef/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@innoai-tech/typedef",
"version": "0.2.15",
"version": "0.2.16",
"monobundle": {
"exports": {
".": "./src/index.ts"
Expand Down Expand Up @@ -36,6 +36,7 @@
"directory": "nodepkg/typedef"
},
"scripts": {
"test": "bun test .",
"lint": "bunx --bun @biomejs/biome check --apply .",
"build": "bunx --bun monobundle",
"prepublishOnly": "bun run build"
Expand Down
46 changes: 37 additions & 9 deletions nodepkg/typedef/src/encoding/JSONSchemaDecoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,39 @@ export class JSONSchemaDecoder {
return e;
}

if (schema["oneOf"]) {
if (schema["discriminator"]) {
const discriminatorPropertyName = schema["discriminator"][
"propertyName"
] as string;
if (schema["discriminator"]) {
const discriminatorPropertyName = schema["discriminator"][
"propertyName"
] as string;

if (discriminatorPropertyName) {
const mapping: Record<string, any> = {};

if (schema["discriminator"]["mapping"]) {
const discriminatorMapping = schema["discriminator"][
"mapping"
] as Record<string, any>;

for (const k in discriminatorMapping) {
const tt = this.decode(discriminatorMapping[k]);
const objectSchema: Record<string, any> = {};

for (const [propName, _, p] of tt.entries(
{},
{ path: [], branch: [] },
)) {
if (p.type === "never") {
continue;
}

if (discriminatorPropertyName) {
const mapping: Record<string, any> = {};
objectSchema[propName] = p;
}

mapping[k] = isEmpty(objectSchema)
? t.object()
: t.object(objectSchema);
}
} else {
for (const o of schema["oneOf"]) {
const tt = this.decode(o);

Expand Down Expand Up @@ -125,11 +149,15 @@ export class JSONSchemaDecoder {
}
}
}

return t.discriminatorMapping(discriminatorPropertyName, mapping);
}

console.log(mapping);

return t.discriminatorMapping(discriminatorPropertyName, mapping);
}
}

if (schema["oneOf"]) {
const oneOf = map(schema["oneOf"], (s) => this.decode(s));

if (oneOf.length === 1) {
Expand Down
27 changes: 27 additions & 0 deletions nodepkg/typedef/src/encoding/__tests__/JSONSchemaDecoder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,32 @@ describe("JSONSchemaDecoder", () => {
},
],
},
TaggedUnionWhenA: {
properties: {
type: { enum: ["A"] },
a: { $ref: "#/definitions/A" },
b: { $ref: "#/definitions/B" },
},
required: ["a"],
additionalProperties: false,
},
TaggedUnion: {
type: "object",
discriminator: {
propertyName: "type",
mapping: {
A: { $ref: "#/definitions/TaggedUnionWhenA" },
B: {
properties: {
type: { enum: ["B"], type: "string" },
b: { $ref: "#/definitions/B" },
},
required: ["b"],
additionalProperties: false,
},
},
},
},
},
type: "object",
additionalProperties: false,
Expand All @@ -72,6 +98,7 @@ describe("JSONSchemaDecoder", () => {
arr: { $ref: "#/definitions/Arr" },
map: { $ref: "#/definitions/Map" },
union: { $ref: "#/definitions/Union" },
tagged: { $ref: "#/definitions/TaggedUnion" },
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,50 @@ exports[`JSONSchemaDecoder decode complex 1`] = `
"required": [],
"type": "object",
},
"TaggedUnion": {
"discriminator": {
"propertyName": "type",
},
"oneOf": [
{
"additionalProperties": false,
"properties": {
"a": {
"$ref": "#/definitions/A",
},
"b": {
"$ref": "#/definitions/B",
},
"type": {
"enum": [
"A",
],
},
},
"required": [
"a",
],
"type": "object",
},
{
"additionalProperties": false,
"properties": {
"b": {
"$ref": "#/definitions/B",
},
"type": {
"enum": [
"B",
],
},
},
"required": [
"b",
],
"type": "object",
},
],
},
"Union": {
"discriminator": {
"propertyName": "type",
Expand Down Expand Up @@ -121,6 +165,9 @@ exports[`JSONSchemaDecoder decode complex 1`] = `
"obj": {
"$ref": "#/definitions/Obj",
},
"tagged": {
"$ref": "#/definitions/TaggedUnion",
},
"union": {
"$ref": "#/definitions/Union",
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,196 +1,4 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`Encoding > JSONSchema encode 1`] = `
{
"allOf": [
{
"additionalProperties": false,
"properties": {
"array": {
"items": {
"type": "boolean",
},
"type": "array",
},
"inputType": {
"$ref": "#/definitions/InputType",
},
"keyValues": {
"additionalProperties": {},
"propertyNames": {
"type": "string",
},
"type": "object",
},
"placement": {
"enum": [
"leading",
"trailing",
],
},
"point": {
"items": [
{
"type": "number",
},
{
"type": "number",
},
],
"type": "array",
},
"strOrInt": {
"$ref": "#/definitions/StrOrInt",
"description": "StrOrInt",
},
},
"required": [
"strOrInt",
"placement",
"array",
"point",
],
"type": "object",
},
{
"discriminator": {
"propertyName": "type",
},
"oneOf": [
{
"additionalProperties": false,
"properties": {
"type": {
"enum": [
"text",
],
},
},
"required": [
"type",
],
"type": "object",
},
{
"additionalProperties": false,
"properties": {
"options": {
"items": {
"additionalProperties": false,
"properties": {
"label": {
"type": "string",
},
"value": {
"type": "string",
},
},
"required": [
"label",
"value",
],
"type": "object",
},
"type": "array",
},
"type": {
"enum": [
"select",
],
},
},
"required": [
"type",
"options",
],
"type": "object",
},
],
},
],
"definitions": {
"InputType": {
"enum": [
"text",
"number",
"select",
],
},
"StrOrInt": {
"oneOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
},
}
`;

exports[`Encoding > TypeScript encode 1`] = `
"
export type Type = ({
\\"strOrInt\\": StrOrInt,
\\"placement\\": \\"leading\\" | \\"trailing\\",
\\"inputType\\"?: InputType,
\\"keyValues\\"?: { [k: string]: any },
\\"array\\": Array<boolean>,
\\"point\\": [number, number],
} & ({
\\"type\\": \\"text\\",
} | {
\\"type\\": \\"select\\",
\\"options\\": Array<{
\\"label\\": string,
\\"value\\": string,
}>,
}))
export type StrOrInt = (string | number)
export enum InputType {
text = \\"text\\",
number = \\"number\\",
select = \\"select\\"
}
export const displayInputType = (v: InputType) => {
return ({
text: \\"文本\\",
number: \\"数字\\",
select: \\"选项\\"
})[v] ?? v
}"
`;
exports[`Encoding > Typedef encode 1`] = `
"
export const TypeSchema = /*#__PURE__*/t.intersection(t.object({
\\"strOrInt\\": t.ref(\\"StrOrInt\\", () => StrOrIntSchema).annotate({ description: \\"StrOrInt\\" }),
\\"placement\\": t.enums([\\"leading\\", \\"trailing\\"]),
\\"inputType\\": t.ref(\\"InputType\\", () => InputTypeSchema).optional(),
\\"keyValues\\": t.record(t.string(), t.any()).optional(),
\\"array\\": t.array(t.boolean()),
\\"point\\": t.tuple([t.number(), t.number()]),
}), t.discriminatorMapping(\\"type\\", {
\\"text\\": t.object(),
\\"select\\": t.object({
\\"options\\": t.array(t.object({
\\"label\\": t.string(),
\\"value\\": t.string(),
})),
})
}))
export const StrOrIntSchema = /*#__PURE__*/t.union(t.string(), t.integer())
export const InputTypeSchema = /*#__PURE__*/t.nativeEnum(InputType)"
`;
// Bun Snapshot v1, https://goo.gl/fbAQLP

exports[`Encoding Typedef encode 1`] = `
"
Expand Down

0 comments on commit 2817099

Please sign in to comment.