Skip to content

Commit

Permalink
feat: Support Kubernetes OpenAPI Schema (#62)
Browse files Browse the repository at this point in the history
  • Loading branch information
Himenon committed Nov 7, 2021
1 parent 47a2377 commit 3e5f4ef
Show file tree
Hide file tree
Showing 26 changed files with 175,959 additions and 2,128 deletions.
5 changes: 5 additions & 0 deletions .eslintingore
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
lib
debug
test/code/
lib/
test/kubernetes
test/argo-rollout
CHANGELOG.md
4 changes: 4 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
package.json
test/code/
lib/
test/code/
test/kubernetes
test/argo-rollout
CHANGELOG.md
8 changes: 3 additions & 5 deletions scripts/testCodeGen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,20 +114,18 @@ const main = () => {
});
generateTypedefWithTemplateCode("test/infer.domain/index.yml", "test/code/typedef-with-template/infer.domain.ts", false, { sync: false });

generateTypedefWithTemplateCode("test/argo-rollout/index.json", "test/code/typedef-with-template/argo-rollout.ts", false, {
generateTypedefWithTemplateCode("test/ref.access/index.yml", "test/code/typedef-with-template/ref-access.ts", false, {
sync: false,
});

generateTypedefWithTemplateCode("test/ref.access/index.yml", "test/code/typedef-with-template/ref-access.ts", false, {
generateTypedefWithTemplateCode("test/kubernetes/openapi-v1.18.5.json", "test/code/kubernetes/client-v1.18.5.ts", false, { sync: false });
generateTypedefWithTemplateCode("test/argo-rollout/index.json", "test/code/argo-rollout/client.ts", false, {
sync: false,
});

generateSplitCode("test/api.test.domain/index.yml", "test/code/split");

generateParameter("test/api.test.domain/index.yml", "test/code/parameter/api.test.domain.json");
generateParameter("test/infer.domain/index.yml", "test/code/parameter/infer.domain.json");


};

main();
5 changes: 3 additions & 2 deletions src/code-templates/api-client/ApiClientClass/Class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ export const create = (factory: TsGenerator.Factory.Type, members: ts.ClassEleme
modifiers: [ts.factory.createModifier(ts.SyntaxKind.PrivateKeyword)],
name: "baseUrl",
type: ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
})
,...members],
}),
...members,
],
typeParameterDeclaration: [
factory.TypeParameterDeclaration.create({
name: "RequestOption",
Expand Down
4 changes: 4 additions & 0 deletions src/internal/Logger/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ export const showFilePosition = (entryPoint: string, currentPoint: string, refer
export const error = (message: string): void => {
console.error(message);
};

export const warn = (message: string): void => {
console.log(message);
};
7 changes: 6 additions & 1 deletion src/internal/OpenApiTools/TypeNodeContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ const generatePath = (entryPoint: string, currentPoint: string, referencePath: s
};
};

const calculateReferencePath = (store: Walker.Store, base: string, pathArray: string[], converterContext: ConverterContext.Types,): ToTypeNode.ResolveReferencePath => {
const calculateReferencePath = (
store: Walker.Store,
base: string,
pathArray: string[],
converterContext: ConverterContext.Types,
): ToTypeNode.ResolveReferencePath => {
let names: string[] = [];
let unresolvedPaths: string[] = [];
pathArray.reduce((previous, lastPath, index) => {
Expand Down
29 changes: 25 additions & 4 deletions src/internal/OpenApiTools/Walker/Store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ import * as Operation from "./Operation";
import * as State from "./State";
import * as Structure from "./structure";

export interface AddStatementOption {
/**
* pathに対して強制的にSchemaを上書きするフラグ
* TypeAliasが先に登録され、Primitiveな型定義が登録されない問題を解決する
*/
override?: boolean;
}

class Store {
private state: State.Type;
private operator: Structure.OperatorType;
Expand Down Expand Up @@ -49,12 +57,16 @@ class Store {
statements,
});
}
private capitalizeFirstLetter(text: string): string {
return text.charAt(0).toUpperCase() + text.slice(1);
}
public getRootStatements(): ts.Statement[] {
// Debug Point: 抽象的なデータ構造全体を把握するために出力すると良い
// fs.writeFileSync("debug/tree.json", JSON.stringify(this.operator.getHierarchy(), null, 2), { encoding: "utf-8" });
const statements = Def.componentNames.reduce<ts.Statement[]>((statements, componentName) => {
const treeOfNamespace = this.getChildByPaths(componentName, "namespace");
if (treeOfNamespace) {
treeOfNamespace.name = this.capitalizeFirstLetter(treeOfNamespace.name);
return statements.concat(this.convertNamespace(treeOfNamespace));
}
return statements;
Expand All @@ -74,23 +86,32 @@ class Store {
/**
* @params path: "components/headers/hoge"
*/
public addStatement(path: string, statement: Structure.ComponentParams): void {
public addStatement(path: string, statement: Structure.ComponentParams, options?: AddStatementOption): void {
if (!path.startsWith("components")) {
throw new UnSupportError(`componentsから始まっていません。path=${path}`);
}
const targetPath = Path.posix.relative("components", path);
// すでにinterfaceとして登録がある場合はスキップ
if (this.hasStatement(targetPath, ["interface"])) {
// すでにinterfaceまたはNAMESPACEとして登録がある場合はスキップ
if (this.hasStatement(targetPath, ["interface", "namespace"])) {
return;
}
// もしTypeAliasが同じスコープに登録されているかつ、interfaceが新しく追加しようとしている場合、既存のstatementを削除する
if (this.hasStatement(targetPath, ["typeAlias"]) && statement.kind === "interface") {
if (!!options?.override || (this.hasStatement(targetPath, ["typeAlias"]) && statement.kind === "interface")) {
this.operator.remove(targetPath, "typeAlias");
}
this.operator.set(targetPath, Structure.createInstance(statement));
}
public getStatement<T extends Structure.DataStructure.Kind>(path: string, kind: T): Structure.DataStructure.GetChild<T> | undefined {
const targetPath = Path.posix.relative("components", path);
// components/schemasの場合
if (path.split("/").length === 2 && kind === "namespace") {
const child = this.getChildByPaths(targetPath, kind);
if (child) {
// FIXME Side Effect
child.name = this.capitalizeFirstLetter(child.name);
}
return child;
}
return this.getChildByPaths(targetPath, kind);
}
public addComponent(componentName: Def.ComponentName, statement: Structure.ComponentParams): void {
Expand Down
28 changes: 5 additions & 23 deletions src/internal/OpenApiTools/components/Operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,23 +55,14 @@ export const generateNamespace = (
deprecated: operation.deprecated,
});

const parameters = [...pathItemParameters || [], ...operation.parameters || []];
const parameters = [...(pathItemParameters || []), ...(operation.parameters || [])];

if (parameters.length > 0) {
const parameterName = "Parameter";
store.addStatement(`${basePath}/Parameter`, {
kind: "interface",
name: parameterName,
value: Parameter.generateInterface(
entryPoint,
currentPoint,
store,
factory,
parameterName,
parameters,
context,
converterContext,
),
value: Parameter.generateInterface(entryPoint, currentPoint, store, factory, parameterName, parameters, context, converterContext),
});
}

Expand Down Expand Up @@ -148,20 +139,11 @@ export const generateStatements = (
throw new Error("not setting operationId\n" + JSON.stringify(operation));
}
store.updateOperationState(httpMethod, requestUri, operationId, {});
const parameters = [...pathItemParameters || [], ...operation.parameters || []];
const parameters = [...(pathItemParameters || []), ...(operation.parameters || [])];
if (parameters.length > 0) {
const parameterName = converterContext.generateParameterName(operationId);
statements.push(
Parameter.generateAliasInterface(
entryPoint,
currentPoint,
store,
factory,
parameterName,
parameters,
context,
converterContext,
),
Parameter.generateAliasInterface(entryPoint, currentPoint, store, factory, parameterName, parameters, context, converterContext),
);
}
if (operation.requestBody) {
Expand All @@ -175,7 +157,7 @@ export const generateStatements = (
export: true,
name: converterContext.generateRequestBodyName(operationId),
type: factory.TypeReferenceNode.create({
name: context.resolveReferencePath(currentPoint, `${reference.path}`) + "." + Name.ComponentChild.Content, // TODO Contextから作成?
name: context.resolveReferencePath(currentPoint, `${reference.path}`).name + "." + Name.ComponentChild.Content, // TODO Contextから作成?
}),
}),
);
Expand Down
Loading

0 comments on commit 3e5f4ef

Please sign in to comment.