Skip to content

fix: accessing nested object properties by reference #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions scripts/testCodeGen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as Writer from "./writer";
const main = () => {
Writer.generateTypedefCodeOnly("test/api.test.domain/index.yml", "test/code/typedef-only/api.test.domain.ts", true);
Writer.generateTypedefCodeOnly("test/infer.domain/index.yml", "test/code/typedef-only/infer.domain.ts", false);
Writer.generateTypedefCodeOnly("test/json.properties/index.yml", "test/code/typedef-only/json.properties.ts", false);

Writer.generateTemplateCodeOnly("test/api.test.domain/index.yml", "test/code/template-only/api.test.domain.ts", true, { sync: false });
Writer.generateTemplateCodeOnly("test/api.test.domain/index.yml", "test/code/template-only/sync-api.test.domain.ts", true, { sync: true });
Expand Down
33 changes: 32 additions & 1 deletion src/internal/OpenApiTools/TypeNodeContext.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as Path from "path";
import DotProp from "dot-prop";

import ts from "typescript";

Expand All @@ -8,6 +9,8 @@ import * as TypeScriptCodeGenerator from "../TsGenerator";
import * as ConverterContext from "./ConverterContext";
import * as ToTypeNode from "./toTypeNode";
import type * as Walker from "./Walker";
import * as Guard from "./Guard";
import * as Reference from "./components/Reference";

export interface ReferencePathSet {
pathArray: string[];
Expand Down Expand Up @@ -93,6 +96,27 @@ export const create = (
const { pathArray, base } = generatePath(entryPoint, currentPoint, referencePath);
return calculateReferencePath(store, base, pathArray, converterContext);
};
const findSchemaByPathArray = (
pathArray: string[],
remainPathArray: string[] = [],
): OpenApi.Schema | OpenApi.Reference | OpenApi.JSONSchemaDefinition => {
const schema = DotProp.get<OpenApi.Schema>(rootSchema, pathArray.join("."));
if (!schema) {
return findSchemaByPathArray(pathArray.slice(0, pathArray.length - 1), [pathArray[pathArray.length - 1], ...remainPathArray]);
}
if (Guard.isReference(schema)) {
const ref = Reference.generate(entryPoint, entryPoint, schema);
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it could be broken during REMOTE REFERENCE.

return findSchemaByPathArray(ref.path.split("/"), remainPathArray);
}
if (remainPathArray.length) {
const moreNestSchema = DotProp.get<OpenApi.Schema>(schema, remainPathArray.join("."));
if (!moreNestSchema) {
throw new Error("Not found");
}
return moreNestSchema;
}
return schema;
};
const setReferenceHandler: ToTypeNode.Context["setReferenceHandler"] = (currentPoint, reference) => {
if (store.hasStatement(reference.path, ["interface", "typeAlias"])) {
return;
Expand All @@ -107,6 +131,7 @@ export const create = (
rootSchema,
setReferenceHandler,
resolveReferencePath,
findSchemaByPathArray,
},
converterContext,
);
Expand All @@ -133,6 +158,7 @@ export const create = (
rootSchema,
setReferenceHandler,
resolveReferencePath,
findSchemaByPathArray,
},
converterContext,
),
Expand Down Expand Up @@ -161,5 +187,10 @@ export const create = (
}
}
};
return { rootSchema, setReferenceHandler: setReferenceHandler, resolveReferencePath: resolveReferencePath };
return {
rootSchema,
setReferenceHandler: setReferenceHandler,
resolveReferencePath: resolveReferencePath,
findSchemaByPathArray: findSchemaByPathArray,
};
};
6 changes: 2 additions & 4 deletions src/internal/OpenApiTools/components/Schemas.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import DotProp from "dot-prop";

