@forge-ts/api 0.19.0 → 0.19.1

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.
package/dist/index.d.ts CHANGED
@@ -67,9 +67,7 @@ declare function extractSDKTypes(symbols: ForgeSymbol[]): SDKType[];
67
67
  * - A `components.schemas` section with one schema per exported type.
68
68
  * - `tags` derived from unique source file paths (grouping by file).
69
69
  * - Visibility filtering: `@internal` symbols are never emitted.
70
- *
71
- * HTTP paths are not yet emitted (`paths` is always `{}`); route extraction
72
- * will be added in a future release.
70
+ * - HTTP paths are extracted from `@route` tags and appropriately mapped.
73
71
  *
74
72
  * @param config - The resolved {@link ForgeConfig}.
75
73
  * @param sdkTypes - SDK types to include as component schemas.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/openapi.ts","../src/schema-mapper.ts","../src/reference.ts","../src/sdk-extractor.ts","../src/index.ts"],"sourcesContent":["import type {\n\tForgeConfig,\n\tForgeSymbol,\n\tOpenAPIDocument,\n\tOpenAPIInfoObject,\n\tOpenAPIOperationObject,\n\tOpenAPIParameterObject,\n\tOpenAPIPathItemObject,\n\tOpenAPISchemaObject,\n} from \"@forge-ts/core\";\nimport { Visibility } from \"@forge-ts/core\";\nimport { signatureToSchema } from \"./schema-mapper.js\";\nimport type { SDKProperty, SDKType } from \"./sdk-extractor.js\";\n\nexport type { OpenAPIDocument };\n\n/**\n * Generates a production-quality OpenAPI 3.2 document from the extracted SDK\n * types.\n *\n * The document is populated with:\n * - An `info` block sourced from the config or reasonable defaults.\n * - A `components.schemas` section with one schema per exported type.\n * - `tags` derived from unique source file paths (grouping by file).\n * - Visibility filtering: `@internal` symbols are never emitted.\n *\n * HTTP paths are not yet emitted (`paths` is always `{}`); route extraction\n * will be added in a future release.\n *\n * @param config - The resolved {@link ForgeConfig}.\n * @param sdkTypes - SDK types to include as component schemas.\n * @param symbols - Raw symbols used to extract HTTP route paths from `@route` tags.\n * @returns An {@link OpenAPIDocument} object.\n * @example\n * ```typescript\n * import { generateOpenAPISpec } from \"@forge-ts/api\";\n * import { extractSDKTypes } from \"@forge-ts/api\";\n * const spec = generateOpenAPISpec(config, extractSDKTypes(symbols), symbols);\n * console.log(spec.openapi); // \"3.2.0\"\n * ```\n * @public\n */\nexport function generateOpenAPISpec(\n\tconfig: ForgeConfig,\n\tsdkTypes: SDKType[],\n\tsymbols: ForgeSymbol[] = [],\n): OpenAPIDocument {\n\t// Visibility filtering: never emit @internal or @private symbols.\n\tconst visibleTypes = sdkTypes.filter(\n\t\t(t) => t.visibility !== Visibility.Internal && t.visibility !== Visibility.Private,\n\t);\n\n\tconst schemas: Record<string, OpenAPISchemaObject> = {};\n\tfor (const t of visibleTypes) {\n\t\tschemas[t.name] = buildSchema(t);\n\t}\n\n\t// Derive tags from unique source files (basename without extension).\n\tconst tagNames = deriveTagNames(visibleTypes);\n\tconst tags = tagNames.map((name) => ({ name }));\n\n\tconst paths = extractPaths(symbols);\n\n\treturn {\n\t\topenapi: \"3.2.0\",\n\t\tinfo: buildInfo(config),\n\t\t...(tags.length > 0 ? { tags } : {}),\n\t\tpaths,\n\t\tcomponents: { schemas },\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Info block\n// ---------------------------------------------------------------------------\n\n/**\n * Builds the OpenAPI `info` block from the config.\n *\n * @param config - The resolved {@link ForgeConfig}.\n * @returns An info object with title, version, and description.\n * @internal\n */\nfunction buildInfo(_config: ForgeConfig): OpenAPIInfoObject {\n\t// We attempt to read name/version from the project root's package.json at\n\t// runtime. If unavailable, fall back to safe defaults.\n\treturn {\n\t\ttitle: \"API Reference\",\n\t\tversion: \"0.0.0\",\n\t\tdescription: \"Generated by forge-ts\",\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Schema builders\n// ---------------------------------------------------------------------------\n\n/**\n * Converts an {@link SDKType} to an OpenAPI schema object.\n *\n * - `interface` / `class` → object schema with `properties` and `required`\n * - `enum` → schema with `enum` array and `type: \"string\"`\n * - `type` alias → schema derived from signature parsing\n *\n * @param sdkType - The type descriptor to convert.\n * @returns An OpenAPI schema object.\n * @internal\n */\nfunction buildSchema(sdkType: SDKType): OpenAPISchemaObject {\n\tconst base: OpenAPISchemaObject = {};\n\n\tif (sdkType.description) {\n\t\tbase.description = sdkType.description;\n\t}\n\n\tif (sdkType.deprecated) {\n\t\tbase.deprecated = true;\n\t}\n\n\tswitch (sdkType.kind) {\n\t\tcase \"interface\":\n\t\tcase \"class\":\n\t\t\treturn { ...base, ...buildObjectSchema(sdkType) };\n\t\tcase \"enum\":\n\t\t\treturn { ...base, ...buildEnumSchema(sdkType) };\n\t\tcase \"type\":\n\t\t\treturn { ...base, ...buildTypeAliasSchema(sdkType) };\n\t\tdefault:\n\t\t\treturn { ...base, type: \"object\" };\n\t}\n}\n\n/**\n * Builds an object schema for an interface or class type.\n *\n * @param sdkType - An interface or class {@link SDKType}.\n * @returns An OpenAPI object schema.\n * @internal\n */\nfunction buildObjectSchema(sdkType: SDKType): OpenAPISchemaObject {\n\tif (sdkType.properties.length === 0) {\n\t\treturn { type: \"object\" };\n\t}\n\n\tconst properties: Record<string, OpenAPISchemaObject> = {};\n\tconst required: string[] = [];\n\n\tfor (const prop of sdkType.properties) {\n\t\tproperties[prop.name] = buildPropertySchema(prop);\n\t\tif (prop.required) {\n\t\t\trequired.push(prop.name);\n\t\t}\n\t}\n\n\tconst schema: OpenAPISchemaObject = { type: \"object\", properties };\n\tif (required.length > 0) {\n\t\tschema.required = required;\n\t}\n\n\treturn schema;\n}\n\n/**\n * Builds the schema for a single property.\n *\n * @param prop - The {@link SDKProperty} to convert.\n * @returns A partial OpenAPI schema for the property.\n * @internal\n */\nfunction buildPropertySchema(prop: SDKProperty): OpenAPISchemaObject {\n\tconst schema: OpenAPISchemaObject = { ...signatureToSchema(prop.type) };\n\n\tif (prop.description) {\n\t\tschema.description = prop.description;\n\t}\n\n\tif (prop.deprecated) {\n\t\tschema.deprecated = true;\n\t}\n\n\treturn schema;\n}\n\n/**\n * Builds an enum schema for an enum type.\n *\n * If the enum has properties (members), their names are used as the enum\n * values. The type defaults to `\"string\"` unless a member type suggests\n * otherwise.\n *\n * @param sdkType - An enum {@link SDKType}.\n * @returns An OpenAPI schema with `enum` values.\n * @internal\n */\nfunction buildEnumSchema(sdkType: SDKType): OpenAPISchemaObject {\n\tif (sdkType.properties.length === 0) {\n\t\treturn { type: \"string\", enum: [] };\n\t}\n\n\tconst values = sdkType.properties.map((p) => {\n\t\t// Use the type value if it looks like a string literal; otherwise use name.\n\t\tconst t = p.type.trim();\n\t\tif (t.startsWith('\"') || t.startsWith(\"'\")) {\n\t\t\treturn t.replace(/^['\"]|['\"]$/g, \"\");\n\t\t}\n\t\treturn p.name;\n\t});\n\n\t// Detect numeric enums: if all values are parseable numbers use \"number\".\n\tconst allNumeric = values.every((v) => !Number.isNaN(Number(v)));\n\n\treturn {\n\t\ttype: allNumeric ? \"number\" : \"string\",\n\t\tenum: allNumeric ? values.map(Number) : values,\n\t};\n}\n\n/**\n * Builds a schema for a type alias.\n *\n * Attempts to parse the signature string directly; falls back to\n * `{ type: \"object\" }` for complex generics or intersections.\n *\n * @param sdkType - A type alias {@link SDKType}.\n * @returns An OpenAPI schema.\n * @internal\n */\nfunction buildTypeAliasSchema(sdkType: SDKType): OpenAPISchemaObject {\n\tif (!sdkType.signature) {\n\t\treturn { type: \"object\" };\n\t}\n\n\t// The signature for a type alias is often `type Name = ActualType`.\n\t// Strip the leading declaration if present.\n\tconst equalsIndex = sdkType.signature.indexOf(\"=\");\n\tconst rawType =\n\t\tequalsIndex !== -1 ? sdkType.signature.slice(equalsIndex + 1).trim() : sdkType.signature;\n\n\treturn signatureToSchema(rawType);\n}\n\n// ---------------------------------------------------------------------------\n// Path extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Builds OpenAPI path items from symbols that carry `@route` TSDoc tags.\n *\n * Each `@route` tag must be in the format `METHOD /path` (e.g. `GET /users/{id}`).\n * Path template variables like `{id}` are emitted as required path parameters.\n * Any `@param` entries not matched to a path variable become query parameters.\n *\n * @param symbols - All {@link ForgeSymbol} instances from the walker.\n * @returns A map of path template strings to their OpenAPI path item objects.\n * @internal\n */\nfunction extractPaths(symbols: ForgeSymbol[]): Record<string, OpenAPIPathItemObject> {\n\tconst paths: Record<string, OpenAPIPathItemObject> = {};\n\n\tfor (const symbol of symbols) {\n\t\tconst routeTags: string[] = symbol.documentation?.tags?.route ?? [];\n\t\tfor (const routeTag of routeTags) {\n\t\t\tconst match = routeTag.match(/^(GET|POST|PUT|DELETE|PATCH|OPTIONS|HEAD)\\s+(\\S+)/i);\n\t\t\tif (!match) continue;\n\n\t\t\tconst method = match[1].toLowerCase() as\n\t\t\t\t| \"get\"\n\t\t\t\t| \"post\"\n\t\t\t\t| \"put\"\n\t\t\t\t| \"delete\"\n\t\t\t\t| \"patch\"\n\t\t\t\t| \"options\"\n\t\t\t\t| \"head\";\n\t\t\tconst path = match[2];\n\n\t\t\tif (!paths[path]) {\n\t\t\t\tpaths[path] = {};\n\t\t\t}\n\n\t\t\tconst fileBasename = symbol.filePath.split(\"/\").pop()?.replace(/\\.ts$/, \"\") ?? \"default\";\n\n\t\t\tconst operation: OpenAPIOperationObject = {\n\t\t\t\toperationId: symbol.name,\n\t\t\t\tsummary: symbol.documentation?.summary,\n\t\t\t\tdescription: symbol.documentation?.summary,\n\t\t\t\ttags: [fileBasename],\n\t\t\t};\n\n\t\t\t// Extract path template variables like {id}\n\t\t\tconst pathParams = [...path.matchAll(/\\{(\\w+)\\}/g)].map((m) => m[1]);\n\t\t\tconst parameters: OpenAPIParameterObject[] = [];\n\n\t\t\tfor (const paramName of pathParams) {\n\t\t\t\tconst paramDoc = symbol.documentation?.params?.find((p) => p.name === paramName);\n\t\t\t\tparameters.push({\n\t\t\t\t\tname: paramName,\n\t\t\t\t\tin: \"path\",\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdescription: paramDoc?.description ?? `The ${paramName} parameter`,\n\t\t\t\t\tschema: { type: \"string\" },\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Non-path @param entries become query parameters\n\t\t\tconst nonPathParams = (symbol.documentation?.params ?? []).filter(\n\t\t\t\t(p) => !pathParams.includes(p.name),\n\t\t\t);\n\t\t\tfor (const param of nonPathParams) {\n\t\t\t\tparameters.push({\n\t\t\t\t\tname: param.name,\n\t\t\t\t\tin: \"query\",\n\t\t\t\t\tdescription: param.description,\n\t\t\t\t\tschema: { type: \"string\" },\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (parameters.length > 0) {\n\t\t\t\toperation.parameters = parameters;\n\t\t\t}\n\n\t\t\t// @returns becomes the 200 response description\n\t\t\tif (symbol.documentation?.returns) {\n\t\t\t\toperation.responses = {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: symbol.documentation.returns.description,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tpaths[path][method] = operation;\n\t\t}\n\t}\n\n\treturn paths;\n}\n\n// ---------------------------------------------------------------------------\n// Tag derivation\n// ---------------------------------------------------------------------------\n\n/**\n * Derives OpenAPI tag names from the unique source file basenames of the\n * provided types (without directory path or extension).\n *\n * @param types - The visible SDK types.\n * @returns A sorted, deduplicated array of tag name strings.\n * @internal\n */\nfunction deriveTagNames(types: SDKType[]): string[] {\n\tconst seen = new Set<string>();\n\tfor (const t of types) {\n\t\tconst basename = t.sourceFile.split(\"/\").pop() ?? t.sourceFile;\n\t\tconst withoutExt = basename.replace(/\\.[^.]+$/, \"\");\n\t\tseen.add(withoutExt);\n\t}\n\treturn Array.from(seen).sort();\n}\n","/**\n * Utility for mapping TypeScript type signatures to OpenAPI 3.2 schemas.\n * @public\n */\n\nimport type { OpenAPISchemaObject } from \"@forge-ts/core\";\n\nexport type { OpenAPISchemaObject };\n\n/**\n * Maps a TypeScript type signature string to an OpenAPI 3.2 schema object.\n *\n * Handles common primitives, arrays, unions, `Record<K, V>`, and falls back\n * to `{ type: \"object\" }` for anything it cannot parse.\n *\n * @param signature - A TypeScript type signature string, e.g. `\"string\"`, `\"number[]\"`,\n * `\"string | number\"`, `\"Record<string, boolean>\"`.\n * @returns An OpenAPI schema object.\n * @example\n * ```typescript\n * import { signatureToSchema } from \"@forge-ts/api\";\n * const schema = signatureToSchema(\"string[]\");\n * // { type: \"array\", items: { type: \"string\" } }\n * ```\n * @public\n */\nexport function signatureToSchema(signature: string): OpenAPISchemaObject {\n\tconst trimmed = signature.trim();\n\n\t// Strip trailing `| undefined` or `| null` for optional detection — callers\n\t// handle the required array separately; here we just produce the base schema.\n\tconst withoutUndefined = trimmed\n\t\t.replace(/\\s*\\|\\s*undefined/g, \"\")\n\t\t.replace(/\\s*\\|\\s*null/g, \"\")\n\t\t.trim();\n\n\t// Union type: A | B\n\tif (withoutUndefined.includes(\" | \")) {\n\t\tconst parts = splitUnion(withoutUndefined);\n\t\tif (parts.length > 1) {\n\t\t\treturn { oneOf: parts.map((p) => signatureToSchema(p)) };\n\t\t}\n\t}\n\n\t// Array shorthand: T[]\n\tconst arrayShorthand = /^(.+)\\[\\]$/.exec(withoutUndefined);\n\tif (arrayShorthand) {\n\t\treturn { type: \"array\", items: signatureToSchema(arrayShorthand[1]) };\n\t}\n\n\t// Generic Array<T>\n\tconst genericArray = /^Array<(.+)>$/.exec(withoutUndefined);\n\tif (genericArray) {\n\t\treturn { type: \"array\", items: signatureToSchema(genericArray[1]) };\n\t}\n\n\t// Record<string, V>\n\tconst record = /^Record<[^,]+,\\s*(.+)>$/.exec(withoutUndefined);\n\tif (record) {\n\t\treturn { type: \"object\", additionalProperties: signatureToSchema(record[1]) };\n\t}\n\n\t// Primitives\n\tswitch (withoutUndefined) {\n\t\tcase \"string\":\n\t\t\treturn { type: \"string\" };\n\t\tcase \"number\":\n\t\t\treturn { type: \"number\" };\n\t\tcase \"boolean\":\n\t\t\treturn { type: \"boolean\" };\n\t\tcase \"null\":\n\t\t\treturn { type: \"null\" };\n\t\tcase \"unknown\":\n\t\tcase \"any\":\n\t\t\treturn {};\n\t\tcase \"void\":\n\t\t\treturn { type: \"null\" };\n\t\tdefault:\n\t\t\treturn { type: \"object\" };\n\t}\n}\n\n/**\n * Splits a union type string by top-level `|` separators (ignoring `|` inside\n * angle brackets or parentheses).\n *\n * @param signature - A union type string such as `\"string | number | boolean\"`.\n * @returns An array of trimmed member type strings.\n * @internal\n */\nfunction splitUnion(signature: string): string[] {\n\tconst parts: string[] = [];\n\tlet depth = 0;\n\tlet start = 0;\n\n\tfor (let i = 0; i < signature.length; i++) {\n\t\tconst ch = signature[i];\n\t\tif (ch === \"<\" || ch === \"(\" || ch === \"{\") {\n\t\t\tdepth++;\n\t\t} else if (ch === \">\" || ch === \")\" || ch === \"}\") {\n\t\t\tdepth--;\n\t\t} else if (ch === \"|\" && depth === 0) {\n\t\t\tparts.push(signature.slice(start, i).trim());\n\t\t\tstart = i + 1;\n\t\t}\n\t}\n\n\tparts.push(signature.slice(start).trim());\n\treturn parts.filter(Boolean);\n}\n","import type { ForgeSymbol } from \"@forge-ts/core\";\nimport { Visibility } from \"@forge-ts/core\";\n\n/**\n * A single entry in the generated API reference.\n * @public\n */\nexport interface ReferenceEntry {\n\t/** Symbol name. */\n\tname: string;\n\t/** Symbol kind. */\n\tkind: ForgeSymbol[\"kind\"];\n\t/** TSDoc summary. */\n\tsummary?: string;\n\t/** Human-readable type signature. */\n\tsignature?: string;\n\t/** Resolved visibility level. */\n\tvisibility: Visibility;\n\t/** Deprecation notice, if present. */\n\tdeprecated?: string;\n\t/** Documented parameters. */\n\tparams?: Array<{ name: string; description: string; type?: string }>;\n\t/** Documented return value. */\n\treturns?: { description: string; type?: string };\n\t/** Documented thrown exceptions. */\n\tthrows?: Array<{ type?: string; description: string }>;\n\t/** Code examples from TSDoc `@example` tags. */\n\texamples?: Array<{ code: string; language: string }>;\n\t/** Nested child symbols (class methods, interface properties, enum members). */\n\tchildren?: ReferenceEntry[];\n\t/** Source file location. */\n\tlocation: { filePath: string; line: number };\n}\n\n/**\n * Builds a structured API reference from a list of exported symbols.\n *\n * Unlike the minimal stub, this version includes nested children (class\n * methods, interface properties) and all available TSDoc metadata.\n *\n * Symbols with {@link Visibility.Internal} or {@link Visibility.Private} are\n * excluded from the top-level results. Children with private/internal\n * visibility are also filtered out.\n *\n * @param symbols - All symbols from the AST walker.\n * @returns An array of {@link ReferenceEntry} objects sorted by name.\n * @example\n * ```typescript\n * import { buildReference } from \"@forge-ts/api\";\n * const entries = buildReference(symbols);\n * console.log(entries[0].name); // first symbol name, alphabetically\n * ```\n * @public\n */\nexport function buildReference(symbols: ForgeSymbol[]): ReferenceEntry[] {\n\treturn symbols\n\t\t.filter(\n\t\t\t(s) =>\n\t\t\t\ts.exported && s.visibility !== Visibility.Internal && s.visibility !== Visibility.Private,\n\t\t)\n\t\t.map(symbolToEntry)\n\t\t.sort((a, b) => a.name.localeCompare(b.name));\n}\n\n/**\n * Converts a single {@link ForgeSymbol} to a {@link ReferenceEntry}.\n *\n * @param symbol - The symbol to convert.\n * @returns A populated {@link ReferenceEntry}.\n * @internal\n */\nfunction symbolToEntry(symbol: ForgeSymbol): ReferenceEntry {\n\tconst entry: ReferenceEntry = {\n\t\tname: symbol.name,\n\t\tkind: symbol.kind,\n\t\tsummary: symbol.documentation?.summary,\n\t\tsignature: symbol.signature,\n\t\tvisibility: symbol.visibility,\n\t\tdeprecated: symbol.documentation?.deprecated,\n\t\tlocation: { filePath: symbol.filePath, line: symbol.line },\n\t};\n\n\tif (symbol.documentation?.params && symbol.documentation.params.length > 0) {\n\t\tentry.params = symbol.documentation.params;\n\t}\n\n\tif (symbol.documentation?.returns) {\n\t\tentry.returns = symbol.documentation.returns;\n\t}\n\n\tif (symbol.documentation?.throws && symbol.documentation.throws.length > 0) {\n\t\tentry.throws = symbol.documentation.throws;\n\t}\n\n\tif (symbol.documentation?.examples && symbol.documentation.examples.length > 0) {\n\t\tentry.examples = symbol.documentation.examples.map((ex) => ({\n\t\t\tcode: ex.code,\n\t\t\tlanguage: ex.language,\n\t\t}));\n\t}\n\n\tif (symbol.children && symbol.children.length > 0) {\n\t\tconst visibleChildren = symbol.children.filter(\n\t\t\t(c) => c.visibility !== Visibility.Internal && c.visibility !== Visibility.Private,\n\t\t);\n\t\tif (visibleChildren.length > 0) {\n\t\t\tentry.children = visibleChildren.map(symbolToEntry);\n\t\t}\n\t}\n\n\treturn entry;\n}\n","import type { ForgeSymbol } from \"@forge-ts/core\";\nimport { Visibility } from \"@forge-ts/core\";\n\n/**\n * A single property extracted from an interface or class symbol.\n * @public\n */\nexport interface SDKProperty {\n\t/** The property name. */\n\tname: string;\n\t/** The TypeScript type string of the property. */\n\ttype: string;\n\t/** TSDoc summary for this property. */\n\tdescription?: string;\n\t/** Whether the property is required (not optional). */\n\trequired: boolean;\n\t/** Deprecation notice, if present. */\n\tdeprecated?: string;\n}\n\n/**\n * An SDK type descriptor extracted from the symbol graph.\n * @public\n */\nexport interface SDKType {\n\t/** The symbol name. */\n\tname: string;\n\t/** Syntactic kind of the type. */\n\tkind: \"interface\" | \"type\" | \"class\" | \"enum\";\n\t/** Human-readable type signature. */\n\tsignature?: string;\n\t/** TSDoc summary. */\n\tdescription?: string;\n\t/** Deprecation notice, if present. */\n\tdeprecated?: string;\n\t/** Resolved visibility level. */\n\tvisibility: Visibility;\n\t/** Extracted properties (for interfaces, classes) or values (for enums). */\n\tproperties: SDKProperty[];\n\t/** Absolute path to the source file. */\n\tsourceFile: string;\n}\n\n/**\n * Extracts SDK-relevant types (interfaces, type aliases, classes, enums) from\n * a list of {@link ForgeSymbol} objects.\n *\n * Only exported symbols whose visibility is not {@link Visibility.Internal} or\n * {@link Visibility.Private} are included.\n *\n * @param symbols - The symbols produced by the core AST walker.\n * @returns An array of {@link SDKType} objects for public-facing type definitions.\n * @example\n * ```typescript\n * import { extractSDKTypes } from \"@forge-ts/api\";\n * const sdkTypes = extractSDKTypes(symbols);\n * console.log(sdkTypes.length); // number of public SDK types\n * ```\n * @public\n */\nexport function extractSDKTypes(symbols: ForgeSymbol[]): SDKType[] {\n\treturn symbols\n\t\t.filter(\n\t\t\t(s) =>\n\t\t\t\ts.exported &&\n\t\t\t\t(s.kind === \"interface\" || s.kind === \"type\" || s.kind === \"class\" || s.kind === \"enum\") &&\n\t\t\t\ts.visibility !== Visibility.Internal &&\n\t\t\t\ts.visibility !== Visibility.Private,\n\t\t)\n\t\t.map((s) => ({\n\t\t\tname: s.name,\n\t\t\tkind: s.kind as SDKType[\"kind\"],\n\t\t\tsignature: s.signature,\n\t\t\tdescription: s.documentation?.summary,\n\t\t\tdeprecated: s.documentation?.deprecated,\n\t\t\tvisibility: s.visibility,\n\t\t\tproperties: extractProperties(s),\n\t\t\tsourceFile: s.filePath,\n\t\t}));\n}\n\n/**\n * Extracts the property list from a symbol's children.\n *\n * For interfaces and classes, children with kind `\"property\"` are mapped to\n * {@link SDKProperty}. For enums, children with kind `\"property\"` (enum\n * members) are also included. Method children are excluded.\n *\n * @param symbol - The parent symbol whose children to extract from.\n * @returns An array of {@link SDKProperty} objects.\n * @internal\n */\nfunction extractProperties(symbol: ForgeSymbol): SDKProperty[] {\n\tif (!symbol.children || symbol.children.length === 0) {\n\t\treturn [];\n\t}\n\n\treturn symbol.children\n\t\t.filter(\n\t\t\t(child) =>\n\t\t\t\tchild.kind === \"property\" &&\n\t\t\t\tchild.visibility !== Visibility.Private &&\n\t\t\t\tchild.visibility !== Visibility.Internal,\n\t\t)\n\t\t.map((child) => {\n\t\t\tconst isOptional = child.signature ? child.signature.includes(\"?\") : false;\n\t\t\tconst rawType = resolveChildType(child);\n\t\t\treturn {\n\t\t\t\tname: child.name,\n\t\t\t\ttype: rawType,\n\t\t\t\tdescription: child.documentation?.summary,\n\t\t\t\trequired: !isOptional,\n\t\t\t\tdeprecated: child.documentation?.deprecated,\n\t\t\t};\n\t\t});\n}\n\n/**\n * Resolves the type string for a child symbol.\n *\n * Uses the signature if present; otherwise falls back to `\"unknown\"`.\n *\n * @param child - A child {@link ForgeSymbol}.\n * @returns A TypeScript type string.\n * @internal\n */\nfunction resolveChildType(child: ForgeSymbol): string {\n\tif (!child.signature) {\n\t\treturn \"unknown\";\n\t}\n\n\t// Signatures for properties often look like `name: type` or `name?: type`.\n\t// Strip the leading `name:` or `name?:` prefix to get the bare type.\n\tconst colonIndex = child.signature.indexOf(\":\");\n\tif (colonIndex !== -1) {\n\t\treturn child.signature.slice(colonIndex + 1).trim();\n\t}\n\n\treturn child.signature;\n}\n","/**\n * @forge-ts/api — OpenAPI spec and API reference generator.\n *\n * Extracts public SDK types from the symbol graph and generates an\n * OpenAPI 3.2 document and a structured API reference.\n *\n * @packageDocumentation\n */\n\nexport { generateOpenAPISpec, type OpenAPIDocument } from \"./openapi.js\";\nexport { buildReference, type ReferenceEntry } from \"./reference.js\";\nexport { type OpenAPISchemaObject, signatureToSchema } from \"./schema-mapper.js\";\nexport { extractSDKTypes, type SDKProperty, type SDKType } from \"./sdk-extractor.js\";\n\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { createWalker, type ForgeConfig, type ForgeResult } from \"@forge-ts/core\";\nimport { generateOpenAPISpec } from \"./openapi.js\";\nimport { extractSDKTypes } from \"./sdk-extractor.js\";\n\n/**\n * Runs the API generation pipeline: walk → extract → generate → write.\n *\n * @param config - The resolved {@link ForgeConfig} for the project.\n * @returns A {@link ForgeResult} with success/failure and any diagnostics.\n * @example\n * ```typescript\n * import { generateApi } from \"@forge-ts/api\";\n * const result = await generateApi(config);\n * console.log(result.success); // true if spec was written successfully\n * ```\n * @public\n * @packageDocumentation\n */\nexport async function generateApi(config: ForgeConfig): Promise<ForgeResult> {\n\tconst start = Date.now();\n\n\tconst walker = createWalker(config);\n\tconst symbols = walker.walk();\n\tconst sdkTypes = extractSDKTypes(symbols);\n\tconst spec = generateOpenAPISpec(config, sdkTypes, symbols);\n\n\tawait mkdir(dirname(config.api.openapiPath), { recursive: true });\n\tawait writeFile(config.api.openapiPath, JSON.stringify(spec, null, 2), \"utf8\");\n\n\treturn {\n\t\tsuccess: true,\n\t\tsymbols,\n\t\terrors: [],\n\t\twarnings: [],\n\t\tduration: Date.now() - start,\n\t};\n}\n"],"mappings":"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","names":["Visibility","Visibility"]}
