import * as Path from "path" ; import { Tree } from "@himenon/path-oriented-data-structure" ; import Dot from "dot-prop" ; import ts from "typescript" ; import type { OpenApi } from "../../../types" ; import { UnSupportError } from "../../Exception" ; import { Factory } from "../../TsGenerator" ; import * as Def from "./Definition" ; 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 ; private getChildByPaths : Structure . GetChildByPaths ; constructor ( private factory , rootDocument ) { this . state = State . createDefaultState ( rootDocument ) ; const { operator , getChildByPaths } = Structure . create ( ) ; this . operator = operator ; this . getChildByPaths = getChildByPaths ; } public convertNamespace ( tree ) { const statements = [ ] ; Object . values ( tree . getChildren ( ) ) . map ( child => { if ( child instanceof Tree || child instanceof Structure . NamespaceTree . Item ) { statements . push ( this . convertNamespace ( child ) ) ; } else if ( child instanceof Structure . InterfaceNode . Item ) { statements . push ( child . value ) ; } else if ( child instanceof Structure . TypeAliasNode . Item ) { statements . push ( child . value ) ; } } ) ; if ( tree instanceof Structure . NamespaceTree . Item ) { return this . factory . Namespace . create ( { export : true , name : tree . params . name , statements , comment : tree . params . comment , deprecated : tree . params . deprecated , } ) ; } return this . factory . Namespace . create ( { export : true , name : tree . name , statements , } ) ; } private capitalizeFirstLetter ( text ) { return text . charAt ( 0 ) . toUpperCase ( ) + text . slice ( 1 ) ; } public getRootStatements ( ) { 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 ; } , [ ] ) ; return statements ; } public getAdditionalStatements ( ) { return this . state . additionalStatements ; } params public hasStatement ( path , types ) { const alreadyRegistered = types . some ( type => ! ! this . operator . getChildByPaths ( path , type ) ) ; return alreadyRegistered ; } params public addStatement ( path , statement , options ? ) { if ( ! path . startsWith ( "components" ) ) { throw new UnSupportError ( `componentsから始まっていません。path=${ path }` ) ; } const targetPath = Path . posix . relative ( "components" , path ) ; if ( this . hasStatement ( targetPath , [ "interface" , "namespace" ] ) ) { return ; } 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 , kind ) { const targetPath = Path . posix . relative ( "components" , path ) ; if ( path . split ( "/" ) . length === 2 && kind === "namespace" ) { const child = this . getChildByPaths ( targetPath , kind ) ; if ( child ) { child . name = this . capitalizeFirstLetter ( child . name ) ; } return child ; } return this . getChildByPaths ( targetPath , kind ) ; } public addComponent ( componentName , statement ) { this . operator . set ( `${ componentName }` , Structure . createInstance ( statement ) ) ; } public getNoReferenceOperationState ( ) { return Operation . create ( this . state . document ) ; } public updateOperationState ( httpMethod , requestUri , operationId , newOperationState ) { let operationState = this . state . operations [ operationId ] ; if ( operationState ) { operationState = { ... operationState , ... newOperationState } ; } else { operationState = State . createDefaultOperationState ( httpMethod , requestUri , newOperationState ) ; } this . state . operations [ operationId ] = operationState ; } public addAdditionalStatement ( statements ) { this . state . additionalStatements = this . state . additionalStatements . concat ( statements ) ; } public getPathItem ( localPath ) { if ( ! localPath . startsWith ( "components/pathItem" ) ) { throw new Error ( "Only use start with 'component/pathItems': " + localPath ) ; } const result = Dot . get < OpenApi . PathItem > ( this . state . document , localPath . replace ( /\//g , "." ) ) ; if ( ! result ) { throw new Error ( `Not found ${ localPath }` ) ; } return result ; } public getParameter ( localPath ) { if ( ! localPath . startsWith ( "components/parameters" ) ) { throw new Error ( "Only use start with 'component/parameters': " + localPath ) ; } const result = Dot . get < OpenApi . Parameter > ( this . state . document , localPath . replace ( /\//g , "." ) ) ; if ( ! result ) { throw new Error ( `Not found ${ localPath }` ) ; } return result ; } public isAfterDefined ( referencePath ) { return ! ! Dot . get ( this . state . document , referencePath . replace ( /\//g , "." ) ) ; } } export { Store } ;