import type { OpenApi } from "../../../types";
import * as Logger from "../..//Logger";
import { UnSupportError } from "../../Exception";
Expand Down Expand Up @@ -39,7 +37,7 @@ export const generateNamespace = (
name: convertContext.escapeReferenceDeclarationText(maybeResolvedName),
});
}
const schema = DotProp.get(context.rootSchema, pathArray.join(".")) as any;
const schema = context.findSchemaByPathArray(pathArray);
return ToTypeNode.convert(entryPoint, currentPoint, factory, schema, context, convertContext, { parent: schema });
};
return store.addStatement(`${basePath}/${name}`, {
Expand Down Expand Up @@ -82,7 +80,7 @@ export const generateNamespace = (
const schema = InferredType.getInferredType(targetSchema);
const path = `${basePath}/${name}`;
if (!schema) {
// Schemaが特定できないためWarningを出力する
// Outputs Warning because Schema cannot be identified
Logger.warn(`Warning: Schema could not be identified. Therefore, it is treated as any. ${name}`);
return store.addStatement(
path,
Expand Down
8 changes: 5 additions & 3 deletions src/internal/OpenApiTools/toTypeNode.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import DotProp from "dot-prop";
import ts from "typescript";

import type { OpenApi } from "../../types";
Expand All @@ -19,14 +18,17 @@ export interface ResolveReferencePath {
* @example components.a.b.c.dの場合 ["a", "b", "c", "d"].length = 4
**/
depth: number;
/** 入力$refを分解したモノ(#は除く) */
/**
* Input $ref divided by / (except #)
*/
pathArray: string[];
}

export interface Context {
readonly rootSchema: OpenApi.Document;
setReferenceHandler: (currentPoint: string, reference: Reference.Type<OpenApi.Schema | OpenApi.JSONSchemaDefinition>) => void;
resolveReferencePath: (currentPoint: string, referencePath: string) => ResolveReferencePath;
findSchemaByPathArray: (paths: string[]) => OpenApi.Schema | OpenApi.Reference | OpenApi.JSONSchemaDefinition;
}

export type Convert = (
Expand Down Expand Up @@ -111,7 +113,7 @@ export const convert: Convert = (
if (depth === 2) {
return factory.TypeReferenceNode.create({ name: converterContext.escapeReferenceDeclarationText(maybeResolvedName) });
} else {
const resolveSchema = DotProp.get(context.rootSchema, pathArray.join(".")) as any;
const resolveSchema = context.findSchemaByPathArray(pathArray);
return convert(entryPoint, currentPoint, factory, resolveSchema, context, converterContext, { parent: schema });
}
}
Expand Down
34 changes: 34 additions & 0 deletions test/__tests__/__snapshots__/typedef-only-test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,39 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Typedef only Reference test that include nested properties 1`] = `
"//
// Generated by @himenon/openapi-typescript-code-generator
//
// OpenApi : 3.0.0
//
// License : MIT
//


export namespace Schemas {
export interface Foo {
bar?: {
baz?: string;
bazbaz?: {
hoge?: number;
};
};
}
export type Bar = {
baz?: string;
bazbaz?: {
hoge?: number;
};
};
export type Baz = string;
export type Hoge = number;
export type BazBaz = {
hoge?: number;
};
}
"
`;

exports[`Typedef only typedef-api.test.domain 1`] = `
"//
// Generated by @himenon/openapi-typescript-code-generator
Expand Down
5 changes: 5 additions & 0 deletions test/__tests__/typedef-only-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ describe("Typedef only", () => {
const text = Utils.replaceVersionInfo(generateCode);
expect(text).toMatchSnapshot();
});
test("Reference test that include nested properties", () => {
const generateCode = fs.readFileSync("test/code/typedef-only/json.properties.ts", { encoding: "utf-8" });
const text = Utils.replaceVersionInfo(generateCode);
expect(text).toMatchSnapshot();
});
});
40 changes: 40 additions & 0 deletions test/json.properties/index.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
openapi: 3.0.0
info:
version: 1.0.0
title: api.test.domain
description: Library test schema
license:
name: MIT

servers:
- url: "http://dev.api.test.domain/"
description: Development Environment
- url: "https://api.test.domain/"
description: Production Environment

tags:
- name: test

components:
schemas:
Foo:
type: object
properties:
bar:
type: object
properties:
baz:
type: string
bazbaz:
type: object
properties:
hoge:
type: number
Bar:
$ref: "#/components/schemas/Foo/properties/bar"
Baz:
$ref: "#/components/schemas/Bar/properties/baz"
Hoge:
$ref: "#/components/schemas/Bar/properties/bazbaz/properties/hoge"
BazBaz:
$ref: "#/components/schemas/Bar/properties/bazbaz"