Skip to content

Commit

Permalink
add primitive and objects
Browse files Browse the repository at this point in the history
  • Loading branch information
RohinBhargava committed Nov 15, 2024
1 parent 3913b36 commit cf42860
Show file tree
Hide file tree
Showing 33 changed files with 712 additions and 138 deletions.
2 changes: 1 addition & 1 deletion packages/parsers/__test__/demo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ComponentsNode } from "../openapi/demo";
import { FdrAPI } from "@fern-api/fdr-sdk";
import { OpenAPIV3_1 } from "openapi-types";
import { describe, it } from "vitest";
import { ApiNodeContext, ErrorCollector } from "../openapi/shared/interfaces/api.node.interface";
import { ApiNodeContext, ErrorCollector } from "../openapi/base.node.interface";

describe("ComponentsNode", () => {
describe("outputFdrShape", () => {
Expand Down
49 changes: 49 additions & 0 deletions packages/parsers/openapi/base.node.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Logger } from "@playwright/test";

export class ErrorCollector {
errors: {
message: string;
path: string;
}[] = [];

addError(error: string, accessPath: string[], pathId?: string): void {
this.errors.push({
message: error,
path: `#/${accessPath.join("/")}${pathId ? `/${pathId}` : ""}`,
});
}
}

export interface ApiNodeContext {
orgId: string;
apiId: string;
logger: Logger;
errorCollector: ErrorCollector;
}

abstract class ApiNode<InputShape, FdrShape> {
context: ApiNodeContext;
input: InputShape;

accessPath: string[];

constructor(context: ApiNodeContext, input: InputShape, accessPath: string[]) {
this.context = context;
this.input = input;
this.accessPath = accessPath;
}

abstract outputFdrShape: () => FdrShape | undefined;
}

export abstract class InputApiNode<InputShape, FdrShape> extends ApiNode<InputShape, FdrShape> {
constructor(context: ApiNodeContext, input: InputShape, accessPath: string[], pathId?: string) {
if (pathId) {
accessPath.push(pathId);
context.logger.log("a", "info", `Processing #/${accessPath.join("/")}/${pathId}`);
}
super(context, input, accessPath);
}
}

export abstract class OutputApiNode<InputShape, FdrShape> extends ApiNode<InputShape, FdrShape> {}
37 changes: 16 additions & 21 deletions packages/parsers/openapi/demo.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
import { FdrAPI } from "@fern-api/fdr-sdk";
import { OpenAPIV3_1 } from "openapi-types";
import { z } from "zod";
import { ApiNode, ApiNodeContext } from "./shared/interfaces/api.node.interface";
import { ApiNodeContext, InputApiNode } from "./base.node.interface";
import { FdrStage } from "./shared/interfaces/fdr.stage.interface";

export class AvailabilityNode implements ApiNode<unknown, FdrAPI.Availability | undefined> {
export class AvailabilityNode implements InputApiNode<unknown, FdrAPI.Availability | undefined> {
id: string;
availability: FdrAPI.Availability | undefined;

"x-fern-availability-shape" = z.object({
"x-fern-availability": z.enum([
"beta",
"deprecated",
"development",
"pre-release",
"stable",
"generally-available",
]),
"x-fern-availability": z.optional(
z.enum(["beta", "deprecated", "development", "pre-release", "stable", "generally-available"]),
),
});

deprecatedShape = z.object({
Expand All @@ -26,13 +21,13 @@ export class AvailabilityNode implements ApiNode<unknown, FdrAPI.Availability |
constructor(
readonly context: ApiNodeContext,
readonly input: unknown,
readonly accessPath: ApiNode<unknown, unknown>[],
readonly accessPath: InputApiNode<unknown, unknown>[],
) {
this.id = `${accessPath.map((node) => node.id).join(".")}.AvailabilityNode`;
if (input && typeof input === "object" && "x-fern-availability" in input) {
const result = this["x-fern-availability-shape"].safeParse(input);
if (result.success) {
this.availability = this.convertAvailability(result.data["x-fern-availability"]);
this.availability = this.convertAvailability(result.data["x-fern-availability"] ?? "");
} else {
context.errorCollector.addError(`Availability is not defined for ${this.id}`);
}
Expand Down Expand Up @@ -74,7 +69,7 @@ export class AvailabilityNode implements ApiNode<unknown, FdrAPI.Availability |
};
}

export class DemoStringNode implements ApiNode<OpenAPIV3_1.SchemaObject, FdrAPI.api.latest.PrimitiveType> {
export class DemoStringNode implements InputApiNode<OpenAPIV3_1.SchemaObject, FdrAPI.api.latest.PrimitiveType> {
id: string;

regex: string | undefined;
Expand All @@ -86,7 +81,7 @@ export class DemoStringNode implements ApiNode<OpenAPIV3_1.SchemaObject, FdrAPI.
constructor(
readonly context: ApiNodeContext,
readonly input: OpenAPIV3_1.SchemaObject,
readonly accessPath: ApiNode<unknown, unknown>[],
readonly accessPath: InputApiNode<unknown, unknown>[],
) {
this.id = `${accessPath.map((node) => node.id).join(".")}.DemoStringNode`;
this.regex = input.pattern;
Expand Down Expand Up @@ -115,7 +110,7 @@ export class DemoTypeShapeStage implements FdrStage<OpenAPIV3_1.SchemaObject, Fd
constructor(
readonly context: ApiNodeContext,
readonly input: OpenAPIV3_1.SchemaObject,
readonly accessPath: ApiNode<unknown, unknown>[],
readonly accessPath: InputApiNode<unknown, unknown>[],
) {
this.id = `${accessPath.map((node) => node.id).join(".")}.DemoTypeShapeStage`;

Expand Down Expand Up @@ -151,7 +146,7 @@ export class DemoTypeShapeStage implements FdrStage<OpenAPIV3_1.SchemaObject, Fd
}

export class DemoPropertyNode
implements ApiNode<OpenAPIV3_1.SchemaObject | OpenAPIV3_1.ReferenceObject, FdrAPI.api.latest.ObjectProperty>
implements InputApiNode<OpenAPIV3_1.SchemaObject | OpenAPIV3_1.ReferenceObject, FdrAPI.api.latest.ObjectProperty>
{
id: string;

Expand All @@ -162,7 +157,7 @@ export class DemoPropertyNode
readonly name: string,
readonly context: ApiNodeContext,
readonly input: OpenAPIV3_1.SchemaObject,
readonly accessPath: ApiNode<unknown, unknown>[],
readonly accessPath: InputApiNode<unknown, unknown>[],
) {
this.id = `${accessPath.map((node) => node.id).join(".")}.DemoPropertyNode`;
if (input.type === "string") {
Expand All @@ -186,7 +181,7 @@ export class DemoPropertyNode
};
}

export class DemoSchemaNode implements ApiNode<OpenAPIV3_1.SchemaObject, FdrAPI.api.latest.TypeDefinition> {
export class DemoSchemaNode implements InputApiNode<OpenAPIV3_1.SchemaObject, FdrAPI.api.latest.TypeDefinition> {
id: string;

shape: DemoTypeShapeStage | undefined = undefined;
Expand All @@ -196,7 +191,7 @@ export class DemoSchemaNode implements ApiNode<OpenAPIV3_1.SchemaObject, FdrAPI.
readonly name: string,
readonly context: ApiNodeContext,
readonly input: OpenAPIV3_1.SchemaObject,
readonly accessPath: ApiNode<unknown, unknown>[],
readonly accessPath: InputApiNode<unknown, unknown>[],
) {
this.id = `${accessPath.map((node) => node.id).join(".")}.DemoTypeDefinitionNode`;
if (this.input.type === "object") {
Expand All @@ -220,15 +215,15 @@ export class DemoSchemaNode implements ApiNode<OpenAPIV3_1.SchemaObject, FdrAPI.
};
}

export class ComponentsNode implements ApiNode<OpenAPIV3_1.ComponentsObject, FdrAPI.api.latest.TypeDefinition[]> {
export class ComponentsNode implements InputApiNode<OpenAPIV3_1.ComponentsObject, FdrAPI.api.latest.TypeDefinition[]> {
id: string;

schemas: DemoSchemaNode[] = [];

constructor(
readonly context: ApiNodeContext,
readonly input: OpenAPIV3_1.ComponentsObject,
readonly accessPath: ApiNode<unknown, unknown>[],
readonly accessPath: InputApiNode<unknown, unknown>[],
) {
this.id = `${accessPath.map((node) => node.id).join(".")}.ComponentsNode`;
this.schemas = Object.entries(this.input.schemas ?? {}).map(([name, schema]) => {
Expand Down
33 changes: 0 additions & 33 deletions packages/parsers/openapi/shared/interfaces/api.node.interface.ts

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

40 changes: 40 additions & 0 deletions packages/parsers/openapi/shared/nodes/object.node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { FdrAPI } from "@fern-api/fdr-sdk";
import { ApiNodeContext, OutputApiNode } from "../../base.node.interface";
import { SchemaObject } from "../openapi.types";
import { ObjectPropertyNode } from "./objectProperty.node";
import { TypeReferenceNode, isReferenceObject } from "./typeReference.node";

export class ObjectNode extends OutputApiNode<SchemaObject, FdrAPI.api.latest.ObjectType> {
extends: FdrAPI.TypeId[] = [];
properties: ObjectPropertyNode[] = [];
extraProperties: TypeReferenceNode | undefined;

constructor(context: ApiNodeContext, input: SchemaObject, accessPath: string[], accessorKey?: string) {
super(context, input, accessPath);

if (input.allOf !== undefined) {
this.extends = input.allOf
.map((type) => (isReferenceObject(type) ? FdrAPI.TypeId(type.$ref) : undefined))
.filter((id): id is FdrAPI.TypeId => id !== undefined);
}

if (input.properties !== undefined) {
Object.entries(input.properties).forEach(([key, property]) => {
this.properties.push(new ObjectPropertyNode(key, context, property, accessPath, accessorKey));
});
}
}

outputFdrShape = (): FdrAPI.api.latest.ObjectType | undefined => {
const properties = this.properties
.map((property) => property.outputFdrShape())
.filter((property): property is FdrAPI.api.latest.ObjectProperty => property !== undefined);

return {
extends: this.extends,
properties,
extraProperties: undefined,
// TODO: add extraProperties
};
};
}
47 changes: 47 additions & 0 deletions packages/parsers/openapi/shared/nodes/objectProperty.node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { FdrAPI } from "@fern-api/fdr-sdk";
import { ApiNodeContext, OutputApiNode } from "../../base.node.interface";
import { ReferenceObject, SchemaObject } from "../openapi.types";
import { isReferenceObject, mapReferenceObject } from "./typeReference.node";
import { TypeShapeNode } from "./typeShape.node";

export class ObjectPropertyNode extends OutputApiNode<
SchemaObject | ReferenceObject,
FdrAPI.api.latest.ObjectProperty
> {
valueShape: TypeShapeNode;
description: string | undefined;
// availability: AvailabilityNode;

constructor(
private readonly key: string,
context: ApiNodeContext,
input: SchemaObject | ReferenceObject,
accessPath: string[],
accessorKey?: string,
) {
super(context, input, accessPath);

if (isReferenceObject(input)) {
input = mapReferenceObject(input);
}

this.valueShape = new TypeShapeNode(context, input, accessPath, accessorKey);
this.description = input.description;
// this.availability = input.availability;
}

outputFdrShape = (): FdrAPI.api.latest.ObjectProperty | undefined => {
const valueShape = this.valueShape.outputFdrShape();
if (valueShape === undefined) {
return undefined;
}

return {
key: FdrAPI.PropertyKey(this.key),
valueShape,
description: this.description,
availability: undefined,
// TODO: update to availability: this.availability.outputFdrShape(),
};
};
}
29 changes: 0 additions & 29 deletions packages/parsers/openapi/shared/nodes/pathPart.node.ts

This file was deleted.

39 changes: 39 additions & 0 deletions packages/parsers/openapi/shared/nodes/primitives/enum.node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { FdrAPI } from "@fern-api/fdr-sdk";
import { OpenAPIV3_1 } from "openapi-types";
import { ApiNodeContext, InputApiNode } from "../../../base.node.interface";

export class EnumNode extends InputApiNode<OpenAPIV3_1.SchemaObject, FdrAPI.api.v1.read.PrimitiveType.Enum> {
default: number | undefined;
format: string | undefined;
minimum: number | undefined;
maximum: number | undefined;

constructor(
context: ApiNodeContext,
input: OpenAPIV3_1.NonArraySchemaObject,
accessPath: string[],
accessorKey?: string,
) {
super(context, input, accessPath, accessorKey);
if (input.type !== "integer") {
context.errorCollector.addError(
`Expected type "integer" for primitive, but got "${input.type}"`,
accessPath,
accessorKey,
);
}
this.format = input.format;
this.default = input.default;
this.minimum = input.minimum;
this.maximum = input.maximum;
}

outputFdrShape = (): FdrAPI.api.v1.read.PrimitiveType.Integer => {
return {
type: "integer",
minimum: this.minimum,
maximum: this.maximum,
default: this.default,
};
};
}
Loading

0 comments on commit cf42860

Please sign in to comment.