1
+ {"version":3,"sources":["../src/openapi.ts","../src/schema-mapper.ts","../src/reference.ts","../src/sdk-extractor.ts","../src/index.ts"],"sourcesContent":["import type {\n\tForgeConfig,\n\tForgeSymbol,\n\tOpenAPIDocument,\n\tOpenAPIInfoObject,\n\tOpenAPIOperationObject,\n\tOpenAPIParameterObject,\n\tOpenAPIPathItemObject,\n\tOpenAPISchemaObject,\n} from \"@forge-ts/core\";\nimport { Visibility } from \"@forge-ts/core\";\nimport { signatureToSchema } from \"./schema-mapper.js\";\nimport type { SDKProperty, SDKType } from \"./sdk-extractor.js\";\n\nexport type { OpenAPIDocument };\n\n/**\n * Generates a production-quality OpenAPI 3.2 document from the extracted SDK\n * types.\n *\n * The document is populated with:\n * - An `info` block sourced from the config or reasonable defaults.\n * - A `components.schemas` section with one schema per exported type.\n * - `tags` derived from unique source file paths (grouping by file).\n * - Visibility filtering: `@internal` symbols are never emitted.\n * - HTTP paths are extracted from `@route` tags and appropriately mapped.\n *\n * @param config - The resolved {@link ForgeConfig}.\n * @param sdkTypes - SDK types to include as component schemas.\n * @param symbols - Raw symbols used to extract HTTP route paths from `@route` tags.\n * @returns An {@link OpenAPIDocument} object.\n * @example\n * ```typescript\n * import { generateOpenAPISpec } from \"@forge-ts/api\";\n * import { extractSDKTypes } from \"@forge-ts/api\";\n * const spec = generateOpenAPISpec(config, extractSDKTypes(symbols), symbols);\n * console.log(spec.openapi); // \"3.2.0\"\n * ```\n * @public\n */\nexport function generateOpenAPISpec(\n\tconfig: ForgeConfig,\n\tsdkTypes: SDKType[],\n\tsymbols: ForgeSymbol[] = [],\n): OpenAPIDocument {\n\t// Visibility filtering: never emit @internal or @private symbols.\n\tconst visibleTypes = sdkTypes.filter(\n\t\t(t) => t.visibility !== Visibility.Internal && t.visibility !== Visibility.Private,\n\t);\n\n\tconst schemas: Record<string, OpenAPISchemaObject> = {};\n\tfor (const t of visibleTypes) {\n\t\tschemas[t.name] = buildSchema(t);\n\t}\n\n\t// Derive tags from unique source files (basename without extension).\n\tconst tagNames = deriveTagNames(visibleTypes);\n\tconst tags = tagNames.map((name) => ({ name }));\n\n\tconst paths = extractPaths(symbols);\n\n\treturn {\n\t\topenapi: \"3.2.0\",\n\t\tinfo: buildInfo(config),\n\t\t...(tags.length > 0 ? { tags } : {}),\n\t\tpaths,\n\t\tcomponents: { schemas },\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Info block\n// ---------------------------------------------------------------------------\n\n/**\n * Builds the OpenAPI `info` block from the config.\n *\n * @param config - The resolved {@link ForgeConfig}.\n * @returns An info object with title, version, and description.\n * @internal\n */\nfunction buildInfo(_config: ForgeConfig): OpenAPIInfoObject {\n\t// We attempt to read name/version from the project root's package.json at\n\t// runtime. If unavailable, fall back to safe defaults.\n\treturn {\n\t\ttitle: \"API Reference\",\n\t\tversion: \"0.0.0\",\n\t\tdescription: \"Generated by forge-ts\",\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Schema builders\n// ---------------------------------------------------------------------------\n\n/**\n * Converts an {@link SDKType} to an OpenAPI schema object.\n *\n * - `interface` / `class` → object schema with `properties` and `required`\n * - `enum` → schema with `enum` array and `type: \"string\"`\n * - `type` alias → schema derived from signature parsing\n *\n * @param sdkType - The type descriptor to convert.\n * @returns An OpenAPI schema object.\n * @internal\n */\nfunction buildSchema(sdkType: SDKType): OpenAPISchemaObject {\n\tconst base: OpenAPISchemaObject = {};\n\n\tif (sdkType.description) {\n\t\tbase.description = sdkType.description;\n\t}\n\n\tif (sdkType.deprecated) {\n\t\tbase.deprecated = true;\n\t}\n\n\tswitch (sdkType.kind) {\n\t\tcase \"interface\":\n\t\tcase \"class\":\n\t\t\treturn { ...base, ...buildObjectSchema(sdkType) };\n\t\tcase \"enum\":\n\t\t\treturn { ...base, ...buildEnumSchema(sdkType) };\n\t\tcase \"type\":\n\t\t\treturn { ...base, ...buildTypeAliasSchema(sdkType) };\n\t\tdefault:\n\t\t\treturn { ...base, type: \"object\" };\n\t}\n}\n\n/**\n * Builds an object schema for an interface or class type.\n *\n * @param sdkType - An interface or class {@link SDKType}.\n * @returns An OpenAPI object schema.\n * @internal\n */\nfunction buildObjectSchema(sdkType: SDKType): OpenAPISchemaObject {\n\tif (sdkType.properties.length === 0) {\n\t\treturn { type: \"object\" };\n\t}\n\n\tconst properties: Record<string, OpenAPISchemaObject> = {};\n\tconst required: string[] = [];\n\n\tfor (const prop of sdkType.properties) {\n\t\tproperties[prop.name] = buildPropertySchema(prop);\n\t\tif (prop.required) {\n\t\t\trequired.push(prop.name);\n\t\t}\n\t}\n\n\tconst schema: OpenAPISchemaObject = { type: \"object\", properties };\n\tif (required.length > 0) {\n\t\tschema.required = required;\n\t}\n\n\treturn schema;\n}\n\n/**\n * Builds the schema for a single property.\n *\n * @param prop - The {@link SDKProperty} to convert.\n * @returns A partial OpenAPI schema for the property.\n * @internal\n */\nfunction buildPropertySchema(prop: SDKProperty): OpenAPISchemaObject {\n\tconst schema: OpenAPISchemaObject = { ...signatureToSchema(prop.type) };\n\n\tif (prop.description) {\n\t\tschema.description = prop.description;\n\t}\n\n\tif (prop.deprecated) {\n\t\tschema.deprecated = true;\n\t}\n\n\treturn schema;\n}\n\n/**\n * Builds an enum schema for an enum type.\n *\n * If the enum has properties (members), their names are used as the enum\n * values. The type defaults to `\"string\"` unless a member type suggests\n * otherwise.\n *\n * @param sdkType - An enum {@link SDKType}.\n * @returns An OpenAPI schema with `enum` values.\n * @internal\n */\nfunction buildEnumSchema(sdkType: SDKType): OpenAPISchemaObject {\n\tif (sdkType.properties.length === 0) {\n\t\treturn { type: \"string\", enum: [] };\n\t}\n\n\tconst values = sdkType.properties.map((p) => {\n\t\t// Use the type value if it looks like a string literal; otherwise use name.\n\t\tconst t = p.type.trim();\n\t\tif (t.startsWith('\"') || t.startsWith(\"'\")) {\n\t\t\treturn t.replace(/^['\"]|['\"]$/g, \"\");\n\t\t}\n\t\treturn p.name;\n\t});\n\n\t// Detect numeric enums: if all values are parseable numbers use \"number\".\n\tconst allNumeric = values.every((v) => !Number.isNaN(Number(v)));\n\n\treturn {\n\t\ttype: allNumeric ? \"number\" : \"string\",\n\t\tenum: allNumeric ? values.map(Number) : values,\n\t};\n}\n\n/**\n * Builds a schema for a type alias.\n *\n * Attempts to parse the signature string directly; falls back to\n * `{ type: \"object\" }` for complex generics or intersections.\n *\n * @param sdkType - A type alias {@link SDKType}.\n * @returns An OpenAPI schema.\n * @internal\n */\nfunction buildTypeAliasSchema(sdkType: SDKType): OpenAPISchemaObject {\n\tif (!sdkType.signature) {\n\t\treturn { type: \"object\" };\n\t}\n\n\t// The signature for a type alias is often `type Name = ActualType`.\n\t// Strip the leading declaration if present.\n\tconst equalsIndex = sdkType.signature.indexOf(\"=\");\n\tconst rawType =\n\t\tequalsIndex !== -1 ? sdkType.signature.slice(equalsIndex + 1).trim() : sdkType.signature;\n\n\treturn signatureToSchema(rawType);\n}\n\n// ---------------------------------------------------------------------------\n// Path extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Builds OpenAPI path items from symbols that carry `@route` TSDoc tags.\n *\n * Each `@route` tag must be in the format `METHOD /path` (e.g. `GET /users/{id}`).\n * Path template variables like `{id}` are emitted as required path parameters.\n * Any `@param` entries not matched to a path variable become query parameters.\n *\n * @param symbols - All {@link ForgeSymbol} instances from the walker.\n * @returns A map of path template strings to their OpenAPI path item objects.\n * @internal\n */\nfunction extractPaths(symbols: ForgeSymbol[]): Record<string, OpenAPIPathItemObject> {\n\tconst paths: Record<string, OpenAPIPathItemObject> = {};\n\n\tfor (const symbol of symbols) {\n\t\tconst routeTags: string[] = symbol.documentation?.tags?.route ?? [];\n\t\tfor (const routeTag of routeTags) {\n\t\t\tconst match = routeTag.match(/^(GET|POST|PUT|DELETE|PATCH|OPTIONS|HEAD)\\s+(\\S+)/i);\n\t\t\tif (!match) continue;\n\n\t\t\tconst method = match[1].toLowerCase() as\n\t\t\t\t| \"get\"\n\t\t\t\t| \"post\"\n\t\t\t\t| \"put\"\n\t\t\t\t| \"delete\"\n\t\t\t\t| \"patch\"\n\t\t\t\t| \"options\"\n\t\t\t\t| \"head\";\n\t\t\tconst path = match[2];\n\n\t\t\tif (!paths[path]) {\n\t\t\t\tpaths[path] = {};\n\t\t\t}\n\n\t\t\tconst fileBasename = symbol.filePath.split(\"/\").pop()?.replace(/\\.ts$/, \"\") ?? \"default\";\n\n\t\t\tconst operation: OpenAPIOperationObject = {\n\t\t\t\toperationId: symbol.name,\n\t\t\t\tsummary: symbol.documentation?.summary,\n\t\t\t\tdescription: symbol.documentation?.summary,\n\t\t\t\ttags: [fileBasename],\n\t\t\t};\n\n\t\t\t// Extract path template variables like {id}\n\t\t\tconst pathParams = [...path.matchAll(/\\{(\\w+)\\}/g)].map((m) => m[1]);\n\t\t\tconst parameters: OpenAPIParameterObject[] = [];\n\n\t\t\tfor (const paramName of pathParams) {\n\t\t\t\tconst paramDoc = symbol.documentation?.params?.find((p) => p.name === paramName);\n\t\t\t\tparameters.push({\n\t\t\t\t\tname: paramName,\n\t\t\t\t\tin: \"path\",\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdescription: paramDoc?.description ?? `The ${paramName} parameter`,\n\t\t\t\t\tschema: { type: \"string\" },\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Non-path @param entries become query parameters\n\t\t\tconst nonPathParams = (symbol.documentation?.params ?? []).filter(\n\t\t\t\t(p) => !pathParams.includes(p.name),\n\t\t\t);\n\t\t\tfor (const param of nonPathParams) {\n\t\t\t\tparameters.push({\n\t\t\t\t\tname: param.name,\n\t\t\t\t\tin: \"query\",\n\t\t\t\t\tdescription: param.description,\n\t\t\t\t\tschema: { type: \"string\" },\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (parameters.length > 0) {\n\t\t\t\toperation.parameters = parameters;\n\t\t\t}\n\n\t\t\t// @returns becomes the 200 response description\n\t\t\tif (symbol.documentation?.returns) {\n\t\t\t\toperation.responses = {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: symbol.documentation.returns.description,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tpaths[path][method] = operation;\n\t\t}\n\t}\n\n\treturn paths;\n}\n\n// ---------------------------------------------------------------------------\n// Tag derivation\n// ---------------------------------------------------------------------------\n\n/**\n * Derives OpenAPI tag names from the unique source file basenames of the\n * provided types (without directory path or extension).\n *\n * @param types - The visible SDK types.\n * @returns A sorted, deduplicated array of tag name strings.\n * @internal\n */\nfunction deriveTagNames(types: SDKType[]): string[] {\n\tconst seen = new Set<string>();\n\tfor (const t of types) {\n\t\tconst basename = t.sourceFile.split(\"/\").pop() ?? t.sourceFile;\n\t\tconst withoutExt = basename.replace(/\\.[^.]+$/, \"\");\n\t\tseen.add(withoutExt);\n\t}\n\treturn Array.from(seen).sort();\n}\n","/**\n * Utility for mapping TypeScript type signatures to OpenAPI 3.2 schemas.\n * @public\n */\n\nimport type { OpenAPISchemaObject } from \"@forge-ts/core\";\n\nexport type { OpenAPISchemaObject };\n\n/**\n * Maps a TypeScript type signature string to an OpenAPI 3.2 schema object.\n *\n * Handles common primitives, arrays, unions, `Record<K, V>`, and falls back\n * to `{ type: \"object\" }` for anything it cannot parse.\n *\n * @param signature - A TypeScript type signature string, e.g. `\"string\"`, `\"number[]\"`,\n * `\"string | number\"`, `\"Record<string, boolean>\"`.\n * @returns An OpenAPI schema object.\n * @example\n * ```typescript\n * import { signatureToSchema } from \"@forge-ts/api\";\n * const schema = signatureToSchema(\"string[]\");\n * // { type: \"array\", items: { type: \"string\" } }\n * ```\n * @public\n */\nexport function signatureToSchema(signature: string): OpenAPISchemaObject {\n\tconst trimmed = signature.trim();\n\n\t// Strip trailing `| undefined` or `| null` for optional detection — callers\n\t// handle the required array separately; here we just produce the base schema.\n\tconst withoutUndefined = trimmed\n\t\t.replace(/\\s*\\|\\s*undefined/g, \"\")\n\t\t.replace(/\\s*\\|\\s*null/g, \"\")\n\t\t.trim();\n\n\t// Union type: A | B\n\tif (withoutUndefined.includes(\" | \")) {\n\t\tconst parts = splitUnion(withoutUndefined);\n\t\tif (parts.length > 1) {\n\t\t\treturn { oneOf: parts.map((p) => signatureToSchema(p)) };\n\t\t}\n\t}\n\n\t// Array shorthand: T[]\n\tconst arrayShorthand = /^(.+)\\[\\]$/.exec(withoutUndefined);\n\tif (arrayShorthand) {\n\t\treturn { type: \"array\", items: signatureToSchema(arrayShorthand[1]) };\n\t}\n\n\t// Generic Array<T>\n\tconst genericArray = /^Array<(.+)>$/.exec(withoutUndefined);\n\tif (genericArray) {\n\t\treturn { type: \"array\", items: signatureToSchema(genericArray[1]) };\n\t}\n\n\t// Record<string, V>\n\tconst record = /^Record<[^,]+,\\s*(.+)>$/.exec(withoutUndefined);\n\tif (record) {\n\t\treturn { type: \"object\", additionalProperties: signatureToSchema(record[1]) };\n\t}\n\n\t// Primitives\n\tswitch (withoutUndefined) {\n\t\tcase \"string\":\n\t\t\treturn { type: \"string\" };\n\t\tcase \"number\":\n\t\t\treturn { type: \"number\" };\n\t\tcase \"boolean\":\n\t\t\treturn { type: \"boolean\" };\n\t\tcase \"null\":\n\t\t\treturn { type: \"null\" };\n\t\tcase \"unknown\":\n\t\tcase \"any\":\n\t\t\treturn {};\n\t\tcase \"void\":\n\t\t\treturn { type: \"null\" };\n\t\tdefault:\n\t\t\treturn { type: \"object\" };\n\t}\n}\n\n/**\n * Splits a union type string by top-level `|` separators (ignoring `|` inside\n * angle brackets or parentheses).\n *\n * @param signature - A union type string such as `\"string | number | boolean\"`.\n * @returns An array of trimmed member type strings.\n * @internal\n */\nfunction splitUnion(signature: string): string[] {\n\tconst parts: string[] = [];\n\tlet depth = 0;\n\tlet start = 0;\n\n\tfor (let i = 0; i < signature.length; i++) {\n\t\tconst ch = signature[i];\n\t\tif (ch === \"<\" || ch === \"(\" || ch === \"{\") {\n\t\t\tdepth++;\n\t\t} else if (ch === \">\" || ch === \")\" || ch === \"}\") {\n\t\t\tdepth--;\n\t\t} else if (ch === \"|\" && depth === 0) {\n\t\t\tparts.push(signature.slice(start, i).trim());\n\t\t\tstart = i + 1;\n\t\t}\n\t}\n\n\tparts.push(signature.slice(start).trim());\n\treturn parts.filter(Boolean);\n}\n","import type { ForgeSymbol } from \"@forge-ts/core\";\nimport { Visibility } from \"@forge-ts/core\";\n\n/**\n * A single entry in the generated API reference.\n * @public\n */\nexport interface ReferenceEntry {\n\t/** Symbol name. */\n\tname: string;\n\t/** Symbol kind. */\n\tkind: ForgeSymbol[\"kind\"];\n\t/** TSDoc summary. */\n\tsummary?: string;\n\t/** Human-readable type signature. */\n\tsignature?: string;\n\t/** Resolved visibility level. */\n\tvisibility: Visibility;\n\t/** Deprecation notice, if present. */\n\tdeprecated?: string;\n\t/** Documented parameters. */\n\tparams?: Array<{ name: string; description: string; type?: string }>;\n\t/** Documented return value. */\n\treturns?: { description: string; type?: string };\n\t/** Documented thrown exceptions. */\n\tthrows?: Array<{ type?: string; description: string }>;\n\t/** Code examples from TSDoc `@example` tags. */\n\texamples?: Array<{ code: string; language: string }>;\n\t/** Nested child symbols (class methods, interface properties, enum members). */\n\tchildren?: ReferenceEntry[];\n\t/** Source file location. */\n\tlocation: { filePath: string; line: number };\n}\n\n/**\n * Builds a structured API reference from a list of exported symbols.\n *\n * Unlike the minimal stub, this version includes nested children (class\n * methods, interface properties) and all available TSDoc metadata.\n *\n * Symbols with {@link Visibility.Internal} or {@link Visibility.Private} are\n * excluded from the top-level results. Children with private/internal\n * visibility are also filtered out.\n *\n * @param symbols - All symbols from the AST walker.\n * @returns An array of {@link ReferenceEntry} objects sorted by name.\n * @example\n * ```typescript\n * import { buildReference } from \"@forge-ts/api\";\n * const entries = buildReference(symbols);\n * console.log(entries[0].name); // first symbol name, alphabetically\n * ```\n * @public\n */\nexport function buildReference(symbols: ForgeSymbol[]): ReferenceEntry[] {\n\treturn symbols\n\t\t.filter(\n\t\t\t(s) =>\n\t\t\t\ts.exported && s.visibility !== Visibility.Internal && s.visibility !== Visibility.Private,\n\t\t)\n\t\t.map(symbolToEntry)\n\t\t.sort((a, b) => a.name.localeCompare(b.name));\n}\n\n/**\n * Converts a single {@link ForgeSymbol} to a {@link ReferenceEntry}.\n *\n * @param symbol - The symbol to convert.\n * @returns A populated {@link ReferenceEntry}.\n * @internal\n */\nfunction symbolToEntry(symbol: ForgeSymbol): ReferenceEntry {\n\tconst entry: ReferenceEntry = {\n\t\tname: symbol.name,\n\t\tkind: symbol.kind,\n\t\tsummary: symbol.documentation?.summary,\n\t\tsignature: symbol.signature,\n\t\tvisibility: symbol.visibility,\n\t\tdeprecated: symbol.documentation?.deprecated,\n\t\tlocation: { filePath: symbol.filePath, line: symbol.line },\n\t};\n\n\tif (symbol.documentation?.params && symbol.documentation.params.length > 0) {\n\t\tentry.params = symbol.documentation.params;\n\t}\n\n\tif (symbol.documentation?.returns) {\n\t\tentry.returns = symbol.documentation.returns;\n\t}\n\n\tif (symbol.documentation?.throws && symbol.documentation.throws.length > 0) {\n\t\tentry.throws = symbol.documentation.throws;\n\t}\n\n\tif (symbol.documentation?.examples && symbol.documentation.examples.length > 0) {\n\t\tentry.examples = symbol.documentation.examples.map((ex) => ({\n\t\t\tcode: ex.code,\n\t\t\tlanguage: ex.language,\n\t\t}));\n\t}\n\n\tif (symbol.children && symbol.children.length > 0) {\n\t\tconst visibleChildren = symbol.children.filter(\n\t\t\t(c) => c.visibility !== Visibility.Internal && c.visibility !== Visibility.Private,\n\t\t);\n\t\tif (visibleChildren.length > 0) {\n\t\t\tentry.children = visibleChildren.map(symbolToEntry);\n\t\t}\n\t}\n\n\treturn entry;\n}\n","import type { ForgeSymbol } from \"@forge-ts/core\";\nimport { Visibility } from \"@forge-ts/core\";\n\n/**\n * A single property extracted from an interface or class symbol.\n * @public\n */\nexport interface SDKProperty {\n\t/** The property name. */\n\tname: string;\n\t/** The TypeScript type string of the property. */\n\ttype: string;\n\t/** TSDoc summary for this property. */\n\tdescription?: string;\n\t/** Whether the property is required (not optional). */\n\trequired: boolean;\n\t/** Deprecation notice, if present. */\n\tdeprecated?: string;\n}\n\n/**\n * An SDK type descriptor extracted from the symbol graph.\n * @public\n */\nexport interface SDKType {\n\t/** The symbol name. */\n\tname: string;\n\t/** Syntactic kind of the type. */\n\tkind: \"interface\" | \"type\" | \"class\" | \"enum\";\n\t/** Human-readable type signature. */\n\tsignature?: string;\n\t/** TSDoc summary. */\n\tdescription?: string;\n\t/** Deprecation notice, if present. */\n\tdeprecated?: string;\n\t/** Resolved visibility level. */\n\tvisibility: Visibility;\n\t/** Extracted properties (for interfaces, classes) or values (for enums). */\n\tproperties: SDKProperty[];\n\t/** Absolute path to the source file. */\n\tsourceFile: string;\n}\n\n/**\n * Extracts SDK-relevant types (interfaces, type aliases, classes, enums) from\n * a list of {@link ForgeSymbol} objects.\n *\n * Only exported symbols whose visibility is not {@link Visibility.Internal} or\n * {@link Visibility.Private} are included.\n *\n * @param symbols - The symbols produced by the core AST walker.\n * @returns An array of {@link SDKType} objects for public-facing type definitions.\n * @example\n * ```typescript\n * import { extractSDKTypes } from \"@forge-ts/api\";\n * const sdkTypes = extractSDKTypes(symbols);\n * console.log(sdkTypes.length); // number of public SDK types\n * ```\n * @public\n */\nexport function extractSDKTypes(symbols: ForgeSymbol[]): SDKType[] {\n\treturn symbols\n\t\t.filter(\n\t\t\t(s) =>\n\t\t\t\ts.exported &&\n\t\t\t\t(s.kind === \"interface\" || s.kind === \"type\" || s.kind === \"class\" || s.kind === \"enum\") &&\n\t\t\t\ts.visibility !== Visibility.Internal &&\n\t\t\t\ts.visibility !== Visibility.Private,\n\t\t)\n\t\t.map((s) => ({\n\t\t\tname: s.name,\n\t\t\tkind: s.kind as SDKType[\"kind\"],\n\t\t\tsignature: s.signature,\n\t\t\tdescription: s.documentation?.summary,\n\t\t\tdeprecated: s.documentation?.deprecated,\n\t\t\tvisibility: s.visibility,\n\t\t\tproperties: extractProperties(s),\n\t\t\tsourceFile: s.filePath,\n\t\t}));\n}\n\n/**\n * Extracts the property list from a symbol's children.\n *\n * For interfaces and classes, children with kind `\"property\"` are mapped to\n * {@link SDKProperty}. For enums, children with kind `\"property\"` (enum\n * members) are also included. Method children are excluded.\n *\n * @param symbol - The parent symbol whose children to extract from.\n * @returns An array of {@link SDKProperty} objects.\n * @internal\n */\nfunction extractProperties(symbol: ForgeSymbol): SDKProperty[] {\n\tif (!symbol.children || symbol.children.length === 0) {\n\t\treturn [];\n\t}\n\n\treturn symbol.children\n\t\t.filter(\n\t\t\t(child) =>\n\t\t\t\tchild.kind === \"property\" &&\n\t\t\t\tchild.visibility !== Visibility.Private &&\n\t\t\t\tchild.visibility !== Visibility.Internal,\n\t\t)\n\t\t.map((child) => {\n\t\t\tconst isOptional = child.signature ? child.signature.includes(\"?\") : false;\n\t\t\tconst rawType = resolveChildType(child);\n\t\t\treturn {\n\t\t\t\tname: child.name,\n\t\t\t\ttype: rawType,\n\t\t\t\tdescription: child.documentation?.summary,\n\t\t\t\trequired: !isOptional,\n\t\t\t\tdeprecated: child.documentation?.deprecated,\n\t\t\t};\n\t\t});\n}\n\n/**\n * Resolves the type string for a child symbol.\n *\n * Uses the signature if present; otherwise falls back to `\"unknown\"`.\n *\n * @param child - A child {@link ForgeSymbol}.\n * @returns A TypeScript type string.\n * @internal\n */\nfunction resolveChildType(child: ForgeSymbol): string {\n\tif (!child.signature) {\n\t\treturn \"unknown\";\n\t}\n\n\t// Signatures for properties often look like `name: type` or `name?: type`.\n\t// Strip the leading `name:` or `name?:` prefix to get the bare type.\n\tconst colonIndex = child.signature.indexOf(\":\");\n\tif (colonIndex !== -1) {\n\t\treturn child.signature.slice(colonIndex + 1).trim();\n\t}\n\n\treturn child.signature;\n}\n","/**\n * @forge-ts/api — OpenAPI spec and API reference generator.\n *\n * Extracts public SDK types from the symbol graph and generates an\n * OpenAPI 3.2 document and a structured API reference.\n *\n * @packageDocumentation\n */\n\nexport { generateOpenAPISpec, type OpenAPIDocument } from \"./openapi.js\";\nexport { buildReference, type ReferenceEntry } from \"./reference.js\";\nexport { type OpenAPISchemaObject, signatureToSchema } from \"./schema-mapper.js\";\nexport { extractSDKTypes, type SDKProperty, type SDKType } from \"./sdk-extractor.js\";\n\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { createWalker, type ForgeConfig, type ForgeResult } from \"@forge-ts/core\";\nimport { generateOpenAPISpec } from \"./openapi.js\";\nimport { extractSDKTypes } from \"./sdk-extractor.js\";\n\n/**\n * Runs the API generation pipeline: walk → extract → generate → write.\n *\n * @param config - The resolved {@link ForgeConfig} for the project.\n * @returns A {@link ForgeResult} with success/failure and any diagnostics.\n * @example\n * ```typescript\n * import { generateApi } from \"@forge-ts/api\";\n * const result = await generateApi(config);\n * console.log(result.success); // true if spec was written successfully\n * ```\n * @public\n * @packageDocumentation\n */\nexport async function generateApi(config: ForgeConfig): Promise<ForgeResult> {\n\tconst start = Date.now();\n\n\tconst walker = createWalker(config);\n\tconst symbols = walker.walk();\n\tconst sdkTypes = extractSDKTypes(symbols);\n\tconst spec = generateOpenAPISpec(config, sdkTypes, symbols);\n\n\tawait mkdir(dirname(config.api.openapiPath), { recursive: true });\n\tawait writeFile(config.api.openapiPath, JSON.stringify(spec, null, 2), \"utf8\");\n\n\treturn {\n\t\tsuccess: true,\n\t\tsymbols,\n\t\terrors: [],\n\t\twarnings: [],\n\t\tduration: Date.now() - start,\n\t};\n}\n"],"mappings":"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","names":["Visibility","Visibility"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forge-ts/api",
3
- "version": "0.19.0",
3
+ "version": "0.19.1",
4
4
  "type": "module",
5
5
  "description": "OpenAPI spec and API reference generator for forge-ts",
6
6
  "license": "MIT",
@@ -24,7 +24,7 @@
24
24
  }
25
25
  },
26
26
  "dependencies": {
27
- "@forge-ts/core": "0.19.0"
27
+ "@forge-ts/core": "0.19.1"
28
28
  },
29
29
  "devDependencies": {
30
30
  "tsup": "^8.3.5",