@ahoo-wang/wow-generator 9.2.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +177 -0
  3. package/README.zh-CN.md +149 -0
  4. package/dist/analysis/aggregates.d.cts +21 -0
  5. package/dist/analysis/aggregates.d.ts +21 -0
  6. package/dist/analysis/analyze.d.cts +18 -0
  7. package/dist/analysis/analyze.d.ts +18 -0
  8. package/dist/analysis/apiClients.d.cts +14 -0
  9. package/dist/analysis/apiClients.d.ts +14 -0
  10. package/dist/analysis/clientNames.d.cts +55 -0
  11. package/dist/analysis/clientNames.d.ts +55 -0
  12. package/dist/analysis/model.d.cts +212 -0
  13. package/dist/analysis/model.d.ts +212 -0
  14. package/dist/analysis/modelInfo.d.cts +23 -0
  15. package/dist/analysis/modelInfo.d.ts +23 -0
  16. package/dist/analysis/models.d.cts +17 -0
  17. package/dist/analysis/models.d.ts +17 -0
  18. package/dist/api/configuration.d.cts +30 -0
  19. package/dist/api/configuration.d.ts +30 -0
  20. package/dist/api/errors.d.cts +41 -0
  21. package/dist/api/errors.d.ts +41 -0
  22. package/dist/api/logger.d.cts +61 -0
  23. package/dist/api/logger.d.ts +61 -0
  24. package/dist/api/options.d.cts +47 -0
  25. package/dist/api/options.d.ts +47 -0
  26. package/dist/cli/program.d.cts +35 -0
  27. package/dist/cli/program.d.ts +35 -0
  28. package/dist/cli/runGenerate.d.cts +65 -0
  29. package/dist/cli/runGenerate.d.ts +65 -0
  30. package/dist/cli.cjs +3 -0
  31. package/dist/cli.cjs.map +1 -0
  32. package/dist/cli.d.cts +6 -0
  33. package/dist/cli.d.ts +6 -0
  34. package/dist/cli.js +98 -0
  35. package/dist/cli.js.map +1 -0
  36. package/dist/codeGenerator-DpDTDC4o.cjs +23 -0
  37. package/dist/codeGenerator-DpDTDC4o.cjs.map +1 -0
  38. package/dist/codeGenerator-kyY9eLML.js +2583 -0
  39. package/dist/codeGenerator-kyY9eLML.js.map +1 -0
  40. package/dist/emit/importRegistry.d.cts +50 -0
  41. package/dist/emit/importRegistry.d.ts +50 -0
  42. package/dist/emit/imports.d.cts +49 -0
  43. package/dist/emit/imports.d.ts +49 -0
  44. package/dist/emit/jsdoc.d.cts +38 -0
  45. package/dist/emit/jsdoc.d.ts +38 -0
  46. package/dist/emit/moduleBuilder.d.cts +80 -0
  47. package/dist/emit/moduleBuilder.d.ts +80 -0
  48. package/dist/emitters/apiClients.d.cts +10 -0
  49. package/dist/emitters/apiClients.d.ts +10 -0
  50. package/dist/emitters/commandClients.d.cts +14 -0
  51. package/dist/emitters/commandClients.d.ts +14 -0
  52. package/dist/emitters/decorators.d.cts +83 -0
  53. package/dist/emitters/decorators.d.ts +83 -0
  54. package/dist/emitters/emit.d.cts +15 -0
  55. package/dist/emitters/emit.d.ts +15 -0
  56. package/dist/emitters/indexFiles.d.cts +12 -0
  57. package/dist/emitters/indexFiles.d.ts +12 -0
  58. package/dist/emitters/models.d.cts +77 -0
  59. package/dist/emitters/models.d.ts +77 -0
  60. package/dist/emitters/queryClients.d.cts +11 -0
  61. package/dist/emitters/queryClients.d.ts +11 -0
  62. package/dist/emitters/target.d.cts +14 -0
  63. package/dist/emitters/target.d.ts +14 -0
  64. package/dist/finalize/finalize.d.cts +16 -0
  65. package/dist/finalize/finalize.d.ts +16 -0
  66. package/dist/finalize/typeOnlyImports.d.cts +13 -0
  67. package/dist/finalize/typeOnlyImports.d.ts +13 -0
  68. package/dist/finalize/verification.d.cts +14 -0
  69. package/dist/finalize/verification.d.ts +14 -0
  70. package/dist/index.cjs +1 -0
  71. package/dist/index.d.cts +8 -0
  72. package/dist/index.d.ts +8 -0
  73. package/dist/index.js +2 -0
  74. package/dist/input/configuration.d.cts +87 -0
  75. package/dist/input/configuration.d.ts +87 -0
  76. package/dist/input/parsers.d.cts +39 -0
  77. package/dist/input/parsers.d.ts +39 -0
  78. package/dist/input/resources.d.cts +36 -0
  79. package/dist/input/resources.d.ts +36 -0
  80. package/dist/naming/modelInfo.d.cts +10 -0
  81. package/dist/naming/modelInfo.d.ts +10 -0
  82. package/dist/naming/naming.d.cts +102 -0
  83. package/dist/naming/naming.d.ts +102 -0
  84. package/dist/naming/order.d.cts +2 -0
  85. package/dist/naming/order.d.ts +2 -0
  86. package/dist/naming/paths.d.cts +27 -0
  87. package/dist/naming/paths.d.ts +27 -0
  88. package/dist/openapi/components.d.cts +55 -0
  89. package/dist/openapi/components.d.ts +55 -0
  90. package/dist/openapi/document.d.cts +25 -0
  91. package/dist/openapi/document.d.ts +25 -0
  92. package/dist/openapi/operations.d.cts +78 -0
  93. package/dist/openapi/operations.d.ts +78 -0
  94. package/dist/openapi/references.d.cts +28 -0
  95. package/dist/openapi/references.d.ts +28 -0
  96. package/dist/openapi/responses.d.cts +44 -0
  97. package/dist/openapi/responses.d.ts +44 -0
  98. package/dist/openapi/schemas.d.cts +112 -0
  99. package/dist/openapi/schemas.d.ts +112 -0
  100. package/dist/output/outputStore.d.cts +92 -0
  101. package/dist/output/outputStore.d.ts +92 -0
  102. package/dist/pipeline/codeGenerator.d.cts +61 -0
  103. package/dist/pipeline/codeGenerator.d.ts +61 -0
  104. package/dist/pipeline/seams.d.cts +29 -0
  105. package/dist/pipeline/seams.d.ts +29 -0
  106. package/dist/types/typeResolver.d.cts +124 -0
  107. package/dist/types/typeResolver.d.ts +124 -0
  108. package/dist/version.d.cts +2 -0
  109. package/dist/version.d.ts +2 -0
  110. package/dist/wow/conventions.d.cts +154 -0
  111. package/dist/wow/conventions.d.ts +154 -0
  112. package/dist/wow/model.d.cts +116 -0
  113. package/dist/wow/model.d.ts +116 -0
  114. package/dist/wow/resolveWowModel.d.cts +21 -0
  115. package/dist/wow/resolveWowModel.d.ts +21 -0
  116. package/package.json +108 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codeGenerator-kyY9eLML.js","names":["DEFAULT_CONFIG_PATH","EXIT_CODES","GeneratorError","message","options","kind","errorMessage","error","defaultDecorate","ConsoleLogger","prefix","symbol","label","params","SilentLogger","NAMING_SEPARATORS","RESERVED_WORDS","isIdentifier","name","prefixLeadingDigit","toIdentifier","identifier","camelCase","isTypeNamePart","part","toTypeIdentifier","pascalCase","splitName","tokenizeName","splitCamelCase","parts","result","current","i","char","isUpper","prevIsLower","firstChar","rest","pascalCaseName","upperSnakeCase","resolvePropertyName","quoteStringLiteral","enumMemberKey","value","NAME_COLLATOR","compareNames","left","right","isReference","schema","resolveLocalPointer","pointer","ref","document","token","key","findDanglingReferences","dangling","seen","visit","item","location","index","child","COMPONENTS_PREFIX","COMPONENTS_PARAMETERS_REF","COMPONENTS_REQUEST_BODIES_REF","COMPONENTS_RESPONSES_REF","COMPONENTS_SCHEMAS_REF","extractComponentKey","reference","resolveComponent","visited","components","extractSchema","extractResponse","extractRequestBody","extractParameter","keySchema","APPLICATION_JSON","TEXT_EVENT_STREAM","mediaTypeOf","contentType","isJsonContentType","mediaType","isTextContentType","findMediaType","exact","content","matches","extractResponseSchema","response","extractResponseJsonSchema","extractResponseEventStreamSchema","extractResponseWildcardSchema","hasTextResponse","PRIMITIVE_TYPES","isPrimitive","type","isEnum","ENUM_TEXT_NAME","getEnumText","isObject","isArray","isAnyOf","isOneOf","isAllOf","isComposition","toArrayType","isMap","X_MAP_KEY_SCHEMA","getMapKeySchema","isEmptyObject","isReadOnly","resolvePrimitiveType","it","resolveOptionalFields","declared","required","admitsNull","walk","operationEndpointComparator","mergeParameters","parameters","parameter","inherited","own","resolved","extractOperationEndpoints","operationEndpoints","path","pathItem","paths","methodOperation","extractOperations","operation","okResponseStatus","statuses","status","extractOkResponse","extractOperationOkResponseJsonSchema","extractParameters","extractPathParameters","inPathOrder","position","a","b","DEFAULT_PATH_PARAMETER_TYPE","resolvePathParameterType","MINIMUM_WOW_VERSION","CONTEXT_ALIAS_EXTENSION","contextAliasOf","openAPI","isAliasAggregate","tagName","tagToAggregate","tag","operationIdToCommandName","operationId","STATE_OPERATION_SUFFIX","FIELDS_OPERATION_SUFFIX","QUERY_FIELDS_EXTENSION","SNAPSHOT_ROUTE","AGGREGATED_SCHEMA_SUFFIXES","aggregatedTypeNames","stateName","suffix","isWowSchema","schemaKey","aggregatedNames","modelName","IMPORT_WOW_PATH","IMPORT_WOW_LEGACY_PATH","WOW_LEGACY_TYPES","WOW_TYPE_MAPPING","wowTypeOf","mappedType","properties","IGNORED_API_CLIENT_TAGS","RESOURCE_ATTRIBUTION_PATH_PARAMETERS","inferPathSpecType","tenantSpecCount","ownerSpecCount","aggregateDefinition","command","clientModulePath","aggregate","fileName","resolveClassName","OPERATION_METHOD_NAME_KEY","resolveMethodName","explicit","configured","isMethodName","uniqueParameterName","unique","used","resolveModelInfo","wowType","modelNameIndex","pathParts","resolveReferenceModelInfo","resolveContextDeclarationName","contextAlias","COMMAND_SUFFIX","analyzeAggregates","wow","aggregates","analyzeAggregate","definition","commandClient","queryClient","members","endpointMemberNames","body","commandMethodName","commandTypeName","assertCommandTypeNamesFree","packagePath","taken","model","models","bodyKey","typeName","taker","names","base","factoryPrefix","event","combinePaths","relative","MODEL_FILE_NAME","modelFilePath","boundedContextFilePath","isWowDocument","withDocOverride","override","RESERVED_PARAMETER_NAMES","analyzeApiClients","ApiClientAnalysis","config","warnings","tags","operations","claimed","modelInfo","clientInfo","clientKey","className","file","apiClientFileName","methods","endpoint","described","description","methodName","located","cookies","cookie","parameterName","requestBody","json","okResponse","responseJsonSchema","jsonSchema","eventStreamSchema","operationTags","clientTags","analyzeContexts","aliases","alias","analyzeModels","schemas","derived","derivedTypeNames","ofApiClients","apiClientSchemaKeys","keys","bodies","messageBodyKeys","info","isEmptyMessageBody","node","$ref","assertUniqueModelNames","byModel","collisions","analyze","contexts","ImportRegistry","imported","moduleSpecifier","requests","except","ModuleBuilder","sourceFile","statement","statements","previous","declaration","StructureKind","blankLineBetween","blankLine","ModuleSet","open","filePath","module","next","membersWithTrailingComma","member","indexSignatureMember","returnType","IMPORT_ALIAS","addImport","namedImports","addImportRefModel","modelModuleSpecifier","outputDir","refModelInfo","relativeModuleSpecifier","join","relativePath","fromDirectory","targetFilePath","sep","addImportBoundedContext","declarationName","jsDoc","descriptions","filtered","v","escapeJsDoc","separator","text","addJSDoc","jsdoc","schemaJSDoc","addJsonJsDoc","addNumericConstraintsJsDoc","addStringConstraintsJsDoc","addArrayConstraintsJsDoc","addSchemaJSDoc","addMainSchemaJSDoc","includeSchema","jsonJsDoc","propertyName","constraintsDescriptions","createTypeContext","namesByPath","naming","GLOBAL_TYPE_NAMES","PRIMITIVE_TYPE_NAMES","ANNOTATION_KEYWORDS","sameKind","schemaKind","kinds","first","clashesWithIndexSignature","indexKind","additionalProperties","propertyKind","propSchema","requiresAdditionalPropertiesIntersection","isNullableReference","matchesLiteralType","resolveLiteral","CodeBlockWriter","Resolution","scope","entry","owner","reservedNames","propName","resolvedPropName","doc","mapType","additionalProps","objectType","mapKeySchema","resolve","root","nodes","constrained","pending","groups","changed","allOf","oneOf","anyOf","isConstrained","simple","compositions","keyword","composed","baseType","literal","keywords","isNullMember","types","discriminator","componentKey","mapped","target","resolveWith","resolution","resolveType","resolveAdditionalProperties","resolveAdditionalPropertyType","resolveRequiredAdditionalPropertyType","resolveMapValueType","FETCHER_MODULE_SPECIFIER","FETCHER_NAMED_IMPORTS","DECORATOR_MODULE_SPECIFIER","DECORATOR_NAMED_IMPORTS","DEFAULT_RETURN_TYPE","STRING_RETURN_TYPE","STREAM_RESULT_EXTRACTOR_METADATA","COMMAND_STREAM_ENDPOINT_METADATA","addImportFetcher","addImportDecorator","createDecoratorClass","extendsClass","apiArgs","addApiMetadataCtor","classDeclaration","defaults","Scope","methodToDecorator","method","EVENTSTREAM_MODULE_SPECIFIER","addImportEventStream","emitApiClient","client","apiClientClass","clientTypes","apiMethod","optional","bodyType","returnTypeOf","returns","DEFAULT_COMMAND_CLIENT_OPTIONS","emitCommandClient","requestTypes","addCommandType","VariableDeclarationKind","commandParameters","commandType","optionalFields","requestType","documentTypeContext","emitModel","ModelEmitter","uniqueEnumMemberNames","values","preferred","candidates","candidate","enumText","textNames","memberName","stringValues","memberNames","writer","propertySignature","interfaceDeclaration","schemaProperties","itemType","DEFAULT_QUERY_CLIENT_OPTIONS","emitQueryClient","emitGeneration","emitBoundedContext","context","emitIndexFiles","indexDirectory","claim","children","dir","baseName","exportedNames","subDir","exports","dirPath","writeIndex","owners","ambiguous","specifiers","indexFile","exported","typeOnly","isTypeOnly","declarations","Node","isTypePosition","parent","clause","SyntaxKind","planTypeOnlyImports","localNames","specifier","valueSymbols","applyTypeOnly","allTypeOnly","inline","applyTypeOnlyImports","plans","sourceFiles","apply","INTEGRITY_DIAGNOSTICS","verifyGeneratedCode","problems","diagnostic","ts","GENERATED_FILE_HEADER","FORMAT_SETTINGS","finalizeSourceFiles","logger","DEFAULT_HTTP_TIMEOUT_MS","isHttpLocation","loadResource","loadHttpResource","loadFile","timeoutMs","timeout","url","reason","networkReason","cause","err","reject","data","parseOpenAPI","inputPath","parseContent","validateOpenAPIDocument","source","inferFileFormat","parse","trimmedContent","LEGACY_CONFIG_PATH","resolveConfiguration","configPath","loadConfiguration","describeSource","loaded","CONFIGURATION_KEYS","API_CLIENT_KEYS","origin","isFileNotFound","parsed","validateConfiguration","describe","isAbsolute","typeOf","isRecord","warnUnknownKeys","unknown","known","validateApiClients","apiClients","apiClient","ignorePathParameters","methodNames","openApiDocument","GENERATION_MANIFEST","LEGACY_GENERATION_MANIFEST","OutputStore","project","outputPath","legacyManifest","fs","legacyManifestPath","manifestPath","manifest","readManifest","hash","assertWithinOutputDir","leaving","last","directory","written","attempt","files","outputFailure","signal","fileHash","remedy","version","action","change","normalized","rel","resolveWowModel","schemaDocOverrides","wowTags","declaredNames","undeclared","endpoints","aggregatesOf","lend","keyed","field","malformed","problem","resourceName","readCommand","commandName","pathParameters","commandRefSchema","commandKeyedSchema","commandDefinition","readState","stateRefSchema","stateKeyedSchema","readEvents","eventStreamArraySchema","eventStreamRefSchema","domainEventSchemas","objectAt","events","eventName","domainEventSchema","eventBodySchema","eventBodyKeyedSchema","readFields","queryFields","fieldRefSchema","conditionRefSchema","fieldKeyedSchema","missing","PROJECT_SEAM","SIGNAL_SEAM","CodeGenerator","createProject","IndentationText","QuoteKind","warn","line","lines","loadOptions","configuration","output","analysis","modules","outputDirectory","Project","tsConfigFilePath"],"sources":["../src/api/configuration.ts","../src/api/errors.ts","../src/api/logger.ts","../src/naming/naming.ts","../src/naming/order.ts","../src/openapi/references.ts","../src/openapi/components.ts","../src/openapi/responses.ts","../src/openapi/schemas.ts","../src/openapi/operations.ts","../src/wow/conventions.ts","../src/analysis/clientNames.ts","../src/analysis/modelInfo.ts","../src/analysis/aggregates.ts","../src/naming/paths.ts","../src/wow/model.ts","../src/analysis/apiClients.ts","../src/analysis/models.ts","../src/analysis/analyze.ts","../src/emit/importRegistry.ts","../src/emit/moduleBuilder.ts","../src/emit/imports.ts","../src/emit/jsdoc.ts","../src/types/typeResolver.ts","../src/emitters/decorators.ts","../src/emitters/apiClients.ts","../src/emitters/commandClients.ts","../src/emitters/models.ts","../src/emitters/queryClients.ts","../src/emitters/emit.ts","../src/emitters/indexFiles.ts","../src/finalize/typeOnlyImports.ts","../src/finalize/verification.ts","../src/finalize/finalize.ts","../src/input/resources.ts","../src/input/parsers.ts","../src/input/configuration.ts","../src/openapi/document.ts","../src/output/outputStore.ts","../src/wow/resolveWowModel.ts","../src/pipeline/seams.ts","../src/pipeline/codeGenerator.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Where the generator looks for its configuration when none is named.\n */\nexport const DEFAULT_CONFIG_PATH = './wow-generator.config.json';\n\n/**\n * The generator configuration, read from {@link DEFAULT_CONFIG_PATH} or the\n * path `GeneratorOptions.configPath` names.\n */\nexport interface GeneratorConfiguration {\n /**\n * tag name -> api client configuration\n */\n apiClients?: Record<string, ApiClientConfiguration>;\n}\n\nexport interface ApiClientConfiguration {\n /**\n * The path parameters the client leaves out, because an interceptor fills\n * them.\n *\n * Default: `['tenantId', 'ownerId']` for a Wow document (one with\n * `x-wow-context-alias` or aggregates), whose CoSec interceptor fills them;\n * none for any other document.\n */\n ignorePathParameters?: string[];\n /**\n * Method names by operationId, overriding the name derived from it. Use it\n * when two operations of one tag derive the same name.\n */\n methodNames?: Record<string, string>;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * What a generation failure is about, which decides the CLI's exit code.\n *\n * - `input`: the OpenAPI document cannot be read, fetched or parsed, or it is\n * not an OpenAPI 3 document.\n * - `configuration`: the generator configuration cannot be read, parsed or\n * understood.\n * - `specification`: the document was read, but it describes something the\n * generator cannot turn into code that compiles: a dangling, cyclic or\n * external reference, names that collide after normalisation, malformed Wow\n * metadata.\n * - `output`: the output directory cannot be written as asked: its manifest\n * (`.wow-generator.json`) is corrupt, a path resolves outside it, or writing\n * or deleting a file fails.\n */\nexport type GeneratorErrorKind =\n 'input' | 'configuration' | 'specification' | 'output';\n\n/**\n * Exit codes of the `wow-generator` CLI. Anything the generator did not\n * anticipate exits with {@link EXIT_CODES.internal}.\n */\nexport const EXIT_CODES = {\n success: 0,\n internal: 1,\n input: 2,\n configuration: 3,\n specification: 4,\n output: 5,\n interrupted: 130,\n} as const;\n\n/**\n * A failure the user can act on. Its message is written as one line that\n * names what went wrong and where; the CLI prints it without a stack trace.\n */\nexport class GeneratorError extends Error {\n constructor(\n readonly kind: GeneratorErrorKind,\n message: string,\n options?: ErrorOptions,\n ) {\n super(message, options);\n this.name = 'GeneratorError';\n }\n\n /** The CLI exit code this failure maps to. */\n get exitCode(): number {\n return EXIT_CODES[this.kind];\n }\n}\n\n/** Renders an error as the tail of a sentence. */\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Where a generation reports what it does.\n *\n * Each method takes a message and, optionally, values to print after it, as\n * `console.log` does. A run calls:\n *\n * - `debug` for every step and detail;\n * - `info` for the outcome of the run;\n * - `warn` for something it carried on past, but that the user probably did\n * not intend; `GenerationResult.warnings` counts these calls;\n * - `error` for a failure.\n */\nexport interface Logger {\n debug(message: string, ...params: unknown[]): void;\n info(message: string, ...params: unknown[]): void;\n warn(message: string, ...params: unknown[]): void;\n error(message: string, ...params: unknown[]): void;\n}\n\n/**\n * How much a {@link ConsoleLogger} prints.\n *\n * - `quiet`: warnings and errors only.\n * - `normal`: also `info`, the outcome of the run.\n * - `verbose`: also `debug`, every detail, with timestamps.\n */\nexport type LogLevel = 'quiet' | 'normal' | 'verbose';\n\nexport interface ConsoleLoggerOptions {\n /** Defaults to `normal`. */\n readonly level?: LogLevel;\n /**\n * Prefix lines with symbols. Defaults to true on a TTY unless `NO_COLOR`\n * is set, so CI logs and pipes stay plain.\n */\n readonly decorate?: boolean;\n}\n\nfunction defaultDecorate(): boolean {\n return !!process.stdout?.isTTY && !process.env.NO_COLOR;\n}\n\n/**\n * Console logger for the CLI.\n *\n * Details go to `debug`, which only `verbose` prints; the default prints the\n * outcome, warnings and errors, so a warning is not lost among hundreds of\n * detail lines.\n */\nexport class ConsoleLogger implements Logger {\n private readonly level: LogLevel;\n private readonly decorate: boolean;\n\n constructor(options: ConsoleLoggerOptions = {}) {\n this.level = options.level ?? 'normal';\n this.decorate = options.decorate ?? defaultDecorate();\n }\n\n private format(symbol: string, label: string, message: string): string {\n const prefix = this.decorate ? `${symbol} ` : label ? `${label}: ` : '';\n const timestamp =\n this.level === 'verbose'\n ? `[${new Date().toTimeString().slice(0, 8)}] `\n : '';\n return `${timestamp}${prefix}${message}`;\n }\n\n debug(message: string, ...params: unknown[]): void {\n if (this.level !== 'verbose') return;\n console.log(this.format('ℹ️ ', '', message), ...params);\n }\n\n info(message: string, ...params: unknown[]): void {\n if (this.level === 'quiet') return;\n console.log(this.format('✅', '', message), ...params);\n }\n\n warn(message: string, ...params: unknown[]): void {\n console.warn(this.format('⚠️ ', 'warning', message), ...params);\n }\n\n error(message: string, ...params: unknown[]): void {\n console.error(this.format('❌', 'error', message), ...params);\n }\n}\n\n/**\n * Logger that prints nothing.\n */\nexport class SilentLogger implements Logger {\n debug(): void {}\n\n info(): void {}\n\n warn(): void {}\n\n error(): void {}\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Anything that is neither a letter, a digit nor `$` separates the words of a\n * name: `-`, `_`, `.`, spaces, and characters no identifier may hold, such as\n * the guillemets of a Springfox `Page«User»`.\n */\nconst NAMING_SEPARATORS = /[^\\p{L}\\p{N}$]+/u;\n\n/**\n * Words JavaScript reserves, in strict mode included, which may not name a\n * parameter or a variable.\n */\nconst RESERVED_WORDS = new Set([\n 'arguments',\n 'await',\n 'break',\n 'case',\n 'catch',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'else',\n 'enum',\n 'eval',\n 'export',\n 'extends',\n 'false',\n 'finally',\n 'for',\n 'function',\n 'if',\n 'implements',\n 'import',\n 'in',\n 'instanceof',\n 'interface',\n 'let',\n 'new',\n 'null',\n 'package',\n 'private',\n 'protected',\n 'public',\n 'return',\n 'static',\n 'super',\n 'switch',\n 'this',\n 'throw',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'while',\n 'with',\n 'yield',\n]);\n\n/**\n * Tells whether a name is a valid identifier as written.\n *\n * @param name - The candidate\n * @returns True when it can name a variable, a parameter or a type\n */\nexport function isIdentifier(name: string): boolean {\n return (\n /^[\\p{ID_Start}$_][\\p{ID_Continue}$\\u200C\\u200D]*$/u.test(name) &&\n !RESERVED_WORDS.has(name)\n );\n}\n\nfunction prefixLeadingDigit(name: string): string {\n return /^\\p{N}/u.test(name) ? `_${name}` : name;\n}\n\n/**\n * Turns a name from the document into a value identifier: a parameter, a\n * method or a variable.\n *\n * A valid identifier is kept as written. Anything else is camel-cased on its\n * separators (`item-id` → `itemId`), prefixed with `_` when it starts with a\n * digit, and suffixed with `_` when it is a reserved word (`default` →\n * `default_`).\n *\n * @param name - The name the document uses\n * @returns A valid identifier\n */\nexport function toIdentifier(name: string): string {\n if (isIdentifier(name)) return name;\n const identifier = prefixLeadingDigit(camelCase(name) || '_');\n return RESERVED_WORDS.has(identifier) ? `${identifier}_` : identifier;\n}\n\n/**\n * Tells whether a part of a type name is kept as written: it starts with an\n * upper-case letter and holds only letters, digits and `$`, so its casing,\n * acronyms included, is the document's own (`MCPListTools`).\n */\nfunction isTypeNamePart(part: string): boolean {\n return /^\\p{Lu}[\\p{L}\\p{N}$]*$/u.test(part) && isIdentifier(part);\n}\n\n/**\n * Turns a name from the document into a type identifier: a model, an enum or\n * a class.\n *\n * Each part that starts with an upper-case letter and holds no separator is\n * kept as written, acronyms included (`MCPListTools` stays `MCPListTools`).\n * Any other part is pascal-cased on its separators (`order_item` →\n * `OrderItem`, `Page«User»` → `PageUser`). The result is prefixed with `_`\n * when it starts with a digit (`1stThing` → `_1stThing`).\n *\n * @param name - A name, or the parts of one\n * @returns A valid type identifier\n */\nexport function toTypeIdentifier(name: string | string[]): string {\n const parts = Array.isArray(name) ? name : [name];\n const identifier = parts\n .map(part => (isTypeNamePart(part) ? part : pascalCase(part)))\n .join('');\n return prefixLeadingDigit(identifier || '_');\n}\n\nexport function splitName(name: string) {\n return name.split(NAMING_SEPARATORS);\n}\n\n/**\n * Splits a name string or array of strings by common naming separators.\n *\n * This function takes a string or array of strings and splits them based on common naming\n * separators including hyphens, underscores, spaces, dots, and before uppercase letters.\n * If an array is provided, each element is split individually and the results are flattened.\n *\n * @param name - A string or array of strings to split by naming separators\n * @returns An array of string parts split by naming separators\n */\nexport function tokenizeName(name: string | string[]): string[] {\n if (Array.isArray(name)) {\n // If input is an array, split each element by naming separators and flatten the result\n return name.flatMap(part => splitCamelCase(splitName(part)));\n }\n return splitCamelCase(splitName(name));\n}\n\n/**\n * Splits camelCase strings properly, keeping consecutive uppercase letters together.\n *\n * @param parts - Array of string parts to process\n * @returns Array of properly split parts\n */\nexport function splitCamelCase(parts: string[]): string[] {\n return parts.flatMap(part => {\n if (part.length === 0) {\n return [];\n }\n\n // Split on uppercase letters that follow lowercase letters\n const result: string[] = [];\n let current = '';\n\n for (let i = 0; i < part.length; i++) {\n const char = part[i];\n const isUpper = /[A-Z]/.test(char);\n const prevIsLower = i > 0 && /[a-z]/.test(part[i - 1]);\n\n if (isUpper && prevIsLower && current) {\n result.push(current);\n current = char;\n } else {\n current += char;\n }\n }\n\n if (current) {\n result.push(current);\n }\n\n return result;\n });\n}\n\n/**\n * Converts a string or array of strings to PascalCase format.\n *\n * This function takes a string or array of strings and converts them to PascalCase format\n * by splitting the input based on common naming separators and capitalizing the first\n * letter of each part.\n *\n * @param name - A string or array of strings to convert to PascalCase\n * @returns The PascalCase formatted string\n */\nexport function pascalCase(name: string | string[]): string {\n if (name === '' || name.length === 0) {\n return '';\n }\n const names: string[] = tokenizeName(name);\n return names\n .filter(part => part.length > 0)\n .map(part => {\n const firstChar = part.charAt(0);\n const rest = part.slice(1);\n return (\n (/[a-zA-Z]/.test(firstChar) ? firstChar.toUpperCase() : firstChar) +\n rest.toLowerCase()\n );\n })\n .join('');\n}\n\n/**\n * Converts a string or array of strings to camelCase format.\n *\n * This function first converts the input to PascalCase and then converts the first character to lowercase.\n *\n * @param name - A string or array of strings to convert to camelCase\n * @returns The camelCase formatted string\n */\nexport function camelCase(name: string | string[]): string {\n const pascalCaseName = pascalCase(name);\n return pascalCaseName.charAt(0).toLowerCase() + pascalCaseName.slice(1);\n}\n\n/**\n * Converts a string or array of strings to UPPER_SNAKE_CASE format.\n *\n * This function takes a string or array of strings and converts them to UPPER_SNAKE_CASE format\n * by splitting the input based on common naming separators, converting each part to uppercase,\n * and joining them with underscores. It properly handles consecutive uppercase letters\n * (like acronyms) by treating them as single units.\n *\n * @param name - A string or array of strings to convert to UPPER_SNAKE_CASE\n * @returns The UPPER_SNAKE_CASE formatted string\n */\nexport function upperSnakeCase(name: string | string[]): string {\n if (name === '' || (Array.isArray(name) && name.length === 0)) {\n return '';\n }\n\n const names = tokenizeName(name);\n return names\n .filter(part => part.length > 0)\n .map(part => part.toUpperCase())\n .join('_');\n}\n\nexport function resolvePropertyName(name: string): string {\n if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)) {\n return name;\n }\n\n return quoteStringLiteral(name);\n}\n\n/**\n * The member key an enum value prefers, before quoting: its UPPER_SNAKE_CASE\n * form, `NUM_` and the digits for a number.\n */\nexport function enumMemberKey(name: string): string {\n if (/^\\d+$/.test(name)) {\n return `NUM_${name}`;\n }\n return upperSnakeCase(name) || name;\n}\n\n/**\n * Renders a value as a single-quoted TypeScript string literal.\n *\n * A property name is whatever the document says it is, so one carrying a\n * quote or a backslash has to be escaped rather than wrapped - `owner'sName`\n * would otherwise close the literal and generate a syntax error.\n *\n * @param value - The string to render\n * @returns The escaped string literal, quotes included\n */\nexport function quoteStringLiteral(value: string): string {\n // JSON escapes backslashes, double quotes, line breaks and control\n // characters; swap the double-quote escaping for single quotes.\n const escaped = JSON.stringify(value)\n .slice(1, -1)\n .replace(/\\\\\"/g, '\"')\n .replace(/'/g, \"\\\\'\");\n return `'${escaped}'`;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Orders names the same way on every machine.\n *\n * `localeCompare` without a locale follows the default locale of the process,\n * which ICU takes from `LANG`: under `tr_TR` a name starting with `I` sorts\n * after one starting with `i`, so the order of a barrel's exports or of a\n * client's methods would depend on where the generator ran. The collator is\n * fixed to `en-US`, the order CI has always produced, so no output changes.\n */\nconst NAME_COLLATOR = new Intl.Collator('en-US');\n\n/** Compares two names in the fixed `en-US` order; a comparator for `sort`. */\nexport function compareNames(left: string, right: string): number {\n return NAME_COLLATOR.compare(left, right);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Reference } from '@ahoo-wang/fetcher-openapi';\n\nexport function isReference(schema: any): schema is Reference {\n return !!(schema && typeof schema === 'object' && '$ref' in schema);\n}\n\n/**\n * Resolves a local JSON pointer (`#/components/schemas/Item`) in a document.\n *\n * @param document - The document the pointer points into\n * @param ref - The `$ref` value, starting with `#`\n * @returns The value it points at, or undefined when there is none\n */\nexport function resolveLocalPointer(document: unknown, ref: string): unknown {\n let pointer = ref.slice(1);\n try {\n pointer = decodeURIComponent(pointer);\n } catch {\n // Not percent-encoded after all; read it as written.\n }\n if (pointer === '') return document;\n let current: unknown = document;\n for (const token of pointer.slice(1).split('/')) {\n if (current === null || typeof current !== 'object') return undefined;\n const key = token.replace(/~1/g, '/').replace(/~0/g, '~');\n if (!Object.hasOwn(current, key)) return undefined;\n current = (current as Record<string, unknown>)[key];\n }\n return current;\n}\n\n/**\n * Finds every reference to a component (`#/components/...`) that points at\n * nothing.\n *\n * A dangling schema reference would otherwise generate a type that names an\n * undeclared model, and a dangling parameter reference would silently drop\n * the parameter. Other references are left alone: a reference to another\n * document is refused where it is read, with a request to bundle it, and a\n * schema may carry JSON Schema `definitions` it references relative to\n * itself (`#/definitions/...`), as Wow 8.11 writes its filter schema.\n *\n * @param document - The parsed OpenAPI document\n * @returns Each dangling reference with the JSON path of the object holding it\n */\nexport function findDanglingReferences(\n document: unknown,\n): { ref: string; location: string }[] {\n const dangling: { ref: string; location: string }[] = [];\n const seen = new Set<object>();\n const visit = (value: unknown, location: string) => {\n if (value === null || typeof value !== 'object' || seen.has(value)) return;\n seen.add(value);\n if (Array.isArray(value)) {\n value.forEach((item, index) => visit(item, `${location}/${index}`));\n return;\n }\n const ref = (value as Record<string, unknown>).$ref;\n if (\n typeof ref === 'string' &&\n ref.startsWith('#/components/') &&\n resolveLocalPointer(document, ref) === undefined\n ) {\n dangling.push({ ref, location: location || '/' });\n }\n for (const [key, child] of Object.entries(value)) {\n visit(\n child,\n `${location}/${key.replace(/~/g, '~0').replace(/\\//g, '~1')}`,\n );\n }\n };\n visit(document, '');\n return dangling;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { GeneratorError } from '../api/errors';\nimport type {\n Components,\n Parameter,\n Reference,\n RequestBody,\n Response,\n Schema,\n} from '@ahoo-wang/fetcher-openapi';\nimport { isReference } from './references';\n\n/** Prefix for OpenAPI components references */\nexport const COMPONENTS_PREFIX = '#/components/';\n/** Reference prefix for parameters components */\nexport const COMPONENTS_PARAMETERS_REF = `${COMPONENTS_PREFIX}parameters/`;\n/** Reference prefix for request bodies components */\nexport const COMPONENTS_REQUEST_BODIES_REF = `${COMPONENTS_PREFIX}requestBodies/`;\n/** Reference prefix for responses components */\nexport const COMPONENTS_RESPONSES_REF = `${COMPONENTS_PREFIX}responses/`;\n/** Reference prefix for schemas components */\nexport const COMPONENTS_SCHEMAS_REF = `${COMPONENTS_PREFIX}schemas/`;\n\n/**\n * Represents a schema with its key identifier.\n */\nexport interface KeySchema<T extends Schema | Reference = Schema> {\n /** The schema key */\n key: string;\n /** The schema definition */\n schema: T;\n}\n\n/**\n * Extracts the component key from an OpenAPI reference.\n * @param reference - The OpenAPI reference object\n * @returns The component key (last part of the reference path)\n */\nexport function extractComponentKey(reference: Reference): string {\n return reference.$ref.split('/').pop() as string;\n}\n\n/**\n * Extracts a schema from OpenAPI components using a reference.\n * @param reference - The reference to the schema\n * @param components - The OpenAPI components object\n * @returns The schema if found, undefined otherwise\n */\nfunction resolveComponent<T>(\n reference: Reference,\n components: Record<string, T | Reference> | undefined,\n prefix: string,\n): T | undefined {\n const visited = new Set<string>();\n let current: T | Reference | undefined = reference;\n while (isReference(current)) {\n // ponytail: local components only; bundle external references before generation.\n if (!current.$ref.startsWith(prefix)) return undefined;\n if (visited.has(current.$ref)) {\n throw new GeneratorError(\n 'specification',\n `Cyclic component reference: ${current.$ref}`,\n );\n }\n visited.add(current.$ref);\n current = components?.[current.$ref.slice(prefix.length)];\n }\n return current;\n}\n\nexport function extractSchema(\n reference: Reference,\n components: Components,\n): Schema | undefined {\n return resolveComponent(\n reference,\n components.schemas,\n COMPONENTS_SCHEMAS_REF,\n );\n}\n\n/**\n * Extracts a response from OpenAPI components using a reference.\n * @param reference - The reference to the response\n * @param components - The OpenAPI components object\n * @returns The response if found, undefined otherwise\n */\nexport function extractResponse(\n reference: Reference,\n components: Components,\n): Response | undefined {\n return resolveComponent(\n reference,\n components.responses,\n COMPONENTS_RESPONSES_REF,\n );\n}\n\n/**\n * Extracts a request body from OpenAPI components using a reference.\n * @param reference - The reference to the request body\n * @param components - The OpenAPI components object\n * @returns The request body if found, undefined otherwise\n */\nexport function extractRequestBody(\n reference: Reference,\n components: Components,\n): RequestBody | undefined {\n return resolveComponent(\n reference,\n components.requestBodies,\n COMPONENTS_REQUEST_BODIES_REF,\n );\n}\n\n/**\n * Extracts a parameter from OpenAPI components using a reference.\n * @param reference - The reference to the parameter\n * @param components - The OpenAPI components object\n * @returns The parameter if found, undefined otherwise\n */\nexport function extractParameter(\n reference: Reference,\n components: Components,\n): Parameter | undefined {\n return resolveComponent(\n reference,\n components.parameters,\n COMPONENTS_PARAMETERS_REF,\n );\n}\n\n/**\n * Creates a KeySchema object from a reference and components.\n * @param reference - The reference to the schema\n * @param components - The OpenAPI components object\n * @returns A KeySchema containing the key and resolved schema\n */\nexport function keySchema(\n reference: Reference,\n components: Components,\n): KeySchema {\n const componentKey = extractComponentKey(reference);\n return {\n key: componentKey,\n schema: extractSchema(reference, components)!,\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n MediaType,\n Reference,\n Response,\n Schema,\n} from '@ahoo-wang/fetcher-openapi';\nimport { isReference } from './references';\n\n/** The media type of JSON. */\nexport const APPLICATION_JSON = 'application/json';\n\n/** The media type of a server-sent event stream. */\nexport const TEXT_EVENT_STREAM = 'text/event-stream';\n\n/**\n * The media type part of a content type, without parameters and in lower\n * case: `application/json;charset=UTF-8` → `application/json`.\n */\nexport function mediaTypeOf(contentType: string): string {\n return contentType.split(';')[0].trim().toLowerCase();\n}\n\n/**\n * Tells whether a content type carries JSON: `application/json`, or any\n * `+json` type such as `application/hal+json` or `application/problem+json`,\n * with or without parameters.\n */\nexport function isJsonContentType(contentType: string): boolean {\n const mediaType = mediaTypeOf(contentType);\n return (\n mediaType === APPLICATION_JSON ||\n /^application\\/[^/]+\\+json$/.test(mediaType)\n );\n}\n\n/**\n * Tells whether a content type is text other than an event stream.\n */\nexport function isTextContentType(contentType: string): boolean {\n const mediaType = mediaTypeOf(contentType);\n return mediaType.startsWith('text/') && mediaType !== TEXT_EVENT_STREAM;\n}\n\n/**\n * Finds the entry of a content map that matches, preferring an exact key.\n *\n * @param content - The content map of a request body or a response\n * @param exact - The content type to prefer as written\n * @param matches - What else qualifies\n * @returns The media type object, or undefined\n */\nexport function findMediaType(\n content: Record<string, MediaType> | undefined,\n exact: string,\n matches: (contentType: string) => boolean = contentType =>\n mediaTypeOf(contentType) === exact,\n): MediaType | undefined {\n if (!content) return undefined;\n if (content[exact]) return content[exact];\n const key = Object.keys(content).find(matches);\n return key === undefined ? undefined : content[key];\n}\n\nexport function extractResponseSchema(\n contentType: string,\n response?: Response | Reference,\n): Schema | Reference | undefined {\n if (!response) {\n return;\n }\n if (isReference(response)) {\n return undefined;\n }\n return findMediaType(response.content, contentType)?.schema;\n}\n\n/**\n * Extracts the JSON schema of a response: `application/json` or any `+json`\n * type, with or without parameters.\n * @param response - The response object or reference\n * @returns The JSON schema from the response content or undefined if not found\n */\nexport function extractResponseJsonSchema(\n response?: Response | Reference,\n): Schema | Reference | undefined {\n if (!response || isReference(response)) return undefined;\n return findMediaType(response.content, APPLICATION_JSON, isJsonContentType)\n ?.schema;\n}\n\nexport function extractResponseEventStreamSchema(\n response?: Response | Reference,\n): Schema | Reference | undefined {\n return extractResponseSchema(TEXT_EVENT_STREAM, response);\n}\n\nexport function extractResponseWildcardSchema(\n response?: Response | Reference,\n): Schema | Reference | undefined {\n return extractResponseSchema('*/*', response);\n}\n\n/**\n * Tells whether a response carries text other than an event stream, such as\n * `text/plain`.\n */\nexport function hasTextResponse(response?: Response | Reference): boolean {\n if (!response || isReference(response)) return false;\n return Object.keys(response.content ?? {}).some(isTextContentType);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n Components,\n Reference,\n Schema,\n SchemaType,\n} from '@ahoo-wang/fetcher-openapi';\nimport { extractSchema } from './components';\nimport { isReference } from './references';\n\n/** List of primitive schema types */\nconst PRIMITIVE_TYPES: SchemaType[] = [\n 'string',\n 'number',\n 'integer',\n 'boolean',\n 'null',\n];\n\n/**\n * Checks if a schema type is primitive.\n * @param type - The schema type to check\n * @returns True if the type is primitive, false otherwise\n */\nexport function isPrimitive(type: SchemaType | SchemaType[]): boolean {\n if (Array.isArray(type)) {\n return true;\n }\n return PRIMITIVE_TYPES.includes(type);\n}\n\nexport type EnumSchema = Schema & { enum: any[] };\n\n/**\n * Checks if a schema represents an enum.\n * @param schema - The schema to check\n * @returns True if the schema has an enum property, false otherwise\n */\nexport function isEnum(schema: Schema): schema is EnumSchema {\n return Array.isArray(schema.enum) && schema.enum.length > 0;\n}\n\nexport type EnumText = Record<string, string>;\nconst ENUM_TEXT_NAME = 'x-enum-text';\n\nexport function getEnumText(schema: EnumSchema): EnumText | undefined {\n return schema[ENUM_TEXT_NAME];\n}\n\nexport type ObjectSchema = Schema & {\n type: 'object';\n properties: Record<string, Schema | Reference>;\n};\n\nexport function isObject(schema: Schema): schema is ObjectSchema {\n return schema.type === 'object' && !!schema.properties;\n}\n\nexport type ArraySchema = Schema & { type: 'array'; items: Schema | Reference };\n\n/**\n * Checks if a schema is an array type.\n * @param schema - The schema to check\n * @returns True if the schema is an array type, false otherwise\n */\nexport function isArray(schema: Schema): schema is ArraySchema {\n return schema.type === 'array' && !!schema.items;\n}\n\nexport type AnyOfSchema = Schema & { anyOf: any[] };\n\n/**\n * Checks if a schema is an anyOf composition.\n * @param schema - The schema to check\n * @returns True if the schema has a non-empty anyOf property, false otherwise\n */\nexport function isAnyOf(schema: Schema): schema is AnyOfSchema {\n return Array.isArray(schema.anyOf) && schema.anyOf.length > 0;\n}\n\nexport type OneOfSchema = Schema & { oneOf: any[] };\n\n/**\n * Checks if a schema is a oneOf composition.\n * @param schema - The schema to check\n * @returns True if the schema has a non-empty oneOf property, false otherwise\n */\nexport function isOneOf(schema: Schema): schema is OneOfSchema {\n return Array.isArray(schema.oneOf) && schema.oneOf.length > 0;\n}\n\nexport type AllOfSchema = Schema & { allOf: any[] };\n\n/**\n * Checks if a schema is an allOf composition.\n * @param schema - The schema to check\n * @returns True if the schema has a non-empty allOf property, false otherwise\n */\nexport function isAllOf(schema: Schema): schema is AllOfSchema {\n return Array.isArray(schema.allOf) && schema.allOf.length > 0;\n}\n\nexport type CompositionSchema = AnyOfSchema | OneOfSchema | AllOfSchema;\n\n/**\n * Checks if a schema is a composition (anyOf, oneOf, or allOf).\n * @param schema - The schema to check\n * @returns True if the schema is anyOf, oneOf, or allOf composition, false otherwise\n */\nexport function isComposition(schema: Schema): schema is CompositionSchema {\n return isAnyOf(schema) || isOneOf(schema) || isAllOf(schema);\n}\n\n/**\n * Converts a type string to an array type.\n * Wraps complex types (containing | or &) in parentheses before adding array notation.\n * @param type - The type string to convert to an array type\n * @returns The array type string\n */\nexport function toArrayType(type: string): string {\n if (type.includes('|') || type.includes('&')) {\n return `(${type})[]`;\n }\n return `${type}[]`;\n}\n\nexport type MapSchema = Schema & {\n type: 'object';\n additionalProperties: boolean | Schema | Reference;\n};\n\nexport function isMap(schema: Schema): schema is MapSchema {\n return (\n schema.type === 'object' &&\n !schema.properties &&\n schema.additionalProperties !== undefined\n );\n}\n\nconst X_MAP_KEY_SCHEMA = 'x-map-key-schema';\n\nexport function getMapKeySchema(\n schema: Schema,\n): Schema | Reference | undefined {\n return schema[X_MAP_KEY_SCHEMA];\n}\n\n/**\n * Checks if a schema represents an empty object.\n * @param schema - The schema to check\n * @returns True if the schema represents an empty object, false otherwise\n */\nexport function isEmptyObject(schema: Schema): boolean {\n if (schema.type !== 'object') {\n return false;\n }\n if (!schema.properties) {\n return true;\n }\n return Object.keys(schema.properties).length === 0;\n}\n\nexport function isReadOnly(schema: Schema | Reference): boolean {\n return (schema as Schema).readOnly === true;\n}\n\n/**\n * Resolves a schema type to its TypeScript equivalent.\n * @param type - The schema type(s) to resolve\n * @returns The TypeScript type string\n */\nexport function resolvePrimitiveType(type: SchemaType | SchemaType[]): string {\n if (Array.isArray(type)) {\n return type.map(it => resolvePrimitiveType(it)).join(' | ');\n }\n switch (type) {\n case 'string':\n return 'string';\n case 'number':\n case 'integer':\n return 'number';\n case 'boolean':\n return 'boolean';\n case 'null':\n return 'null';\n default:\n return 'any';\n }\n}\n\n/**\n * Lists the property names a command body may omit.\n *\n * A command type wraps its body in `PartialBy<Command, ...>` built from this\n * list, which is where a request's declared optionality lives: generated model\n * properties are always required. The walk follows `allOf` branches and\n * references, because a command that inherits a base schema declares its\n * properties there - reading only the top level would demand fields the\n * document leaves optional.\n *\n * A property is optional when no branch requires it. `anyOf` and `oneOf` are\n * not followed: a branch an instance need not match says nothing about the\n * properties a command carries.\n *\n * @param schema - The command body schema, or a reference to it\n * @param components - The components a reference resolves against\n * @returns The declared property names absent from every `required` list\n */\nexport function resolveOptionalFields(\n schema: Schema | Reference,\n components?: Components,\n): string[] {\n const declared: string[] = [];\n const required = new Set<string>();\n const visited = new Set<Schema | Reference>();\n // A schema that admits null generates `T | null`, whose `keyof` is `never`:\n // naming a field of it would make `PartialBy<Model, 'field'>` violate\n // `K extends keyof T` (TS2344). Such a command takes no PartialBy at all.\n let admitsNull = false;\n const walk = (current: Schema | Reference | undefined): void => {\n if (!current || visited.has(current) || admitsNull) {\n return;\n }\n visited.add(current);\n if (isReference(current)) {\n // A reference the document does not carry contributes nothing rather\n // than making every property of the command look required.\n walk(components && extractSchema(current, components));\n return;\n }\n if (current.nullable || Array.isArray(current.type)) {\n admitsNull = true;\n return;\n }\n for (const name of current.required ?? []) {\n required.add(name);\n }\n for (const name of Object.keys(current.properties ?? {})) {\n if (!declared.includes(name)) {\n declared.push(name);\n }\n }\n current.allOf?.forEach(walk);\n };\n walk(schema);\n return admitsNull ? [] : declared.filter(name => !required.has(name));\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n Components,\n HTTPMethod,\n Operation,\n Parameter,\n PathItem,\n Paths,\n Reference,\n Response,\n Schema,\n} from '@ahoo-wang/fetcher-openapi';\nimport { compareNames } from '../naming/order';\nimport { extractParameter, extractResponse } from './components';\nimport { isReference } from './references';\nimport { extractResponseJsonSchema } from './responses';\nimport { isPrimitive, resolvePrimitiveType } from './schemas';\n\n/**\n * Represents an HTTP method and its associated operation.\n */\nexport interface MethodOperation {\n /** The HTTP method */\n method: HTTPMethod;\n /** The OpenAPI operation */\n operation: Operation;\n}\n\nexport interface OperationEndpoint extends MethodOperation {\n path: string;\n}\n\nexport function operationEndpointComparator(\n left: OperationEndpoint,\n right: OperationEndpoint,\n): number {\n if (left.operation.operationId && right.operation.operationId) {\n return compareNames(\n left.operation.operationId,\n right.operation.operationId,\n );\n }\n if (left.path && right.path) {\n return compareNames(left.path, right.path);\n }\n if (left.method && right.method) {\n return compareNames(left.method, right.method);\n }\n return 0;\n}\n\nfunction mergeParameters(\n inherited: (Parameter | Reference)[],\n own: (Parameter | Reference)[],\n components?: Components,\n): (Parameter | Reference)[] {\n const parameters = new Map<string, Parameter | Reference>();\n for (const parameter of [...inherited, ...own]) {\n const resolved = isReference(parameter)\n ? components && extractParameter(parameter, components)\n : parameter;\n const key = resolved\n ? `${resolved.in}:${resolved.name}`\n : (parameter as Reference).$ref;\n parameters.set(key, parameter);\n }\n return [...parameters.values()];\n}\n\nexport function extractOperationEndpoints(\n paths: Paths,\n components?: Components,\n): Array<OperationEndpoint> {\n const operationEndpoints: OperationEndpoint[] = [];\n for (const [path, pathItem] of Object.entries(paths)) {\n extractOperations(pathItem).forEach(methodOperation => {\n operationEndpoints.push({\n method: methodOperation.method,\n operation: pathItem.parameters?.length\n ? {\n ...methodOperation.operation,\n parameters: mergeParameters(\n pathItem.parameters,\n methodOperation.operation.parameters ?? [],\n components,\n ),\n }\n : methodOperation.operation,\n path,\n });\n });\n }\n return operationEndpoints.sort(operationEndpointComparator);\n}\n\n/**\n * Extracts all operations from a path item.\n * @param pathItem - The OpenAPI path item\n * @returns Array of method-operation pairs\n */\nexport function extractOperations(pathItem: PathItem): MethodOperation[] {\n return [\n { method: 'get', operation: pathItem.get },\n { method: 'put', operation: pathItem.put },\n { method: 'post', operation: pathItem.post },\n { method: 'delete', operation: pathItem.delete },\n { method: 'options', operation: pathItem.options },\n { method: 'head', operation: pathItem.head },\n { method: 'patch', operation: pathItem.patch },\n { method: 'trace', operation: pathItem.trace },\n ].filter(({ operation }) => operation !== undefined) as Array<{\n method: HTTPMethod;\n operation: Operation;\n }>;\n}\n\n/**\n * Picks the status code of an operation's success response: `200`, else the\n * lowest other 2xx code, else `2XX`.\n *\n * @param operation - The OpenAPI operation\n * @returns The status code key, or undefined when no 2xx response is declared\n */\nexport function okResponseStatus(operation: Operation): string | undefined {\n const statuses = Object.keys(operation.responses ?? {});\n if (statuses.includes('200')) return '200';\n const exact = statuses.filter(status => /^2\\d\\d$/.test(status)).sort();\n if (exact.length > 0) return exact[0];\n return statuses.find(status => status.toUpperCase() === '2XX');\n}\n\n/**\n * Extracts the success response from an operation: `200`, else the lowest\n * other 2xx response, else `2XX`.\n * @param operation - The OpenAPI operation\n * @param components - Optional components used to resolve response references\n * @returns The success response or undefined if not found\n */\nexport function extractOkResponse(\n operation: Operation,\n components?: Components,\n): Response | Reference | undefined {\n const status = okResponseStatus(operation);\n const response = status ? operation.responses[status] : undefined;\n return components && isReference(response)\n ? extractResponse(response, components)\n : response;\n}\n\n/**\n * Extracts the JSON schema from the OK response of an operation.\n * @param operation - The OpenAPI operation\n * @param components - Optional components used to resolve response references\n * @returns The JSON schema from the OK response or undefined if not found\n */\nexport function extractOperationOkResponseJsonSchema(\n operation: Operation,\n components?: Components,\n): Schema | Reference | undefined {\n const okResponse = extractOkResponse(operation, components);\n return extractResponseJsonSchema(okResponse);\n}\n\n/**\n * Extracts the parameters of an operation, references resolved, in document\n * order.\n * @param operation - The OpenAPI operation\n * @param components - The OpenAPI components object used to resolve references\n * @returns The parameters\n */\nexport function extractParameters(\n operation: Operation,\n components: Components,\n): Parameter[] {\n return (operation.parameters ?? [])\n .map(parameter =>\n isReference(parameter)\n ? extractParameter(parameter, components)\n : parameter,\n )\n .filter((parameter): parameter is Parameter => parameter !== undefined);\n}\n\n/**\n * Extracts path parameters from an operation.\n * @param operation - The OpenAPI operation to extract path parameters from\n * @param components - The OpenAPI components object used to resolve references\n * @returns Array of path parameters\n */\nexport function extractPathParameters(\n operation: Operation,\n components: Components,\n): Parameter[] {\n if (!operation.parameters) {\n return [];\n }\n return operation.parameters\n .map(parameter => {\n if (isReference(parameter)) {\n return extractParameter(parameter, components);\n }\n return parameter;\n })\n .filter((parameter): parameter is Parameter => parameter?.in === 'path');\n}\n\n/**\n * Orders path parameters as the path holds them, whatever order the document\n * lists them in: `/cart/{id}/{customerId}` gives `id`, then `customerId`.\n * A method takes them in this order, so a route that gains a variable keeps\n * the arguments before it where they were. Parameters the path does not\n * hold keep their order, after the others.\n *\n * @param path - The route, with `{name}` variables\n * @param parameters - Its path parameters\n * @returns A new array, sorted\n */\nexport function inPathOrder<P extends Pick<Parameter, 'name'>>(\n path: string,\n parameters: readonly P[],\n): P[] {\n const position = (parameter: P) => {\n const index = path.indexOf(`{${parameter.name}}`);\n return index < 0 ? Number.MAX_SAFE_INTEGER : index;\n };\n return [...parameters].sort((a, b) => position(a) - position(b));\n}\n\nconst DEFAULT_PATH_PARAMETER_TYPE = 'string';\n\n/**\n * Resolves the type of a path parameter.\n * @param parameter - The path parameter to resolve the type for\n * @returns The resolved primitive type as a string, or the default path parameter type if the schema is missing,\n * is a reference, lacks a type, or the type is not primitive\n */\nexport function resolvePathParameterType(parameter: Parameter): string {\n if (\n !parameter.schema ||\n isReference(parameter.schema) ||\n !parameter.schema.type ||\n !isPrimitive(parameter.schema.type)\n ) {\n return DEFAULT_PATH_PARAMETER_TYPE;\n }\n return resolvePrimitiveType(parameter.schema.type);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The conventions of the OpenAPI documents a Wow service writes\n * (`wow-openapi`), in one place: how its tags name aggregates, which\n * operations carry commands, state, events and query fields, which schemas\n * are Wow's own and which wow-client type each maps to, which tags and path\n * parameters the generated clients leave out, and how a query client's\n * resource attribution follows from the command routes.\n *\n * Every rule here applies only to what Wow's metadata names, so a document\n * that is not a Wow one is left alone.\n */\n\nimport type { OpenAPI, Tag } from '@ahoo-wang/fetcher-openapi';\nimport type { AggregateDefinition, TagAliasAggregate } from './model';\n\n/** The oldest Wow server whose OpenAPI metadata the generator reads fully. */\nexport const MINIMUM_WOW_VERSION = '8.10';\n\n/** The `info` extension naming the bounded context the document serves. */\nexport const CONTEXT_ALIAS_EXTENSION = 'x-wow-context-alias';\n\n/** The bounded context a document names, if it is a Wow service's. */\nexport function contextAliasOf(openAPI: OpenAPI): string | undefined {\n return openAPI.info[CONTEXT_ALIAS_EXTENSION];\n}\n\n// --- Aggregates and their operations -------------------------------------\n\n/**\n * Reads an aggregate off a tag named `<contextAlias>.<aggregateName>`.\n *\n * @param tagName - The tag name\n * @returns `[contextAlias, aggregateName]`, or null when the tag names no aggregate\n */\nexport function isAliasAggregate(tagName: string): [string, string] | null {\n const parts = tagName.split('.');\n if (parts.length != 2 || parts[0].length === 0 || parts[1].length === 0) {\n return null;\n }\n return parts as [string, string];\n}\n\n/**\n * The aggregate a tag names, or null when it names none.\n *\n * @param tag - The tag\n */\nexport function tagToAggregate(tag: Tag): TagAliasAggregate | null {\n const parts = isAliasAggregate(tag.name);\n if (!parts) {\n return null;\n }\n return {\n tag,\n contextAlias: parts[0],\n aggregateName: parts[1],\n };\n}\n\n/**\n * The command an operation sends, read off its id\n * `<contextAlias>.<aggregateName>.<command>`.\n *\n * @param operationId - The operation id\n * @returns The command name, or null when the id has another shape\n */\nexport function operationIdToCommandName(operationId?: string): string | null {\n if (!operationId) {\n return null;\n }\n const parts = operationId.split('.');\n if (parts.length != 3) {\n return null;\n }\n return parts[2];\n}\n\n/** The operation that sends any command; it belongs to no aggregate. */\nexport const SEND_COMMAND_OPERATION_ID = 'wow.command.send';\n\n/** The response every command operation answers with. */\nexport const COMMAND_OK_RESPONSE_REF = '#/components/responses/wow.CommandOk';\n\n/** The operation id suffix of the operation that loads an aggregate's state. */\nexport const STATE_OPERATION_SUFFIX = '.snapshot_state.single';\n\n/** The operation id suffix of the operation that lists an aggregate's events. */\nexport const EVENTS_OPERATION_SUFFIX = '.event.list_query';\n\n/** The operation id suffix of the operation that counts snapshots by a condition. */\nexport const FIELDS_OPERATION_SUFFIX = '.snapshot.count';\n\n/** The request body extension naming an aggregate's query fields (Wow 8.11.1+). */\nexport const QUERY_FIELDS_EXTENSION = 'x-wow-query-fields';\n\n/**\n * The route segment of an aggregate, read off one of its snapshot routes:\n * `/tenant/{tenantId}/owner/{ownerId}/sales-order/snapshot/count` →\n * `sales-order`. It differs from the aggregate name when the aggregate sets\n * a resource name (`@AggregateRoute(resourceName = \"sales-order\")`).\n */\nexport const SNAPSHOT_ROUTE =\n /^(?:\\/tenant\\/\\{tenantId\\})?(?:\\/owner\\/\\{ownerId\\})?\\/(.+?)\\/snapshot(?:\\/|$)/;\n\n// --- Schemas ---------------------------------------------------------------\n\n/**\n * The suffixes of the types Wow derives from an aggregate's state; the\n * wow-client generics stand for them, so they generate no model.\n */\nexport const AGGREGATED_SCHEMA_SUFFIXES: readonly string[] = [\n 'MaterializedSnapshot',\n 'MaterializedSnapshotPagedList',\n 'MaterializedSnapshotCursorPage',\n 'MaterializedSnapshotServerSentEventNonNullData',\n 'PagedList',\n 'ServerSentEventNonNullData',\n 'Snapshot',\n 'StateEvent',\n];\n\n/**\n * The names of the types Wow derives from an aggregate's state model.\n *\n * @param stateName - The name of the state model\n */\nexport function aggregatedTypeNames(stateName: string): string[] {\n return AGGREGATED_SCHEMA_SUFFIXES.map(suffix => stateName + suffix);\n}\n\n/**\n * Tells whether a schema is Wow's own, which wow-client already declares, so\n * it generates no model: every `wow.` schema but the paged lists and operator\n * maps of the query API, the aggregated query and event stream types, and\n * the types derived from an aggregate's state.\n *\n * @param schemaKey - The schema's component key\n * @param modelName - The name of the model the schema would generate, read\n * only when the key alone does not decide\n * @param aggregatedNames - The names of the types derived from the aggregates' states\n */\nexport function isWowSchema(\n schemaKey: string,\n modelName: () => string,\n aggregatedNames: ReadonlySet<string>,\n): boolean {\n if (\n schemaKey !== 'wow.api.query.PagedList' &&\n schemaKey.startsWith('wow.api.query.') &&\n schemaKey.endsWith('PagedList')\n ) {\n return false;\n }\n\n if (\n schemaKey.startsWith('wow.api.query.Operator') &&\n schemaKey.endsWith('Map')\n ) {\n return false;\n }\n\n if (\n schemaKey.startsWith('wow.') ||\n schemaKey.endsWith('AggregatedCondition') ||\n schemaKey.endsWith('AggregatedDomainEventStream') ||\n schemaKey.endsWith('AggregatedDomainEventStreamPagedList') ||\n schemaKey.endsWith('AggregatedDomainEventStreamCursorPage') ||\n schemaKey.endsWith(\n 'AggregatedDomainEventStreamServerSentEventNonNullData',\n ) ||\n schemaKey.endsWith('AggregatedListQuery') ||\n schemaKey.endsWith('AggregatedPagedQuery') ||\n schemaKey.endsWith('AggregatedSingleQuery')\n ) {\n return true;\n }\n return aggregatedNames.has(modelName());\n}\n\n/** Import path for the WOW framework types */\nexport const IMPORT_WOW_PATH = '@ahoo-wang/wow-client';\n\n/**\n * Import path for the deprecated Condition query model, which\n * `@ahoo-wang/wow-client` keeps on its `/legacy` subpath for Wow 8.10 servers.\n */\nexport const IMPORT_WOW_LEGACY_PATH = '@ahoo-wang/wow-client/legacy';\n\n// compat(wow<9): the schemas of Wow < 8.11 query only through the Condition model, so the\n// types they map to come from `/legacy`; the subpath and this set go in v10, and users regenerate.\n/** The mapped type names that `IMPORT_WOW_LEGACY_PATH` exports. */\nexport const WOW_LEGACY_TYPES: ReadonlySet<string> = new Set([\n 'Condition',\n 'ConditionOptions',\n 'ListQuery',\n 'Operator',\n 'PagedQuery',\n]);\n\n/** Mapping of OpenAPI schema keys to WOW framework types */\nexport const WOW_TYPE_MAPPING = {\n 'wow.command.CommandResult': 'CommandResult',\n 'wow.command.CommandResultArray': 'CommandResultArray',\n 'wow.MessageHeaderSqlType': 'MessageHeaderSqlType',\n 'wow.api.BindingError': 'BindingError',\n 'wow.api.DefaultErrorInfo': 'ErrorInfo',\n 'wow.api.RecoverableType': 'RecoverableType',\n 'wow.api.command.DefaultDeleteAggregate': 'DeleteAggregate',\n 'wow.api.command.DefaultRecoverAggregate': 'RecoverAggregate',\n 'wow.api.abac.DefaultApplyResourceTags': 'ApplyResourceTags',\n 'wow.api.messaging.FunctionInfoData': 'FunctionInfo',\n 'wow.api.messaging.FunctionKind': 'FunctionKind',\n 'wow.api.modeling.AggregateId': 'AggregateId',\n // Condition, ConditionOptions, ListQuery, Operator and PagedQuery name the deprecated\n // Condition API types of `/legacy` (see WOW_LEGACY_TYPES); a ListQuery or PagedQuery schema\n // that carries `filter` maps to FilterListQuery or FilterPagedQuery instead (wowTypeOf).\n 'wow.api.query.Condition': 'Condition',\n 'wow.api.query.ConditionOptions': 'ConditionOptions',\n 'wow.api.query.ListQuery': 'ListQuery',\n 'wow.api.query.Operator': 'Operator',\n 'wow.api.query.PagedQuery': 'PagedQuery',\n 'wow.api.query.Pagination': 'Pagination',\n 'wow.api.query.Projection': 'Projection',\n 'wow.api.query.Sort': 'FieldSort',\n 'wow.api.query.Sort.Direction': 'SortDirection',\n 'wow.api.query.DynamicDocument': 'DynamicDocument',\n 'wow.api.query.DynamicDocumentArray': 'DynamicDocumentArray',\n 'wow.command.CommandStage': 'CommandStage',\n 'wow.command.SimpleWaitSignal': 'WaitSignal',\n 'wow.configuration.Aggregate': 'Aggregate',\n 'wow.configuration.BoundedContext': 'BoundedContext',\n 'wow.configuration.WowMetadata': 'WowMetadata',\n 'wow.modeling.DomainEvent': 'DomainEvent',\n 'wow.openapi.BatchResult': 'BatchResult',\n 'wow.messaging.CompensationTarget': 'CompensationTarget',\n};\n\n/**\n * The wow-client type a schema maps to, and the module that exports it.\n *\n * @param schemaKey - The schema's component key\n * @param properties - The schema's properties, if the caller has the schema:\n * a ListQuery or PagedQuery that carries `filter` is the filter model's\n * @returns The type, or undefined when the schema is not one of Wow's own\n */\nexport function wowTypeOf(\n schemaKey: string,\n properties?: Record<string, unknown>,\n): { name: string; path: string } | undefined {\n let mappedType: string | undefined =\n WOW_TYPE_MAPPING[schemaKey as keyof typeof WOW_TYPE_MAPPING];\n if (properties && 'filter' in properties) {\n if (schemaKey === 'wow.api.query.ListQuery') {\n mappedType = 'FilterListQuery';\n } else if (schemaKey === 'wow.api.query.PagedQuery') {\n mappedType = 'FilterPagedQuery';\n }\n }\n if (!mappedType) return undefined;\n return {\n name: mappedType,\n path: WOW_LEGACY_TYPES.has(mappedType)\n ? IMPORT_WOW_LEGACY_PATH\n : IMPORT_WOW_PATH,\n };\n}\n\n// --- What the generated clients leave out ---------------------------------\n\n/**\n * Tags whose operations generate no API client: Wow's own endpoints and\n * Spring's actuator. The tags of aggregates are left out as well; their\n * operations go to the command and query clients.\n */\nexport const IGNORED_API_CLIENT_TAGS: ReadonlySet<string> = new Set([\n 'wow',\n 'Actuator',\n]);\n\n/**\n * The resource-attribution path parameters Wow's CoSec interceptor fills,\n * which generated clients therefore leave out.\n */\nexport const RESOURCE_ATTRIBUTION_PATH_PARAMETERS: readonly string[] = [\n 'tenantId',\n 'ownerId',\n];\n\n/** The route prefix of a tenant's resources (wow-client `ResourceAttributionPathSpec.TENANT`). */\nexport const TENANT_PATH_PREFIX = '/tenant/{tenantId}';\n\n/** The route prefix of an owner's resources (wow-client `ResourceAttributionPathSpec.OWNER`). */\nexport const OWNER_PATH_PREFIX = '/owner/{ownerId}';\n\n/**\n * The resource attribution a query client of an aggregate uses, as the\n * `ResourceAttributionPathSpec` member it generates: the prefix most of the\n * aggregate's command routes start with, owner on a tie, none when no route\n * starts with either.\n *\n * @example\n * ```typescript\n * // commands at /tenant/{tenantId}/users, /tenant/{tenantId}/orders and /owner/{ownerId}/profile\n * inferPathSpecType(aggregate); // 'ResourceAttributionPathSpec.TENANT'\n * ```\n */\nexport function inferPathSpecType(\n aggregateDefinition: Pick<AggregateDefinition, 'commands'>,\n): string {\n let tenantSpecCount = 0;\n let ownerSpecCount = 0;\n aggregateDefinition.commands.forEach(command => {\n if (command.path.startsWith(TENANT_PATH_PREFIX)) {\n tenantSpecCount += 1;\n }\n if (command.path.startsWith(OWNER_PATH_PREFIX)) {\n ownerSpecCount += 1;\n }\n });\n if (tenantSpecCount === 0 && ownerSpecCount === 0) {\n return 'ResourceAttributionPathSpec.NONE';\n }\n return tenantSpecCount > ownerSpecCount\n ? 'ResourceAttributionPathSpec.TENANT'\n : 'ResourceAttributionPathSpec.OWNER';\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { TagAliasAggregate } from '../wow/model';\nimport { GeneratorError } from '../api/errors';\nimport {\n camelCase,\n isIdentifier,\n toIdentifier,\n toTypeIdentifier,\n} from '../naming/naming';\nimport type { Operation } from '@ahoo-wang/fetcher-openapi';\n\n/**\n * The path of a client module of an aggregate, relative to the output\n * directory: `<contextAlias>/<aggregateName>/<fileName>.ts`.\n *\n * @param aggregate - The aggregate metadata containing context alias and aggregate name\n * @param fileName - The name of the file, without extension\n *\n * @example\n * ```typescript\n * clientModulePath({ contextAlias: 'user', aggregateName: 'profile' }, 'queryClient');\n * // 'user/profile/queryClient.ts'\n * ```\n */\nexport function clientModulePath(\n aggregate: Pick<TagAliasAggregate, 'contextAlias' | 'aggregateName'>,\n fileName: string,\n): string {\n return `${aggregate.contextAlias}/${aggregate.aggregateName}/${fileName}.ts`;\n}\n\n/**\n * The name of a class or type of an aggregate: its name as a type, then the\n * suffix (`order`, `CommandClient` → `OrderCommandClient`).\n */\nexport function resolveClassName(\n aggregate: Pick<TagAliasAggregate, 'aggregateName'>,\n suffix: string,\n): string {\n return `${toTypeIdentifier(aggregate.aggregateName)}${suffix}`;\n}\n\n/** Operation extension naming the method an operation generates. */\nexport const OPERATION_METHOD_NAME_KEY = 'x-fetcher-method';\n\n/**\n * Names the method an operation generates.\n *\n * The name depends on the operation alone, so adding an operation never\n * renames an existing method:\n *\n * 1. a name configured for the operationId (`apiClients[tag].methodNames`);\n * 2. else the operation's `x-fetcher-method` extension;\n * 3. else the last dot-separated segment of the operationId, camel-cased:\n * `getUserById` → `getUserById`, `delete_user_by_id` → `deleteUserById`,\n * `getUser_1` → `getUser1`, `users.list` → `list`,\n * `example.cart.add_cart_item` → `addCartItem`; a name starting with a\n * digit is prefixed with `_`.\n *\n * Two operations of one client that arrive at the same name are an error the\n * caller reports; the first two sources resolve it.\n *\n * @param operation - The OpenAPI operation\n * @param configured - The name configured for its operationId, if any\n * @returns The method name, or undefined for an operation without an operationId\n * @throws GeneratorError when a configured or extension name is not a valid method name\n */\nexport function resolveMethodName(\n operation: Operation,\n configured?: string,\n): string | undefined {\n const explicit = configured ?? operation[OPERATION_METHOD_NAME_KEY];\n if (explicit !== undefined) {\n if (typeof explicit !== 'string' || !isMethodName(explicit)) {\n throw new GeneratorError(\n 'specification',\n `${OPERATION_METHOD_NAME_KEY} of ${operation.operationId ?? 'an operation'} is ${JSON.stringify(explicit)}, which is not a valid method name.`,\n );\n }\n return explicit;\n }\n if (!operation.operationId) {\n return undefined;\n }\n const lastSegment = operation.operationId.split('.').pop()!;\n const name = camelCase(lastSegment) || '_';\n return /^\\p{N}/u.test(name) ? `_${name}` : name;\n}\n\n/**\n * Tells whether a name can name a method. Unlike a variable, a method may be\n * named by a reserved word: `delete()` is fine.\n */\nfunction isMethodName(name: string): boolean {\n return isIdentifier(name) || /^[a-z]+$/.test(name);\n}\n\n/**\n * Turns a parameter name from the document into a unique parameter\n * identifier: `item-id` → `itemId`, and `id` twice → `id`, `id2`.\n *\n * @param name - The name the document uses\n * @param used - The identifiers the method already uses; updated\n * @returns The identifier\n */\nexport function uniqueParameterName(name: string, used: Set<string>): string {\n const identifier = toIdentifier(name);\n let unique = identifier;\n for (let suffix = 2; used.has(unique); suffix++) {\n unique = `${identifier}${suffix}`;\n }\n used.add(unique);\n return unique;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { GeneratorError } from '../api/errors';\nimport type { Components, Reference, Schema } from '@ahoo-wang/fetcher-openapi';\nimport {\n COMPONENTS_SCHEMAS_REF,\n extractComponentKey,\n extractSchema,\n} from '../openapi/components';\nimport type { ModelInfo } from '../naming/modelInfo';\nimport { toTypeIdentifier, upperSnakeCase } from '../naming/naming';\nimport { wowTypeOf } from '../wow/conventions';\n\nexport type { ModelInfo } from '../naming/modelInfo';\n\n/**\n * Resolves model information from a schema key.\n *\n * This function parses a dot-separated schema key and extracts the model name and path.\n * It assumes that the model name is the first part that starts with an uppercase letter.\n * All parts before the model name are treated as the path.\n *\n * @example\n *\n * - \"wow.api.BindingError\" -> {path:'/wow/api',name:'BindingError'}\n * - \"compensation.ApiVersion\" -> {path:'/compensation',name:'ApiVersion'}\n * - \"ai.AiMessage.Assistant\" -> {path:'/ai',name:'AiMessageAssistant'}\n * - \"Result\" -> {path:'/',name:'Result'}\n *\n * @param schemaKey - The dot-separated schema key (e.g., \"com.example.User\")\n * @returns ModelInfo object containing the parsed name and path\n */\nexport function resolveModelInfo(\n schemaKey: string,\n schema?: Schema,\n): ModelInfo {\n if (!schemaKey) {\n return { name: '', path: '/' };\n }\n const wowType = wowTypeOf(schemaKey, schema?.properties);\n if (wowType) {\n return wowType;\n }\n\n const parts = schemaKey.split('.');\n let modelNameIndex = -1;\n\n // Find the first part that starts with an uppercase letter\n for (let i = 0; i < parts.length; i++) {\n if (parts[i] && /^[A-Z]/.test(parts[i])) {\n modelNameIndex = i;\n break;\n }\n }\n\n // Construct the path from parts before the model name\n const pathParts = parts.slice(0, modelNameIndex);\n const path = pathParts.length > 0 ? `/${pathParts.join('/')}` : '/';\n\n // Construct the model name from the remaining parts\n const nameParts = parts.slice(modelNameIndex);\n const name = toTypeIdentifier(nameParts);\n\n return { name, path };\n}\n\nexport function resolveReferenceModelInfo(\n reference: Reference,\n components?: Components,\n): ModelInfo {\n if (!reference.$ref.startsWith(COMPONENTS_SCHEMAS_REF)) {\n throw new GeneratorError(\n 'specification',\n `Unsupported schema reference: ${reference.$ref}. Bundle or inline external schemas before generation.`,\n );\n }\n const componentKey = extractComponentKey(reference);\n const schema = components ? extractSchema(reference, components) : undefined;\n return resolveModelInfo(componentKey, schema);\n}\n\nexport function resolveContextDeclarationName(contextAlias: string): string {\n const contextUpperName = upperSnakeCase(contextAlias);\n const name = `${contextUpperName}_BOUNDED_CONTEXT_ALIAS`;\n return /^\\p{N}/u.test(name) ? `_${name}` : name;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { GeneratorError } from '../api/errors';\nimport type { ModelInfo } from '../naming/modelInfo';\nimport { camelCase, resolvePropertyName } from '../naming/naming';\nimport type { OpenApiDocument } from '../openapi/document';\nimport { inPathOrder, resolvePathParameterType } from '../openapi/operations';\nimport { isEmptyObject, resolveOptionalFields } from '../openapi/schemas';\nimport {\n IMPORT_WOW_PATH,\n inferPathSpecType,\n RESOURCE_ATTRIBUTION_PATH_PARAMETERS,\n} from '../wow/conventions';\nimport type {\n AggregateDefinition,\n CommandDefinition,\n WowModel,\n} from '../wow/model';\nimport {\n clientModulePath,\n resolveClassName,\n uniqueParameterName,\n} from './clientNames';\nimport type {\n AggregateModel,\n CommandClientModel,\n CommandModel,\n ModelDeclaration,\n QueryClientModel,\n} from './model';\n\nconst COMMAND_SUFFIX = 'Command';\nimport { resolveContextDeclarationName, resolveModelInfo } from './modelInfo';\n\n/**\n * The command and query clients of every aggregate that has state and query\n * fields, by bounded context in the order the Wow metadata lists them.\n */\nexport function analyzeAggregates(\n document: OpenApiDocument,\n wow: WowModel,\n): AggregateModel[] {\n return [...wow.contexts.values()].flatMap(aggregates =>\n [...aggregates].map(aggregate => analyzeAggregate(document, aggregate)),\n );\n}\n\nfunction analyzeAggregate(\n document: OpenApiDocument,\n definition: AggregateDefinition,\n): AggregateModel {\n const { contextAlias, aggregateName } = definition.aggregate;\n return {\n contextAlias,\n aggregateName,\n context: {\n alias: contextAlias,\n constantName: resolveContextDeclarationName(contextAlias),\n },\n commandClient: commandClient(document, definition),\n queryClient: queryClient(definition),\n };\n}\n\nfunction commandClient(\n document: OpenApiDocument,\n definition: AggregateDefinition,\n): CommandClientModel {\n const aggregate = definition.aggregate;\n const members = endpointMemberNames(definition);\n return {\n file: clientModulePath(aggregate, 'commandClient'),\n endpointPathsName: resolveClassName(aggregate, 'CommandEndpointPaths'),\n className: resolveClassName(aggregate, 'CommandClient'),\n streamClassName: resolveClassName(aggregate, 'StreamCommandClient'),\n commands: [...definition.commands.values()].map((command): CommandModel => {\n const body = resolveModelInfo(command.schema.key);\n const used = new Set(['commandRequest', 'attributes']);\n return {\n path: command.path,\n endpointMember: members.get(command)!,\n httpMethod: command.method,\n methodName: commandMethodName(command),\n typeName: commandTypeName(body),\n body,\n bodyKey: command.schema.key,\n optionalFields: resolveOptionalFields(\n command.schema.schema,\n document.components,\n ),\n requestOptional: isEmptyObject(command.schema.schema),\n pathParameters: inPathOrder(command.path, command.pathParameters)\n .filter(\n parameter =>\n !RESOURCE_ATTRIBUTION_PATH_PARAMETERS.includes(parameter.name),\n )\n .map(parameter => ({\n name: uniqueParameterName(parameter.name, used),\n pathName: parameter.name,\n type: resolvePathParameterType(parameter),\n })),\n docs: [\n command.summary,\n command.description,\n `- operationId: \\`${command.operation.operationId}\\``,\n `- path: \\`${command.path}\\``,\n ],\n };\n }),\n };\n}\n\n/**\n * The name of the alias a command's body type is declared under: the body's\n * name with `Command` appended, `AddCartItem` → `AddCartItemCommand`. A body\n * whose name already ends in `Command` gets none, so no name repeats the\n * suffix: its methods take `CommandBody<MountedCommand>` itself. Wow's own\n * commands have theirs in wow-client.\n */\nfunction commandTypeName(body: ModelInfo): string | undefined {\n if (body.path === IMPORT_WOW_PATH) return `${body.name}Command`;\n return body.name.endsWith(COMMAND_SUFFIX)\n ? undefined\n : `${body.name}${COMMAND_SUFFIX}`;\n}\n\n/**\n * Fails when a command's type would take a name its module or its package\n * already holds: the alias of another command, a command body the client\n * imports, or a model of the aggregate's package, which the package's index\n * exports beside it. `Foo` and `FooCommand` as two commands of one aggregate\n * do this: `Foo`'s alias is `FooCommand`, the other's body.\n *\n * @param aggregates - The aggregates, as analysed\n * @param models - The models of the document\n * @throws GeneratorError naming the command, the model it collides with and\n * the schemas to rename\n */\nexport function assertCommandTypeNamesFree(\n aggregates: readonly AggregateModel[],\n models: readonly ModelDeclaration[],\n): void {\n for (const aggregate of aggregates) {\n const packagePath = `/${aggregate.contextAlias}/${aggregate.aggregateName}`;\n // Each name, with what holds it, the schema behind that, and for a\n // command type the body it stands for.\n const taken = new Map<\n string,\n { holder: string; key: string; bodyKey?: string }\n >();\n for (const model of models) {\n if (model.info.path === packagePath) {\n taken.set(model.info.name, {\n holder: `the model of schema ${model.key}`,\n key: model.key,\n });\n }\n }\n for (const { body, bodyKey } of aggregate.commandClient.commands) {\n if (body.path !== IMPORT_WOW_PATH) {\n taken.set(body.name, {\n holder: `the model of schema ${bodyKey}`,\n key: bodyKey,\n });\n }\n }\n for (const command of aggregate.commandClient.commands) {\n const { typeName, bodyKey } = command;\n if (typeName === undefined || command.body.path === IMPORT_WOW_PATH) {\n continue;\n }\n const taker = taken.get(typeName);\n // Two commands of one body share its type.\n if (taker !== undefined && taker.bodyKey !== bodyKey) {\n throw new GeneratorError(\n 'specification',\n `Command ${command.methodName}() of aggregate ${aggregate.contextAlias}.${aggregate.aggregateName} generates the type ${typeName} for its body ${bodyKey}, but ${taker.holder} already has that name. Rename the schema ${bodyKey} or ${taker.key} in the document.`,\n );\n }\n taken.set(typeName, {\n holder: `the type of command ${command.methodName}()`,\n key: bodyKey,\n bodyKey,\n });\n }\n }\n}\n\n/**\n * Names each command's endpoint member: its name upper-cased\n * (`add_cart_item` → `ADD_CART_ITEM`), with characters no identifier may\n * hold replaced by `_` (`pay-order` → `PAY_ORDER`), a leading digit\n * prefixed with `_`, and a number appended to the second of two commands\n * that end up alike.\n */\nfunction endpointMemberNames(\n definition: AggregateDefinition,\n): Map<CommandDefinition, string> {\n const names = new Map<CommandDefinition, string>();\n const used = new Set<string>();\n for (const command of definition.commands.values()) {\n let base = command.name.toUpperCase().replace(/[^\\p{L}\\p{N}_$]/gu, '_');\n if (!base || /^\\p{N}/u.test(base)) base = `_${base}`;\n let name = base;\n for (let suffix = 2; used.has(name); suffix++) name = `${base}_${suffix}`;\n used.add(name);\n names.set(command, name);\n }\n return names;\n}\n\n/**\n * The method a command generates: its name camel-cased, as\n * `add_cart_item` → `addCartItem`.\n */\nfunction commandMethodName(definition: CommandDefinition): string {\n const name = camelCase(definition.name) || '_';\n return /^\\p{N}/u.test(name) ? `_${name}` : name;\n}\n\nfunction queryClient(definition: AggregateDefinition): QueryClientModel {\n const aggregate = definition.aggregate;\n const factoryPrefix = camelCase(aggregate.aggregateName) || '_';\n return {\n file: clientModulePath(aggregate, 'queryClient'),\n // aggregateName is the route segment the query paths use, which the\n // aggregate's resource name can make differ from its name.\n resourceName: definition.resourceName,\n resourceAttribution: inferPathSpecType(definition),\n state: resolveModelInfo(definition.state.key),\n fields: resolveModelInfo(definition.fields.key),\n eventTitlesName: resolveClassName(aggregate, 'DomainEventTypeMapTitle'),\n eventTypeName: resolveClassName(aggregate, 'DomainEventType'),\n events: [...definition.events.values()].map(event => ({\n memberName: resolvePropertyName(event.name),\n title: event.title,\n body: resolveModelInfo(event.schema.key),\n })),\n factoryName: `${/^\\p{N}/u.test(factoryPrefix) ? '_' : ''}${factoryPrefix}QueryClientFactory`,\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Joins a relative path onto a base with exactly one `/` between them, as\n * `@ahoo-wang/fetcher`'s `combineURLs` does, so the generator process need\n * not load fetcher for it: `('a/', '/b.ts')` → `a/b.ts`. An empty relative\n * path gives the base, and a URL with a scheme (`https://…`, `//host/…`)\n * replaces it.\n *\n * @param base - The path to join onto\n * @param relative - The path to join\n */\nexport function combinePaths(base: string, relative: string): string {\n if (/^([a-z][a-z\\d+\\-.]*:)?\\/\\//i.test(relative)) return relative;\n return relative\n ? `${base.replace(/\\/+$/, '')}/${relative.replace(/^\\/+/, '')}`\n : base;\n}\n\n/** The file every model of a package is declared in. */\nexport const MODEL_FILE_NAME = 'types.ts';\n\n/**\n * The file a model is declared in, relative to the output directory: the\n * `types.ts` of its package.\n *\n * @param model - The model, whose path is its package (`/` for the root)\n */\nexport function modelFilePath(model: { readonly path: string }): string {\n return combinePaths(model.path, MODEL_FILE_NAME);\n}\n\n/**\n * The file that declares a bounded context's alias constant, relative to the\n * output directory.\n */\nexport function boundedContextFilePath(contextAlias: string): string {\n return `${contextAlias}/boundedContext.ts`;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n HTTPMethod,\n Operation,\n Parameter,\n Tag,\n} from '@ahoo-wang/fetcher-openapi';\nimport type { AliasAggregate, Named } from '@ahoo-wang/wow-client';\nimport type { KeySchema } from '../openapi/components';\n\nexport interface CommandDefinition extends Named {\n /**\n * The name of the command\n */\n name: string;\n /**\n * The HTTP method for the command\n */\n method: HTTPMethod;\n /**\n * The endpoint path for the command\n */\n path: string;\n /**\n * The path parameters for the command\n */\n pathParameters: Parameter[];\n summary?: string;\n description?: string;\n /**\n * The schema for the command body\n */\n schema: KeySchema;\n operation: Operation;\n}\n\nexport interface EventDefinition extends Named {\n /**\n * The name of the event\n */\n name: string;\n /**\n * The title of the event\n */\n title: string;\n\n /**\n * The schema for the event body\n */\n schema: KeySchema;\n}\n\nexport interface TagAliasAggregate extends AliasAggregate {\n tag: Tag;\n}\n\n/**\n * Complete definition of an aggregate including its commands, events, and state schemas.\n */\nexport interface AggregateDefinition {\n /** The aggregate metadata with tag and alias information */\n aggregate: TagAliasAggregate;\n /**\n * The aggregate's route segment, which is its name unless the aggregate\n * sets a resource name: `sales-order` for the aggregate `order`.\n */\n resourceName: string;\n /**\n * The schema for the aggregate root state\n */\n state: KeySchema;\n /**\n * The fields schema for aggregate queries\n */\n fields: KeySchema;\n /**\n * Map of command names to command definitions\n */\n commands: Map<string, CommandDefinition>;\n /**\n * Map of event names to event definitions\n */\n events: Map<string, EventDefinition>;\n}\n\n/**\n * Map of context aliases to sets of aggregate definitions\n */\nexport type BoundedContextAggregates = Map<string, Set<AggregateDefinition>>;\n\n/**\n * The doc comment the Wow metadata lends a schema: a command body takes its\n * operation's summary and description where it has none of its own, an event\n * body the title of its domain event. It holds every field the metadata\n * sets, in the order it sets them, so a model's doc reads the schema with\n * these over it the way it read the document the old resolver changed in\n * place: a field the schema lacks comes last, and an `undefined` one is left\n * out. The document itself is never changed.\n */\nexport type SchemaDocOverride = Readonly<\n Partial<Record<'title' | 'description', string | undefined>>\n>;\n\n/** What the Wow metadata of a document says, read without changing it. */\nexport interface WowModel {\n /** The bounded context the document names (`info.x-wow-context-alias`). */\n readonly contextAlias?: string;\n /** The aggregates that have state and query fields, by context alias. */\n readonly contexts: BoundedContextAggregates;\n /**\n * The tags of every aggregate that exposes a Wow route, resolved or not.\n * Their operations belong to command and query clients, not to API clients.\n */\n readonly aggregateTags: ReadonlySet<string>;\n /** The doc comments the metadata lends schemas, by component key. */\n readonly schemaDocOverrides: ReadonlyMap<string, SchemaDocOverride>;\n /** Aggregates and commands skipped for missing metadata, a warning each. */\n readonly warnings: readonly string[];\n}\n\n/**\n * Tells whether the document comes from a Wow service: it names its bounded\n * context, or it has aggregates.\n */\nexport function isWowDocument(\n wow: Pick<WowModel, 'contextAlias' | 'aggregateTags'>,\n): boolean {\n return wow.contextAlias !== undefined || wow.aggregateTags.size > 0;\n}\n\n/**\n * A schema as a model's doc reads it: the schema with the doc comment the\n * Wow metadata lends it over it.\n *\n * @param schema - The schema, left unchanged\n * @param override - What the metadata lends it, if anything\n */\nexport function withDocOverride<T extends object>(\n schema: T,\n override: SchemaDocOverride | undefined,\n): T {\n return override ? { ...schema, ...override } : schema;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Operation, RequestBody, Tag } from '@ahoo-wang/fetcher-openapi';\nimport type { GeneratorConfiguration } from '../api/configuration';\nimport { GeneratorError } from '../api/errors';\nimport type { ModelInfo } from '../naming/modelInfo';\nimport { combinePaths } from '../naming/paths';\nimport { extractRequestBody, extractSchema } from '../openapi/components';\nimport type { OpenApiDocument } from '../openapi/document';\nimport type { OperationEndpoint } from '../openapi/operations';\nimport {\n extractOkResponse,\n extractParameters,\n inPathOrder,\n} from '../openapi/operations';\nimport { isReference } from '../openapi/references';\nimport {\n APPLICATION_JSON,\n extractResponseEventStreamSchema,\n extractResponseJsonSchema,\n extractResponseWildcardSchema,\n findMediaType,\n hasTextResponse,\n isJsonContentType,\n isTextContentType,\n} from '../openapi/responses';\nimport { isArray, resolveOptionalFields } from '../openapi/schemas';\nimport {\n IGNORED_API_CLIENT_TAGS,\n RESOURCE_ATTRIBUTION_PATH_PARAMETERS,\n} from '../wow/conventions';\nimport type { WowModel } from '../wow/model';\nimport { isWowDocument } from '../wow/model';\nimport { resolveMethodName, uniqueParameterName } from './clientNames';\nimport type {\n ApiClientModel,\n ApiMethodModel,\n BodyModel,\n ContextReference,\n ParameterModel,\n ReturnModel,\n} from './model';\nimport {\n resolveContextDeclarationName,\n resolveModelInfo,\n resolveReferenceModelInfo,\n} from './modelInfo';\n\n/** Parameter names every generated method uses itself. */\nconst RESERVED_PARAMETER_NAMES = ['httpRequest', 'attributes'];\n\n/**\n * The API clients of a document: one per tag that is neither Wow's own, the\n * actuator's, nor an aggregate's, holding a method per operation.\n *\n * @param warnings - Receives a line for every operation left out and every\n * client renamed\n * @throws GeneratorError when two operations of a client name the same\n * method, or a configured or extension method name is not one\n */\nexport function analyzeApiClients(\n document: OpenApiDocument,\n wow: WowModel,\n config: GeneratorConfiguration,\n warnings: string[],\n): ApiClientModel[] {\n const analysis = new ApiClientAnalysis(document, wow, config, warnings);\n return analysis.clients();\n}\n\nclass ApiClientAnalysis {\n private readonly basePath?: ContextReference;\n private readonly wowDocument: boolean;\n\n constructor(\n private readonly document: OpenApiDocument,\n private readonly wow: WowModel,\n private readonly config: GeneratorConfiguration,\n private readonly warnings: string[],\n ) {\n this.wowDocument = isWowDocument(wow);\n if (wow.contextAlias) {\n this.basePath = {\n alias: wow.contextAlias,\n constantName: resolveContextDeclarationName(wow.contextAlias),\n };\n }\n }\n\n /**\n * One client per tag, sorted by tag name.\n *\n * Two tags can name the same class once normalised - `user-controller` and\n * `UserController`. The tag sorting first keeps the name, the others get a\n * numbered one, with a warning.\n */\n clients(): ApiClientModel[] {\n const tags = this.tags();\n const operations = this.groupOperations(tags);\n const claimed = new Map<string, string>();\n return [...operations.keys()].sort().map(tagName => {\n const modelInfo = resolveModelInfo(tagName);\n let clientInfo = modelInfo;\n for (let suffix = 2; claimed.has(clientKey(clientInfo)); suffix++) {\n clientInfo = { ...modelInfo, name: `${modelInfo.name}${suffix}` };\n }\n if (clientInfo !== modelInfo) {\n this.warnings.push(\n `Tags ${claimed.get(clientKey(modelInfo))} and ${tagName} both name the API client ${modelInfo.name}ApiClient; ${tagName} generates ${clientInfo.name}ApiClient.`,\n );\n }\n claimed.set(clientKey(clientInfo), tagName);\n return this.client(tags.get(tagName)!, clientInfo, [\n ...operations.get(tagName)!,\n ]);\n });\n }\n\n /** The client of a tag, under the name it was given. */\n private client(\n tag: Tag,\n modelInfo: ModelInfo,\n operations: readonly OperationEndpoint[],\n ): ApiClientModel {\n const className = `${modelInfo.name}ApiClient`;\n let file = modelInfo.path;\n if (this.wow.contextAlias) {\n file = combinePaths(this.wow.contextAlias, file);\n }\n file = combinePaths(file, apiClientFileName(className));\n const methods = new Map<string, string>();\n return {\n tagName: tag.name,\n className,\n file,\n description: tag.description,\n basePath: this.basePath,\n methods: operations.map(operation =>\n this.method(tag, className, operation, methods),\n ),\n };\n }\n\n /** The method an operation generates. */\n private method(\n tag: Tag,\n className: string,\n endpoint: OperationEndpoint,\n methods: Map<string, string>,\n ): ApiMethodModel {\n const { operation } = endpoint;\n const name = this.methodName(tag, className, endpoint, methods);\n const used = new Set(RESERVED_PARAMETER_NAMES);\n const parameters = this.parameters(tag, endpoint, used);\n const body = this.body(operation, used);\n // The method takes the required parameters first; its doc follows suit.\n const described = [\n ...parameters.filter(({ parameter }) => parameter.required),\n ...parameters.filter(({ parameter }) => !parameter.required),\n ].filter(({ description }) => description);\n return {\n name,\n httpMethod: endpoint.method,\n path: endpoint.path,\n parameters: parameters.map(({ parameter }) => parameter),\n body,\n returns: this.returns(operation),\n docs: [\n operation.summary,\n operation.description,\n `- operationId: \\`${operation.operationId}\\``,\n `- path: \\`${endpoint.path}\\``,\n ...described.map(\n ({ parameter, description }) =>\n `@param ${parameter.name} - ${description!.replace(/\\s*\\n\\s*/g, ' ')}`,\n ),\n ],\n };\n }\n\n /**\n * Names the method an operation generates, failing when another operation\n * of the client already took the name: renaming either one to make room\n * would rename an existing method when an operation is added.\n */\n private methodName(\n tag: Tag,\n className: string,\n endpoint: OperationEndpoint,\n methods: Map<string, string>,\n ): string {\n const operationId = endpoint.operation.operationId!;\n const methodName = resolveMethodName(\n endpoint.operation,\n this.config.apiClients?.[tag.name]?.methodNames?.[operationId],\n )!;\n const taken = methods.get(methodName);\n if (taken !== undefined) {\n throw new GeneratorError(\n 'specification',\n `Operations ${taken} and ${operationId} of tag ${tag.name} both generate the method ${className}.${methodName}(). Name one of them with apiClients[\"${tag.name}\"].methodNames in the generator configuration, or with the ${'x-fetcher-method'} extension.`,\n );\n }\n methods.set(methodName, operationId);\n return methodName;\n }\n\n /**\n * The path, query and header parameters of an operation, each named after\n * the document's name (`item-id` → `itemId`), in the order their types\n * resolve: the path parameters in the order the path holds them, then the\n * query and header parameters in the document's order. Path parameters the bounded context's interceptor fills are\n * left out (see {@link ignoresPathParameter}), and cookie parameters, which\n * the browser sends, are left out with a warning.\n */\n private parameters(\n tag: Tag,\n endpoint: OperationEndpoint,\n used: Set<string>,\n ): { parameter: ParameterModel; description?: string }[] {\n const declared = extractParameters(\n endpoint.operation,\n this.document.components ?? {},\n );\n const parameters: { parameter: ParameterModel; description?: string }[] =\n [];\n for (const location of ['path', 'query', 'header'] as const) {\n const located = declared.filter(parameter => parameter.in === location);\n for (const parameter of location === 'path'\n ? inPathOrder(endpoint.path, located)\n : located) {\n if (\n location === 'path' &&\n this.ignoresPathParameter(tag.name, parameter.name)\n ) {\n continue;\n }\n parameters.push({\n parameter: {\n name: uniqueParameterName(parameter.name, used),\n location,\n parameterName: parameter.name,\n schema: parameter.schema,\n required: location === 'path' || parameter.required === true,\n },\n description: parameter.description,\n });\n }\n }\n const cookies = declared.filter(parameter => parameter.in === 'cookie');\n if (cookies.length > 0) {\n this.warnings.push(\n `${endpoint.method.toUpperCase()} ${endpoint.path} leaves out its cookie parameter(s) ${cookies.map(cookie => cookie.name).join(', ')}: the browser sends cookies, and fetch cannot set them.`,\n );\n }\n return parameters;\n }\n\n /**\n * Tells whether an API client leaves a path parameter out: the ones the\n * configuration names for the tag, else in a Wow document the resource\n * attribution parameters Wow's interceptor fills.\n */\n private ignoresPathParameter(tagName: string, parameterName: string) {\n const ignored =\n this.config.apiClients?.[tagName]?.ignorePathParameters ??\n (this.wowDocument ? RESOURCE_ATTRIBUTION_PATH_PARAMETERS : []);\n return ignored.includes(parameterName);\n }\n\n /**\n * The body an operation sends, by its content: JSON (`application/json`,\n * `+json`), `multipart/form-data`, `application/x-www-form-urlencoded`,\n * `text/*`, or anything else.\n */\n private body(operation: Operation, used: Set<string>): BodyModel | undefined {\n if (!operation.requestBody) {\n return undefined;\n }\n const requestBody: RequestBody | undefined = isReference(\n operation.requestBody,\n )\n ? extractRequestBody(operation.requestBody, this.document.components!)\n : operation.requestBody;\n if (!requestBody) {\n return undefined;\n }\n const required = requestBody.required === true;\n const content = requestBody.content ?? {};\n const json = findMediaType(content, APPLICATION_JSON, isJsonContentType);\n const name = uniqueParameterName('body', used);\n if (json?.schema) {\n return {\n name,\n required,\n content: {\n kind: 'json',\n schema: json.schema,\n optionalFields: resolveOptionalFields(\n json.schema,\n this.document.components,\n ),\n },\n };\n }\n if (findMediaType(content, 'multipart/form-data')) {\n return { name, required, content: { kind: 'formData' } };\n }\n if (findMediaType(content, 'application/x-www-form-urlencoded')) {\n return { name, required, content: { kind: 'urlEncoded' } };\n }\n if (Object.keys(content).some(isTextContentType)) {\n return { name, required, content: { kind: 'text' } };\n }\n return { name, required, content: { kind: 'binary' } };\n }\n\n /**\n * What an operation returns, read from its success response: `200`, else\n * the lowest other 2xx.\n */\n private returns(operation: Operation): ReturnModel {\n const okResponse = extractOkResponse(operation, this.document.components);\n if (!okResponse) {\n return { kind: 'response' };\n }\n const responseJsonSchema = extractResponseJsonSchema(okResponse);\n const jsonSchema =\n responseJsonSchema || extractResponseWildcardSchema(okResponse);\n if (jsonSchema) {\n return {\n kind: 'json',\n schema: jsonSchema,\n wildcard: !responseJsonSchema,\n };\n }\n const eventStreamSchema = extractResponseEventStreamSchema(okResponse);\n if (eventStreamSchema) {\n if (isReference(eventStreamSchema)) {\n const schema = extractSchema(\n eventStreamSchema,\n this.document.components!,\n )!;\n if (isArray(schema) && isReference(schema.items)) {\n const modelInfo = resolveReferenceModelInfo(\n schema.items,\n this.document.components,\n );\n return {\n kind: 'eventStream',\n items: schema.items,\n serverSentEvent: modelInfo.name.includes('ServerSentEvent'),\n };\n }\n }\n return { kind: 'eventStream', serverSentEvent: false };\n }\n if (hasTextResponse(okResponse)) {\n return { kind: 'text' };\n }\n return { kind: 'response' };\n }\n\n /**\n * Groups operations by their tags.\n *\n * An operation needs an operationId, which names its method, and a tag,\n * which names its client; one without either is skipped with a warning.\n */\n private groupOperations(\n tags: Map<string, Tag>,\n ): Map<string, Set<OperationEndpoint>> {\n const operations = new Map<string, Set<OperationEndpoint>>();\n for (const endpoint of this.document.endpoints) {\n const label = `${endpoint.method.toUpperCase()} ${endpoint.path}`;\n const operationTags = endpoint.operation.tags ?? [];\n if (operationTags.length === 0) {\n this.warnings.push(\n `Skipping ${label}: it has no tag, and the tag names its API client.`,\n );\n continue;\n }\n const clientTags = operationTags.filter(tagName => tags.has(tagName));\n // Wow tags an aggregate's routes with the aggregate and with its own\n // tags; they belong to the command and query clients.\n if (clientTags.length < operationTags.length) continue;\n if (!endpoint.operation.operationId) {\n this.warnings.push(\n `Skipping ${label}: it has no operationId, and the operationId names its method.`,\n );\n continue;\n }\n for (const tagName of clientTags) {\n if (!operations.has(tagName)) {\n operations.set(tagName, new Set());\n }\n operations.get(tagName)!.add(endpoint);\n }\n }\n return operations;\n }\n\n /**\n * The tags that generate API clients: the ones the operations use or the\n * document declares, but Wow's own, the actuator's and the aggregates'.\n */\n private tags(): Map<string, Tag> {\n const tags = new Map<string, Tag>();\n for (const { operation } of this.document.endpoints) {\n operation.tags?.forEach(tagName => {\n if (!this.ignoresTag(tagName) && !tags.has(tagName)) {\n tags.set(tagName, { name: tagName, description: '' });\n }\n });\n }\n this.document.openAPI.tags?.forEach(tag => {\n if (!this.ignoresTag(tag.name)) tags.set(tag.name, tag);\n });\n return tags;\n }\n\n private ignoresTag(tagName: string): boolean {\n return (\n IGNORED_API_CLIENT_TAGS.has(tagName) ||\n this.wow.aggregateTags.has(tagName)\n );\n }\n}\n\n/**\n * The file an API client is declared in: its class name with the first\n * letter lowered, `CartApiClient` → `cartApiClient.ts`, camelCase like every\n * other generated file. Client names differ by more than case (see\n * {@link clientKey}), so no two clients share a file, even on a file system\n * that ignores case.\n */\nfunction apiClientFileName(className: string): string {\n return `${className.charAt(0).toLowerCase()}${className.slice(1)}.ts`;\n}\n\nfunction clientKey(modelInfo: ModelInfo): string {\n return `${modelInfo.path}/${modelInfo.name}`.toLowerCase();\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Reference, Schema } from '@ahoo-wang/fetcher-openapi';\nimport { GeneratorError } from '../api/errors';\nimport { boundedContextFilePath, modelFilePath } from '../naming/paths';\nimport type { OpenApiDocument } from '../openapi/document';\nimport { isReference } from '../openapi/references';\nimport { isComposition } from '../openapi/schemas';\nimport { COMPONENTS_PREFIX } from '../openapi/components';\nimport {\n aggregatedTypeNames,\n IGNORED_API_CLIENT_TAGS,\n isWowSchema,\n} from '../wow/conventions';\nimport type { WowModel } from '../wow/model';\nimport { withDocOverride } from '../wow/model';\nimport type { BoundedContextModel, ModelDeclaration } from './model';\nimport { resolveContextDeclarationName, resolveModelInfo } from './modelInfo';\n\n/**\n * The bounded contexts whose alias constant is generated: every context with\n * aggregates, and the document's own, which API clients take their base path\n * from. Sorted by alias.\n */\nexport function analyzeContexts(wow: WowModel): BoundedContextModel[] {\n const aliases = new Set(wow.contexts.keys());\n if (wow.contextAlias) aliases.add(wow.contextAlias);\n return [...aliases].sort().map(alias => ({\n alias,\n constantName: resolveContextDeclarationName(alias),\n file: boundedContextFilePath(alias),\n }));\n}\n\n/**\n * The models of a document: one per component schema, in the document's\n * order, but for Wow's own schemas, which wow-client declares (`wow.*`, and\n * the types every aggregate derives from its state).\n *\n * @throws GeneratorError when two schemas generate the same model\n */\nexport function analyzeModels(\n document: OpenApiDocument,\n wow: WowModel,\n): ModelDeclaration[] {\n const schemas = document.components?.schemas;\n if (!schemas) return [];\n const derived = derivedTypeNames(wow);\n const ofApiClients = apiClientSchemaKeys(document, wow);\n const keys = Object.keys(schemas).filter(\n key =>\n !isWowSchema(key, () => resolveModelInfo(key).name, derived) ||\n // A type derived from an aggregate's state that an API client returns\n // or takes (a service's own route answering a snapshot): the query\n // clients name it by wow-client's generics, but the API client by the\n // schema, so it is generated like any other model.\n (!key.startsWith('wow.') && ofApiClients.has(key)),\n );\n assertUniqueModelNames(keys);\n const bodies = messageBodyKeys(wow);\n return keys.map(key => {\n const schema = schemas[key];\n const info = resolveModelInfo(key);\n return {\n key,\n info,\n file: modelFilePath(info),\n schema,\n // The doc reads the schema with what the Wow metadata lends it; the\n // types read the schema as the document has it.\n docSchema: withDocOverride(schema, wow.schemaDocOverrides.get(key)),\n emptyMessageBody: bodies.has(key) && isEmptyMessageBody(schema),\n };\n });\n}\n\n/**\n * The schemas the operations of the API clients reach: those of their\n * parameters, bodies and responses, and every schema those reach in turn.\n * An API client holds the operations whose tags are all neither Wow's own,\n * the actuator's nor an aggregate's (`analyzeApiClients`).\n */\nfunction apiClientSchemaKeys(\n document: OpenApiDocument,\n wow: WowModel,\n): Set<string> {\n const keys = new Set<string>();\n const seen = new Set<unknown>();\n const components = (document.components ?? {}) as Record<\n string,\n Record<string, unknown> | undefined\n >;\n const visit = (node: unknown): void => {\n if (node === null || typeof node !== 'object' || seen.has(node)) return;\n seen.add(node);\n if (Array.isArray(node)) {\n node.forEach(visit);\n return;\n }\n const { $ref } = node as { $ref?: unknown };\n if (typeof $ref === 'string' && $ref.startsWith(COMPONENTS_PREFIX)) {\n const [kind, ...name] = $ref.slice(COMPONENTS_PREFIX.length).split('/');\n const key = name.join('/');\n if (kind === 'schemas') keys.add(key);\n visit(components[kind]?.[key]);\n }\n Object.values(node).forEach(visit);\n };\n for (const { operation } of document.endpoints) {\n const tags = operation.tags ?? [];\n if (\n tags.length > 0 &&\n tags.every(\n tag => !IGNORED_API_CLIENT_TAGS.has(tag) && !wow.aggregateTags.has(tag),\n )\n ) {\n visit(operation);\n }\n }\n return keys;\n}\n\n/** The types wow-client derives from the state of every aggregate. */\nfunction derivedTypeNames(wow: WowModel): Set<string> {\n const names = new Set<string>();\n for (const aggregates of wow.contexts.values()) {\n for (const aggregate of aggregates) {\n const state = resolveModelInfo(aggregate.state.key);\n aggregatedTypeNames(state.name).forEach(name => names.add(name));\n }\n }\n return names;\n}\n\n/**\n * Fails when two schemas generate the same model in the same file.\n *\n * Names are normalised to PascalCase, so `Foo-Bar`, `FooBar` and `foo_bar`\n * all become `FooBar`; TypeScript would silently merge three interfaces of\n * that name into one type that matches none of them.\n *\n * @throws GeneratorError listing every group of colliding schema keys\n */\nfunction assertUniqueModelNames(keys: readonly string[]) {\n const byModel = new Map<string, string[]>();\n for (const key of keys) {\n const modelInfo = resolveModelInfo(key);\n const model = `${modelInfo.path === '/' ? '' : modelInfo.path}/${modelInfo.name}`;\n byModel.set(model, [...(byModel.get(model) ?? []), key]);\n }\n const collisions = [...byModel].filter(([, keys]) => keys.length > 1);\n if (collisions.length === 0) return;\n throw new GeneratorError(\n 'specification',\n `Schemas generate the same model: ${collisions\n .map(([model, keys]) => `${keys.join(', ')} → ${model}`)\n .join('; ')}. Rename all but one of them in the document.`,\n );\n}\n\n/** The schema keys of every command and event body of the aggregates. */\nfunction messageBodyKeys(wow: WowModel): Set<string> {\n return new Set(\n [...wow.contexts.values()].flatMap(aggregates =>\n [...aggregates].flatMap(aggregate => [\n ...[...aggregate.commands.values()].map(command => command.schema.key),\n ...[...aggregate.events.values()].map(event => event.schema.key),\n ]),\n ),\n );\n}\n\n/**\n * Tells whether a schema is an object with nothing declared: no properties,\n * no additional properties, no composition. A command or event of this shape\n * - a Kotlin `data object` - is an empty object, not any object: `{type:\n * object}` alone would otherwise generate `Record<string, any>`, which every\n * event union absorbs.\n */\nfunction isEmptyMessageBody(schema: Schema | Reference): boolean {\n if (isReference(schema)) return false;\n return (\n schema.type === 'object' &&\n Object.keys(schema.properties ?? {}).length === 0 &&\n (schema.additionalProperties === undefined ||\n schema.additionalProperties === false) &&\n !schema.required?.length &&\n !isComposition(schema) &&\n schema.enum === undefined &&\n schema.const === undefined\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { GeneratorConfiguration } from '../api/configuration';\nimport type { OpenApiDocument } from '../openapi/document';\nimport type { WowModel } from '../wow/model';\nimport { analyzeAggregates, assertCommandTypeNamesFree } from './aggregates';\nimport { analyzeApiClients } from './apiClients';\nimport type { Analysis } from './model';\nimport { analyzeContexts, analyzeModels } from './models';\n\n/**\n * Decides what a document generates: its bounded contexts, models, command\n * and query clients and API clients. A pure function of the document, its\n * Wow model and the configuration; nothing is written and nothing logged.\n *\n * @param document - The document, left unchanged\n * @param wow - Its Wow model\n * @param config - The generator configuration\n * @returns The generation model, and the warnings for what it leaves out\n * @throws GeneratorError when the document asks for code that cannot\n * compile: two schemas of one model, a command type named like a model,\n * two operations of one method\n */\nexport function analyze(\n document: OpenApiDocument,\n wow: WowModel,\n config: GeneratorConfiguration,\n): Analysis {\n const warnings: string[] = [];\n const contexts = analyzeContexts(wow);\n const models = analyzeModels(document, wow);\n const aggregates = analyzeAggregates(document, wow);\n assertCommandTypeNamesFree(aggregates, models);\n const apiClients = analyzeApiClients(document, wow, config, warnings);\n return { model: { contexts, models, aggregates, apiClients }, warnings };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { ImportDeclarationStructure, OptionalKind } from 'ts-morph';\n\n/** A name one module imports from another, under an alias or its own name. */\nexport interface NamedImport {\n readonly name: string;\n alias?: string;\n}\n\n/**\n * The imports of one generated module, kept in memory until the module is\n * written.\n *\n * Declarations stay in the order their modules were first imported, and\n * names in the order they were first asked for, as the file would have\n * received them one by one; `organizeImports` sorts them when the file is\n * finished.\n */\nexport class ImportRegistry {\n private readonly declarations = new Map<string, NamedImport[]>();\n\n /**\n * Imports names from a module, keeping the ones it already imports.\n *\n * @param moduleSpecifier - The module to import from\n * @param names - The names to import\n * @returns The names the module now imports\n */\n add(\n moduleSpecifier: string,\n names: readonly string[],\n ): readonly NamedImport[] {\n let imported = this.declarations.get(moduleSpecifier);\n if (!imported) {\n imported = [];\n this.declarations.set(moduleSpecifier, imported);\n }\n for (const name of names) {\n if (!imported.some(item => item.name === name)) {\n imported.push({ name });\n }\n }\n return imported;\n }\n\n /**\n * Applies imports a resolved type asks for, in order: each name is\n * imported, and takes the alias the request gives it.\n *\n * @param requests - The imports, as `types/typeResolver.ts` returns them\n */\n apply(\n requests: readonly {\n moduleSpecifier: string;\n name: string;\n alias?: string;\n }[],\n ): void {\n for (const { moduleSpecifier, name, alias } of requests) {\n const item = this.add(moduleSpecifier, [name]).find(\n imported => imported.name === name,\n )!;\n if (alias !== undefined) item.alias = alias;\n }\n }\n\n /** Every name imported, with its module and alias, in the order first asked for. */\n entries(): { moduleSpecifier: string; name: string; alias?: string }[] {\n return [...this.declarations].flatMap(([moduleSpecifier, imported]) =>\n imported.map(({ name, alias }) =>\n alias === undefined\n ? { moduleSpecifier, name }\n : { moduleSpecifier, name, alias },\n ),\n );\n }\n\n /**\n * The local names every import binds, the ones of `except` aside: an\n * alias where it has one, else the name.\n */\n localNames(except?: NamedImport): string[] {\n return [...this.declarations.values()]\n .flat()\n .filter(item => item !== except)\n .map(item => item.alias ?? item.name);\n }\n\n /** The import declarations, in the order they were first asked for. */\n structures(): OptionalKind<ImportDeclarationStructure>[] {\n return [...this.declarations].map(([moduleSpecifier, imported]) => ({\n moduleSpecifier,\n namedImports: imported.map(({ name, alias }) =>\n alias === undefined ? name : { name, alias },\n ),\n }));\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n ClassDeclarationStructure,\n CodeBlockWriter,\n EnumDeclarationStructure,\n EnumMemberStructure,\n ImportDeclarationStructure,\n InterfaceDeclarationStructure,\n OptionalKind,\n SourceFile,\n StatementStructures,\n TypeAliasDeclarationStructure,\n VariableStatementStructure,\n WriterFunction,\n} from 'ts-morph';\nimport { StructureKind } from 'ts-morph';\nimport { ImportRegistry } from './importRegistry';\n\n/** A top-level statement of a generated module. */\nexport type ModuleStatement =\n | ClassDeclarationStructure\n | EnumDeclarationStructure\n | InterfaceDeclarationStructure\n | TypeAliasDeclarationStructure\n | VariableStatementStructure\n | string;\n\n/**\n * A generated module, collected in memory and written into its source file\n * once.\n *\n * ts-morph re-parses the whole file on every change, so a file written a\n * declaration, a property and a doc comment at a time costs time that grows\n * with the square of its length: the root `types.ts` of a large document runs\n * to 20,000 lines. Here the emitters describe each declaration as a ts-morph\n * structure, with its members and docs, and {@link build} inserts the lot in\n * one change, printed by the same printers.\n *\n * The blank lines between statements are the ones the file would have got\n * receiving the statements one by one, so the output is byte for byte the\n * same: a type alias follows a type alias, and a variable statement a\n * variable statement, on the next line; anything else is set off by a blank\n * line.\n */\nexport class ModuleBuilder {\n /** The imports of the module. */\n readonly imports = new ImportRegistry();\n private readonly statements: ModuleStatement[] = [];\n\n /**\n * @param sourceFile - The file the module is written into; it stays empty\n * until {@link build}.\n */\n constructor(readonly sourceFile: SourceFile) {}\n\n /** The directory of the module's file, which relative imports start from. */\n get directoryPath(): string {\n return this.sourceFile.getDirectoryPath();\n }\n\n /**\n * Adds a top-level statement. A structure stays open to changes until the\n * module is built.\n *\n * @returns The statement added\n */\n add<T extends ModuleStatement>(statement: T): T {\n this.statements.push(statement);\n return statement;\n }\n\n /** Writes the imports and the statements into the file in one change. */\n build(): SourceFile {\n const statements: (StatementStructures | string | WriterFunction)[] = [];\n let previous: ModuleStatement | ImportDeclarationStructure | undefined;\n for (const declaration of this.imports.structures()) {\n previous = { ...declaration, kind: StructureKind.ImportDeclaration };\n statements.push(previous);\n }\n for (const statement of this.statements) {\n if (previous && blankLineBetween(previous, statement)) {\n statements.push(blankLine);\n }\n statements.push(statement);\n previous = statement;\n }\n if (statements.length > 0) {\n this.sourceFile.addStatements(statements);\n }\n return this.sourceFile;\n }\n}\n\n/**\n * The modules of one generation, one builder per file, written together at\n * the end.\n */\nexport class ModuleSet {\n private readonly modules = new Map<string, ModuleBuilder>();\n\n /**\n * @param open - Returns the source file a path relative to the output\n * directory is written to, claiming it for the generation\n */\n constructor(private readonly open: (filePath: string) => SourceFile) {}\n\n /**\n * The module written to a path under the output directory, created the\n * first time it is asked for.\n */\n module(filePath: string): ModuleBuilder {\n const sourceFile = this.open(filePath);\n const key = sourceFile.getFilePath();\n let module = this.modules.get(key);\n if (!module) {\n module = new ModuleBuilder(sourceFile);\n this.modules.set(key, module);\n }\n return module;\n }\n\n /** Writes every module into its file, each in one go. */\n build(): void {\n for (const module of this.modules.values()) module.build();\n this.modules.clear();\n }\n}\n\n/** Starts the next statement after a blank line. */\nconst blankLine: WriterFunction = (writer: CodeBlockWriter) => {\n writer.blankLineIfLastNot();\n};\n\n/**\n * Tells whether a statement added after another one is set off by a blank\n * line, as ts-morph separates statements added one at a time.\n */\nfunction blankLineBetween(\n previous: ModuleStatement | ImportDeclarationStructure,\n next: ModuleStatement,\n): boolean {\n if (typeof next === 'string') return false;\n switch (next.kind) {\n case StructureKind.TypeAlias:\n case StructureKind.VariableStatement:\n return typeof previous === 'string' || previous.kind !== next.kind;\n default:\n return true;\n }\n}\n\n/**\n * Enum members printed as adding them one at a time to an enum leaves them:\n * each one followed by a comma, the last one too. The printer separates\n * members with commas only where a member does not already end with one.\n *\n * @param members - The members, each with a string initializer\n */\nexport function membersWithTrailingComma(\n members: readonly OptionalKind<EnumMemberStructure>[],\n): OptionalKind<EnumMemberStructure>[] {\n return members.map(member => ({\n ...member,\n initializer: `${member.initializer as string},`,\n }));\n}\n\n/**\n * The index signature of an interface, as a member printed after its\n * properties, where adding it after them puts it: a structure's\n * `indexSignatures` are printed first.\n *\n * @param returnType - The type of the additional properties\n * @param docs - Its doc comments\n */\nexport function indexSignatureMember(\n returnType: string,\n docs?: string[],\n): OptionalKind<\n NonNullable<InterfaceDeclarationStructure['properties']>[number]\n> {\n return { name: '[key: string]', type: returnType, docs };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { join, relative, sep } from 'path';\nimport type { ModelInfo } from '../naming/modelInfo';\nimport { boundedContextFilePath, MODEL_FILE_NAME } from '../naming/paths';\nimport type { NamedImport } from './importRegistry';\nimport type { ModuleBuilder } from './moduleBuilder';\n\n/** Alias for import paths */\nconst IMPORT_ALIAS = '@';\n\n/**\n * Adds named imports to a module.\n * @param module - The module to modify\n * @param moduleSpecifier - The module to import from\n * @param namedImports - Array of named imports to add\n * @returns The names the module now imports from `moduleSpecifier`\n */\nexport function addImport(\n module: ModuleBuilder,\n moduleSpecifier: string,\n namedImports: string[],\n): readonly NamedImport[] {\n return module.imports.add(moduleSpecifier, namedImports);\n}\n\n/**\n * Adds an import for a referenced model.\n * @param module - The module to modify\n * @param outputDir - The output directory\n * @param refModelInfo - The referenced model information\n */\nexport function addImportRefModel(\n module: ModuleBuilder,\n outputDir: string,\n refModelInfo: ModelInfo,\n): readonly NamedImport[] {\n return addImport(\n module,\n modelModuleSpecifier(module, outputDir, refModelInfo),\n [refModelInfo.name],\n );\n}\n\n/**\n * The specifier a module imports a model by: the package of a model imported\n * from one (a path starting with `@`), else the relative path of the\n * `types.ts` that declares it.\n *\n * @param module - The importing module\n * @param outputDir - The output directory\n * @param model - The model\n */\nexport function modelModuleSpecifier(\n module: ModuleBuilder,\n outputDir: string,\n model: ModelInfo,\n): string {\n if (model.path.startsWith(IMPORT_ALIAS)) return model.path;\n return relativeModuleSpecifier(\n module.directoryPath,\n join(outputDir, model.path, MODEL_FILE_NAME),\n );\n}\n\n/**\n * The specifier a source file imports another generated file by.\n *\n * Relative specifiers carry the `.js` extension, which every module\n * resolution TypeScript offers accepts for a `.ts` file: `NodeNext` and\n * `Node16` require it, and `bundler` and `node10` map it back to the source.\n *\n * @param fromDirectory - The directory of the importing file\n * @param targetFilePath - The imported `.ts` file, or a directory holding an `index.ts`\n * @returns A specifier starting with `./` or `../` and ending with `.js`\n */\nexport function relativeModuleSpecifier(\n fromDirectory: string,\n targetFilePath: string,\n): string {\n let relativePath = relative(fromDirectory, targetFilePath)\n .split(sep)\n .join('/');\n relativePath = relativePath.endsWith('.ts')\n ? relativePath.replace(/\\.ts$/, '.js')\n : `${relativePath}/index.js`;\n return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;\n}\n\n/**\n * Imports a bounded context's alias constant into a generated file.\n *\n * @param module - The importing module\n * @param outputDir - The output directory\n * @param contextAlias - The bounded context alias\n * @param declarationName - The name of the alias constant\n */\nexport function addImportBoundedContext(\n module: ModuleBuilder,\n outputDir: string,\n contextAlias: string,\n declarationName: string,\n): readonly NamedImport[] {\n return addImport(\n module,\n relativeModuleSpecifier(\n module.directoryPath,\n join(outputDir, boundedContextFilePath(contextAlias)),\n ),\n [declarationName],\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Reference, Schema } from '@ahoo-wang/fetcher-openapi';\nimport type { JSDocableNodeStructure } from 'ts-morph';\n\n/**\n * Generates a JSDoc comment string from a title and description.\n * @returns The formatted JSDoc string or undefined if both title and description are empty\n */\nexport function jsDoc(\n descriptions: (string | undefined)[],\n separator = '\\n',\n): string | undefined {\n if (!Array.isArray(descriptions)) {\n return undefined;\n }\n const filtered = descriptions\n .filter((v): v is string => typeof v === 'string' && v.length > 0)\n .map(escapeJsDoc);\n return filtered.length > 0 ? filtered.join(separator) : undefined;\n}\n\n/**\n * Keeps document text from ending the comment it is written into: a\n * description holding `*` followed by `/` - a cron expression such as\n * `*` `/5 * * * *`, a glob - would otherwise close the JSDoc early.\n *\n * @param text - Text taken from the document\n * @returns The text with every comment terminator broken up\n */\nexport function escapeJsDoc(text: string): string {\n return text.replace(/\\*\\//g, '*\\\\/');\n}\n\n/**\n * Adds a JSDoc comment to a declaration with the provided title and\n * description, after the ones it already has.\n */\nexport function addJSDoc(\n node: JSDocableNodeStructure,\n descriptions: (string | undefined)[],\n) {\n const jsdoc = jsDoc(descriptions);\n if (!jsdoc) {\n return;\n }\n node.docs = [...(node.docs ?? []), jsdoc];\n}\n\nexport function schemaJSDoc(schema: Schema, key?: string) {\n const descriptions: (string | undefined)[] = [\n schema.title,\n schema.description,\n ];\n if (key) {\n descriptions.push(`- key: ${key}`);\n }\n if (schema.format) {\n descriptions.push(\n schema.format === 'int64'\n ? '- format: int64 (a value beyond Number.MAX_SAFE_INTEGER loses precision)'\n : `- format: ${schema.format}`,\n );\n }\n\n addJsonJsDoc(descriptions, schema, 'default');\n addJsonJsDoc(descriptions, schema, 'example');\n addNumericConstraintsJsDoc(descriptions, schema);\n addStringConstraintsJsDoc(descriptions, schema);\n addArrayConstraintsJsDoc(descriptions, schema);\n return descriptions;\n}\n\n/**\n * Adds a JSDoc comment to a declaration based on the schema's title and description.\n * @param node - The declaration to add the JSDoc comment to\n * @param schema - The schema containing title and description\n * @param key - The key associated with the schema\n */\nexport function addSchemaJSDoc(\n node: JSDocableNodeStructure,\n schema: Schema | Reference,\n key?: string,\n) {\n const descriptions = schemaJSDoc(schema as Schema, key);\n addJSDoc(node, descriptions);\n}\n\n/**\n * Adds the doc comment of a model.\n *\n * @param node - The model declaration\n * @param schema - The schema it is generated from\n * @param key - The schema's component key\n * @param includeSchema - Also embed the complete JSON schema\n */\nexport function addMainSchemaJSDoc(\n node: JSDocableNodeStructure,\n schema: Schema | Reference,\n key?: string,\n includeSchema = false,\n) {\n const descriptions = schemaJSDoc(schema as Schema, key);\n if (includeSchema) {\n jsonJsDoc(descriptions, 'schema', schema);\n }\n addJSDoc(node, descriptions);\n}\n\nfunction addJsonJsDoc(\n descriptions: (string | undefined)[],\n schema: any,\n propertyName: keyof Schema,\n) {\n const json = schema[propertyName];\n if (!json) {\n return;\n }\n if (typeof json !== 'object') {\n descriptions.push(`- ${propertyName}: \\`${json}\\``);\n return;\n }\n jsonJsDoc(descriptions, propertyName, json);\n}\n\nfunction jsonJsDoc(\n descriptions: (string | undefined)[],\n name: string,\n json: any,\n) {\n descriptions.push(`- ${name}: `);\n descriptions.push('```json');\n descriptions.push(JSON.stringify(json, null, 2));\n descriptions.push('```');\n}\n\nfunction addNumericConstraintsJsDoc(\n descriptions: (string | undefined)[],\n schema: Schema,\n) {\n const constraintsDescriptions = ['- Numeric Constraints'];\n if (schema.minimum !== undefined) {\n constraintsDescriptions.push(` - minimum: ${schema.minimum}`);\n }\n if (schema.maximum !== undefined) {\n constraintsDescriptions.push(` - maximum: ${schema.maximum}`);\n }\n if (schema.exclusiveMinimum !== undefined) {\n constraintsDescriptions.push(\n ` - exclusiveMinimum: ${schema.exclusiveMinimum}`,\n );\n }\n if (schema.exclusiveMaximum !== undefined) {\n constraintsDescriptions.push(\n ` - exclusiveMaximum: ${schema.exclusiveMaximum}`,\n );\n }\n if (schema.multipleOf !== undefined) {\n constraintsDescriptions.push(` - multipleOf: ${schema.multipleOf}`);\n }\n if (constraintsDescriptions.length === 1) {\n return;\n }\n descriptions.push(...constraintsDescriptions);\n}\n\nfunction addStringConstraintsJsDoc(\n descriptions: (string | undefined)[],\n schema: Schema,\n) {\n const constraintsDescriptions = ['- String Constraints'];\n if (schema.minLength !== undefined) {\n constraintsDescriptions.push(` - minLength: ${schema.minLength}`);\n }\n if (schema.maxLength !== undefined) {\n constraintsDescriptions.push(` - maxLength: ${schema.maxLength}`);\n }\n if (schema.pattern !== undefined) {\n constraintsDescriptions.push(` - pattern: ${schema.pattern}`);\n }\n if (constraintsDescriptions.length === 1) {\n return;\n }\n descriptions.push(...constraintsDescriptions);\n}\n\nfunction addArrayConstraintsJsDoc(\n descriptions: (string | undefined)[],\n schema: Schema,\n) {\n const constraintsDescriptions = ['- Array Constraints'];\n if (schema.minItems !== undefined) {\n constraintsDescriptions.push(` - minItems: ${schema.minItems}`);\n }\n if (schema.maxItems !== undefined) {\n constraintsDescriptions.push(` - maxItems: ${schema.maxItems}`);\n }\n if (schema.uniqueItems !== undefined) {\n constraintsDescriptions.push(` - uniqueItems: ${schema.uniqueItems}`);\n }\n if (constraintsDescriptions.length === 1) {\n return;\n }\n descriptions.push(...constraintsDescriptions);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Components, Reference, Schema } from '@ahoo-wang/fetcher-openapi';\nimport { CodeBlockWriter } from 'ts-morph';\nimport { jsDoc, schemaJSDoc } from '../emit/jsdoc';\nimport type { ModelInfo } from '../naming/modelInfo';\nimport { quoteStringLiteral, resolvePropertyName } from '../naming/naming';\nimport { extractComponentKey, extractSchema } from '../openapi/components';\nimport { isReference } from '../openapi/references';\nimport type { MapSchema, ObjectSchema } from '../openapi/schemas';\nimport {\n getMapKeySchema,\n isAllOf,\n isComposition,\n isEnum,\n isMap,\n isObject,\n isReadOnly,\n resolvePrimitiveType,\n toArrayType,\n} from '../openapi/schemas';\n\n/**\n * Schema → TypeScript type expression, as pure functions.\n *\n * Every entry point takes a schema and a {@link TypeScope} - where the type\n * is written - and returns a {@link ResolvedType}: the type's text, and the\n * imports the module needs for it. Nothing is written; the caller applies the\n * imports to its module (`ImportRegistry.apply`) before it resolves the next\n * type, so a later reference sees the names and aliases an earlier one took.\n */\n\n/** An import a resolved type needs: a name, and the alias it goes by. */\nexport interface ImportRequest {\n readonly moduleSpecifier: string;\n readonly name: string;\n readonly alias?: string;\n}\n\n/** A type expression, and the imports it needs. */\nexport interface ResolvedType {\n readonly text: string;\n readonly imports: readonly ImportRequest[];\n}\n\n/** The imports a module already holds, as the resolver reads them. */\nexport interface ImportLookup {\n entries(): readonly ImportRequest[];\n}\n\n/**\n * What stays the same for every type of one document: its components, how a\n * component names its model, and the model names declared at each path.\n */\nexport interface TypeContext {\n readonly components?: Components;\n /** The model a reference names. */\n modelOf(reference: Reference): ModelInfo;\n /** The models declared at a path, with their `EnumText` companions. */\n namesAt(path: string): readonly string[];\n}\n\n/**\n * How a document's component keys name models: `resolveModelInfo` and\n * `resolveReferenceModelInfo` of `analysis/modelInfo.ts`.\n */\nexport interface ModelNaming {\n ofKey(key: string): ModelInfo;\n ofReference(reference: Reference, components?: Components): ModelInfo;\n}\n\n/**\n * Builds the context of a document. The model names of each path are read\n * once, on first use, rather than from every component for every reference.\n */\nexport function createTypeContext(\n components: Components | undefined,\n naming: ModelNaming,\n): TypeContext {\n let namesByPath: Map<string, string[]> | undefined;\n return {\n components,\n modelOf: reference => naming.ofReference(reference, components),\n namesAt(path) {\n if (!namesByPath) {\n namesByPath = new Map();\n for (const key of Object.keys(components?.schemas ?? {})) {\n const model = naming.ofKey(key);\n let names = namesByPath.get(model.path);\n if (!names) {\n names = [];\n namesByPath.set(model.path, names);\n }\n names.push(model.name, `${model.name}EnumText`);\n }\n }\n return namesByPath.get(path) ?? [];\n },\n };\n}\n\n/** Where a type is written. */\nexport interface TypeScope {\n readonly context: TypeContext;\n /**\n * The declaration the type belongs to. An import never takes its name.\n * With a `path`, it is a model: the models of that path are declared beside\n * it, so a reference to one needs no import, and an import takes none of\n * their names. Without, every referenced model is imported.\n */\n readonly owner: { readonly name: string; readonly path?: string };\n /** The specifier the module imports a model by. */\n specifierOf(model: ModelInfo): string;\n /** The imports the module holds. */\n readonly imports: ImportLookup;\n}\n\n/**\n * Global names generated code relies on. A model imported under one of these\n * names would shadow the global, so the import is aliased instead: a model\n * named `Response` must not turn `Promise<Response>` into a promise of the\n * model.\n */\nexport const GLOBAL_TYPE_NAMES: readonly string[] = [\n 'Array',\n 'Blob',\n 'Exclude',\n 'FormData',\n 'Partial',\n 'Promise',\n 'ReadonlyArray',\n 'Record',\n 'Response',\n 'Symbol',\n 'URLSearchParams',\n];\n\n/** The TypeScript types a primitive schema type resolves to. */\nconst PRIMITIVE_TYPE_NAMES = new Set(['string', 'number', 'boolean']);\n\n/**\n * Keywords that describe a schema without constraining its instances.\n */\nconst ANNOTATION_KEYWORDS = new Set([\n '$comment',\n '$schema',\n 'default',\n 'deprecated',\n 'description',\n 'example',\n 'examples',\n 'externalDocs',\n 'readOnly',\n 'title',\n 'writeOnly',\n 'xml',\n]);\n\n/**\n * What a schema generates, as far as assignability to an index signature goes.\n *\n * A primitive carries its resolved TypeScript type; `object` and `array` need\n * no further detail, since neither is ever assignable to a primitive.\n */\ntype SchemaKind = 'object' | 'array' | { primitive: string };\n\n/** Tells whether two classifications describe the same generated shape. */\nfunction sameKind(left: SchemaKind | undefined, right: SchemaKind): boolean {\n if (left === undefined) return false;\n if (typeof left === 'string' || typeof right === 'string') {\n return left === right;\n }\n return left.primitive === right.primitive;\n}\n\n/**\n * Classifies a schema, following references through the components.\n *\n * Returns undefined - undecided - for anything whose assignability cannot be\n * read off the schema: a composition, a const, a nullable schema, a type\n * union, a missing `type`, a reference that cannot be resolved and a\n * reference cycle. An enum is decided by the type it sits beside, since it\n * generates literals of exactly that type.\n *\n * @param schema - The schema to classify\n * @param components - The components a reference resolves against\n * @param seen - The references already followed, guarding against a cycle\n * @returns The schema's kind, or undefined when it cannot be decided\n */\nfunction schemaKind(\n schema: Schema | Reference,\n components?: Components,\n seen: Set<string> = new Set(),\n): SchemaKind | undefined {\n if (isReference(schema)) {\n if (!components || seen.has(schema.$ref)) return undefined;\n seen.add(schema.$ref);\n const resolved = extractSchema(schema, components);\n return resolved ? schemaKind(resolved, components, seen) : undefined;\n }\n if (schema.nullable || Array.isArray(schema.type)) {\n return undefined;\n }\n // An `allOf` narrows to whatever its branches agree on, so it is decided\n // when every one of them decides and they all say the same thing. `anyOf`\n // and `oneOf` widen instead, and stay undecided.\n if (isAllOf(schema) && schema.type === undefined) {\n const kinds = schema.allOf.map(member =>\n schemaKind(member, components, seen),\n );\n const [first] = kinds;\n return first !== undefined && kinds.every(kind => sameKind(kind, first))\n ? first\n : undefined;\n }\n if (\n isComposition(schema) ||\n schema.const !== undefined ||\n schema.type === undefined\n ) {\n return undefined;\n }\n // An enum beside a sibling type generates literals of that type, which a\n // matching primitive index accepts - `'a' | 'b'` sits beside `string`.\n if (schema.type === 'object') return 'object';\n if (schema.type === 'array') return 'array';\n return { primitive: resolvePrimitiveType(schema.type) };\n}\n\n/**\n * Tells whether a named property provably cannot sit beside the index signature.\n *\n * The index type has to resolve to a primitive. That is not about proving the\n * clash - it is what keeps the alias sound: `Record<string, T>` in a type alias\n * may not lead back to the alias itself (TS2456), and only a primitive `T` is\n * certain never to. A property may reference anything, including the model\n * itself, because an object member defers.\n *\n * Against a primitive index, an object and an array are as incompatible as a\n * different primitive is, and so is a property whose kind cannot be read off\n * the schema: a nullable property generates `T | null`, a type array and a\n * typeless enum generate a union, and none of those is assignable to a\n * primitive index (TS2411). Undecided therefore takes the intersection, which\n * has no index-assignability rule to break. It cannot be circular either\n * (TS2456), because the index resolved to a primitive before we got here, so\n * the `Record` this generates can never lead back to the alias.\n *\n * @param propSchema - The named property's schema\n * @param additionalProperties - The additional-property schema\n * @param components - The components a reference resolves against\n * @returns True when the property may not be assignable to the index type\n */\nfunction clashesWithIndexSignature(\n propSchema: Schema | Reference,\n additionalProperties: Schema | Reference,\n components?: Components,\n): boolean {\n const indexKind = schemaKind(additionalProperties, components);\n if (typeof indexKind !== 'object') return false;\n const propertyKind = schemaKind(propSchema, components);\n if (propertyKind === undefined) return true;\n return (\n typeof propertyKind === 'string' ||\n propertyKind.primitive !== indexKind.primitive\n );\n}\n\n/**\n * Chooses the intersection representation over an interface with an index\n * signature.\n *\n * An interface may only carry a named property whose type is assignable to\n * its index signature (TS2411). Every generated property is required, so\n * only a clash that can be PROVEN off the schemas moves one - see\n * {@link clashesWithIndexSignature}. Anything undecided keeps the interface,\n * which is the only form that can reference itself through an index\n * signature: an alias reaching itself through `Record` is circular (TS2456),\n * which is what a dictionary of its own type would generate.\n *\n * @param schema - The object schema to represent\n * @param components - The components a reference resolves against\n * @returns True when the schema needs the intersection form\n */\nexport function requiresAdditionalPropertiesIntersection(\n schema: Schema,\n components?: Components,\n): boolean {\n const additionalProperties = schema.additionalProperties;\n if (typeof additionalProperties !== 'object') {\n return false;\n }\n return Object.values(schema.properties ?? {}).some(propSchema =>\n clashesWithIndexSignature(propSchema, additionalProperties, components),\n );\n}\n\n/**\n * Tells whether a schema is the OpenAPI 3.0 idiom for a nullable reference:\n * `nullable: true` beside a composition of references alone, such as\n * `{nullable: true, allOf: [{$ref: X}]}`.\n *\n * Strictly, `nullable` only widens a sibling `type`, and a member that\n * requires an object rules null out; springdoc and Swagger nevertheless write\n * this form for a property that may be null, and mean `X | null`. An inline\n * member keeps the strict reading.\n */\nfunction isNullableReference(schema: Schema): boolean {\n if (schema.nullable !== true || isEnum(schema) || !isComposition(schema)) {\n return false;\n }\n return [schema.allOf, schema.oneOf, schema.anyOf].every(\n members => members === undefined || members.every(isReference),\n );\n}\n\nfunction matchesLiteralType(value: unknown, schema: Schema): boolean {\n if (schema.type === undefined) return true;\n if (value === null && schema.nullable) return true;\n return [schema.type].flat().some(type => {\n if (type === 'null') return value === null;\n if (type === 'array') return Array.isArray(value);\n if (type === 'object') {\n return (\n value !== null && typeof value === 'object' && !Array.isArray(value)\n );\n }\n if (type === 'integer')\n return typeof value === 'number' && Number.isInteger(value);\n return typeof value === type;\n });\n}\n\n/**\n * Renders a JSON value as a TypeScript literal type: a string in single\n * quotes, escaped as ts-morph's printer escapes it, an array as a tuple, an\n * object as an object type that no array matches.\n *\n * @param value - The value from the document\n * @returns The literal type\n */\nexport function resolveLiteral(value: unknown): string {\n if (typeof value === 'string') {\n return new CodeBlockWriter({ useSingleQuote: true })\n .quote(value)\n .toString();\n }\n if (Array.isArray(value)) {\n return `[${value.map(item => resolveLiteral(item)).join(', ')}]`;\n }\n if (value !== null && typeof value === 'object') {\n const properties = Object.entries(value).map(\n ([name, item]) => `${resolvePropertyName(name)}: ${resolveLiteral(item)}`,\n );\n return properties.length\n ? `{ ${properties.join('; ')}; readonly [globalThis.Symbol.iterator]?: never }`\n : 'globalThis.Record<string, never>';\n }\n return JSON.stringify(value) ?? 'never';\n}\n\n/** An import as one resolution sees it: the module's, or one it added. */\ninterface ImportEntry {\n readonly moduleSpecifier: string;\n readonly name: string;\n alias?: string;\n}\n\n/**\n * One resolution: the scope, and the imports it has seen and asked for. It\n * starts from the module's imports and never changes them; what it asks for\n * is its result.\n */\nclass Resolution {\n private readonly entries: ImportEntry[];\n private readonly requested: ImportEntry[] = [];\n\n constructor(private readonly scope: TypeScope) {\n this.entries = scope.imports.entries().map(entry => ({ ...entry }));\n }\n\n get components(): Components | undefined {\n return this.scope.context.components;\n }\n\n /** The imports asked for, in the order first asked, with their aliases. */\n imports(): ImportRequest[] {\n return this.requested.map(({ moduleSpecifier, name, alias }) =>\n alias === undefined\n ? { moduleSpecifier, name }\n : { moduleSpecifier, name, alias },\n );\n }\n\n private request(entry: ImportEntry): void {\n if (!this.requested.includes(entry)) this.requested.push(entry);\n }\n\n /**\n * The name a reference goes by in the module: the model's own name when it\n * is declared beside the owner or imported as it is, else the alias of its\n * import. An import whose name the owner, a global, a model beside the\n * owner or another import already takes is aliased with leading `_`s.\n */\n reference(reference: Reference): string {\n const model = this.scope.context.modelOf(reference);\n const { owner } = this.scope;\n if (owner.path === model.path) return model.name;\n const moduleSpecifier = this.scope.specifierOf(model);\n let entry = this.entries.find(\n item =>\n item.moduleSpecifier === moduleSpecifier && item.name === model.name,\n );\n if (!entry) {\n entry = { moduleSpecifier, name: model.name };\n this.entries.push(entry);\n }\n this.request(entry);\n if (entry.alias) return entry.alias;\n const reservedNames = new Set([\n ...GLOBAL_TYPE_NAMES,\n owner.name,\n ...(owner.path === undefined\n ? []\n : this.scope.context.namesAt(owner.path)),\n ...this.entries\n .filter(item => item !== entry)\n .map(item => item.alias ?? item.name),\n ]);\n if (!reservedNames.has(model.name)) return model.name;\n let alias = `_${model.name}`;\n while (reservedNames.has(alias)) alias = `_${alias}`;\n entry.alias = alias;\n return alias;\n }\n\n additionalProperties(schema: Schema): string {\n if (\n schema.additionalProperties === false ||\n (schema.additionalProperties === undefined &&\n !schema.required?.some(\n name => !Object.hasOwn(schema.properties ?? {}, name),\n ))\n ) {\n return '';\n }\n\n if (\n schema.additionalProperties === true ||\n schema.additionalProperties === undefined\n ) {\n return '[key: string]: any';\n }\n\n return `[key: string]: ${this.additionalPropertyType(schema)}`;\n }\n\n additionalPropertyType(schema: Schema): string {\n return this.type(\n typeof schema.additionalProperties === 'object'\n ? schema.additionalProperties\n : {},\n );\n }\n\n requiredAdditionalPropertyType(schema: Schema): string {\n if (schema.additionalProperties === false) return 'never';\n if (typeof schema.additionalProperties === 'object') {\n return this.type(schema.additionalProperties);\n }\n return 'null | string | number | boolean | globalThis.Record<string, unknown> | readonly unknown[]';\n }\n\n private propertyDefinitions(schema: ObjectSchema): string[] {\n const { properties } = schema;\n return Object.entries(properties).map(([propName, propSchema]) => {\n const type = this.type(propSchema);\n const resolvedPropName =\n (isReadOnly(propSchema) ? 'readonly ' : '') +\n resolvePropertyName(propName);\n if (!isReference(propSchema)) {\n const jsDocDescriptions = schemaJSDoc(propSchema);\n const doc = jsDoc(jsDocDescriptions, '\\n * ');\n if (doc) {\n return `\n /**\n * ${doc}\n */\n ${resolvedPropName}: ${type}\n `;\n }\n }\n return `${resolvedPropName}: ${type}`;\n });\n }\n\n private objectType(schema: Schema): string {\n const parts: string[] = [];\n if (isObject(schema)) {\n parts.push(...this.propertyDefinitions(schema));\n }\n\n for (const name of schema.required ?? []) {\n if (!Object.hasOwn(schema.properties ?? {}, name)) {\n parts.push(\n `${resolvePropertyName(name)}: ${this.requiredAdditionalPropertyType(schema)}`,\n );\n }\n }\n const mapType =\n isMap(schema) && getMapKeySchema(schema)\n ? this.mapType(schema)\n : requiresAdditionalPropertiesIntersection(schema, this.components)\n ? `globalThis.Record<string, ${this.additionalPropertyType(schema)}>`\n : undefined;\n const additionalProps = mapType ? '' : this.additionalProperties(schema);\n if (additionalProps) {\n parts.push(additionalProps);\n }\n\n if (parts.length === 0) {\n return 'globalThis.Record<string, any>';\n }\n\n const objectType = `{\\n ${parts.join(';\\n ')}; \\n}`;\n return mapType ? `(${objectType} & ${mapType})` : objectType;\n }\n\n mapValueType(schema: MapSchema): string {\n if (\n schema.additionalProperties === undefined ||\n schema.additionalProperties === false ||\n schema.additionalProperties === true\n ) {\n return 'any';\n }\n return this.type(schema.additionalProperties);\n }\n\n private mapKeyType(schema: Schema): string {\n const mapKeySchema = getMapKeySchema(schema);\n if (!mapKeySchema) {\n return 'string';\n }\n return this.type(mapKeySchema);\n }\n\n private mapType(schema: MapSchema): string {\n const keyType = this.mapKeyType(schema);\n const valueType = this.mapValueType(schema);\n return `globalThis.Record<${keyType},${valueType}>`;\n }\n\n private objectConstrained(schema: Schema | Reference): boolean {\n const resolve = (member: Schema | Reference): Schema | undefined =>\n isReference(member)\n ? this.components && extractSchema(member, this.components)\n : member;\n const root = resolve(schema);\n const nodes = new Map<Schema, (Schema | undefined)[][]>();\n const constrained = new Set<Schema>();\n const pending = root ? [root] : [];\n for (const current of pending) {\n if (nodes.has(current)) continue;\n const groups = [current.allOf, current.oneOf, current.anyOf].map(\n members => members?.map(resolve) ?? [],\n );\n nodes.set(current, groups);\n for (const members of groups) {\n for (const member of members) {\n if (member && !nodes.has(member)) pending.push(member);\n }\n }\n if (\n current.type === 'object' ||\n current.type === 'null' ||\n (Array.isArray(current.type) &&\n current.type.length > 0 &&\n current.type.every(type => type === 'object' || type === 'null'))\n )\n constrained.add(current);\n }\n\n // ponytail: O(V * (V + E)); use a dependency worklist for very large graphs.\n let changed = true;\n while (changed) {\n changed = false;\n for (const [current, [allOf, oneOf, anyOf]] of nodes) {\n if (constrained.has(current)) continue;\n const isConstrained = (member: Schema | undefined) =>\n member !== undefined && constrained.has(member);\n if (\n allOf.some(isConstrained) ||\n [oneOf, anyOf].some(\n members => members.length > 0 && members.every(isConstrained),\n )\n ) {\n constrained.add(current);\n changed = true;\n }\n }\n }\n return root !== undefined && constrained.has(root);\n }\n\n type(schema: Schema | Reference): string {\n if (isReference(schema)) {\n return this.reference(schema);\n }\n if (Array.isArray(schema.type)) {\n return schema.type\n .map(type => {\n const resolved = this.type({ ...schema, type });\n return /[|&]/.test(resolved) ? `(${resolved})` : resolved;\n })\n .join(' | ');\n }\n if (isNullableReference(schema)) {\n // OpenAPI 3.0 writes a nullable reference as {nullable, allOf: [$ref]}.\n return `(${this.type({ ...schema, nullable: false })}) | null`;\n }\n if (isComposition(schema)) {\n const simple = this.simpleComposition(schema);\n if (simple !== undefined) return simple;\n const compositions = (['allOf', 'oneOf', 'anyOf'] as const).flatMap(\n keyword => {\n const schemas = schema[keyword];\n if (!schemas?.length) return [];\n const types = schemas.map(member => {\n const type = this.memberType(schema, keyword, member);\n return type === 'any'\n ? 'unknown'\n : /[|&]/.test(type)\n ? `(${type})`\n : type;\n });\n return [`(${types.join(keyword === 'allOf' ? ' & ' : ' | ')})`];\n },\n );\n const composed =\n compositions.length === 1\n ? compositions[0]\n : `(${compositions.join(' & ')})`;\n const base = {\n ...schema,\n oneOf: undefined,\n anyOf: undefined,\n allOf: undefined,\n };\n const baseType = this.type(base);\n const type =\n baseType === 'any' ? composed : `(${composed} & (${baseType}))`;\n // Weak object types can otherwise admit non-object branches through intersections.\n return this.objectConstrained(schema)\n ? `globalThis.Exclude<${type}, string | number | boolean | readonly unknown[]> & ({ readonly [globalThis.Symbol.iterator]?: never } | null)`\n : type;\n }\n if (schema.const !== undefined) {\n if (!matchesLiteralType(schema.const, schema)) return 'never';\n const literal = resolveLiteral(schema.const);\n const baseType = this.type({ ...schema, const: undefined });\n return baseType === 'any' ? literal : `(${literal}) & (${baseType})`;\n }\n if (schema.nullable && schema.type && !isEnum(schema)) {\n return `(${this.type({ ...schema, nullable: false })}) | null`;\n }\n if (isEnum(schema)) {\n const literal =\n schema.enum\n .filter(value => matchesLiteralType(value, schema))\n .map(value => resolveLiteral(value))\n .join(' | ') || 'never';\n const baseType = this.type({ ...schema, enum: undefined });\n // Every literal already matches its primitive type, so intersecting\n // with a bare primitive adds nothing but noise.\n return baseType === 'any' || PRIMITIVE_TYPE_NAMES.has(baseType)\n ? literal\n : `(${literal}) & (${baseType})`;\n }\n if (isMap(schema) && !schema.required?.length) {\n return this.mapType(schema);\n }\n\n if (schema.type === 'array') {\n return toArrayType(this.type(schema.items ?? {}));\n }\n if (schema.type === 'object') {\n return this.objectType(schema);\n }\n if (!schema.type) {\n if (\n schema.required?.length ||\n Object.keys(schema.properties ?? {}).length > 0\n ) {\n // Object keywords constrain object instances without rejecting other JSON types.\n const objectType = this.objectType({\n ...schema,\n type: 'object',\n additionalProperties: schema.additionalProperties ?? true,\n });\n return `(${objectType} | null | string | number | boolean | readonly unknown[])`;\n }\n return 'any';\n }\n return resolvePrimitiveType(schema.type);\n }\n\n /**\n * Resolves a composition of references alone - `allOf: [$ref]`,\n * `anyOf: [$ref, {type: null}]`, a discriminated `oneOf` - to the plain\n * union or intersection of its members.\n *\n * With no sibling keyword that constrains the instance, the members say\n * everything, and none of the guards the general form needs applies.\n *\n * @returns The type, or undefined when the composition is not that simple\n */\n private simpleComposition(schema: Schema): string | undefined {\n const keywords = (['allOf', 'oneOf', 'anyOf'] as const).filter(\n keyword => schema[keyword]?.length,\n );\n if (keywords.length !== 1) return undefined;\n const [keyword] = keywords;\n const constraining = Object.keys(schema).filter(\n key =>\n key !== keyword &&\n key !== 'discriminator' &&\n !key.startsWith('x-') &&\n !ANNOTATION_KEYWORDS.has(key),\n );\n if (constraining.length > 0) return undefined;\n const members: (Schema | Reference)[] = schema[keyword]!;\n const isNullMember = (member: Schema) =>\n keyword !== 'allOf' &&\n [member.type].flat().every(type => type === 'null') &&\n member.type !== undefined &&\n Object.keys(member).every(\n key => key === 'type' || ANNOTATION_KEYWORDS.has(key),\n );\n if (!members.every(member => isReference(member) || isNullMember(member))) {\n return undefined;\n }\n const types = members.map(member =>\n isReference(member) ? this.memberType(schema, keyword, member) : 'null',\n );\n return [...new Set(types)].join(keyword === 'allOf' ? ' & ' : ' | ');\n }\n\n /**\n * Resolves one member of a composition. A member of a `oneOf` or `anyOf`\n * that carries a `discriminator` is intersected with the literal the\n * discriminator property holds for it, so checking that property narrows\n * the union: `(Cat & { petType: 'cat' }) | (Dog & { petType: 'dog' })`.\n */\n private memberType(\n schema: Schema,\n keyword: 'allOf' | 'oneOf' | 'anyOf',\n member: Schema | Reference,\n ): string {\n const type = this.type(member);\n const discriminator = schema.discriminator;\n if (\n keyword === 'allOf' ||\n !discriminator?.propertyName ||\n !isReference(member)\n ) {\n return type;\n }\n const componentKey = extractComponentKey(member);\n const mapped = Object.entries(discriminator.mapping ?? {})\n .filter(([, target]) => target === member.$ref || target === componentKey)\n .map(([value]) => value);\n const literal = (mapped.length > 0 ? mapped : [componentKey])\n .map(value => quoteStringLiteral(value))\n .join(' | ');\n return `(${type} & { ${resolvePropertyName(discriminator.propertyName)}: ${literal} })`;\n }\n}\n\nfunction resolveWith(\n scope: TypeScope,\n resolve: (resolution: Resolution) => string,\n): ResolvedType {\n const resolution = new Resolution(scope);\n const text = resolve(resolution);\n return { text, imports: resolution.imports() };\n}\n\n/**\n * The type a schema generates.\n *\n * @param schema - The schema, or a reference to a component\n * @param scope - Where the type is written\n * @returns The type expression and the imports it needs\n */\nexport function resolveType(\n schema: Schema | Reference,\n scope: TypeScope,\n): ResolvedType {\n return resolveWith(scope, resolution => resolution.type(schema));\n}\n\n/**\n * The index signature an object schema's additional properties generate, as\n * `[key: string]: T`, or `''` when it admits none beyond the ones it names.\n */\nexport function resolveAdditionalProperties(\n schema: Schema,\n scope: TypeScope,\n): ResolvedType {\n return resolveWith(scope, resolution =>\n resolution.additionalProperties(schema),\n );\n}\n\n/** The type of an object schema's additional properties; `any` when open. */\nexport function resolveAdditionalPropertyType(\n schema: Schema,\n scope: TypeScope,\n): ResolvedType {\n return resolveWith(scope, resolution =>\n resolution.additionalPropertyType(schema),\n );\n}\n\n/**\n * The type of a property an object schema requires without declaring it: its\n * additional-property type, `never` when it admits none, else any JSON value.\n */\nexport function resolveRequiredAdditionalPropertyType(\n schema: Schema,\n scope: TypeScope,\n): ResolvedType {\n return resolveWith(scope, resolution =>\n resolution.requiredAdditionalPropertyType(schema),\n );\n}\n\n/** The value type of a map schema; `any` when its values are open. */\nexport function resolveMapValueType(\n schema: MapSchema,\n scope: TypeScope,\n): ResolvedType {\n return resolveWith(scope, resolution => resolution.mapValueType(schema));\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { ClassDeclarationStructure } from 'ts-morph';\nimport { Scope, StructureKind } from 'ts-morph';\nimport { addImport } from '../emit/imports';\nimport type { ModuleBuilder } from '../emit/moduleBuilder';\n\nexport const FETCHER_MODULE_SPECIFIER = '@ahoo-wang/fetcher';\nexport const FETCHER_NAMED_IMPORTS = ['ContentTypeValues', 'ResultExtractors'];\n\n/**\n * The module specifier for the fetcher-decorator package.\n */\nexport const DECORATOR_MODULE_SPECIFIER = '@ahoo-wang/fetcher-decorator';\n\n/**\n * Named imports from the fetcher-decorator package.\n */\nexport const DECORATOR_NAMED_IMPORTS = [\n 'ApiMetadata',\n 'ApiMetadataCapable',\n 'ParameterRequest',\n 'api',\n 'get',\n 'post',\n 'put',\n 'patch',\n 'del',\n 'request',\n 'attribute',\n 'path',\n 'query',\n 'header',\n 'body',\n 'autoGeneratedError',\n];\n\nexport interface MethodReturnType {\n type: string;\n metadata?: string;\n}\n\nexport const DEFAULT_RETURN_TYPE: MethodReturnType = {\n type: 'Promise<Response>',\n metadata: `{resultExtractor: ResultExtractors.Response }`,\n};\n\nexport const STRING_RETURN_TYPE: MethodReturnType = {\n type: 'Promise<string>',\n metadata: `{resultExtractor: ResultExtractors.Text }`,\n};\n\n/**\n * Metadata configuration for stream result extraction.\n */\nexport const STREAM_RESULT_EXTRACTOR_METADATA = `{\n headers: { Accept: ContentTypeValues.TEXT_EVENT_STREAM },\n resultExtractor: JsonEventStreamResultExtractor,\n}`;\n\n/**\n * The endpoint options of a streaming command client, imported from\n * `@ahoo-wang/wow-client`: `Accept: text/event-stream` and a result\n * extractor that errors the stream with a `WowError` when the server sends an\n * error event instead of passing the event on as a result.\n */\nexport const COMMAND_STREAM_ENDPOINT_METADATA = 'COMMAND_STREAM_ENDPOINT';\n\nexport function addImportFetcher(module: ModuleBuilder) {\n addImport(module, FETCHER_MODULE_SPECIFIER, FETCHER_NAMED_IMPORTS);\n}\n/**\n * Adds the necessary imports for decorator functionality to a module.\n *\n * @param module - The module to add imports to\n */\nexport function addImportDecorator(module: ModuleBuilder) {\n addImport(module, DECORATOR_MODULE_SPECIFIER, DECORATOR_NAMED_IMPORTS);\n}\n\n/**\n * Adds a class declaration with the @api decorator to a module.\n *\n * @param className - The name of the class to create\n * @param module - The module to add the class to\n * @param apiArgs - Optional arguments for the @api decorator\n * @param typeParameters - Optional type parameters for the class\n * @param extendsClass - Optional class to extend\n * @returns The class declaration, open to members until the module is built\n *\n * @example\n * ```typescript\n * const classDecl = createDecoratorClass('UserApi', module, ['baseUrl']);\n * ```\n */\nexport function createDecoratorClass(\n className: string,\n module: ModuleBuilder,\n apiArgs: string[] = [],\n typeParameters: string[] = [],\n extendsClass?: string,\n): ClassDeclarationStructure {\n return module.add<ClassDeclarationStructure>({\n kind: StructureKind.Class,\n name: className,\n isExported: true,\n typeParameters: typeParameters,\n extends: extendsClass,\n decorators: [\n {\n name: 'api',\n arguments: apiArgs,\n },\n ],\n });\n}\n\n/**\n * Adds the ApiMetadataCapable interface implementation and constructor to a class declaration.\n *\n * With defaults, the constructor merges what the caller passes over them, so\n * `new CartCommandClient({ fetcher })` keeps the bounded context's base path:\n *\n * ```typescript\n * readonly apiMetadata: ApiMetadata;\n * constructor(apiMetadata?: ApiMetadata) {\n * this.apiMetadata = { ...DEFAULT_COMMAND_CLIENT_OPTIONS, ...apiMetadata };\n * }\n * ```\n *\n * @param classDeclaration - The class declaration to modify\n * @param defaults - Object literal entries the constructor starts from, such\n * as `...DEFAULT_COMMAND_CLIENT_OPTIONS` or `basePath: X`; none by default\n */\nexport function addApiMetadataCtor(\n classDeclaration: ClassDeclarationStructure,\n defaults?: string,\n) {\n classDeclaration.implements = [\n ...[classDeclaration.implements ?? []].flat(),\n 'ApiMetadataCapable',\n ];\n classDeclaration.ctors ??= [];\n if (defaults === undefined) {\n classDeclaration.ctors.push({\n parameters: [\n {\n name: 'apiMetadata',\n type: 'ApiMetadata',\n hasQuestionToken: true,\n scope: Scope.Public,\n isReadonly: true,\n },\n ],\n });\n return;\n }\n classDeclaration.properties = [\n ...(classDeclaration.properties ?? []),\n {\n name: 'apiMetadata',\n type: 'ApiMetadata',\n isReadonly: true,\n },\n ];\n classDeclaration.ctors.push({\n parameters: [\n {\n name: 'apiMetadata',\n type: 'ApiMetadata',\n hasQuestionToken: true,\n },\n ],\n statements: `this.apiMetadata = { ${defaults}, ...apiMetadata };`,\n docs: [\n '@param apiMetadata - Merged over the defaults, so passing only a `fetcher` keeps the base path.',\n ],\n });\n}\n\n/**\n * The decorator of an HTTP method: its name, but `del` for `delete`, a\n * reserved word.\n *\n * @example\n * ```typescript\n * methodToDecorator('get'); // 'get'\n * methodToDecorator('delete'); // 'del'\n * ```\n */\nexport function methodToDecorator(method: string): string {\n return method === 'delete' ? 'del' : method;\n}\n\nexport const EVENTSTREAM_MODULE_SPECIFIER = '@ahoo-wang/fetcher-eventstream';\n\nexport function addImportEventStream(module: ModuleBuilder) {\n addImport(module, EVENTSTREAM_MODULE_SPECIFIER, [\n 'JsonEventStreamResultExtractor',\n 'JsonServerSentEventStream',\n ]);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Reference, Schema } from '@ahoo-wang/fetcher-openapi';\nimport type {\n MethodDeclarationStructure,\n OptionalKind,\n ParameterDeclarationStructure,\n} from 'ts-morph';\nimport type {\n ApiClientModel,\n ApiMethodModel,\n BodyModel,\n ReturnModel,\n} from '../analysis/model';\nimport {\n addImport,\n addImportBoundedContext,\n modelModuleSpecifier,\n} from '../emit/imports';\nimport { addJSDoc } from '../emit/jsdoc';\nimport type { ModuleBuilder } from '../emit/moduleBuilder';\nimport { quoteStringLiteral } from '../naming/naming';\nimport type { TypeScope } from '../types/typeResolver';\nimport { resolveType } from '../types/typeResolver';\nimport type { MethodReturnType } from './decorators';\nimport {\n addApiMetadataCtor,\n addImportDecorator,\n addImportEventStream,\n addImportFetcher,\n createDecoratorClass,\n DEFAULT_RETURN_TYPE,\n FETCHER_MODULE_SPECIFIER,\n methodToDecorator,\n STREAM_RESULT_EXTRACTOR_METADATA,\n STRING_RETURN_TYPE,\n} from './decorators';\nimport type { EmitTarget } from './target';\n\n/** Resolves schemas to types in one client module, importing the models they use. */\ninterface ClientTypes {\n readonly module: ModuleBuilder;\n resolveType(schema: Schema | Reference): string;\n}\n\n/**\n * Writes the API client of a tag: a decorated class with a method per\n * operation.\n *\n * @param client - The client\n * @param target - Where it is written\n */\nexport function emitApiClient(\n client: ApiClientModel,\n target: EmitTarget,\n): void {\n const module = target.modules.module(client.file);\n addImportFetcher(module);\n addImportDecorator(module);\n addImportEventStream(module);\n const apiClientClass = createDecoratorClass(client.className, module);\n addJSDoc(apiClientClass, [client.description]);\n let defaults: string | undefined;\n if (client.basePath) {\n addImportBoundedContext(\n module,\n target.outputDir,\n client.basePath.alias,\n client.basePath.constantName,\n );\n defaults = `basePath: ${client.basePath.constantName}`;\n }\n addApiMetadataCtor(apiClientClass, defaults);\n const types = clientTypes(client.className, module, target);\n for (const method of client.methods) {\n (apiClientClass.methods ??= []).push(apiMethod(method, types));\n }\n}\n\n/**\n * The types of a client module. The client imports every model it uses,\n * and no import takes the class's own name.\n */\nfunction clientTypes(\n className: string,\n module: ModuleBuilder,\n target: EmitTarget,\n): ClientTypes {\n const scope: TypeScope = {\n context: target.types,\n owner: { name: className },\n specifierOf: model => modelModuleSpecifier(module, target.outputDir, model),\n imports: module.imports,\n };\n return {\n module,\n resolveType(schema) {\n const resolved = resolveType(schema, scope);\n module.imports.apply(resolved.imports);\n return resolved.text;\n },\n };\n}\n\n/**\n * The method of an operation. Its types resolve in document order - the\n * parameters, the body, the response - so a later reference sees the\n * aliases an earlier one took; its parameters are then ordered required\n * first, so a caller never passes `undefined` to reach a required one:\n *\n * ```typescript\n * search(id: string, q: string, body: Filter, page?: number,\n * httpRequest?: ParameterRequest, attributes?: Record<string, unknown>)\n * ```\n *\n * `httpRequest` carries anything else a request may set: headers, a\n * timeout, a signal.\n */\nfunction apiMethod(\n method: ApiMethodModel,\n types: ClientTypes,\n): OptionalKind<MethodDeclarationStructure> {\n const required: OptionalKind<ParameterDeclarationStructure>[] = [];\n const optional: OptionalKind<ParameterDeclarationStructure>[] = [];\n for (const parameter of method.parameters) {\n (parameter.required ? required : optional).push({\n name: parameter.name,\n type: parameter.schema ? types.resolveType(parameter.schema) : 'string',\n hasQuestionToken: !parameter.required,\n decorators: [\n {\n name: parameter.location,\n arguments: [quoteStringLiteral(parameter.parameterName)],\n },\n ],\n });\n }\n if (method.body) {\n (method.body.required ? required : optional).push({\n name: method.body.name,\n type: bodyType(method.body, types),\n hasQuestionToken: !method.body.required,\n decorators: [{ name: 'body', arguments: [] }],\n });\n }\n const parameters = [\n ...required,\n ...optional,\n {\n name: 'httpRequest',\n hasQuestionToken: true,\n type: 'ParameterRequest',\n decorators: [{ name: 'request', arguments: [] }],\n },\n {\n name: 'attributes',\n hasQuestionToken: true,\n type: 'Record<string, unknown>',\n decorators: [{ name: 'attribute', arguments: [] }],\n },\n ];\n const returnType = returnTypeOf(method.returns, types);\n const path = quoteStringLiteral(method.path);\n const declaration: OptionalKind<MethodDeclarationStructure> = {\n name: method.name,\n decorators: [\n {\n name: methodToDecorator(method.httpMethod),\n arguments: returnType.metadata ? [path, returnType.metadata] : [path],\n },\n ],\n parameters,\n returnType: returnType.type,\n statements: [\n `throw autoGeneratedError(${parameters.map(parameter => parameter.name).join(',')});`,\n ],\n };\n addJSDoc(declaration, [...method.docs]);\n return declaration;\n}\n\n/**\n * The type of a body. A JSON body leaves optional the properties its schema\n * does not require, as a command body does (`PartialBy<Item, 'id'>`), unless\n * its type is a union, an intersection or `any`.\n */\nfunction bodyType(body: BodyModel, types: ClientTypes): string {\n const { content } = body;\n switch (content.kind) {\n case 'json': {\n const type = types.resolveType(content.schema);\n const optional = content.optionalFields;\n if (optional.length === 0 || /[|&]/.test(type) || type === 'any') {\n return type;\n }\n addImport(types.module, FETCHER_MODULE_SPECIFIER, ['PartialBy']);\n return `PartialBy<${type}, ${optional.map(quoteStringLiteral).join(' | ')}>`;\n }\n case 'formData':\n return 'FormData';\n case 'urlEncoded':\n return 'URLSearchParams';\n case 'text':\n return 'string';\n case 'binary':\n return 'BodyInit';\n }\n}\n\n/** The return type of a method, and the decorator metadata it needs. */\nfunction returnTypeOf(\n returns: ReturnModel,\n types: ClientTypes,\n): MethodReturnType {\n switch (returns.kind) {\n case 'json': {\n const type = types.resolveType(returns.schema);\n return returns.wildcard && type === 'string'\n ? STRING_RETURN_TYPE\n : { type: `Promise<${type}>` };\n }\n case 'eventStream': {\n if (!returns.items) {\n return {\n type: `Promise<JsonServerSentEventStream<any>>`,\n metadata: STREAM_RESULT_EXTRACTOR_METADATA,\n };\n }\n const typeName = types.resolveType(returns.items);\n const dataType = returns.serverSentEvent\n ? `${typeName}['data']`\n : typeName;\n return {\n type: `Promise<JsonServerSentEventStream<${dataType}>>`,\n metadata: STREAM_RESULT_EXTRACTOR_METADATA,\n };\n }\n case 'text':\n return STRING_RETURN_TYPE;\n case 'response':\n return DEFAULT_RETURN_TYPE;\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n EnumDeclarationStructure,\n MethodDeclarationStructure,\n OptionalKind,\n ParameterDeclarationStructure,\n TypeAliasDeclarationStructure,\n VariableStatementStructure,\n} from 'ts-morph';\nimport { StructureKind, VariableDeclarationKind } from 'ts-morph';\nimport type { AggregateModel, CommandModel } from '../analysis/model';\nimport {\n addImport,\n addImportBoundedContext,\n addImportRefModel,\n} from '../emit/imports';\nimport { addJSDoc } from '../emit/jsdoc';\nimport type { ModuleBuilder } from '../emit/moduleBuilder';\nimport { membersWithTrailingComma } from '../emit/moduleBuilder';\nimport { quoteStringLiteral } from '../naming/naming';\nimport { IMPORT_WOW_PATH } from '../wow/conventions';\nimport {\n addApiMetadataCtor,\n addImportDecorator,\n COMMAND_STREAM_ENDPOINT_METADATA,\n createDecoratorClass,\n methodToDecorator,\n} from './decorators';\nimport type { EmitTarget } from './target';\n\nconst DEFAULT_COMMAND_CLIENT_OPTIONS = 'DEFAULT_COMMAND_CLIENT_OPTIONS';\n\n/**\n * Writes the command client of an aggregate: the enum of its command routes,\n * a type per command body whose name does not already end in `Command`, the client, whose methods send the commands, and\n * the streaming client, which waits on their results as server-sent events.\n * An aggregate the document routes no command to (every command route\n * disabled or closed by the service) gets none: a client without a method\n * sends nothing, and its result type would go unused.\n *\n * @param aggregate - The aggregate\n * @param target - Where it is written\n */\nexport function emitCommandClient(\n aggregate: AggregateModel,\n target: EmitTarget,\n): void {\n const client = aggregate.commandClient;\n if (client.commands.length === 0) return;\n const module = target.modules.module(client.file);\n module.add<EnumDeclarationStructure>({\n kind: StructureKind.Enum,\n name: client.endpointPathsName,\n isExported: true,\n members: membersWithTrailingComma(\n client.commands.map(command => ({\n name: command.endpointMember,\n initializer: quoteStringLiteral(command.path),\n })),\n ),\n });\n const declared = new Set<string>();\n const requestTypes = client.commands.map(command =>\n addCommandType(module, target.outputDir, command, declared),\n );\n addImportBoundedContext(\n module,\n target.outputDir,\n aggregate.context.alias,\n aggregate.context.constantName,\n );\n module.add<VariableStatementStructure>({\n kind: StructureKind.VariableStatement,\n declarationKind: VariableDeclarationKind.Const,\n declarations: [\n {\n name: DEFAULT_COMMAND_CLIENT_OPTIONS,\n type: 'ApiMetadata',\n initializer: `{\n basePath: ${aggregate.context.constantName}\n }`,\n },\n ],\n isExported: false,\n });\n addImport(module, IMPORT_WOW_PATH, [\n 'CommandRequest',\n 'CommandResult',\n 'CommandResultEventStream',\n 'CommandBody',\n COMMAND_STREAM_ENDPOINT_METADATA,\n ]);\n addImport(module, '@ahoo-wang/fetcher', ['PartialBy']);\n addImportDecorator(module);\n\n const commandClient = createDecoratorClass(\n client.className,\n module,\n [],\n ['R = CommandResult'],\n );\n addApiMetadataCtor(commandClient, `...${DEFAULT_COMMAND_CLIENT_OPTIONS}`);\n for (const [index, command] of client.commands.entries()) {\n const parameters = commandParameters(command, requestTypes[index]);\n const method: OptionalKind<MethodDeclarationStructure> = {\n name: command.methodName,\n decorators: [\n {\n name: methodToDecorator(command.httpMethod),\n arguments: [`${client.endpointPathsName}.${command.endpointMember}`],\n },\n ],\n parameters,\n returnType: 'Promise<R>',\n statements: `throw autoGeneratedError(${parameters.map(parameter => parameter.name).join(',')});`,\n };\n (commandClient.methods ??= []).push(method);\n addJSDoc(method, [...command.docs]);\n }\n\n // Inherits the constructor, which merges apiMetadata over the defaults.\n // wow-client's endpoint preset errors the stream with a WowError at the\n // server's error event, as CommandClient.sendAndWaitStream does.\n createDecoratorClass(\n client.streamClassName,\n module,\n [`''`, COMMAND_STREAM_ENDPOINT_METADATA],\n [],\n `${client.className}<CommandResultEventStream>`,\n );\n}\n\n/**\n * The type of a command's body, `CommandBody<PartialBy<Body, 'optional'>>`,\n * declared under the command's type name; Wow's own commands have theirs in\n * wow-client.\n *\n * @param declared - The aliases the module declares so far; updated\n * @returns The type a method's request carries: the alias, or for a command\n * without one the type itself\n */\nfunction addCommandType(\n module: ModuleBuilder,\n outputDir: string,\n command: CommandModel,\n declared: Set<string>,\n): string {\n if (command.body.path === IMPORT_WOW_PATH) {\n addImport(module, IMPORT_WOW_PATH, [command.typeName!]);\n return command.typeName!;\n }\n addImportRefModel(module, outputDir, command.body);\n let commandType = command.body.name;\n const optionalFields = command.optionalFields\n .map(quoteStringLiteral)\n .join(' | ');\n if (optionalFields !== '') {\n commandType = `PartialBy<${commandType},${optionalFields}>`;\n }\n const bodyType = `CommandBody<${commandType}>`;\n if (command.typeName === undefined) return bodyType;\n // Two commands of one body share its type.\n if (declared.has(command.typeName)) return command.typeName;\n declared.add(command.typeName);\n module.add<TypeAliasDeclarationStructure>({\n kind: StructureKind.TypeAlias,\n name: command.typeName,\n type: bodyType,\n isExported: true,\n });\n return command.typeName;\n}\n\n/** The path parameters, the command request and the attributes of a method. */\nfunction commandParameters(\n command: CommandModel,\n requestType: string,\n): OptionalKind<ParameterDeclarationStructure>[] {\n return [\n ...command.pathParameters.map(parameter => ({\n name: parameter.name,\n type: parameter.type,\n hasQuestionToken: false,\n decorators: [\n { name: 'path', arguments: [quoteStringLiteral(parameter.pathName)] },\n ],\n })),\n {\n name: 'commandRequest',\n hasQuestionToken: command.requestOptional,\n type: `CommandRequest<${requestType}>`,\n decorators: [{ name: 'request', arguments: [] }],\n },\n {\n name: 'attributes',\n hasQuestionToken: true,\n type: 'Record<string, unknown>',\n decorators: [{ name: 'attribute', arguments: [] }],\n },\n ];\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Components, Reference, Schema } from '@ahoo-wang/fetcher-openapi';\nimport type {\n EnumDeclarationStructure,\n InterfaceDeclarationStructure,\n JSDocableNodeStructure,\n OptionalKind,\n PropertySignatureStructure,\n TypeAliasDeclarationStructure,\n} from 'ts-morph';\nimport { StructureKind, VariableDeclarationKind } from 'ts-morph';\nimport type { ModelDeclaration } from '../analysis/model';\nimport {\n resolveModelInfo,\n resolveReferenceModelInfo,\n} from '../analysis/modelInfo';\nimport { modelModuleSpecifier } from '../emit/imports';\nimport { addMainSchemaJSDoc, addSchemaJSDoc } from '../emit/jsdoc';\nimport type { ModuleBuilder } from '../emit/moduleBuilder';\nimport { indexSignatureMember } from '../emit/moduleBuilder';\nimport { enumMemberKey, resolvePropertyName } from '../naming/naming';\nimport { isReference } from '../openapi/references';\nimport type {\n ArraySchema,\n CompositionSchema,\n EnumSchema,\n MapSchema,\n ObjectSchema,\n} from '../openapi/schemas';\nimport {\n getEnumText,\n getMapKeySchema,\n isArray,\n isComposition,\n isEnum,\n isMap,\n isObject,\n isReadOnly,\n toArrayType,\n} from '../openapi/schemas';\nimport type {\n ResolvedType,\n TypeContext,\n TypeScope,\n} from '../types/typeResolver';\nimport {\n createTypeContext,\n requiresAdditionalPropertiesIntersection,\n resolveAdditionalProperties,\n resolveAdditionalPropertyType,\n resolveLiteral,\n resolveMapValueType,\n resolveRequiredAdditionalPropertyType,\n resolveType,\n} from '../types/typeResolver';\nimport type { EmitTarget } from './target';\n\n/**\n * The type context of a document: its components, named the way the\n * generator names models. Build it once per generation and share it, so the\n * model names of each path are read once.\n *\n * @param components - The document's components\n */\nexport function documentTypeContext(components?: Components): TypeContext {\n return createTypeContext(components, {\n ofKey: key => resolveModelInfo(key),\n ofReference: resolveReferenceModelInfo,\n });\n}\n\n/**\n * Writes a model into the `types.ts` of its package: an interface, an enum or\n * a type alias, with its doc comment, and imports the models it uses.\n *\n * @param declaration - The model\n * @param target - Where it is written\n */\nexport function emitModel(\n declaration: ModelDeclaration,\n target: EmitTarget,\n): void {\n const module = target.modules.module(declaration.file);\n if (declaration.emptyMessageBody) {\n const alias = module.add<TypeAliasDeclarationStructure>({\n kind: StructureKind.TypeAlias,\n name: declaration.info.name,\n type: 'globalThis.Record<string, never>',\n isExported: true,\n });\n addMainSchemaJSDoc(\n alias,\n declaration.docSchema,\n declaration.key,\n target.schemaDocs === 'full',\n );\n return;\n }\n new ModelEmitter(declaration, module, target).write();\n}\n\n/**\n * Names the members of an enum. Each value takes its UPPER_SNAKE_CASE form;\n * when another value already took that form - `in-progress`, `IN_PROGRESS`\n * and `inProgress` all give `IN_PROGRESS` - it takes its own value as a\n * quoted member name, or else a numbered form.\n *\n * @param values - The distinct values, in document order\n * @returns The member name of each value, quoted where it has to be\n */\nexport function uniqueEnumMemberNames(\n values: readonly string[],\n): Map<string, string> {\n const used = new Set<string>();\n const names = new Map<string, string>();\n for (const value of values) {\n const preferred = enumMemberKey(value);\n const candidates = [preferred];\n // A numeric name cannot name an enum member, even quoted.\n if (!/^\\d/.test(value)) candidates.push(value);\n let key = candidates.find(candidate => !used.has(candidate));\n for (let index = 2; key === undefined; index++) {\n if (!used.has(`${preferred}_${index}`)) key = `${preferred}_${index}`;\n }\n used.add(key);\n names.set(value, resolvePropertyName(key));\n }\n return names;\n}\n\n/** The model a {@link ModelEmitter} writes. */\nexport type ModelSource = Pick<\n ModelDeclaration,\n 'key' | 'info' | 'schema' | 'docSchema'\n>;\n\n/**\n * Writes one model into a module: the declaration its schema calls for,\n * with the model's doc comment.\n */\nexport class ModelEmitter {\n private readonly modelInfo: ModelSource['info'];\n private readonly components?: Components;\n\n /**\n * @param model - The model\n * @param module - The module the model is written into, which also\n * receives its imports\n * @param target - The output directory, the document's type context and\n * how much of the schema the doc comment carries\n */\n constructor(\n private readonly model: ModelSource,\n readonly module: ModuleBuilder,\n private readonly target: Pick<\n EmitTarget,\n 'outputDir' | 'types' | 'schemaDocs'\n >,\n ) {\n this.modelInfo = model.info;\n this.components = target.types.components;\n this.scope = {\n context: target.types,\n owner: model.info,\n specifierOf: info => modelModuleSpecifier(module, target.outputDir, info),\n imports: module.imports,\n };\n }\n\n /** Writes the model's declaration and its doc comment. */\n write(): void {\n const node = this.process();\n if (node) {\n addMainSchemaJSDoc(\n node,\n this.model.docSchema,\n this.model.key,\n this.target.schemaDocs === 'full',\n );\n }\n }\n\n private process(): JSDocableNodeStructure | undefined {\n const { schema } = this.model;\n if (isReference(schema)) {\n return this.processTypeAlias(schema);\n }\n if (isEnum(schema)) {\n return this.processEnum(schema);\n }\n if (schema.const !== undefined) {\n return this.processTypeAlias(schema);\n }\n if (\n (schema.nullable && schema.type) ||\n (isComposition(schema) &&\n (schema.type || schema.properties || schema.required))\n ) {\n return this.processTypeAlias(schema);\n }\n if (isObject(schema)) {\n return this.processInterface(schema);\n }\n if (\n isMap(schema) &&\n typeof schema.additionalProperties === 'object' &&\n !getMapKeySchema(schema) &&\n !schema.required?.length\n ) {\n return this.processIndexSignature(schema);\n }\n if (isArray(schema)) {\n return this.processArray(schema);\n }\n if (isComposition(schema)) {\n return this.processComposition(schema);\n }\n return this.processTypeAlias(schema);\n }\n\n /** Where the types of this model are written. */\n private readonly scope: TypeScope;\n\n /** Applies the imports a resolved type needs to the module. */\n private emit(resolved: ResolvedType): string {\n this.module.imports.apply(resolved.imports);\n return resolved.text;\n }\n\n /** The type a schema generates in this model's module, its imports added. */\n resolveType(schema: Schema | Reference): string {\n return this.emit(resolveType(schema, this.scope));\n }\n\n private processEnum(schema: EnumSchema): JSDocableNodeStructure | undefined {\n const enumText = getEnumText(schema);\n if (enumText) {\n const textNames = uniqueEnumMemberNames(Object.keys(enumText));\n this.module.add<EnumDeclarationStructure>({\n kind: StructureKind.Enum,\n name: this.modelInfo.name + 'EnumText',\n isExported: true,\n members: [...textNames].map(([name, memberName]) => {\n return {\n name: memberName,\n initializer: resolveLiteral(enumText[name]),\n };\n }),\n });\n }\n const stringValues = [\n ...new Set(\n schema.enum.filter(\n (value): value is string => typeof value === 'string',\n ),\n ),\n ];\n const memberNames = uniqueEnumMemberNames(stringValues);\n if (\n isComposition(schema) ||\n schema.const !== undefined ||\n (schema.type !== undefined && schema.type !== 'string') ||\n schema.enum.some(value => typeof value !== 'string')\n ) {\n if (stringValues.length) {\n this.module.add({\n kind: StructureKind.VariableStatement,\n declarationKind: VariableDeclarationKind.Const,\n isExported: true,\n declarations: [\n {\n name: this.modelInfo.name,\n initializer: writer => {\n writer.inlineBlock(() => {\n for (const value of stringValues) {\n writer\n .write(`${memberNames.get(value)}: `)\n .quote(value)\n .write(',')\n .newLine();\n }\n });\n writer.write(' as const');\n },\n },\n ],\n });\n }\n return this.processTypeAlias(schema);\n }\n return this.module.add<EnumDeclarationStructure>({\n kind: StructureKind.Enum,\n name: this.modelInfo.name,\n isExported: true,\n members: stringValues.map(value => ({\n name: memberNames.get(value)!,\n initializer: resolveLiteral(value),\n })),\n });\n }\n\n /**\n * Adds a declared property. Property names are distinct, and\n * `resolvePropertyName` keeps them distinct: a name is kept or quoted.\n */\n private addPropertyToInterface(\n interfaceDeclaration: InterfaceDeclarationStructure,\n propName: string,\n propSchema: Schema | Reference,\n ): void {\n const propertySignature: OptionalKind<PropertySignatureStructure> = {\n name: resolvePropertyName(propName),\n type: this.resolveType(propSchema),\n isReadonly: isReadOnly(propSchema),\n };\n (interfaceDeclaration.properties ??= []).push(propertySignature);\n addSchemaJSDoc(propertySignature, propSchema);\n }\n\n private processInterface(\n schema: ObjectSchema,\n ): JSDocableNodeStructure | undefined {\n if (requiresAdditionalPropertiesIntersection(schema, this.components)) {\n return this.processTypeAlias(schema);\n }\n const properties: OptionalKind<PropertySignatureStructure>[] = [];\n const interfaceDeclaration = this.module.add<InterfaceDeclarationStructure>(\n {\n kind: StructureKind.Interface,\n name: this.modelInfo.name,\n isExported: true,\n properties,\n },\n );\n\n const schemaProperties = schema.properties || {};\n\n Object.entries(schemaProperties).forEach(([propName, propSchema]) => {\n this.addPropertyToInterface(interfaceDeclaration, propName, propSchema);\n });\n\n for (const name of schema.required ?? []) {\n if (!Object.hasOwn(schemaProperties, name)) {\n properties.push({\n name: resolvePropertyName(name),\n type: this.emit(\n resolveRequiredAdditionalPropertyType(schema, this.scope),\n ),\n });\n }\n }\n\n if (this.emit(resolveAdditionalProperties(schema, this.scope))) {\n properties.push(\n indexSignatureMember(\n this.emit(resolveAdditionalPropertyType(schema, this.scope)),\n ['Additional properties'],\n ),\n );\n }\n return interfaceDeclaration;\n }\n\n private processArray(\n schema: ArraySchema,\n ): JSDocableNodeStructure | undefined {\n const itemType = this.resolveType(schema.items);\n return this.module.add<TypeAliasDeclarationStructure>({\n kind: StructureKind.TypeAlias,\n name: this.modelInfo.name,\n type: toArrayType(itemType),\n isExported: true,\n });\n }\n\n /**\n * A string-keyed map is an interface with an index signature rather than an\n * alias of `Record`: an alias may not reference itself through `Record`\n * (TS2456), and a map of its own type - a tree of dictionaries - does.\n */\n private processIndexSignature(\n schema: MapSchema,\n ): JSDocableNodeStructure | undefined {\n return this.module.add<InterfaceDeclarationStructure>({\n kind: StructureKind.Interface,\n name: this.modelInfo.name,\n isExported: true,\n properties: [\n indexSignatureMember(\n this.emit(resolveMapValueType(schema, this.scope)),\n ),\n ],\n });\n }\n\n private processComposition(\n schema: CompositionSchema,\n ): JSDocableNodeStructure | undefined {\n return this.module.add<TypeAliasDeclarationStructure>({\n kind: StructureKind.TypeAlias,\n name: this.modelInfo.name,\n type: this.resolveType(schema),\n isExported: true,\n });\n }\n\n private processTypeAlias(\n schema: Schema | Reference,\n ): JSDocableNodeStructure | undefined {\n return this.module.add<TypeAliasDeclarationStructure>({\n kind: StructureKind.TypeAlias,\n name: this.modelInfo.name,\n type: this.resolveType(schema),\n isExported: true,\n });\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n EnumDeclarationStructure,\n TypeAliasDeclarationStructure,\n VariableStatementStructure,\n} from 'ts-morph';\nimport { StructureKind, VariableDeclarationKind } from 'ts-morph';\nimport type { AggregateModel } from '../analysis/model';\nimport {\n addImport,\n addImportBoundedContext,\n addImportRefModel,\n} from '../emit/imports';\nimport { membersWithTrailingComma } from '../emit/moduleBuilder';\nimport { quoteStringLiteral } from '../naming/naming';\nimport { IMPORT_WOW_PATH } from '../wow/conventions';\nimport type { EmitTarget } from './target';\n\nconst DEFAULT_QUERY_CLIENT_OPTIONS = 'DEFAULT_QUERY_CLIENT_OPTIONS';\n\n/**\n * Writes the query client of an aggregate: the enum of its event titles, the\n * union of its event types, and the factory of its snapshot and event\n * stream query clients.\n *\n * @param aggregate - The aggregate\n * @param target - Where it is written\n */\nexport function emitQueryClient(\n aggregate: AggregateModel,\n target: EmitTarget,\n): void {\n const client = aggregate.queryClient;\n const module = target.modules.module(client.file);\n addImport(module, IMPORT_WOW_PATH, [\n 'QueryClientFactory',\n 'QueryClientOptions',\n 'ResourceAttributionPathSpec',\n ]);\n addImportBoundedContext(\n module,\n target.outputDir,\n aggregate.context.alias,\n aggregate.context.constantName,\n );\n module.add<VariableStatementStructure>({\n kind: StructureKind.VariableStatement,\n declarationKind: VariableDeclarationKind.Const,\n declarations: [\n {\n name: DEFAULT_QUERY_CLIENT_OPTIONS,\n type: 'QueryClientOptions',\n initializer: `{\n contextAlias: ${aggregate.context.constantName},\n aggregateName: ${quoteStringLiteral(client.resourceName)},\n resourceAttribution: ${client.resourceAttribution},\n }`,\n },\n ],\n isExported: false,\n });\n module.add<EnumDeclarationStructure>({\n kind: StructureKind.Enum,\n name: client.eventTitlesName,\n isExported: true,\n members: membersWithTrailingComma(\n client.events.map(event => ({\n name: event.memberName,\n initializer: quoteStringLiteral(event.title),\n })),\n ),\n });\n for (const event of client.events) {\n addImportRefModel(module, target.outputDir, event.body);\n }\n module.add<TypeAliasDeclarationStructure>({\n kind: StructureKind.TypeAlias,\n isExported: true,\n name: client.eventTypeName,\n type: client.events.map(event => event.body.name).join(' | ') || 'never',\n });\n addImportRefModel(module, target.outputDir, client.state);\n addImportRefModel(module, target.outputDir, client.fields);\n module.add<VariableStatementStructure>({\n kind: StructureKind.VariableStatement,\n declarationKind: VariableDeclarationKind.Const,\n declarations: [\n {\n name: client.factoryName,\n // `${Fields}` is the union of the field enum's values: a field is\n // named by its enum member or by its string, and a misspelt one does\n // not compile.\n initializer: `new QueryClientFactory<${client.state.name}, \\`\\${${client.fields.name}}\\`, ${client.eventTypeName}>(${DEFAULT_QUERY_CLIENT_OPTIONS})`,\n },\n ],\n isExported: true,\n });\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { BoundedContextModel, GenerationModel } from '../analysis/model';\nimport { quoteStringLiteral } from '../naming/naming';\nimport { emitApiClient } from './apiClients';\nimport { emitCommandClient } from './commandClients';\nimport { emitModel } from './models';\nimport { emitQueryClient } from './queryClients';\nimport type { EmitTarget } from './target';\n\n/**\n * Describes every file of a generation to its module: the bounded contexts,\n * the models, the query and command clients of each aggregate, then the API\n * clients. Nothing reaches a source file until the modules are built.\n *\n * The order is the one the files have always been written in, so the\n * imports of a module, and the aliases a name clash gives them, come out\n * the same.\n *\n * @param model - What the document generates\n * @param target - Where it is written\n */\nexport function emitGeneration(\n model: GenerationModel,\n target: EmitTarget,\n): void {\n model.contexts.forEach(context => emitBoundedContext(context, target));\n model.models.forEach(declaration => emitModel(declaration, target));\n model.aggregates.forEach(aggregate => emitQueryClient(aggregate, target));\n model.aggregates.forEach(aggregate => emitCommandClient(aggregate, target));\n model.apiClients.forEach(client => emitApiClient(client, target));\n}\n\n/** Writes a bounded context's alias constant into its own file. */\nfunction emitBoundedContext(\n context: BoundedContextModel,\n target: EmitTarget,\n): void {\n target.modules\n .module(context.file)\n .add(\n `export const ${context.constantName} = ${quoteStringLiteral(context.alias)};`,\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Directory, SourceFile } from 'ts-morph';\nimport { Node } from 'ts-morph';\nimport { compareNames } from '../naming/order';\n\n/** A name a module exports, mapped to whether it is only a type. */\ntype ExportedNames = Map<string, boolean>;\n\n/** A module an index re-exports. */\ninterface IndexChild {\n readonly specifier: string;\n readonly exports: ExportedNames;\n}\n\n/**\n * Writes an `index.ts` into the output directory and each directory under\n * it, re-exporting its files and the indexes of its subdirectories.\n *\n * @param outputDir - The output directory, holding the files written\n * @param claim - Returns the index file of a directory, emptied and claimed\n * for the generation\n * @returns A warning for every name an index leaves out because two of its\n * children export it\n */\nexport function emitIndexFiles(\n outputDir: Directory,\n claim: (directoryPath: string) => SourceFile,\n): string[] {\n const warnings: string[] = [];\n indexDirectory(outputDir, claim, warnings);\n return warnings;\n}\n\n/**\n * Writes the index files of a directory and its subdirectories.\n *\n * @returns The names the directory's index exports, each mapped to whether\n * it is a type only; undefined when the directory has no index.\n */\nfunction indexDirectory(\n dir: Directory,\n claim: (directoryPath: string) => SourceFile,\n warnings: string[],\n): ExportedNames | undefined {\n const children: IndexChild[] = [];\n for (const file of dir.getSourceFiles()) {\n const baseName = file.getBaseName();\n if (!baseName.endsWith('.ts') || baseName === 'index.ts') continue;\n children.push({\n specifier: `./${file.getBaseNameWithoutExtension()}.js`,\n exports: exportedNames(file),\n });\n }\n for (const subDir of dir.getDirectories()) {\n const exports = indexDirectory(subDir, claim, warnings);\n if (exports) {\n children.push({\n specifier: `./${subDir.getBaseName()}/index.js`,\n exports,\n });\n }\n }\n const dirPath = dir.getPath();\n if (children.length === 0) {\n return dir.getProject().getSourceFile(`${dirPath}/index.ts`)\n ? new Map()\n : undefined;\n }\n return writeIndex(dirPath, children, claim, warnings);\n}\n\n/**\n * Writes one index file.\n *\n * `export *` from two modules that export the same name is an error\n * (TS2308); it happens when two packages hold a model of the same name. A\n * child exporting such a name is re-exported by name instead, leaving the\n * ambiguous names out: they stay importable from their own modules.\n *\n * @returns The names the index exports\n */\nfunction writeIndex(\n dirPath: string,\n children: IndexChild[],\n claim: (directoryPath: string) => SourceFile,\n warnings: string[],\n): ExportedNames {\n const owners = new Map<string, string[]>();\n for (const child of children) {\n for (const name of child.exports.keys()) {\n owners.set(name, [...(owners.get(name) ?? []), child.specifier]);\n }\n }\n const ambiguous = [...owners]\n .filter(([, specifiers]) => specifiers.length > 1)\n .map(([name]) => name)\n .sort();\n for (const name of ambiguous) {\n warnings.push(\n `${name} is exported by both ${owners.get(name)!.join(' and ')} in ${dirPath}; its index leaves it out, so import it from its own module.`,\n );\n }\n const indexFile = claim(dirPath);\n indexFile.removeText();\n const exported: ExportedNames = new Map();\n for (const child of children) {\n const names = [...child.exports]\n .filter(([name]) => !ambiguous.includes(name))\n .sort(([left], [right]) => compareNames(left, right));\n names.forEach(([name, typeOnly]) => exported.set(name, typeOnly));\n if (names.length === child.exports.size) {\n indexFile.addExportDeclaration({ moduleSpecifier: child.specifier });\n } else if (names.length > 0) {\n indexFile.addExportDeclaration({\n moduleSpecifier: child.specifier,\n namedExports: names.map(([name, isTypeOnly]) => ({\n name,\n isTypeOnly,\n })),\n });\n }\n }\n if (indexFile.getStatements().length === 0) {\n // Every name was ambiguous; the index stays a module its parent re-exports.\n indexFile.addStatements('export {};');\n }\n return exported;\n}\n\n/**\n * The names a generated file exports. A name is type-only when every one of\n * its declarations is an interface or a type alias; an enum or a class is a\n * value as well.\n */\nfunction exportedNames(file: SourceFile): ExportedNames {\n const names: ExportedNames = new Map();\n for (const [name, declarations] of file.getExportedDeclarations()) {\n names.set(\n name,\n declarations.every(\n declaration =>\n Node.isInterfaceDeclaration(declaration) ||\n Node.isTypeAliasDeclaration(declaration),\n ),\n );\n }\n return names;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n ImportDeclaration,\n ImportSpecifier,\n SourceFile,\n ts,\n} from 'ts-morph';\nimport { Node, SyntaxKind } from 'ts-morph';\n\n/**\n * Whether an identifier sits in a position TypeScript erases: a type\n * annotation, a type argument, an `implements` clause, an interface's\n * `extends` clause or a `typeof` type query. A class's `extends` clause, a\n * decorator, an initializer or an `export { … }` is a value position.\n *\n * This is the classification `@typescript-eslint/consistent-type-imports`\n * applies, so the generated imports satisfy that rule.\n */\nfunction isTypePosition(identifier: Node): boolean {\n let child: Node = identifier;\n for (\n let parent = child.getParent();\n parent;\n child = parent, parent = parent.getParent()\n ) {\n // `Namespace.Type` and `namespace.value`: the reference is the leftmost name.\n if (Node.isQualifiedName(parent)) {\n if (parent.getLeft() !== child) return false;\n continue;\n }\n if (Node.isPropertyAccessExpression(parent)) {\n if (parent.getExpression() !== child) return false;\n continue;\n }\n if (Node.isExpressionWithTypeArguments(parent)) {\n const clause = parent.getParent();\n const owner = clause?.getParent();\n return !(\n Node.isHeritageClause(clause) &&\n clause.getToken() === SyntaxKind.ExtendsKeyword &&\n (Node.isClassDeclaration(owner) || Node.isClassExpression(owner))\n );\n }\n return Node.isTypeNode(parent);\n }\n return false;\n}\n\n/**\n * Plans the type-only form of every named import in a source file. Planning\n * reads the type checker; applying only edits text, so every file can be\n * planned against one program before any file changes.\n */\nfunction planTypeOnlyImports(sourceFile: SourceFile): (() => void)[] {\n const declarations = sourceFile\n .getImportDeclarations()\n .filter(\n declaration =>\n !declaration.getDefaultImport() &&\n !declaration.getNamespaceImport() &&\n declaration.getNamedImports().length > 0,\n );\n if (declarations.length === 0) return [];\n\n const localNames = new Set(\n declarations.flatMap(declaration =>\n declaration\n .getNamedImports()\n .map(specifier =>\n (specifier.getAliasNode() ?? specifier.getNameNode()).getText(),\n ),\n ),\n );\n const valueSymbols = new Set<ts.Symbol>();\n sourceFile.forEachDescendant((node, traversal) => {\n if (Node.isImportDeclaration(node)) {\n traversal.skip();\n return;\n }\n if (\n Node.isIdentifier(node) &&\n localNames.has(node.getText()) &&\n !isTypePosition(node)\n ) {\n // The checker resolves shadowing: a parameter named like an import is\n // a different symbol from the import's alias.\n const symbol = node.getSymbol();\n if (symbol) valueSymbols.add(symbol.compilerSymbol);\n }\n });\n\n return declarations.map(declaration =>\n applyTypeOnly(declaration, specifier => {\n const symbol = specifier.getSymbol();\n // Without a symbol the use cannot be proven type-only; keep it a value.\n return !!symbol && !valueSymbols.has(symbol.compilerSymbol);\n }),\n );\n}\n\nfunction applyTypeOnly(\n declaration: ImportDeclaration,\n isTypeOnly: (specifier: ImportSpecifier) => boolean,\n): () => void {\n const specifiers = declaration.getNamedImports();\n const typeOnly = specifiers.map(isTypeOnly);\n const allTypeOnly = typeOnly.every(Boolean);\n return () => {\n specifiers.forEach((specifier, index) => {\n const inline = !allTypeOnly && typeOnly[index];\n if (specifier.isTypeOnly() !== inline) specifier.setIsTypeOnly(inline);\n });\n if (declaration.isTypeOnly() !== allTypeOnly) {\n declaration.setIsTypeOnly(allTypeOnly);\n }\n };\n}\n\n/**\n * Rewrites named imports by how each file uses them, as\n * `@typescript-eslint/consistent-type-imports` expects:\n *\n * - every specifier used only as a type: `import type { A, B } from '…'`;\n * - values and types mixed: `import { type A, b } from '…'`;\n * - values only: `import { a, b } from '…'`.\n *\n * Usage alone decides, so an existing `type` modifier that a value use\n * contradicts is removed. Default and namespace imports are left as they are.\n */\nexport function applyTypeOnlyImports(sourceFiles: readonly SourceFile[]): void {\n const plans = sourceFiles.flatMap(planTypeOnlyImports);\n for (const apply of plans) apply();\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { SourceFile } from 'ts-morph';\nimport { ts } from 'ts-morph';\n\n/**\n * Diagnostics that mean the generated code itself is broken, whatever the\n * project around it resolves:\n *\n * - 2304, 2552, 2503: a name, possibly misspelled, or a namespace that is\n * neither declared nor imported;\n * - 2300, 2451, 2393: a name declared twice in one scope;\n * - 2308: an index re-exporting the same name from two modules;\n * - 2456: a type alias that references itself.\n *\n * Diagnostics that depend on the modules the output directory resolves -\n * a missing package (2307), a missing export (2305) - are the project's to\n * report, and are left out.\n */\nconst INTEGRITY_DIAGNOSTICS = new Set([\n 2300, 2304, 2308, 2393, 2451, 2456, 2503, 2552,\n]);\n\n/**\n * Fails when generated code references a name it does not declare or import,\n * or declares one twice.\n *\n * This is a safety net under the emitters, which write every import\n * explicitly: the output must be the same whether or not its directory\n * resolves `@ahoo-wang/*`, and it must never be saved in a state that cannot\n * compile.\n *\n * @param sourceFiles - The generated files\n * @throws Error listing each diagnostic with its file and line\n */\nexport function verifyGeneratedCode(sourceFiles: readonly SourceFile[]): void {\n const problems: string[] = [];\n for (const sourceFile of sourceFiles) {\n for (const diagnostic of sourceFile.getPreEmitDiagnostics()) {\n if (!INTEGRITY_DIAGNOSTICS.has(diagnostic.getCode())) continue;\n if (diagnostic.getSourceFile() !== sourceFile) continue;\n const message = ts.flattenDiagnosticMessageText(\n diagnostic.compilerObject.messageText,\n ' ',\n );\n problems.push(\n `${sourceFile.getFilePath()}:${diagnostic.getLineNumber() ?? 0} TS${diagnostic.getCode()} ${message}`,\n );\n }\n }\n if (problems.length > 0) {\n throw new Error(\n `The generated code does not compile; nothing was written. This is a wow-generator bug:\\n${problems.join('\\n')}`,\n );\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FormatCodeSettings, SourceFile } from 'ts-morph';\nimport type { Logger } from '../api/logger';\nimport { applyTypeOnlyImports } from './typeOnlyImports';\nimport { verifyGeneratedCode } from './verification';\n\n/**\n * The first line of every generated file. \"Code generated … DO NOT EDIT.\" is\n * the marker tools recognise as generated code.\n */\nconst GENERATED_FILE_HEADER =\n '// Code generated by wow-generator. DO NOT EDIT.\\n\\n';\n\n/**\n * Formatting of the generated code: two-space indentation, single quotes and\n * semicolons, as Prettier's defaults close to what the rest of a TypeScript\n * project uses.\n */\nconst FORMAT_SETTINGS: FormatCodeSettings = {\n indentSize: 2,\n tabSize: 2,\n convertTabsToSpaces: true,\n semicolons: 'insert' as FormatCodeSettings['semicolons'],\n insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,\n};\n\n/**\n * Finishes the files a generation wrote: formats them, organizes and types\n * their imports, checks that the result declares or imports every name it\n * uses, and adds the generated-file header.\n *\n * Imports are written explicitly while generating, never inferred from\n * whatever the output directory happens to resolve, so the output is the\n * same wherever it is written.\n *\n * @param sourceFiles - The files to finish, each written by this generation\n * @param logger - Receives a debug line for each file\n * @throws Error listing each diagnostic when the code does not compile\n */\nexport function finalizeSourceFiles(\n sourceFiles: readonly SourceFile[],\n logger: Logger,\n): void {\n sourceFiles.forEach((sourceFile, index) => {\n logger.debug(\n `Optimizing file [${sourceFile.getFilePath()}] - ${index + 1}/${sourceFiles.length}`,\n );\n sourceFile.formatText(FORMAT_SETTINGS);\n sourceFile.organizeImports(FORMAT_SETTINGS);\n });\n applyTypeOnlyImports(sourceFiles);\n verifyGeneratedCode(sourceFiles);\n for (const sourceFile of sourceFiles) {\n sourceFile.insertText(0, GENERATED_FILE_HEADER);\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { readFile } from 'fs';\n\n/** How long a remote document may take before the request is abandoned. */\nexport const DEFAULT_HTTP_TIMEOUT_MS = 30_000;\n\n/**\n * Options for loading a resource over HTTP. Files ignore them.\n */\nexport interface LoadResourceOptions {\n /** Request headers, for example `Authorization`. */\n readonly headers?: Record<string, string>;\n /** Milliseconds before the request is abandoned. */\n readonly timeoutMs?: number;\n /** Abandons the request when it aborts, as an interrupted run does. */\n readonly signal?: AbortSignal;\n}\n\n/**\n * Tells whether a location names an http(s) resource rather than a file.\n *\n * @param path - A file path or URL\n * @returns True for an `http://` or `https://` URL\n */\nexport function isHttpLocation(path: string): boolean {\n return /^https?:\\/\\//i.test(path);\n}\n\nexport function loadResource(\n path: string,\n options: LoadResourceOptions = {},\n): Promise<string> {\n if (isHttpLocation(path)) {\n return loadHttpResource(path, options);\n }\n return loadFile(path);\n}\n\n/**\n * Fetches a resource and returns its body.\n *\n * A response outside 2xx is a failure: a 401 or 404 page is not the document\n * the caller asked for, and parsing it would only fail later with a message\n * about the page instead of the request.\n *\n * @param url - The http(s) URL\n * @param options - Headers and timeout\n * @returns The response body as text\n * @throws Error naming the status, the timeout or the network failure; the\n * caller names the URL\n */\nexport async function loadHttpResource(\n url: string,\n options: LoadResourceOptions = {},\n): Promise<string> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_HTTP_TIMEOUT_MS;\n let response: Response;\n try {\n const timeout = AbortSignal.timeout(timeoutMs);\n response = await fetch(url, {\n headers: options.headers,\n signal: options.signal\n ? AbortSignal.any([options.signal, timeout])\n : timeout,\n });\n } catch (error) {\n const reason =\n error instanceof Error && error.name === 'TimeoutError'\n ? `no response within ${timeoutMs} ms`\n : networkReason(error);\n throw new Error(reason, { cause: error });\n }\n if (!response.ok) {\n const status = [response.status, response.statusText]\n .filter(Boolean)\n .join(' ');\n throw new Error(`HTTP ${status}`);\n }\n return await response.text();\n}\n\n/**\n * Explains a failed fetch. Node reports every network failure as \"fetch\n * failed\" and keeps the actual reason - DNS, refused connection, TLS - in\n * `cause`.\n */\nfunction networkReason(error: unknown): string {\n if (!(error instanceof Error)) return String(error);\n const cause = error.cause;\n if (cause instanceof Error && cause.message) {\n return `${error.message} (${cause.message})`;\n }\n return error.message;\n}\n\nexport function loadFile(path: string): Promise<string> {\n return new Promise((resolve, reject) => {\n readFile(path, 'utf-8', (err, data) => {\n if (err) {\n reject(err);\n } else {\n resolve(data);\n }\n });\n });\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { OpenAPI } from '@ahoo-wang/fetcher-openapi';\nimport { parse } from 'yaml';\nimport { errorMessage, GeneratorError } from '../api/errors';\nimport type { LoadResourceOptions } from './resources';\nimport { loadResource } from './resources';\n\n/**\n * Loads and parses an OpenAPI 3 document.\n *\n * Every failure is a {@link GeneratorError} of kind `input` whose message\n * names the document: it cannot be read or fetched, it is neither JSON nor\n * YAML, or it is not an OpenAPI 3 document. A Swagger 2.0 document is\n * refused rather than generated into clients without models.\n *\n * @param inputPath - The path or http(s) URL of the document\n * @param options - Headers and timeout for an http(s) document\n * @returns The parsed document; `paths` is an empty object when it has none\n */\nexport async function parseOpenAPI(\n inputPath: string,\n options?: LoadResourceOptions,\n): Promise<OpenAPI> {\n let content: string;\n try {\n content = await loadResource(inputPath, options);\n } catch (error) {\n throw new GeneratorError(\n 'input',\n `Cannot read the OpenAPI document ${inputPath}: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n let document: unknown;\n try {\n document = parseContent(content);\n } catch (error) {\n throw new GeneratorError(\n 'input',\n `Cannot parse the OpenAPI document ${inputPath}: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n return validateOpenAPIDocument(document, inputPath);\n}\n\n/**\n * Checks that a parsed document is an OpenAPI 3 document the generator reads.\n *\n * @param document - The parsed document\n * @param source - Where it came from, for messages\n * @returns The document, with `paths` defaulted to an empty object\n * @throws GeneratorError when it is not an OpenAPI 3.x document\n */\nexport function validateOpenAPIDocument(\n document: unknown,\n source: string,\n): OpenAPI {\n if (\n typeof document !== 'object' ||\n document === null ||\n Array.isArray(document)\n ) {\n throw new GeneratorError(\n 'input',\n `${source} is not an OpenAPI document: expected an object at the top level.`,\n );\n }\n const candidate = document as Record<string, unknown>;\n if (candidate.swagger !== undefined) {\n throw new GeneratorError(\n 'input',\n `${source} is a Swagger ${String(candidate.swagger)} document; wow-generator reads OpenAPI 3.x only. Convert it first, for example with swagger2openapi.`,\n );\n }\n if (\n typeof candidate.openapi !== 'string' ||\n !/^3\\.\\d+/.test(candidate.openapi)\n ) {\n throw new GeneratorError(\n 'input',\n `${source} is not an OpenAPI 3.x document: its \"openapi\" field is ${candidate.openapi === undefined ? 'missing' : JSON.stringify(candidate.openapi)}.`,\n );\n }\n if (\n typeof candidate.info !== 'object' ||\n candidate.info === null ||\n Array.isArray(candidate.info)\n ) {\n throw new GeneratorError(\n 'input',\n `${source} is not a valid OpenAPI document: its \"info\" object is missing.`,\n );\n }\n // OpenAPI 3.1 allows a document without paths (webhooks or components only).\n return { ...candidate, paths: candidate.paths ?? {} } as OpenAPI;\n}\n\n/**\n * Parses already-loaded document content in whichever format it is written.\n *\n * Callers name the source in their own error, so a failure here carries only\n * what went wrong with the text.\n *\n * @param content - The document text\n * @returns The parsed document\n */\nexport function parseContent<T>(content: string): T {\n // inferFileFormat answers with a format or throws, so the switch is\n // exhaustive - a `default` here would be a branch no input can reach.\n switch (inferFileFormat(content)) {\n case FileFormat.JSON:\n return JSON.parse(content);\n case FileFormat.YAML:\n return parse(content);\n }\n}\n\nexport enum FileFormat {\n JSON = 'json',\n YAML = 'yaml',\n}\n\nexport function inferFileFormat(content: string): FileFormat {\n // Trim whitespace and BOM characters from the beginning\n const trimmedContent = content.trimStart();\n\n if (trimmedContent.startsWith('{') || trimmedContent.startsWith('[')) {\n return FileFormat.JSON;\n }\n\n // YAML can start with various characters, but commonly with '-' (for arrays) or '%YAML'\n // We'll check for common YAML indicators\n if (trimmedContent.startsWith('-') || trimmedContent.startsWith('%YAML')) {\n return FileFormat.YAML;\n }\n\n // Try to parse as JSON to see if it's valid JSON despite not starting with { or [\n try {\n JSON.parse(trimmedContent);\n return FileFormat.JSON;\n } catch {\n // If it's not valid JSON, we'll assume it's YAML if it's not empty\n if (trimmedContent.length > 0) {\n return FileFormat.YAML;\n }\n }\n\n throw new Error('Unable to infer file format');\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { isAbsolute, resolve } from 'path';\nimport type { GeneratorConfiguration } from '../api/configuration';\nimport { DEFAULT_CONFIG_PATH } from '../api/configuration';\nimport { errorMessage, GeneratorError } from '../api/errors';\nimport type { Logger } from '../api/logger';\nimport { isIdentifier } from '../naming/naming';\nimport { parseContent } from './parsers';\nimport type { LoadResourceOptions } from './resources';\nimport { isHttpLocation, loadResource } from './resources';\n\n// compat(fetcher): the configuration was named fetcher-generator.config.json before the\n// package moved to Wow; read it, with a deprecation warning, when the new name is absent.\n// Removed in v10.\nexport const LEGACY_CONFIG_PATH = './fetcher-generator.config.json';\n\n/**\n * A configuration, and the warnings reading it gave: keys the generator does\n * not read, an empty file.\n */\nexport interface LoadedConfiguration {\n readonly config: GeneratorConfiguration;\n /** One line each, in the order they arose. */\n readonly warnings: readonly string[];\n}\n\n/**\n * A configuration, the place it was read from, and the warnings reading it\n * gave.\n */\nexport interface ResolvedConfiguration extends LoadedConfiguration {\n /** The absolute path or URL read, or undefined when there was none. */\n readonly origin?: string;\n}\n\n/**\n * Finds and loads the generator configuration.\n *\n * A path the caller names has to exist. Without one the generator reads\n * {@link DEFAULT_CONFIG_PATH}, then the pre-Wow name\n * {@link LEGACY_CONFIG_PATH} with a deprecation warning, and generates with\n * the defaults when neither exists.\n *\n * @param configPath - The path or URL the caller named, if any\n * @param logger - Receives what was read, at `debug`\n * @param options - Headers and timeout for a configuration read over http(s)\n * @returns The configuration, where it came from and the warnings it gave\n * @throws GeneratorError of kind `configuration` when it cannot be read,\n * parsed or understood\n */\nexport async function resolveConfiguration(\n configPath: string | undefined,\n logger: Logger,\n options?: LoadResourceOptions,\n): Promise<ResolvedConfiguration> {\n if (configPath !== undefined) {\n const loaded = await loadConfiguration(\n { path: configPath, explicit: true },\n logger,\n options,\n );\n return { ...loaded, origin: describeSource(configPath) };\n }\n for (const path of [DEFAULT_CONFIG_PATH, LEGACY_CONFIG_PATH]) {\n const loaded = await loadConfiguration(\n { path, explicit: false },\n logger,\n options,\n );\n if (loaded === undefined) continue;\n const warnings = [...loaded.warnings];\n if (path === LEGACY_CONFIG_PATH) {\n warnings.push(\n `${describeSource(path)} uses the deprecated name; rename it to ${DEFAULT_CONFIG_PATH.slice(2)}. The old name is no longer read from v10.`,\n );\n }\n return { config: loaded.config, origin: describeSource(path), warnings };\n }\n logger.debug('No configuration file found, generating with defaults');\n return { config: {}, warnings: [] };\n}\n\n/** Top-level keys a generator configuration may declare. */\nconst CONFIGURATION_KEYS = ['apiClients'];\n/** Keys an `apiClients` entry may declare. */\nconst API_CLIENT_KEYS = ['ignorePathParameters', 'methodNames'];\n\n/**\n * Where a configuration is read from, and whether the caller chose that place.\n */\nexport interface ConfigurationSource {\n /** A file path, or an http(s) URL. */\n readonly path: string;\n /**\n * True when the caller asked for this path. An absent file is then a\n * mistake worth failing on; under the default path it is merely the common\n * case of a project that has no configuration.\n */\n readonly explicit: boolean;\n}\n\n/**\n * Reads, validates and reports a generator configuration.\n *\n * A configuration that fails to load used to degrade to the defaults with a\n * single line among hundreds of progress lines, so a misplaced file looked\n * exactly like a generator that ignores its options. Loading now either\n * succeeds and says what it read, or fails loudly - with the sole exception of\n * the default path being absent, which stays a normal, quiet outcome.\n *\n * @param source - Where to read the configuration from\n * @param logger - Receives what was read and the settings it resolved to, at\n * `debug`\n * @param options - Headers and timeout for a configuration read over http(s)\n * @returns The validated configuration and the warnings about it; undefined\n * when a path the caller did not name does not exist\n * @throws GeneratorError of kind `configuration` when the configuration\n * cannot be read, parsed or understood\n */\nexport async function loadConfiguration(\n source: ConfigurationSource & { explicit: true },\n logger: Logger,\n options?: LoadResourceOptions,\n): Promise<LoadedConfiguration>;\nexport async function loadConfiguration(\n source: ConfigurationSource,\n logger: Logger,\n options?: LoadResourceOptions,\n): Promise<LoadedConfiguration | undefined>;\nexport async function loadConfiguration(\n source: ConfigurationSource,\n logger: Logger,\n options?: LoadResourceOptions,\n): Promise<LoadedConfiguration | undefined> {\n const origin = describeSource(source.path);\n logger.debug(`Reading configuration: ${origin}`);\n let content: string;\n try {\n content = await loadResource(source.path, options);\n } catch (error) {\n if (!source.explicit && isFileNotFound(error)) {\n logger.debug(`No configuration file at ${origin}`);\n return undefined;\n }\n throw new GeneratorError(\n 'configuration',\n `Cannot read configuration ${origin}: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n if (!content.trim()) {\n return {\n config: {},\n warnings: [`Configuration ${origin} is empty, generating with defaults`],\n };\n }\n let parsed: unknown;\n try {\n parsed = parseContent(content);\n } catch (error) {\n throw new GeneratorError(\n 'configuration',\n `Cannot parse configuration ${origin}: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n const loaded = validateConfiguration(parsed, origin);\n logger.debug(\n `Configuration loaded from ${origin}: ${describe(loaded.config)}`,\n );\n return loaded;\n}\n\n/**\n * Resolves a configuration path to what the user needs to see in a message.\n * A relative path is resolved against the working directory, because \"not\n * found\" is unactionable until it says which file was looked for.\n *\n * @param path - The configured file path or URL\n * @returns An absolute path, or the URL unchanged\n */\nfunction describeSource(path: string): string {\n if (isHttpLocation(path) || isAbsolute(path)) {\n return path;\n }\n return resolve(path);\n}\n\n/** Tells whether an error reports a missing file rather than a failed read. */\nfunction isFileNotFound(error: unknown): boolean {\n return (\n typeof error === 'object' &&\n error !== null &&\n (error as NodeJS.ErrnoException).code === 'ENOENT'\n );\n}\n\n/** Names a value's type the way a configuration author would recognise it. */\nfunction typeOf(value: unknown): string {\n if (value === null) return 'null';\n if (Array.isArray(value)) return 'an array';\n return `a ${typeof value}`;\n}\n\n/** Tells whether a value is a plain object a configuration block can be. */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Warns about keys the generator does not read.\n *\n * A misspelled key is the failure this whole module exists for: it parses,\n * it validates, and it does nothing at all.\n *\n * @param warnings - Receives the warning\n * @param origin - Where the configuration was read from\n * @param scope - The block the keys sit in, for the message\n * @param value - The block to inspect\n * @param known - The keys the generator reads\n */\nfunction warnUnknownKeys(\n warnings: string[],\n origin: string,\n scope: string,\n value: Record<string, unknown>,\n known: string[],\n): void {\n const unknown = Object.keys(value).filter(key => !known.includes(key));\n if (!unknown.length) {\n return;\n }\n warnings.push(\n `Ignoring unknown ${scope} option(s) in ${origin}: ${unknown.join(', ')}. Known option(s): ${known.join(', ')}`,\n );\n}\n\n/**\n * Checks a parsed configuration against the options the generator reads.\n *\n * Shape errors throw: a block the generator cannot read is a request the user\n * made and the generator would otherwise drop. Unknown keys only warn, so a\n * configuration written for a newer version still generates.\n *\n * @param parsed - The parsed configuration document\n * @param origin - Where it was read from, for messages\n * @returns The same configuration, typed, and a warning for every key the\n * generator ignores\n * @throws GeneratorError of kind `configuration` when a block or option has\n * a shape the generator cannot read\n */\nexport function validateConfiguration(\n parsed: unknown,\n origin: string,\n): LoadedConfiguration {\n if (!isRecord(parsed)) {\n throw new GeneratorError(\n 'configuration',\n `Configuration ${origin} must be a JSON or YAML object, found ${typeOf(parsed)}`,\n );\n }\n const warnings: string[] = [];\n warnUnknownKeys(\n warnings,\n origin,\n 'configuration',\n parsed,\n CONFIGURATION_KEYS,\n );\n validateApiClients(parsed.apiClients, origin, warnings);\n return { config: parsed as GeneratorConfiguration, warnings };\n}\n\n/** Checks the `apiClients` block and each tag entry within it. */\nfunction validateApiClients(\n apiClients: unknown,\n origin: string,\n warnings: string[],\n): void {\n if (apiClients === undefined) {\n return;\n }\n if (!isRecord(apiClients)) {\n throw new GeneratorError(\n 'configuration',\n `apiClients in ${origin} must be an object keyed by tag name, found ${typeOf(apiClients)}`,\n );\n }\n for (const [tag, apiClient] of Object.entries(apiClients)) {\n if (!isRecord(apiClient)) {\n throw new GeneratorError(\n 'configuration',\n `apiClients[\"${tag}\"] in ${origin} must be an object, found ${typeOf(apiClient)}`,\n );\n }\n warnUnknownKeys(\n warnings,\n origin,\n `apiClients[\"${tag}\"]`,\n apiClient,\n API_CLIENT_KEYS,\n );\n const { ignorePathParameters } = apiClient;\n if (\n ignorePathParameters !== undefined &&\n !(\n Array.isArray(ignorePathParameters) &&\n ignorePathParameters.every(name => typeof name === 'string')\n )\n ) {\n throw new GeneratorError(\n 'configuration',\n `apiClients[\"${tag}\"].ignorePathParameters in ${origin} must be an array of strings, found ${typeOf(ignorePathParameters)}`,\n );\n }\n const { methodNames } = apiClient;\n if (methodNames === undefined) continue;\n if (!isRecord(methodNames)) {\n throw new GeneratorError(\n 'configuration',\n `apiClients[\"${tag}\"].methodNames in ${origin} must be an object mapping operationIds to method names, found ${typeOf(methodNames)}`,\n );\n }\n for (const [operationId, methodName] of Object.entries(methodNames)) {\n if (typeof methodName !== 'string' || !isIdentifier(methodName)) {\n throw new GeneratorError(\n 'configuration',\n `apiClients[\"${tag}\"].methodNames[\"${operationId}\"] in ${origin} must be a valid method name, found ${JSON.stringify(methodName)}`,\n );\n }\n }\n }\n}\n\n/**\n * Summarises the settings a configuration resolved to, so the log answers\n * \"did my option take effect?\" without a second run.\n *\n * @param config - The validated configuration\n * @returns A one-line summary of every option the generator reads\n */\nfunction describe(config: GeneratorConfiguration): string {\n const tags = Object.keys(config.apiClients ?? {});\n return `apiClients=${tags.length ? tags.join(', ') : 'none'}`;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Components, OpenAPI } from '@ahoo-wang/fetcher-openapi';\nimport type { OperationEndpoint } from './operations';\nimport { extractOperationEndpoints } from './operations';\n\n/**\n * A parsed OpenAPI document as the generator reads it: the document itself,\n * which nothing changes, and its operations, listed once.\n */\nexport interface OpenApiDocument {\n /** The parsed document. Read only: every stage reads the same one. */\n readonly openAPI: OpenAPI;\n /** Its components, if it has any. */\n readonly components?: Components;\n /**\n * Every operation with its method and path, the path item's parameters\n * merged into its own (an operation's parameter overrides the path item's\n * one of the same name and location), ordered by operation id, then path,\n * then method.\n */\n readonly endpoints: readonly OperationEndpoint[];\n}\n\n/**\n * Reads a parsed document: lists its operations once, for every stage.\n *\n * @param openAPI - The parsed document; left unchanged\n */\nexport function openApiDocument(openAPI: OpenAPI): OpenApiDocument {\n return {\n openAPI,\n components: openAPI.components,\n endpoints: extractOperationEndpoints(openAPI.paths, openAPI.components),\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { isAbsolute, join, relative, resolve, sep } from 'path';\nimport type { Project, SourceFile } from 'ts-morph';\nimport { ts } from 'ts-morph';\nimport { errorMessage, GeneratorError } from '../api/errors';\nimport { combinePaths } from '../naming/paths';\n\n/** The manifest that records the files a generation wrote, and their hashes. */\nexport const GENERATION_MANIFEST = '.wow-generator.json';\n// compat(fetcher): generations before the move to Wow recorded their files in\n// .fetcher-generator.json; read it when the new manifest is absent so a regeneration still\n// removes files an older run wrote, and delete it once the new manifest is written.\n// Removed in v10.\nexport const LEGACY_GENERATION_MANIFEST = '.fetcher-generator.json';\n\n/**\n * The version of the manifest format this generator reads and writes. A\n * change a reader of this version would misread bumps it; see section 3 of\n * docs/design/architecture.md.\n */\nexport const MANIFEST_VERSION = 1;\n\n/**\n * The output directory of one generation: which files it owns, which of the\n * files an earlier run wrote it may remove, and writing them.\n *\n * The manifest (`.wow-generator.json`) records every file a run wrote and\n * the hash it wrote. A file of the last run that this run does not write is\n * stale; it is removed only if its bytes are still the ones recorded, so a\n * hand-edited file is never lost. A file the manifest does not name is never\n * touched.\n *\n * One store per run: {@link open} reads the manifest, {@link claim} hands\n * out the files the run writes, {@link commit} writes them, removes the stale\n * ones and writes the new manifest.\n */\nexport class OutputStore {\n /** The files this run writes, by absolute path. */\n private readonly written = new Set<string>();\n /** Files of the last run this run does not write and may remove. */\n private readonly stale = new Set<string>();\n\n private constructor(\n private readonly project: Project,\n /** The output directory as the caller named it. */\n private readonly outputPath: string,\n /** The output directory, absolute. */\n private readonly outputDir: string,\n /** The files of the last run, with the hash each was written with. */\n private readonly previous: ReadonlyMap<string, string>,\n /** A pre-Wow manifest to delete once the new one is written. */\n private readonly legacyManifest: string | undefined,\n ) {}\n\n /**\n * Reads the manifest of an output directory, the pre-Wow one when the new\n * one is absent, and takes the files it names out of the project: a run\n * writes its files afresh.\n *\n * @param project - The project the run writes into\n * @param outputDir - The output directory, absolute or relative to the\n * project's working directory\n * @param last - The store of the last run into the same project, whose\n * files, written or only drafted, leave the project too\n * @throws GeneratorError (`output`) when the manifest cannot be parsed, was\n * written by a newer generator, is not one, or names a file outside the\n * output directory\n */\n static open(\n project: Project,\n outputDir: string,\n last?: OutputStore,\n ): OutputStore {\n const fs = project.getFileSystem();\n const outputPath = outputDir;\n outputDir = resolve(fs.getCurrentDirectory(), outputDir);\n const legacyManifestPath = join(outputDir, LEGACY_GENERATION_MANIFEST);\n const legacyManifest = fs.fileExistsSync(legacyManifestPath)\n ? legacyManifestPath\n : undefined;\n let manifestPath = join(outputDir, GENERATION_MANIFEST);\n if (!fs.fileExistsSync(manifestPath) && legacyManifest) {\n manifestPath = legacyManifest;\n }\n const previous = new Map<string, string>();\n if (fs.fileExistsSync(manifestPath)) {\n const manifest = readManifest(\n manifestPath,\n fs.readFileSync(manifestPath),\n );\n for (const [path, hash] of Object.entries(manifest.files)) {\n const fileName = resolve(outputDir, path);\n assertWithinOutputDir(outputDir, fileName);\n if (\n isAbsolute(path) ||\n !path.endsWith('.ts') ||\n typeof hash !== 'string' ||\n !/^[a-f0-9]{64}$/.test(hash)\n ) {\n throw new GeneratorError(\n 'output',\n `Invalid generated file entry in ${manifestPath}: ${path}`,\n );\n }\n previous.set(fileName, hash);\n }\n }\n // Looked up by the files the project holds, not by path: where the file\n // system ignores case, ts-morph remembers the case of a path it is asked\n // for, and a file this run creates under that path in another case\n // would take the old case.\n const leaving = new Set([...(last?.written ?? []), ...previous.keys()]);\n for (const file of project.getSourceFiles()) {\n if (leaving.has(file.getFilePath())) file.forget();\n }\n return new OutputStore(\n project,\n outputPath,\n outputDir,\n previous,\n legacyManifest,\n );\n }\n\n /** The files this run writes, by absolute path. */\n get files(): ReadonlySet<string> {\n return this.written;\n }\n\n /**\n * The source file of a path under a directory of the output, claimed for\n * this run: the first claim empties it, and {@link commit} writes it.\n *\n * @param filePath - The path, relative to `directory`\n * @param directory - The output directory as the caller named it, or a\n * directory under it\n * @throws GeneratorError (`output`) when the path resolves outside it\n */\n claim(filePath: string, directory: string = this.outputPath): SourceFile {\n const fileName = combinePaths(directory, filePath);\n assertWithinOutputDir(directory, fileName);\n const file =\n this.project.getSourceFile(fileName) ??\n this.project.createSourceFile(fileName, '', { overwrite: true });\n const path = file.getFilePath();\n if (!this.written.has(path)) {\n file.removeText();\n this.written.add(path);\n }\n return file;\n }\n\n /**\n * Takes the files of the last run this run does not write out of the\n * project, when they are still as that run wrote them, so the indexes do\n * not export them; {@link commit} removes them. Nothing on disk changes.\n */\n forgetStale(): void {\n for (const [path, hash] of this.previous) {\n if (!this.written.has(path) && this.isUnchanged(path, hash)) {\n this.stale.add(path);\n }\n }\n // By exact path: a file this run writes may differ from a stale one only\n // in case, which ts-morph matches where the file system ignores case.\n for (const file of this.project.getSourceFiles()) {\n if (this.stale.has(file.getFilePath())) file.forget();\n }\n }\n\n /**\n * Writes the files this run claimed, then removes the stale ones that are\n * still as the last run wrote them, then writes the manifest and deletes a\n * pre-Wow one. A stale file this run writes again under a name that\n * differs only in case is removed before the writing instead.\n *\n * @param signal - Stops the run after the files are written: nothing is\n * removed and the manifest stays the last run's, so an interrupted run\n * never records files it did not finish\n * @throws GeneratorError (`output`) when writing or removing a file fails;\n * the signal's reason when it was aborted\n */\n async commit(signal?: AbortSignal): Promise<void> {\n signal?.throwIfAborted();\n const fs = this.project.getFileSystem();\n // A stale file whose path differs from a written one only in case is the\n // same file where the file system ignores case (macOS, Windows): writing\n // first would keep the old name, and removing it after would remove the\n // new file. It goes first, so the new name is the one on disk.\n const written = new Set([...this.written].map(path => path.toLowerCase()));\n for (const path of this.stale) {\n if (\n !this.written.has(path) &&\n written.has(path.toLowerCase()) &&\n this.isUnchanged(path, this.previous.get(path)!)\n ) {\n await attempt('delete', path, () => fs.delete(path));\n this.stale.delete(path);\n }\n }\n const files = [...this.written]\n .sort()\n .map(path => this.project.getSourceFileOrThrow(path));\n const saved = await Promise.allSettled(files.map(file => file.save()));\n saved.forEach((result, index) => {\n if (result.status === 'rejected') {\n throw outputFailure('write', files[index].getFilePath(), result.reason);\n }\n });\n signal?.throwIfAborted();\n for (const path of this.stale) {\n if (\n !this.written.has(path) &&\n this.isUnchanged(path, this.previous.get(path)!)\n ) {\n await attempt('delete', path, () => fs.delete(path));\n }\n }\n const manifestPath = join(this.outputDir, GENERATION_MANIFEST);\n const manifest =\n JSON.stringify(\n {\n version: MANIFEST_VERSION,\n files: Object.fromEntries(\n files.map(file => [\n relative(this.outputDir, file.getFilePath()).split(sep).join('/'),\n fileHash(fs.readFileSync(file.getFilePath())),\n ]),\n ),\n },\n null,\n 2,\n ) + '\\n';\n await attempt('write', manifestPath, async () => {\n fs.mkdirSync(this.outputDir);\n await fs.writeFile(manifestPath, manifest);\n });\n const legacyManifest = this.legacyManifest;\n if (legacyManifest && fs.fileExistsSync(legacyManifest)) {\n await attempt('delete', legacyManifest, () => fs.delete(legacyManifest));\n }\n }\n\n /**\n * Tells whether a file of the last run is still as it wrote it: present,\n * inside the output directory once links are followed, and of the hash the\n * manifest records.\n */\n private isUnchanged(path: string, hash: string): boolean {\n const fs = this.project.getFileSystem();\n if (!fs.fileExistsSync(path)) return false;\n assertWithinOutputDir(\n fs.realpathSync(this.outputDir),\n fs.realpathSync(path),\n );\n return fileHash(fs.readFileSync(path)) === hash;\n }\n}\n\n/**\n * Parses the text of a manifest, telling apart the failures a user resolves\n * differently: a file that is not JSON (a merge conflict, most often), one a\n * newer generator wrote, and one that is not a manifest at all.\n *\n * @throws GeneratorError (`output`) naming the manifest and what to do\n */\nfunction readManifest(\n manifestPath: string,\n text: string,\n): { files: Record<string, unknown> } {\n const remedy =\n 'delete it; without it this run cannot remove the stale files of the last run';\n let manifest;\n try {\n manifest = JSON.parse(text);\n } catch (error) {\n throw new GeneratorError(\n 'output',\n `Cannot parse the generation manifest ${manifestPath}: ${errorMessage(error)}. Resolve the merge conflict in it if it has one, or ${remedy}.`,\n { cause: error },\n );\n }\n const version = manifest?.version;\n if (\n typeof version === 'number' &&\n Number.isInteger(version) &&\n version > MANIFEST_VERSION\n ) {\n throw new GeneratorError(\n 'output',\n `The generation manifest ${manifestPath} was written by a newer wow-generator (manifest version ${version}); this one reads version ${MANIFEST_VERSION}. Upgrade wow-generator.`,\n );\n }\n if (\n version !== MANIFEST_VERSION ||\n !manifest.files ||\n typeof manifest.files !== 'object' ||\n Array.isArray(manifest.files)\n ) {\n throw new GeneratorError(\n 'output',\n `Invalid generation manifest ${manifestPath}: expected \"version\": ${MANIFEST_VERSION} and a \"files\" object. Restore it from version control, or ${remedy}.`,\n );\n }\n return manifest;\n}\n\nfunction fileHash(text: string): string {\n if (!ts.sys.createSHA256Hash) {\n throw new Error('SHA-256 hashing is unavailable in this environment.');\n }\n return ts.sys.createSHA256Hash(text);\n}\n\n/**\n * Reports a failure to change the output directory as an `output` error the\n * user can act on, keeping one that already is a {@link GeneratorError}.\n */\nfunction outputFailure(\n action: 'write' | 'delete',\n path: string,\n error: unknown,\n): GeneratorError {\n if (error instanceof GeneratorError) return error;\n return new GeneratorError(\n 'output',\n `Cannot ${action} ${path}: ${errorMessage(error)}`,\n { cause: error },\n );\n}\n\nasync function attempt(\n action: 'write' | 'delete',\n path: string,\n change: () => void | Promise<void>,\n): Promise<void> {\n try {\n await change();\n } catch (error) {\n throw outputFailure(action, path, error);\n }\n}\n\n/**\n * Guards against path traversal: `filePath` derives from a (possibly remote /\n * attacker-controlled) OpenAPI schema key. After joining with `outputDir`, the\n * resolved path must remain INSIDE `outputDir` — otherwise a key like\n * `../../etc/cron.d/pwn` would let `createSourceFile` write or clobber files\n * outside the output directory.\n *\n * `fileName` is the value actually handed to ts-morph (`combinePaths(outputDir,\n * filePath)`), so it is what gets written. We resolve THAT path (not a second\n * join against outputDir) and verify it stays under outputDir — otherwise the\n * checked path and the written path can diverge for relative outputDir values.\n *\n * @throws GeneratorError (`output`) if the resolved path escapes `outputDir`\n */\nfunction assertWithinOutputDir(outputDir: string, fileName: string): void {\n // `combinePaths` yields a URL-style path (forward slashes); normalize to the\n // platform filesystem path before resolving.\n const normalized = fileName.split('/').join(sep);\n const base = resolve(outputDir);\n // fileName already includes the outputDir prefix (it is the write target),\n // so resolve it directly (relative to cwd, or absolute as-is) — do NOT join\n // base again, which would double the prefix and check the wrong location.\n const target = resolve(normalized);\n const rel = relative(base, target);\n // An empty relative path means target === base (a directory, not a file);\n // a path starting with '..' or an absolute path escapes the base.\n const escapes = rel === '' || rel.startsWith('..') || isAbsolute(rel);\n if (escapes) {\n throw new GeneratorError(\n 'output',\n `Path traversal detected: \"${fileName}\" resolves outside the output directory \"${outputDir}\".`,\n );\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n Operation,\n Reference,\n RequestBody,\n Schema,\n Tag,\n} from '@ahoo-wang/fetcher-openapi';\nimport type { PartialBy } from '@ahoo-wang/fetcher';\nimport { GeneratorError } from '../api/errors';\nimport type { KeySchema } from '../openapi/components';\nimport {\n COMPONENTS_RESPONSES_REF,\n extractRequestBody,\n extractSchema,\n keySchema,\n} from '../openapi/components';\nimport type { OpenApiDocument } from '../openapi/document';\nimport type { OperationEndpoint } from '../openapi/operations';\nimport {\n extractOkResponse,\n extractOperationOkResponseJsonSchema,\n extractPathParameters,\n} from '../openapi/operations';\nimport { isReference } from '../openapi/references';\nimport { APPLICATION_JSON } from '../openapi/responses';\nimport {\n COMMAND_OK_RESPONSE_REF,\n contextAliasOf,\n EVENTS_OPERATION_SUFFIX,\n FIELDS_OPERATION_SUFFIX,\n MINIMUM_WOW_VERSION,\n operationIdToCommandName,\n QUERY_FIELDS_EXTENSION,\n SEND_COMMAND_OPERATION_ID,\n SNAPSHOT_ROUTE,\n STATE_OPERATION_SUFFIX,\n tagToAggregate,\n} from './conventions';\nimport type {\n AggregateDefinition,\n CommandDefinition,\n EventDefinition,\n SchemaDocOverride,\n WowModel,\n} from './model';\n\ntype PartialAggregateDefinition = PartialBy<\n AggregateDefinition,\n 'state' | 'fields' | 'resourceName'\n>;\n\n/**\n * Reads the Wow metadata of a document: its bounded context, and each\n * aggregate its tags name with the aggregate's commands, events, state,\n * query fields and route segment.\n *\n * An aggregate needs its state (`snapshot_state.single`) and its query fields\n * (`snapshot.count`) to generate clients; one that lacks either is left out\n * with a warning, and so is a command whose body is not a component schema.\n *\n * It is a pure function: the document is left as it was. The doc comments the\n * metadata lends command and event bodies are in\n * {@link WowModel.schemaDocOverrides}.\n *\n * @param document - The document\n * @returns The Wow model, and the warnings to log\n * @throws GeneratorError (`specification`) when an aggregate's Wow metadata\n * is malformed, or a command's response references form a cycle\n */\nexport function resolveWowModel(document: OpenApiDocument): WowModel {\n const { openAPI, components, endpoints } = document;\n const warnings: string[] = [];\n const schemaDocOverrides = new Map<string, Record<string, unknown>>();\n /** Tags of aggregates that expose at least one Wow route. */\n const wowTags = new Set<string>();\n\n const declared = openAPI.tags ?? [];\n const declaredNames = new Set(declared.map(tag => tag.name));\n // A document may tag operations without declaring the tags.\n const undeclared = new Set(\n endpoints\n .flatMap(endpoint => endpoint.operation.tags ?? [])\n .filter(name => !declaredNames.has(name)),\n );\n const aggregates = new Map<string, PartialAggregateDefinition>();\n for (const tag of [\n ...declared,\n ...[...undeclared].map((name): Tag => ({ name })),\n ]) {\n const aggregate = tagToAggregate(tag);\n if (aggregate) {\n aggregates.set(tag.name, {\n aggregate,\n commands: new Map(),\n events: new Map(),\n });\n }\n }\n\n const aggregatesOf = (operation: Operation): PartialAggregateDefinition[] =>\n (operation.tags ?? []).flatMap(tag => {\n const aggregate = aggregates.get(tag);\n if (!aggregate) return [];\n wowTags.add(tag);\n return [aggregate];\n });\n\n /**\n * Lends a schema a doc field where it has none, as `field ||= value`\n * would, recording the result instead of writing it into the schema.\n */\n const lend = (\n keyed: KeySchema,\n field: 'title' | 'description',\n value: string | undefined,\n ) => {\n let override = schemaDocOverrides.get(keyed.key);\n if (!override) {\n override = {};\n schemaDocOverrides.set(keyed.key, override);\n }\n const current = field in override ? override[field] : keyed.schema[field];\n override[field] = current || value;\n };\n\n const malformed = (operation: Operation, problem: string) =>\n new GeneratorError(\n 'specification',\n `Cannot read the Wow metadata of ${operation.operationId}: ${problem}. wow-generator reads documents from Wow ${MINIMUM_WOW_VERSION} or later.`,\n );\n\n /** Records the route segment of the aggregates a snapshot route belongs to. */\n const resourceName = (owners: PartialAggregateDefinition[], path: string) => {\n const name = SNAPSHOT_ROUTE.exec(path)?.[1];\n if (!name) return;\n owners.forEach(aggregate => {\n aggregate.resourceName ??= name;\n });\n };\n\n const readCommand = (endpoint: OperationEndpoint) => {\n const { operation, path } = endpoint;\n if (operation.operationId === SEND_COMMAND_OPERATION_ID) {\n return;\n }\n const commandName = operationIdToCommandName(operation.operationId);\n if (!commandName) {\n return;\n }\n let okResponse = extractOkResponse(operation);\n const visited = new Set<string>();\n while (\n okResponse &&\n isReference(okResponse) &&\n okResponse.$ref !== COMMAND_OK_RESPONSE_REF\n ) {\n if (!okResponse.$ref.startsWith(COMPONENTS_RESPONSES_REF)) return;\n if (visited.has(okResponse.$ref)) {\n throw new GeneratorError(\n 'specification',\n `Cyclic component reference: ${okResponse.$ref}`,\n );\n }\n visited.add(okResponse.$ref);\n okResponse =\n components?.responses?.[\n okResponse.$ref.slice(COMPONENTS_RESPONSES_REF.length)\n ];\n }\n if (\n !okResponse ||\n !isReference(okResponse) ||\n okResponse.$ref !== COMMAND_OK_RESPONSE_REF\n ) {\n return;\n }\n const owners = aggregatesOf(operation);\n if (!operation.requestBody) {\n return;\n }\n\n const pathParameters = extractPathParameters(operation, components ?? {});\n const requestBody = isReference(operation.requestBody)\n ? extractRequestBody(operation.requestBody, components ?? {})\n : operation.requestBody;\n const commandRefSchema = requestBody?.content?.[APPLICATION_JSON]?.schema;\n if (!isReference(commandRefSchema)) {\n if (owners.length > 0) {\n warnings.push(\n `Skipping command ${operation.operationId} (${endpoint.method.toUpperCase()} ${path}): its application/json request body is not a $ref to a component schema.`,\n );\n }\n return;\n }\n const commandKeyedSchema = keySchema(commandRefSchema, components ?? {});\n if (!commandKeyedSchema.schema) return;\n lend(commandKeyedSchema, 'title', operation.summary);\n lend(commandKeyedSchema, 'description', operation.description);\n const commandDefinition: CommandDefinition = {\n name: commandName,\n method: endpoint.method,\n path,\n pathParameters,\n summary: operation.summary,\n description: operation.description,\n schema: commandKeyedSchema,\n operation: operation,\n };\n owners.forEach(aggregate => {\n aggregate.commands.set(commandName, commandDefinition);\n });\n };\n\n const readState = ({ operation, path }: OperationEndpoint) => {\n if (!operation.operationId?.endsWith(STATE_OPERATION_SUFFIX)) {\n return;\n }\n const owners = aggregatesOf(operation);\n resourceName(owners, path);\n const stateRefSchema = extractOperationOkResponseJsonSchema(\n operation,\n components,\n );\n if (!isReference(stateRefSchema)) {\n if (owners.length > 0) {\n throw malformed(\n operation,\n 'its 200 application/json response is not a $ref to the state schema',\n );\n }\n return;\n }\n const stateKeyedSchema = keySchema(stateRefSchema, components!);\n owners.forEach(aggregate => {\n aggregate.state = stateKeyedSchema;\n });\n };\n\n const readEvents = ({ operation }: OperationEndpoint) => {\n if (!components) {\n return;\n }\n if (!operation.operationId?.endsWith(EVENTS_OPERATION_SUFFIX)) {\n return;\n }\n const owners = aggregatesOf(operation);\n if (owners.length === 0) return;\n const eventStreamArraySchema = extractOperationOkResponseJsonSchema(\n operation,\n components,\n );\n if (isReference(eventStreamArraySchema)) {\n return;\n }\n const eventStreamRefSchema = eventStreamArraySchema?.items;\n if (!isReference(eventStreamRefSchema)) {\n throw malformed(\n operation,\n 'its 200 application/json response is not an array of a $ref to the event stream schema',\n );\n }\n const eventStreamSchema = extractSchema(eventStreamRefSchema, components);\n const domainEventSchemas = objectAt(eventStreamSchema, [\n 'properties',\n 'body',\n 'items',\n 'anyOf',\n ]);\n if (!Array.isArray(domainEventSchemas)) {\n throw malformed(\n operation,\n `the event stream schema ${eventStreamRefSchema.$ref} has no properties.body.items.anyOf listing the domain events`,\n );\n }\n const events: EventDefinition[] = domainEventSchemas.map(\n (domainEventSchema: Schema, index: number) => {\n const eventName = objectAt(domainEventSchema, [\n 'properties',\n 'name',\n 'const',\n ]);\n const eventBodySchema = objectAt(domainEventSchema, [\n 'properties',\n 'body',\n ]);\n if (typeof eventName !== 'string' || !isReference(eventBodySchema)) {\n throw malformed(\n operation,\n `domain event ${index} of ${eventStreamRefSchema.$ref} needs a properties.name.const and a properties.body that is a $ref to the event schema`,\n );\n }\n const eventBodyKeyedSchema = keySchema(eventBodySchema, components);\n lend(eventBodyKeyedSchema, 'title', domainEventSchema.title);\n return {\n title: domainEventSchema.title ?? eventName,\n name: eventName,\n schema: eventBodyKeyedSchema,\n };\n },\n );\n\n owners.forEach(aggregate => {\n events.forEach(event => {\n aggregate.events.set(event.name, event);\n });\n });\n };\n\n const readFields = ({ operation, path }: OperationEndpoint) => {\n if (!components) {\n return;\n }\n if (!operation.operationId?.endsWith(FIELDS_OPERATION_SUFFIX)) {\n return;\n }\n const owners = aggregatesOf(operation);\n if (owners.length === 0) return;\n resourceName(owners, path);\n const requestBody = operation.requestBody\n ? isReference(operation.requestBody)\n ? extractRequestBody(operation.requestBody, components)\n : (operation.requestBody as RequestBody)\n : undefined;\n if (!requestBody) {\n throw malformed(operation, 'it has no request body');\n }\n const queryFields = requestBody[QUERY_FIELDS_EXTENSION];\n let fieldRefSchema: Reference;\n if (queryFields !== undefined) {\n if (!isReference(queryFields)) {\n throw malformed(\n operation,\n `${QUERY_FIELDS_EXTENSION} must be a schema reference`,\n );\n }\n fieldRefSchema = queryFields;\n } else {\n // compat(wow<9): servers before Wow 8.11.1 have no x-wow-query-fields and name the\n // query fields only on the Condition schema's `field` (Ahoo-Wang/fetcher#1359).\n const conditionRefSchema =\n requestBody.content?.[APPLICATION_JSON]?.schema;\n const conditionSchema = isReference(conditionRefSchema)\n ? extractSchema(conditionRefSchema, components)\n : undefined;\n const field = conditionSchema?.properties?.field;\n if (!isReference(field)) {\n throw malformed(\n operation,\n `its request body has no ${QUERY_FIELDS_EXTENSION}, and its condition schema has no field $ref to read the query fields from`,\n );\n }\n fieldRefSchema = field;\n }\n const fieldKeyedSchema = keySchema(fieldRefSchema, components);\n owners.forEach(aggregate => {\n aggregate.fields = fieldKeyedSchema;\n });\n };\n\n for (const endpoint of endpoints) {\n readCommand(endpoint);\n readState(endpoint);\n readEvents(endpoint);\n readFields(endpoint);\n }\n\n const contexts = new Map<string, Set<AggregateDefinition>>();\n for (const [tag, aggregate] of aggregates) {\n if (!aggregate.state || !aggregate.fields) {\n if (wowTags.has(tag)) {\n const missing = [\n aggregate.state ? undefined : `${tag}${STATE_OPERATION_SUFFIX}`,\n aggregate.fields ? undefined : `${tag}${FIELDS_OPERATION_SUFFIX}`,\n ].filter(Boolean);\n warnings.push(\n `Skipping aggregate ${tag}: the document has no ${missing.join(' or ')} operation, so it generates neither command nor query clients for it.`,\n );\n }\n continue;\n }\n const contextAlias = aggregate.aggregate.contextAlias;\n let resolved = contexts.get(contextAlias);\n if (!resolved) {\n resolved = new Set<AggregateDefinition>();\n contexts.set(contextAlias, resolved);\n }\n resolved.add({\n ...aggregate,\n resourceName: aggregate.resourceName ?? aggregate.aggregate.aggregateName,\n } as AggregateDefinition);\n }\n\n return {\n contextAlias: contextAliasOf(openAPI),\n contexts,\n aggregateTags: wowTags,\n schemaDocOverrides: schemaDocOverrides as ReadonlyMap<\n string,\n SchemaDocOverride\n >,\n warnings,\n };\n}\n\n/** Reads a nested property of a schema that may be anything. */\nfunction objectAt(value: unknown, path: string[]): any {\n let current: any = value;\n for (const key of path) {\n if (current === null || typeof current !== 'object') return undefined;\n current = current[key];\n }\n return current;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Project } from 'ts-morph';\nimport type { GeneratorOptions } from '../api/options';\n\n/**\n * Test seam: an option under this key hands a generator the ts-morph project\n * to write into, such as an in-memory one, instead of one it reads from\n * `tsConfigFilePath`. A symbol the package does not export, so it is no part\n * of the public options. It lives apart from `CodeGenerator`, whose\n * declaration therefore names neither it nor ts-morph, whose major version it\n * would follow.\n */\nexport const PROJECT_SEAM = Symbol('project');\n\n/**\n * The CLI's seam: an option under this key stops a run when it aborts, as\n * Ctrl-C does. A run stops at its next step; once it writes, it finishes\n * writing its files and then stops without removing anything or recording\n * the files in the manifest.\n */\nexport const SIGNAL_SEAM = Symbol('signal');\n\n/**\n * What the package itself may hand a generator beyond its public options,\n * each under a symbol it does not export.\n */\nexport interface Seams {\n readonly [PROJECT_SEAM]?: Project;\n readonly [SIGNAL_SEAM]?: AbortSignal;\n}\n\n/** The options, with the {@link Seams} the package may add. */\nexport interface SeamOptions extends GeneratorOptions, Seams {}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { IndentationText, Project, QuoteKind } from 'ts-morph';\nimport { analyze } from '../analysis/analyze';\nimport { errorMessage, GeneratorError } from '../api/errors';\nimport type { Logger } from '../api/logger';\nimport { ConsoleLogger } from '../api/logger';\nimport type { GenerationResult, GeneratorOptions } from '../api/options';\nimport { ModuleSet } from '../emit/moduleBuilder';\nimport { emitGeneration } from '../emitters/emit';\nimport { emitIndexFiles } from '../emitters/indexFiles';\nimport { documentTypeContext } from '../emitters/models';\nimport { finalizeSourceFiles } from '../finalize/finalize';\nimport { resolveConfiguration } from '../input/configuration';\nimport { parseOpenAPI } from '../input/parsers';\nimport { openApiDocument } from '../openapi/document';\nimport { findDanglingReferences } from '../openapi/references';\nimport { OutputStore } from '../output/outputStore';\nimport { resolveWowModel } from '../wow/resolveWowModel';\nimport type { SeamOptions } from './seams';\nimport { PROJECT_SEAM, SIGNAL_SEAM } from './seams';\n\n/**\n * Main code generator class that orchestrates the generation of TypeScript code from OpenAPI specifications.\n * This class handles the entire code generation process, including parsing OpenAPI specs,\n * resolving aggregates, generating models and clients, and formatting the output.\n *\n * @example\n * ```typescript\n * const generator = new CodeGenerator({\n * inputPath: './openapi.yaml',\n * outputDir: './generated',\n * tsConfigFilePath: './tsconfig.json',\n * logger: new ConsoleLogger({ level: 'verbose' }),\n * });\n * const { files } = await generator.generate();\n * ```\n */\nexport class CodeGenerator {\n private readonly project: Project;\n private readonly logger: Logger;\n private readonly signal?: AbortSignal;\n /** The output of the last run, whose files the next run starts without. */\n private output?: OutputStore;\n\n /**\n * Creates a new CodeGenerator instance with the specified options.\n *\n * @param options - Input, output, configuration and logging of the run.\n * @throws GeneratorError of kind `configuration` if the TypeScript\n * configuration cannot be read.\n */\n constructor(private readonly options: GeneratorOptions) {\n this.logger = options.logger ?? new ConsoleLogger();\n this.signal = (options as SeamOptions)[SIGNAL_SEAM];\n this.project =\n (options as SeamOptions)[PROJECT_SEAM] ??\n createProject(options.tsConfigFilePath);\n this.project.manipulationSettings.set({\n indentationText: IndentationText.TwoSpaces,\n quoteKind: QuoteKind.Single,\n useTrailingCommas: true,\n });\n this.logger.debug(\n `Project instance created with tsConfigFilePath: ${this.options.tsConfigFilePath}`,\n );\n }\n\n /**\n * Generates TypeScript code from the OpenAPI specification:\n *\n * 1. reads the generator configuration, then the document, which it checks\n * for dangling references;\n * 2. reads the document's Wow model: bounded contexts and aggregates;\n * 3. decides what the document generates (`analysis/`);\n * 4. writes every module once (`emitters/`), then the index files;\n * 5. formats, organises and types the imports, and checks the output\n * compiles (`finalize/`);\n * 6. writes the files, removes the stale ones of the last run and records\n * the manifest (`output/`).\n *\n * Every warning is logged as it arises, and counted.\n *\n * @returns The files written, the configuration read and how many warnings\n * the run logged.\n * @throws GeneratorError when the document or the configuration cannot be\n * read or understood, the document describes code that cannot compile, or\n * the output cannot be written. A configuration is only optional at\n * `DEFAULT_CONFIG_PATH`; one the caller named has to exist.\n *\n * @example\n * ```typescript\n * await generator.generate();\n * ```\n */\n async generate(): Promise<GenerationResult> {\n const { logger, signal, options } = this;\n let warnings = 0;\n const warn = (lines: readonly string[]) => {\n for (const line of lines) {\n warnings++;\n logger.warn(line);\n }\n };\n logger.debug('Starting code generation from OpenAPI specification');\n logger.debug(`Work directory: ${process.cwd()}`);\n logger.debug(`Input path: ${options.inputPath}`);\n logger.debug(`Output directory: ${options.outputDir}`);\n\n const loadOptions = {\n headers: options.headers,\n timeoutMs: options.timeoutMs,\n signal,\n };\n // The configuration first: a mistake in it fails before a remote\n // document is fetched and read.\n const configuration = await resolveConfiguration(\n options.configPath,\n logger,\n loadOptions,\n );\n warn(configuration.warnings);\n signal?.throwIfAborted();\n\n logger.debug('Parsing OpenAPI specification');\n const openAPI = await parseOpenAPI(options.inputPath, loadOptions);\n signal?.throwIfAborted();\n logger.debug('OpenAPI specification parsed successfully');\n const dangling = findDanglingReferences(openAPI);\n if (dangling.length > 0) {\n throw new GeneratorError(\n 'specification',\n `${options.inputPath} has ${dangling.length} $ref(s) that point at nothing: ${dangling\n .slice(0, 10)\n .map(({ ref, location }) => `${ref} (at ${location})`)\n .join(', ')}${dangling.length > 10 ? ', …' : ''}`,\n );\n }\n\n const document = openApiDocument(openAPI);\n logger.debug('Resolving bounded context aggregates');\n const wow = resolveWowModel(document);\n warn(wow.warnings);\n logger.debug(`Resolved ${wow.contexts.size} bounded context aggregates`);\n\n const output = OutputStore.open(\n this.project,\n options.outputDir,\n this.output,\n );\n this.output = output;\n\n logger.debug('Analysing the document');\n const analysis = analyze(document, wow, configuration.config);\n warn(analysis.warnings);\n\n logger.debug('Writing generated modules');\n const modules = new ModuleSet(filePath => output.claim(filePath));\n emitGeneration(analysis.model, {\n modules,\n outputDir: options.outputDir,\n types: documentTypeContext(document.components),\n schemaDocs: options.schemaDocs ?? 'summary',\n });\n modules.build();\n logger.debug('Generated modules written');\n output.forgetStale();\n const outputDirectory = this.project.getDirectory(options.outputDir);\n if (outputDirectory) {\n logger.debug('Generating index files');\n warn(\n emitIndexFiles(outputDirectory, directory =>\n output.claim('index.ts', directory),\n ),\n );\n logger.debug('Optimizing source files');\n const sourceFiles = outputDirectory\n .getDescendantSourceFiles()\n .filter(file => output.files.has(file.getFilePath()));\n finalizeSourceFiles(sourceFiles, logger);\n logger.debug('Source files optimized successfully');\n } else {\n logger.debug('Output directory not found.');\n }\n\n logger.debug('Saving project to disk');\n await output.commit(signal);\n logger.debug('Code generation completed successfully');\n return {\n files: [...output.files].sort(),\n configPath: configuration.origin,\n warnings,\n };\n }\n}\n\n/**\n * The project a run writes into. Only the compiler options of the tsconfig\n * matter: the files it includes would be read, parsed and type-checked on\n * every run for nothing, and their global declarations could sway the\n * output.\n *\n * @throws GeneratorError of kind `configuration` when the tsconfig cannot be\n * read\n */\nfunction createProject(tsConfigFilePath: string | undefined): Project {\n try {\n return new Project({ tsConfigFilePath, skipAddingFilesFromTsConfig: true });\n } catch (error) {\n throw new GeneratorError(\n 'configuration',\n `Cannot read the TypeScript configuration ${tsConfigFilePath}: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n}\n"],"mappings":"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"}