@forge-ts/core 0.3.0 → 0.4.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.
package/dist/index.d.ts CHANGED
@@ -49,6 +49,11 @@ interface ForgeSymbol {
49
49
  }>;
50
50
  tags?: Record<string, string[]>;
51
51
  deprecated?: string;
52
+ /** {@link} cross-references found in this symbol's TSDoc. */
53
+ links?: Array<{
54
+ target: string;
55
+ line: number;
56
+ }>;
52
57
  };
53
58
  /** Human-readable type signature of the symbol. */
54
59
  signature?: string;
@@ -57,6 +62,35 @@ interface ForgeSymbol {
57
62
  /** Whether this symbol is part of the public module exports. */
58
63
  exported: boolean;
59
64
  }
65
+ /**
66
+ * Severity level for an individual enforcement rule.
67
+ * - `"error"` — violation fails the build.
68
+ * - `"warn"` — violation is reported but does not fail the build.
69
+ * - `"off"` — rule is disabled entirely.
70
+ * @public
71
+ */
72
+ type RuleSeverity = "error" | "warn" | "off";
73
+ /**
74
+ * Per-rule severity configuration for the TSDoc enforcer.
75
+ * Each key corresponds to one of the E001–E007 rule codes.
76
+ * @public
77
+ */
78
+ interface EnforceRules {
79
+ /** E001: Exported symbol missing TSDoc summary. */
80
+ "require-summary": RuleSeverity;
81
+ /** E002: Function parameter missing @param tag. */
82
+ "require-param": RuleSeverity;
83
+ /** E003: Non-void function missing @returns tag. */
84
+ "require-returns": RuleSeverity;
85
+ /** E004: Exported function missing @example block. */
86
+ "require-example": RuleSeverity;
87
+ /** E005: Entry point missing @packageDocumentation. */
88
+ "require-package-doc": RuleSeverity;
89
+ /** E006: Class member missing documentation. */
90
+ "require-class-member-doc": RuleSeverity;
91
+ /** E007: Interface/type member missing documentation. */
92
+ "require-interface-member-doc": RuleSeverity;
93
+ }
60
94
  /**
61
95
  * Full configuration for a forge-ts run.
62
96
  * Loaded from forge-ts.config.ts or the "forge-ts" key in package.json.
@@ -76,6 +110,8 @@ interface ForgeConfig {
76
110
  minVisibility: Visibility;
77
111
  /** Fail on warnings rather than only on errors. */
78
112
  strict: boolean;
113
+ /** Per-rule severity overrides. When strict is true, all "warn" become "error". */
114
+ rules: EnforceRules;
79
115
  };
80
116
  /** DocTest configuration. */
81
117
  doctest: {
@@ -164,6 +200,12 @@ interface ForgeWarning {
164
200
  *
165
201
  * @param rootDir - Absolute path to the project root.
166
202
  * @returns A fully-populated default configuration.
203
+ * @example
204
+ * ```typescript
205
+ * import { defaultConfig } from "@forge-ts/core";
206
+ * const config = defaultConfig("/path/to/project");
207
+ * console.log(config.enforce.enabled); // true
208
+ * ```
167
209
  * @public
168
210
  */
169
211
  declare function defaultConfig(rootDir: string): ForgeConfig;
@@ -178,6 +220,12 @@ declare function defaultConfig(rootDir: string): ForgeConfig;
178
220
  *
179
221
  * @param rootDir - The project root to search for config. Defaults to `process.cwd()`.
180
222
  * @returns A fully-resolved {@link ForgeConfig}.
223
+ * @example
224
+ * ```typescript
225
+ * import { loadConfig } from "@forge-ts/core";
226
+ * const config = await loadConfig("/path/to/project");
227
+ * // config is fully resolved with defaults
228
+ * ```
181
229
  * @public
182
230
  */
183
231
  declare function loadConfig(rootDir?: string): Promise<ForgeConfig>;
@@ -196,20 +244,35 @@ declare function loadConfig(rootDir?: string): Promise<ForgeConfig>;
196
244
  * @public
197
245
  */
198
246
  interface OpenAPISchemaObject {
247
+ /** The data type of the schema (e.g., "string", "number", "object", "array"). */
199
248
  type?: "string" | "number" | "integer" | "boolean" | "array" | "object" | "null";
249
+ /** A format hint for the data type (e.g., "int32", "date-time", "email", "uuid"). */
200
250
  format?: string;
251
+ /** A human-readable description of the schema's purpose or constraints. */
201
252
  description?: string;
253
+ /** Property definitions for object-type schemas. Maps each property name to its schema. */
202
254
  properties?: Record<string, OpenAPISchemaObject>;
255
+ /** List of property names that must be present on the object. */
203
256
  required?: string[];
257
+ /** Schema definition for the elements of an array-type schema. Required when `type` is "array". */
204
258
  items?: OpenAPISchemaObject;
259
+ /** Controls whether additional properties are allowed (`true`/`false`) or defines their schema. */
205
260
  additionalProperties?: boolean | OpenAPISchemaObject;
261
+ /** Restricts the value to one of the listed constants. */
206
262
  enum?: Array<string | number | boolean>;
263
+ /** Validates the value against exactly one of the listed sub-schemas. */
207
264
  oneOf?: OpenAPISchemaObject[];
265
+ /** Validates the value against all of the listed sub-schemas (intersection). */
208
266
  allOf?: OpenAPISchemaObject[];
267
+ /** Validates the value against at least one of the listed sub-schemas. */
209
268
  anyOf?: OpenAPISchemaObject[];
269
+ /** Indicates that the value may be `null` in addition to its declared type. */
210
270
  nullable?: boolean;
271
+ /** Marks the schema as deprecated, signalling that it may be removed in a future version. */
211
272
  deprecated?: boolean;
273
+ /** The default value to use when the property is absent. */
212
274
  default?: string | number | boolean | null;
275
+ /** A JSON Reference (`$ref`) pointing to another schema definition in the document. */
213
276
  $ref?: string;
214
277
  }
215
278
  /**
@@ -217,10 +280,15 @@ interface OpenAPISchemaObject {
217
280
  * @public
218
281
  */
219
282
  interface OpenAPIInfoObject {
283
+ /** The human-readable name of the API. */
220
284
  title: string;
285
+ /** The version string for the API (e.g., "1.0.0"). */
221
286
  version: string;
287
+ /** A detailed description of the API, supporting CommonMark markdown. */
222
288
  description?: string;
289
+ /** A short summary of the API, intended for display in tooling. */
223
290
  summary?: string;
291
+ /** Licensing information for the exposed API, including name, URL, and SPDX identifier. */
224
292
  license?: {
225
293
  name: string;
226
294
  url?: string;
@@ -232,7 +300,9 @@ interface OpenAPIInfoObject {
232
300
  * @public
233
301
  */
234
302
  interface OpenAPITagObject {
303
+ /** The name of the tag, used to group operations in the document. */
235
304
  name: string;
305
+ /** An optional description of the tag, supporting CommonMark markdown. */
236
306
  description?: string;
237
307
  }
238
308
  /**
@@ -240,17 +310,29 @@ interface OpenAPITagObject {
240
310
  * @public
241
311
  */
242
312
  interface OpenAPIPathItemObject {
313
+ /** A short summary of the path item, intended for tooling display. */
243
314
  summary?: string;
315
+ /** A detailed description of the path item, supporting CommonMark markdown. */
244
316
  description?: string;
317
+ /** The operation definition for HTTP GET requests to this path. */
245
318
  get?: OpenAPIOperationObject;
319
+ /** The operation definition for HTTP POST requests to this path. */
246
320
  post?: OpenAPIOperationObject;
321
+ /** The operation definition for HTTP PUT requests to this path. */
247
322
  put?: OpenAPIOperationObject;
323
+ /** The operation definition for HTTP DELETE requests to this path. */
248
324
  delete?: OpenAPIOperationObject;
325
+ /** The operation definition for HTTP PATCH requests to this path. */
249
326
  patch?: OpenAPIOperationObject;
327
+ /** The operation definition for HTTP OPTIONS requests to this path. */
250
328
  options?: OpenAPIOperationObject;
329
+ /** The operation definition for HTTP HEAD requests to this path. */
251
330
  head?: OpenAPIOperationObject;
331
+ /** The operation definition for HTTP TRACE requests to this path. */
252
332
  trace?: OpenAPIOperationObject;
333
+ /** The operation definition for HTTP QUERY requests to this path (OpenAPI 3.2 extension). */
253
334
  query?: OpenAPIOperationObject;
335
+ /** Additional non-standard HTTP method operations keyed by method name. */
254
336
  additionalOperations?: Record<string, OpenAPIOperationObject>;
255
337
  }
256
338
  /**
@@ -258,11 +340,17 @@ interface OpenAPIPathItemObject {
258
340
  * @public
259
341
  */
260
342
  interface OpenAPIOperationObject {
343
+ /** A unique string identifier for the operation, used by tooling to reference it. */
261
344
  operationId?: string;
345
+ /** A short, human-readable summary of what the operation does. */
262
346
  summary?: string;
347
+ /** A detailed description of the operation's behaviour, supporting CommonMark markdown. */
263
348
  description?: string;
349
+ /** A list of tag names that logically group this operation in documentation and tooling. */
264
350
  tags?: string[];
351
+ /** The list of parameters applicable to this operation. */
265
352
  parameters?: OpenAPIParameterObject[];
353
+ /** The possible responses returned by this operation, keyed by HTTP status code or "default". */
266
354
  responses?: Record<string, OpenAPIResponseObject>;
267
355
  }
268
356
  /**
@@ -270,11 +358,17 @@ interface OpenAPIOperationObject {
270
358
  * @public
271
359
  */
272
360
  interface OpenAPIParameterObject {
361
+ /** The name of the parameter, case-sensitive. */
273
362
  name: string;
363
+ /** The location of the parameter: path, query, header, cookie, or querystring. */
274
364
  in: "query" | "header" | "path" | "cookie" | "querystring";
365
+ /** A human-readable description of the parameter's purpose, supporting CommonMark markdown. */
275
366
  description?: string;
367
+ /** Whether the parameter is mandatory. Required for `in: "path"` parameters. */
276
368
  required?: boolean;
369
+ /** The schema defining the type and constraints of the parameter value. */
277
370
  schema?: OpenAPISchemaObject;
371
+ /** Marks the parameter as deprecated; clients should avoid using it. */
278
372
  deprecated?: boolean;
279
373
  }
280
374
  /**
@@ -282,10 +376,15 @@ interface OpenAPIParameterObject {
282
376
  * @public
283
377
  */
284
378
  interface OpenAPIEncodingObject {
379
+ /** The MIME type to use for encoding a specific property (e.g., "application/json"). */
285
380
  contentType?: string;
381
+ /** Additional headers to send alongside the encoded part, keyed by header name. */
286
382
  headers?: Record<string, OpenAPIParameterObject>;
383
+ /** The serialization style for the encoded value (e.g., "form", "spaceDelimited"). */
287
384
  style?: string;
385
+ /** Whether arrays and objects should be exploded into separate query parameters. */
288
386
  explode?: boolean;
387
+ /** Whether reserved characters in the encoded value should be allowed without percent-encoding. */
289
388
  allowReserved?: boolean;
290
389
  }
291
390
  /**
@@ -293,7 +392,9 @@ interface OpenAPIEncodingObject {
293
392
  * @public
294
393
  */
295
394
  interface OpenAPIMediaTypeObject {
395
+ /** The schema defining the structure and type of the media type's payload. */
296
396
  schema?: OpenAPISchemaObject;
397
+ /** Encoding information for specific properties of a `multipart` or `application/x-www-form-urlencoded` request body. */
297
398
  encoding?: Record<string, OpenAPIEncodingObject>;
298
399
  }
299
400
  /**
@@ -301,8 +402,11 @@ interface OpenAPIMediaTypeObject {
301
402
  * @public
302
403
  */
303
404
  interface OpenAPIResponseObject {
405
+ /** A required human-readable description of the response, supporting CommonMark markdown. */
304
406
  description: string;
407
+ /** HTTP headers returned with this response, keyed by header name. */
305
408
  headers?: Record<string, OpenAPIParameterObject>;
409
+ /** The response body content, keyed by media type (e.g., "application/json"). */
306
410
  content?: Record<string, OpenAPIMediaTypeObject>;
307
411
  }
308
412
  /**
@@ -310,14 +414,20 @@ interface OpenAPIResponseObject {
310
414
  * @public
311
415
  */
312
416
  interface OpenAPIDocument {
417
+ /** The OpenAPI specification version this document conforms to. Must be "3.2.0". */
313
418
  openapi: "3.2.0";
419
+ /** An optional self-referencing URL for this document, used for tooling and resolution. */
314
420
  $self?: string;
421
+ /** Metadata about the API including title, version, and description. */
315
422
  info: OpenAPIInfoObject;
423
+ /** The available paths and their operations, keyed by path template (e.g., "/users/{id}"). */
316
424
  paths: Record<string, OpenAPIPathItemObject>;
425
+ /** Reusable schema and media type definitions shared across the document. */
317
426
  components: {
318
427
  schemas: Record<string, OpenAPISchemaObject>;
319
428
  mediaTypes?: Record<string, OpenAPIMediaTypeObject>;
320
429
  };
430
+ /** A list of tags used to group operations, with optional descriptions. */
321
431
  tags?: OpenAPITagObject[];
322
432
  }
323
433
 
@@ -332,6 +442,12 @@ interface OpenAPIDocument {
332
442
  *
333
443
  * @param tags - The parsed `tags` map from `ForgeSymbol.documentation`.
334
444
  * @returns The resolved {@link Visibility} value.
445
+ * @example
446
+ * ```typescript
447
+ * import { resolveVisibility } from "@forge-ts/core";
448
+ * const vis = resolveVisibility({ internal: [] });
449
+ * // vis === Visibility.Internal
450
+ * ```
335
451
  * @public
336
452
  */
337
453
  declare function resolveVisibility(tags: Record<string, string[]> | undefined): Visibility;
@@ -344,6 +460,12 @@ declare function resolveVisibility(tags: Record<string, string[]> | undefined):
344
460
  * @param candidate - The visibility of the symbol being tested.
345
461
  * @param minVisibility - The minimum visibility threshold.
346
462
  * @returns `true` if `candidate` is at least as visible as `minVisibility`.
463
+ * @example
464
+ * ```typescript
465
+ * import { meetsVisibility, Visibility } from "@forge-ts/core";
466
+ * meetsVisibility(Visibility.Public, Visibility.Public); // true
467
+ * meetsVisibility(Visibility.Internal, Visibility.Public); // false
468
+ * ```
347
469
  * @public
348
470
  */
349
471
  declare function meetsVisibility(candidate: Visibility, minVisibility: Visibility): boolean;
@@ -354,6 +476,11 @@ declare function meetsVisibility(candidate: Visibility, minVisibility: Visibilit
354
476
  * @param symbols - The full list of symbols to filter.
355
477
  * @param minVisibility - The minimum visibility threshold to keep.
356
478
  * @returns A new array containing only symbols that pass the visibility check.
479
+ * @example
480
+ * ```typescript
481
+ * import { filterByVisibility, Visibility } from "@forge-ts/core";
482
+ * const publicOnly = filterByVisibility(symbols, Visibility.Public);
483
+ * ```
357
484
  * @public
358
485
  */
359
486
  declare function filterByVisibility(symbols: ForgeSymbol[], minVisibility: Visibility): ForgeSymbol[];
@@ -379,8 +506,16 @@ interface ASTWalker {
379
506
  *
380
507
  * @param config - The resolved {@link ForgeConfig} for the project.
381
508
  * @returns An {@link ASTWalker} instance whose `walk()` method performs the extraction.
509
+ * @example
510
+ * ```typescript
511
+ * import { loadConfig, createWalker } from "@forge-ts/core";
512
+ * const config = await loadConfig();
513
+ * const walker = createWalker(config);
514
+ * const symbols = walker.walk();
515
+ * console.log(`Found ${symbols.length} symbols`);
516
+ * ```
382
517
  * @public
383
518
  */
384
519
  declare function createWalker(config: ForgeConfig): ASTWalker;
385
520
 
386
- export { type ASTWalker, type ForgeConfig, type ForgeError, type ForgeResult, type ForgeSymbol, type ForgeWarning, type OpenAPIDocument, type OpenAPIEncodingObject, type OpenAPIInfoObject, type OpenAPIMediaTypeObject, type OpenAPIOperationObject, type OpenAPIParameterObject, type OpenAPIPathItemObject, type OpenAPIResponseObject, type OpenAPISchemaObject, type OpenAPITagObject, Visibility, createWalker, defaultConfig, filterByVisibility, loadConfig, meetsVisibility, resolveVisibility };
521
+ export { type ASTWalker, type EnforceRules, type ForgeConfig, type ForgeError, type ForgeResult, type ForgeSymbol, type ForgeWarning, type OpenAPIDocument, type OpenAPIEncodingObject, type OpenAPIInfoObject, type OpenAPIMediaTypeObject, type OpenAPIOperationObject, type OpenAPIParameterObject, type OpenAPIPathItemObject, type OpenAPIResponseObject, type OpenAPISchemaObject, type OpenAPITagObject, type RuleSeverity, Visibility, createWalker, defaultConfig, filterByVisibility, loadConfig, meetsVisibility, resolveVisibility };
package/dist/index.js CHANGED
@@ -22,7 +22,16 @@ function defaultConfig(rootDir) {
22
22
  enforce: {
23
23
  enabled: true,
24
24
  minVisibility: "public" /* Public */,
25
- strict: false
25
+ strict: false,
26
+ rules: {
27
+ "require-summary": "error",
28
+ "require-param": "error",
29
+ "require-returns": "error",
30
+ "require-example": "error",
31
+ "require-package-doc": "warn",
32
+ "require-class-member-doc": "error",
33
+ "require-interface-member-doc": "error"
34
+ }
26
35
  },
27
36
  doctest: {
28
37
  enabled: true,
@@ -46,7 +55,11 @@ function mergeWithDefaults(rootDir, partial) {
46
55
  return {
47
56
  ...defaults,
48
57
  ...partial,
49
- enforce: { ...defaults.enforce, ...partial.enforce },
58
+ enforce: {
59
+ ...defaults.enforce,
60
+ ...partial.enforce,
61
+ rules: { ...defaults.enforce.rules, ...partial.enforce?.rules }
62
+ },
50
63
  doctest: { ...defaults.doctest, ...partial.doctest },
51
64
  api: { ...defaults.api, ...partial.api },
52
65
  gen: { ...defaults.gen, ...partial.gen }
@@ -190,6 +203,9 @@ function parseTSDoc(rawComment, startLine) {
190
203
  if (comment.modifierTagSet.hasTag(StandardTags.alpha)) {
191
204
  tags.alpha = [];
192
205
  }
206
+ if (comment.modifierTagSet.hasTag(StandardTags.packageDocumentation)) {
207
+ tags.packageDocumentation = [];
208
+ }
193
209
  let deprecated;
194
210
  if (comment.deprecatedBlock) {
195
211
  deprecated = renderBlock(comment.deprecatedBlock).trim() || "true";
@@ -212,7 +228,33 @@ function parseTSDoc(rawComment, startLine) {
212
228
  throws.push({ description: renderBlock(block) });
213
229
  }
214
230
  }
231
+ for (const block of comment.customBlocks) {
232
+ if (block.blockTag.tagName.toLowerCase() === "@route") {
233
+ const routeText = renderBlock(block).trim();
234
+ const match = routeText.match(/^(GET|POST|PUT|DELETE|PATCH|OPTIONS|HEAD)\s+(\S+)/i);
235
+ if (match) {
236
+ if (!tags.route) tags.route = [];
237
+ tags.route.push(`${match[1].toUpperCase()} ${match[2]}`);
238
+ }
239
+ }
240
+ }
215
241
  const examples = extractExamples(comment, startLine);
242
+ const links = [];
243
+ function walkForLinks(node) {
244
+ if (node.kind === DocNodeKind.LinkTag) {
245
+ const linkTag = node;
246
+ if (linkTag.codeDestination) {
247
+ const target = linkTag.codeDestination.memberReferences.map((ref) => ref.memberIdentifier?.identifier ?? "").filter(Boolean).join(".");
248
+ if (target) {
249
+ links.push({ target, line: startLine });
250
+ }
251
+ }
252
+ }
253
+ for (const child of node.getChildNodes()) {
254
+ walkForLinks(child);
255
+ }
256
+ }
257
+ walkForLinks(comment);
216
258
  const summary = renderDocSection(comment.summarySection);
217
259
  return {
218
260
  summary: summary || void 0,
@@ -221,7 +263,8 @@ function parseTSDoc(rawComment, startLine) {
221
263
  throws: throws.length > 0 ? throws : void 0,
222
264
  examples: examples.length > 0 ? examples : void 0,
223
265
  tags: Object.keys(tags).length > 0 ? tags : void 0,
224
- deprecated
266
+ deprecated,
267
+ links: links.length > 0 ? links : void 0
225
268
  };
226
269
  }
227
270
  function getLeadingComment(node, sourceFile) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts","../src/types.ts","../src/visibility.ts","../src/walker.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { type ForgeConfig, Visibility } from \"./types.js\";\n\n/**\n * Constructs a sensible default {@link ForgeConfig} rooted at `rootDir`.\n *\n * @param rootDir - Absolute path to the project root.\n * @returns A fully-populated default configuration.\n * @public\n */\nexport function defaultConfig(rootDir: string): ForgeConfig {\n\treturn {\n\t\trootDir,\n\t\ttsconfig: join(rootDir, \"tsconfig.json\"),\n\t\toutDir: join(rootDir, \"docs\"),\n\t\tenforce: {\n\t\t\tenabled: true,\n\t\t\tminVisibility: Visibility.Public,\n\t\t\tstrict: false,\n\t\t},\n\t\tdoctest: {\n\t\t\tenabled: true,\n\t\t\tcacheDir: join(rootDir, \".cache\", \"doctest\"),\n\t\t},\n\t\tapi: {\n\t\t\tenabled: false,\n\t\t\topenapi: false,\n\t\t\topenapiPath: join(rootDir, \"docs\", \"openapi.json\"),\n\t\t},\n\t\tgen: {\n\t\t\tenabled: true,\n\t\t\tformats: [\"markdown\"],\n\t\t\tllmsTxt: true,\n\t\t\treadmeSync: false,\n\t\t},\n\t};\n}\n\n/**\n * Merges a partial user config with the defaults so every field is present.\n *\n * @param rootDir - Absolute path to the project root.\n * @param partial - Partial config from the user's config file.\n * @returns A fully-populated {@link ForgeConfig}.\n * @internal\n */\nfunction mergeWithDefaults(rootDir: string, partial: Partial<ForgeConfig>): ForgeConfig {\n\tconst defaults = defaultConfig(rootDir);\n\treturn {\n\t\t...defaults,\n\t\t...partial,\n\t\tenforce: { ...defaults.enforce, ...partial.enforce },\n\t\tdoctest: { ...defaults.doctest, ...partial.doctest },\n\t\tapi: { ...defaults.api, ...partial.api },\n\t\tgen: { ...defaults.gen, ...partial.gen },\n\t};\n}\n\n/**\n * Attempts to load a TypeScript or JavaScript config file via dynamic import.\n *\n * @param filePath - Absolute path to the config file.\n * @returns The default export of the config module, or `null` on failure.\n * @internal\n */\nasync function loadModuleConfig(filePath: string): Promise<Partial<ForgeConfig> | null> {\n\ttry {\n\t\tconst fileUrl = pathToFileURL(filePath).href;\n\t\tconst mod = (await import(fileUrl)) as {\n\t\t\tdefault?: Partial<ForgeConfig>;\n\t\t};\n\t\treturn mod.default ?? null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Minimal shape of a `package.json` file relevant to forge-ts config loading.\n * @internal\n */\ninterface PackageJson {\n\tname?: string;\n\tversion?: string;\n\t\"forge-ts\"?: Partial<ForgeConfig>;\n}\n\n/**\n * Attempts to read the `\"forge-ts\"` key from a `package.json` file.\n *\n * @param pkgPath - Absolute path to `package.json`.\n * @returns The value of the `\"forge-ts\"` key, or `null` if absent.\n * @internal\n */\nasync function loadPackageJsonConfig(pkgPath: string): Promise<Partial<ForgeConfig> | null> {\n\ttry {\n\t\tconst raw = await readFile(pkgPath, \"utf8\");\n\t\tconst pkg = JSON.parse(raw) as PackageJson;\n\t\tconst key = pkg[\"forge-ts\"];\n\t\tif (key) {\n\t\t\treturn key;\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Loads the forge-ts configuration for a project.\n *\n * Resolution order:\n * 1. `<rootDir>/forge-ts.config.ts`\n * 2. `<rootDir>/forge-ts.config.js`\n * 3. `\"forge-ts\"` key inside `<rootDir>/package.json`\n * 4. Built-in defaults (returned when none of the above is found)\n *\n * @param rootDir - The project root to search for config. Defaults to `process.cwd()`.\n * @returns A fully-resolved {@link ForgeConfig}.\n * @public\n */\nexport async function loadConfig(rootDir?: string): Promise<ForgeConfig> {\n\tconst root = resolve(rootDir ?? process.cwd());\n\n\tconst candidates = [join(root, \"forge-ts.config.ts\"), join(root, \"forge-ts.config.js\")];\n\n\tfor (const candidate of candidates) {\n\t\tif (existsSync(candidate)) {\n\t\t\tconst partial = await loadModuleConfig(candidate);\n\t\t\tif (partial) {\n\t\t\t\treturn mergeWithDefaults(root, partial);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst pkgPath = join(root, \"package.json\");\n\tif (existsSync(pkgPath)) {\n\t\tconst partial = await loadPackageJsonConfig(pkgPath);\n\t\tif (partial) {\n\t\t\treturn mergeWithDefaults(root, partial);\n\t\t}\n\t}\n\n\treturn defaultConfig(root);\n}\n","/**\n * Visibility levels for exported symbols.\n * Derived from TSDoc release tags (@public, @beta, @internal).\n * @public\n */\nexport enum Visibility {\n\tPublic = \"public\",\n\tBeta = \"beta\",\n\tInternal = \"internal\",\n\tPrivate = \"private\",\n}\n\n/**\n * A single extracted and annotated symbol from the TypeScript AST.\n * @public\n */\nexport interface ForgeSymbol {\n\t/** The declared name of the symbol. */\n\tname: string;\n\t/** The syntactic kind of the symbol. */\n\tkind: \"function\" | \"class\" | \"interface\" | \"type\" | \"enum\" | \"variable\" | \"method\" | \"property\";\n\t/** Resolved visibility from TSDoc release tags. */\n\tvisibility: Visibility;\n\t/** Absolute path to the source file. */\n\tfilePath: string;\n\t/** 1-based line number of the declaration. */\n\tline: number;\n\t/** 0-based column of the declaration. */\n\tcolumn: number;\n\t/** Parsed TSDoc documentation, if present. */\n\tdocumentation?: {\n\t\tsummary?: string;\n\t\tparams?: Array<{ name: string; description: string; type?: string }>;\n\t\treturns?: { description: string; type?: string };\n\t\tthrows?: Array<{ type?: string; description: string }>;\n\t\texamples?: Array<{ code: string; language: string; line: number }>;\n\t\ttags?: Record<string, string[]>;\n\t\tdeprecated?: string;\n\t};\n\t/** Human-readable type signature of the symbol. */\n\tsignature?: string;\n\t/** Child symbols (e.g., class members, enum values). */\n\tchildren?: ForgeSymbol[];\n\t/** Whether this symbol is part of the public module exports. */\n\texported: boolean;\n}\n\n/**\n * Full configuration for a forge-ts run.\n * Loaded from forge-ts.config.ts or the \"forge-ts\" key in package.json.\n * @public\n */\nexport interface ForgeConfig {\n\t/** Root directory of the project. */\n\trootDir: string;\n\t/** Path to the tsconfig.json to compile against. */\n\ttsconfig: string;\n\t/** Output directory for generated files. */\n\toutDir: string;\n\t/** Enforce TSDoc on all public exports. */\n\tenforce: {\n\t\tenabled: boolean;\n\t\t/** Minimum visibility level to enforce documentation on. */\n\t\tminVisibility: Visibility;\n\t\t/** Fail on warnings rather than only on errors. */\n\t\tstrict: boolean;\n\t};\n\t/** DocTest configuration. */\n\tdoctest: {\n\t\tenabled: boolean;\n\t\t/** Cache directory for virtual test files. */\n\t\tcacheDir: string;\n\t};\n\t/** API generation configuration. */\n\tapi: {\n\t\tenabled: boolean;\n\t\t/** Generate an OpenAPI spec from exported HTTP handlers. */\n\t\topenapi: boolean;\n\t\t/** Output path for the OpenAPI spec file. */\n\t\topenapiPath: string;\n\t};\n\t/** Output generation configuration. */\n\tgen: {\n\t\tenabled: boolean;\n\t\t/** Output formats to generate. */\n\t\tformats: Array<\"markdown\" | \"mdx\">;\n\t\t/** Generate an llms.txt companion file. */\n\t\tllmsTxt: boolean;\n\t\t/** Synchronise summaries back into README.md. */\n\t\treadmeSync: boolean;\n\t\t/** Static site generator to target for output format. */\n\t\tssgTarget?: \"docusaurus\" | \"mintlify\" | \"nextra\" | \"vitepress\";\n\t};\n}\n\n/**\n * The result of a forge-ts compilation pass.\n * @public\n */\nexport interface ForgeResult {\n\t/** Whether the run succeeded without errors. */\n\tsuccess: boolean;\n\t/** All symbols extracted during this run. */\n\tsymbols: ForgeSymbol[];\n\t/** Errors that caused or would cause failure. */\n\terrors: ForgeError[];\n\t/** Non-fatal warnings. */\n\twarnings: ForgeWarning[];\n\t/** Wall-clock duration of the run in milliseconds. */\n\tduration: number;\n}\n\n/**\n * A diagnostic error produced during a forge-ts run.\n * @public\n */\nexport interface ForgeError {\n\t/** Machine-readable error code (e.g. \"E001\"). */\n\tcode: string;\n\t/** Human-readable description of the error. */\n\tmessage: string;\n\t/** Absolute path of the file where the error occurred. */\n\tfilePath: string;\n\t/** 1-based line number. */\n\tline: number;\n\t/** 0-based column. */\n\tcolumn: number;\n\t/** Suggested fix for the agent — exact TSDoc block to add. */\n\tsuggestedFix?: string;\n\t/** The symbol name that needs fixing. */\n\tsymbolName?: string;\n\t/** The symbol kind (function, class, interface, etc.). */\n\tsymbolKind?: string;\n}\n\n/**\n * A diagnostic warning produced during a forge-ts run.\n * @public\n */\nexport interface ForgeWarning {\n\t/** Machine-readable warning code (e.g. \"W001\"). */\n\tcode: string;\n\t/** Human-readable description of the warning. */\n\tmessage: string;\n\t/** Absolute path of the file where the warning occurred. */\n\tfilePath: string;\n\t/** 1-based line number. */\n\tline: number;\n\t/** 0-based column. */\n\tcolumn: number;\n}\n","import { type ForgeSymbol, Visibility } from \"./types.js\";\n\n/**\n * Determines the visibility level of a symbol from its TSDoc release tags.\n *\n * The precedence order is:\n * 1. `@internal` → {@link Visibility.Internal}\n * 2. `@beta` → {@link Visibility.Beta}\n * 3. `@public` → {@link Visibility.Public}\n * 4. (no tag) → {@link Visibility.Public} (default for exports)\n *\n * @param tags - The parsed `tags` map from `ForgeSymbol.documentation`.\n * @returns The resolved {@link Visibility} value.\n * @public\n */\nexport function resolveVisibility(tags: Record<string, string[]> | undefined): Visibility {\n\tif (!tags) return Visibility.Public;\n\n\tif (\"internal\" in tags) return Visibility.Internal;\n\tif (\"beta\" in tags) return Visibility.Beta;\n\tif (\"public\" in tags) return Visibility.Public;\n\n\treturn Visibility.Public;\n}\n\n/**\n * Numeric rank used for visibility comparisons.\n * Lower numbers are more restrictive.\n * @internal\n */\nconst VISIBILITY_RANK: Record<Visibility, number> = {\n\t[Visibility.Public]: 0,\n\t[Visibility.Beta]: 1,\n\t[Visibility.Internal]: 2,\n\t[Visibility.Private]: 3,\n};\n\n/**\n * Returns whether `candidate` meets or exceeds the required minimum visibility.\n *\n * \"Meets\" means the symbol is at least as visible as `minVisibility`.\n * For example, `Public` meets a minimum of `Public`, but `Internal` does not.\n *\n * @param candidate - The visibility of the symbol being tested.\n * @param minVisibility - The minimum visibility threshold.\n * @returns `true` if `candidate` is at least as visible as `minVisibility`.\n * @public\n */\nexport function meetsVisibility(candidate: Visibility, minVisibility: Visibility): boolean {\n\treturn VISIBILITY_RANK[candidate] <= VISIBILITY_RANK[minVisibility];\n}\n\n/**\n * Filters an array of {@link ForgeSymbol} objects to only include symbols\n * whose visibility meets or exceeds `minVisibility`.\n *\n * @param symbols - The full list of symbols to filter.\n * @param minVisibility - The minimum visibility threshold to keep.\n * @returns A new array containing only symbols that pass the visibility check.\n * @public\n */\nexport function filterByVisibility(\n\tsymbols: ForgeSymbol[],\n\tminVisibility: Visibility,\n): ForgeSymbol[] {\n\treturn symbols.filter((s) => meetsVisibility(s.visibility, minVisibility));\n}\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport {\n\ttype DocBlock,\n\ttype DocCodeSpan,\n\ttype DocComment,\n\ttype DocFencedCode,\n\ttype DocNode,\n\tDocNodeKind,\n\ttype DocParagraph,\n\ttype DocPlainText,\n\ttype DocSection,\n\tStandardTags,\n\tTSDocConfiguration,\n\tTSDocParser,\n} from \"@microsoft/tsdoc\";\nimport ts from \"typescript\";\nimport type { ForgeConfig, ForgeSymbol } from \"./types.js\";\nimport { resolveVisibility } from \"./visibility.js\";\n\n// ---------------------------------------------------------------------------\n// Public API surface\n// ---------------------------------------------------------------------------\n\n/**\n * The return type of {@link createWalker}.\n * @public\n */\nexport interface ASTWalker {\n\t/**\n\t * Walk all source files referenced by the configured tsconfig and return\n\t * one {@link ForgeSymbol} per exported declaration.\n\t */\n\twalk(): ForgeSymbol[];\n}\n\n// ---------------------------------------------------------------------------\n// TSDoc helpers\n// ---------------------------------------------------------------------------\n\n/** Render inline nodes (PlainText, CodeSpan, SoftBreak) to a plain string. @internal */\nfunction renderInlineNodes(nodes: readonly DocNode[]): string {\n\tconst parts: string[] = [];\n\tfor (const node of nodes) {\n\t\tswitch (node.kind) {\n\t\t\tcase DocNodeKind.PlainText:\n\t\t\t\tparts.push((node as DocPlainText).text);\n\t\t\t\tbreak;\n\t\t\tcase DocNodeKind.CodeSpan:\n\t\t\t\tparts.push(`\\`${(node as DocCodeSpan).code}\\``);\n\t\t\t\tbreak;\n\t\t\tcase DocNodeKind.SoftBreak:\n\t\t\t\tparts.push(\" \");\n\t\t\t\tbreak;\n\t\t\tcase DocNodeKind.Paragraph:\n\t\t\t\t// Recurse into paragraph nodes to extract nested text\n\t\t\t\tparts.push(renderInlineNodes((node as DocParagraph).nodes));\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\treturn parts.join(\"\");\n}\n\n/** Render a `DocSection` (or similar node) to a plain string. @internal */\nfunction renderDocSection(section: DocSection | undefined): string {\n\tif (!section) return \"\";\n\treturn renderInlineNodes(section.nodes).trim();\n}\n\n/** Render a `DocBlock`'s content to a plain string. @internal */\nfunction renderBlock(block: DocBlock): string {\n\treturn renderDocSection(block.content);\n}\n\n/** Extract all `@example` fenced code blocks from a parsed comment. @internal */\nfunction extractExamples(\n\tcomment: DocComment,\n\tstartLine: number,\n): Array<{ code: string; language: string; line: number }> {\n\tconst examples: Array<{ code: string; language: string; line: number }> = [];\n\n\tfor (const block of comment.customBlocks) {\n\t\tif (block.blockTag.tagName.toLowerCase() !== \"@example\") continue;\n\n\t\tfor (const node of block.content.nodes) {\n\t\t\tif (node.kind === DocNodeKind.FencedCode) {\n\t\t\t\tconst fenced = node as DocFencedCode;\n\t\t\t\texamples.push({\n\t\t\t\t\tcode: fenced.code,\n\t\t\t\t\tlanguage: fenced.language || \"typescript\",\n\t\t\t\t\tline: startLine,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn examples;\n}\n\n/** Parse a raw JSDoc/TSDoc comment string into a structured documentation object. @internal */\nfunction parseTSDoc(rawComment: string, startLine: number): ForgeSymbol[\"documentation\"] {\n\tconst configuration = new TSDocConfiguration();\n\tconst parser = new TSDocParser(configuration);\n\tconst result = parser.parseString(rawComment);\n\tconst comment = result.docComment;\n\n\tconst tags: Record<string, string[]> = {};\n\n\t// Release tags\n\tif (comment.modifierTagSet.hasTag(StandardTags.public)) {\n\t\ttags.public = [];\n\t}\n\tif (comment.modifierTagSet.hasTag(StandardTags.beta)) {\n\t\ttags.beta = [];\n\t}\n\tif (comment.modifierTagSet.hasTag(StandardTags.internal)) {\n\t\ttags.internal = [];\n\t}\n\tif (comment.modifierTagSet.hasTag(StandardTags.alpha)) {\n\t\ttags.alpha = [];\n\t}\n\n\t// @deprecated\n\tlet deprecated: string | undefined;\n\tif (comment.deprecatedBlock) {\n\t\tdeprecated = renderBlock(comment.deprecatedBlock).trim() || \"true\";\n\t}\n\n\t// @param blocks\n\tconst params: Array<{ name: string; description: string; type?: string }> = [];\n\tfor (const paramBlock of comment.params.blocks) {\n\t\tparams.push({\n\t\t\tname: paramBlock.parameterName,\n\t\t\tdescription: renderBlock(paramBlock),\n\t\t});\n\t}\n\n\t// @returns block\n\tlet returns: { description: string; type?: string } | undefined;\n\tif (comment.returnsBlock) {\n\t\tconst desc = renderBlock(comment.returnsBlock);\n\t\tif (desc) returns = { description: desc };\n\t}\n\n\t// @throws blocks\n\tconst throws: Array<{ type?: string; description: string }> = [];\n\tfor (const block of comment.customBlocks) {\n\t\tif (block.blockTag.tagName.toLowerCase() === \"@throws\") {\n\t\t\tthrows.push({ description: renderBlock(block) });\n\t\t}\n\t}\n\n\t// @example blocks\n\tconst examples = extractExamples(comment, startLine);\n\n\tconst summary = renderDocSection(comment.summarySection);\n\n\treturn {\n\t\tsummary: summary || undefined,\n\t\tparams: params.length > 0 ? params : undefined,\n\t\treturns,\n\t\tthrows: throws.length > 0 ? throws : undefined,\n\t\texamples: examples.length > 0 ? examples : undefined,\n\t\ttags: Object.keys(tags).length > 0 ? tags : undefined,\n\t\tdeprecated,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// TypeScript AST helpers\n// ---------------------------------------------------------------------------\n\n/** Extract the leading JSDoc comment text for a node. @internal */\nfunction getLeadingComment(node: ts.Node, sourceFile: ts.SourceFile): string | undefined {\n\tconst fullText = sourceFile.getFullText();\n\tconst ranges = ts.getLeadingCommentRanges(fullText, node.getFullStart());\n\tif (!ranges || ranges.length === 0) return undefined;\n\n\t// Take the last leading comment (closest to the declaration)\n\tconst range = ranges[ranges.length - 1];\n\tif (\n\t\trange.kind !== ts.SyntaxKind.MultiLineCommentTrivia ||\n\t\t!fullText.slice(range.pos, range.end).startsWith(\"/**\")\n\t) {\n\t\treturn undefined;\n\t}\n\n\treturn fullText.slice(range.pos, range.end);\n}\n\n/** Map a TypeScript `SyntaxKind` to a `ForgeSymbol` kind string. @internal */\nfunction kindToString(kind: ts.SyntaxKind): ForgeSymbol[\"kind\"] | null {\n\tswitch (kind) {\n\t\tcase ts.SyntaxKind.FunctionDeclaration:\n\t\tcase ts.SyntaxKind.ArrowFunction:\n\t\tcase ts.SyntaxKind.FunctionExpression:\n\t\t\treturn \"function\";\n\t\tcase ts.SyntaxKind.ClassDeclaration:\n\t\t\treturn \"class\";\n\t\tcase ts.SyntaxKind.InterfaceDeclaration:\n\t\t\treturn \"interface\";\n\t\tcase ts.SyntaxKind.TypeAliasDeclaration:\n\t\t\treturn \"type\";\n\t\tcase ts.SyntaxKind.EnumDeclaration:\n\t\t\treturn \"enum\";\n\t\tcase ts.SyntaxKind.VariableDeclaration:\n\t\tcase ts.SyntaxKind.VariableStatement:\n\t\t\treturn \"variable\";\n\t\tcase ts.SyntaxKind.MethodDeclaration:\n\t\tcase ts.SyntaxKind.MethodSignature:\n\t\t\treturn \"method\";\n\t\tcase ts.SyntaxKind.PropertyDeclaration:\n\t\tcase ts.SyntaxKind.PropertySignature:\n\t\tcase ts.SyntaxKind.EnumMember:\n\t\t\treturn \"property\";\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\n/** Build a human-readable type signature string using the type checker. @internal */\nfunction buildSignature(node: ts.Declaration, checker: ts.TypeChecker): string | undefined {\n\ttry {\n\t\tconst symbol = checker.getSymbolAtLocation((node as ts.NamedDeclaration).name ?? node);\n\t\tif (!symbol) return undefined;\n\t\tconst type = checker.getTypeOfSymbolAtLocation(symbol, node);\n\t\treturn checker.typeToString(type);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Walker implementation\n// ---------------------------------------------------------------------------\n\n/** @internal */\nfunction extractSymbolsFromFile(\n\tsourceFile: ts.SourceFile,\n\tchecker: ts.TypeChecker,\n\t_tsdocParser: TSDocParser,\n): ForgeSymbol[] {\n\tconst symbols: ForgeSymbol[] = [];\n\tconst filePath = sourceFile.fileName;\n\n\tfunction visit(node: ts.Node, parentExported: boolean): void {\n\t\tconst isExported =\n\t\t\tparentExported ||\n\t\t\t(ts.getCombinedModifierFlags(node as ts.Declaration) & ts.ModifierFlags.Export) !== 0;\n\n\t\t// Handle export declarations: `export { Foo, Bar }`\n\t\tif (ts.isExportDeclaration(node)) {\n\t\t\tts.forEachChild(node, (child) => visit(child, true));\n\t\t\treturn;\n\t\t}\n\n\t\tconst kind = kindToString(node.kind);\n\n\t\t// Variable statements need special handling: `export const foo = ...`\n\t\tif (ts.isVariableStatement(node)) {\n\t\t\tif (!isExported) {\n\t\t\t\tts.forEachChild(node, (child) => visit(child, false));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const decl of node.declarationList.declarations) {\n\t\t\t\tconst name = decl.name.getText(sourceFile);\n\t\t\t\tconst pos = sourceFile.getLineAndCharacterOfPosition(decl.getStart());\n\t\t\t\tconst rawComment = getLeadingComment(node, sourceFile);\n\t\t\t\tconst documentation = rawComment ? parseTSDoc(rawComment, pos.line + 1) : undefined;\n\t\t\t\tconst tags = documentation?.tags;\n\t\t\t\tconst visibility = resolveVisibility(tags);\n\n\t\t\t\tsymbols.push({\n\t\t\t\t\tname,\n\t\t\t\t\tkind: \"variable\",\n\t\t\t\t\tvisibility,\n\t\t\t\t\tfilePath,\n\t\t\t\t\tline: pos.line + 1,\n\t\t\t\t\tcolumn: pos.character,\n\t\t\t\t\tdocumentation,\n\t\t\t\t\tsignature: buildSignature(decl, checker),\n\t\t\t\t\texported: true,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kind === null || !isExported) {\n\t\t\tts.forEachChild(node, (child) => visit(child, isExported));\n\t\t\treturn;\n\t\t}\n\n\t\tconst namedNode = node as ts.NamedDeclaration;\n\t\tconst nameNode = namedNode.name;\n\t\tif (!nameNode) {\n\t\t\tts.forEachChild(node, (child) => visit(child, isExported));\n\t\t\treturn;\n\t\t}\n\n\t\tconst name = nameNode.getText(sourceFile);\n\t\tconst pos = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n\t\tconst rawComment = getLeadingComment(node, sourceFile);\n\t\tconst documentation = rawComment ? parseTSDoc(rawComment, pos.line + 1) : undefined;\n\t\tconst tags = documentation?.tags;\n\t\tconst visibility = resolveVisibility(tags);\n\n\t\tconst children: ForgeSymbol[] = [];\n\n\t\t// Walk class members / interface members / enum members\n\t\tif (\n\t\t\tts.isClassDeclaration(node) ||\n\t\t\tts.isInterfaceDeclaration(node) ||\n\t\t\tts.isEnumDeclaration(node)\n\t\t) {\n\t\t\tfor (const member of node.members) {\n\t\t\t\tconst memberKind = kindToString(member.kind);\n\t\t\t\tif (!memberKind) continue;\n\t\t\t\tconst memberName = (member as ts.NamedDeclaration).name?.getText(sourceFile) ?? \"\";\n\t\t\t\tconst memberPos = sourceFile.getLineAndCharacterOfPosition(member.getStart());\n\t\t\t\tconst memberComment = getLeadingComment(member, sourceFile);\n\t\t\t\tconst memberDoc = memberComment ? parseTSDoc(memberComment, memberPos.line + 1) : undefined;\n\t\t\t\tconst memberTags = memberDoc?.tags;\n\t\t\t\tconst memberVisibility = resolveVisibility(memberTags);\n\n\t\t\t\tchildren.push({\n\t\t\t\t\tname: memberName,\n\t\t\t\t\tkind: memberKind,\n\t\t\t\t\tvisibility: memberVisibility,\n\t\t\t\t\tfilePath,\n\t\t\t\t\tline: memberPos.line + 1,\n\t\t\t\t\tcolumn: memberPos.character,\n\t\t\t\t\tdocumentation: memberDoc,\n\t\t\t\t\tsignature: buildSignature(member as ts.Declaration, checker),\n\t\t\t\t\texported: false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tsymbols.push({\n\t\t\tname,\n\t\t\tkind,\n\t\t\tvisibility,\n\t\t\tfilePath,\n\t\t\tline: pos.line + 1,\n\t\t\tcolumn: pos.character,\n\t\t\tdocumentation,\n\t\t\tsignature: buildSignature(namedNode as ts.Declaration, checker),\n\t\t\tchildren: children.length > 0 ? children : undefined,\n\t\t\texported: isExported,\n\t\t});\n\t}\n\n\tts.forEachChild(sourceFile, (node) => visit(node, false));\n\treturn symbols;\n}\n\n/**\n * Creates an {@link ASTWalker} configured for the given forge config.\n *\n * The walker uses the TypeScript Compiler API to create a `ts.Program` from\n * the project's tsconfig, then visits every source file to extract exported\n * declarations. TSDoc comments are parsed with `@microsoft/tsdoc` to\n * populate the `documentation` field on each {@link ForgeSymbol}.\n *\n * @param config - The resolved {@link ForgeConfig} for the project.\n * @returns An {@link ASTWalker} instance whose `walk()` method performs the extraction.\n * @public\n */\nexport function createWalker(config: ForgeConfig): ASTWalker {\n\treturn {\n\t\twalk(): ForgeSymbol[] {\n\t\t\t// Load tsconfig\n\t\t\tconst tsconfigPath = resolve(config.tsconfig);\n\t\t\tconst configFile = ts.readConfigFile(tsconfigPath, (path) => readFileSync(path, \"utf8\"));\n\n\t\t\tif (configFile.error) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to read tsconfig at ${tsconfigPath}: ${ts.flattenDiagnosticMessageText(configFile.error.messageText, \"\\n\")}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst parsedCommandLine = ts.parseJsonConfigFileContent(\n\t\t\t\tconfigFile.config,\n\t\t\t\tts.sys,\n\t\t\t\tresolve(config.rootDir),\n\t\t\t);\n\n\t\t\tconst program = ts.createProgram({\n\t\t\t\trootNames: parsedCommandLine.fileNames,\n\t\t\t\toptions: parsedCommandLine.options,\n\t\t\t});\n\n\t\t\tconst checker = program.getTypeChecker();\n\n\t\t\tconst tsdocConfiguration = new TSDocConfiguration();\n\t\t\tconst tsdocParser = new TSDocParser(tsdocConfiguration);\n\n\t\t\tconst allSymbols: ForgeSymbol[] = [];\n\n\t\t\tfor (const sourceFile of program.getSourceFiles()) {\n\t\t\t\t// Skip declaration files and node_modules\n\t\t\t\tif (sourceFile.isDeclarationFile || sourceFile.fileName.includes(\"node_modules\")) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst fileSymbols = extractSymbolsFromFile(sourceFile, checker, tsdocParser);\n\t\t\t\tallSymbols.push(...fileSymbols);\n\t\t\t}\n\n\t\t\treturn allSymbols;\n\t\t},\n\t};\n}\n"],"mappings":"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","names":["Visibility","resolve","name","pos","rawComment","documentation","tags","visibility","resolve"]}
1
+ {"version":3,"sources":["../src/config.ts","../src/types.ts","../src/visibility.ts","../src/walker.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { type ForgeConfig, Visibility } from \"./types.js\";\n\n/**\n * Constructs a sensible default {@link ForgeConfig} rooted at `rootDir`.\n *\n * @param rootDir - Absolute path to the project root.\n * @returns A fully-populated default configuration.\n * @example\n * ```typescript\n * import { defaultConfig } from \"@forge-ts/core\";\n * const config = defaultConfig(\"/path/to/project\");\n * console.log(config.enforce.enabled); // true\n * ```\n * @public\n */\nexport function defaultConfig(rootDir: string): ForgeConfig {\n\treturn {\n\t\trootDir,\n\t\ttsconfig: join(rootDir, \"tsconfig.json\"),\n\t\toutDir: join(rootDir, \"docs\"),\n\t\tenforce: {\n\t\t\tenabled: true,\n\t\t\tminVisibility: Visibility.Public,\n\t\t\tstrict: false,\n\t\t\trules: {\n\t\t\t\t\"require-summary\": \"error\",\n\t\t\t\t\"require-param\": \"error\",\n\t\t\t\t\"require-returns\": \"error\",\n\t\t\t\t\"require-example\": \"error\",\n\t\t\t\t\"require-package-doc\": \"warn\",\n\t\t\t\t\"require-class-member-doc\": \"error\",\n\t\t\t\t\"require-interface-member-doc\": \"error\",\n\t\t\t},\n\t\t},\n\t\tdoctest: {\n\t\t\tenabled: true,\n\t\t\tcacheDir: join(rootDir, \".cache\", \"doctest\"),\n\t\t},\n\t\tapi: {\n\t\t\tenabled: false,\n\t\t\topenapi: false,\n\t\t\topenapiPath: join(rootDir, \"docs\", \"openapi.json\"),\n\t\t},\n\t\tgen: {\n\t\t\tenabled: true,\n\t\t\tformats: [\"markdown\"],\n\t\t\tllmsTxt: true,\n\t\t\treadmeSync: false,\n\t\t},\n\t};\n}\n\n/**\n * Merges a partial user config with the defaults so every field is present.\n *\n * @param rootDir - Absolute path to the project root.\n * @param partial - Partial config from the user's config file.\n * @returns A fully-populated {@link ForgeConfig}.\n * @internal\n */\nfunction mergeWithDefaults(rootDir: string, partial: Partial<ForgeConfig>): ForgeConfig {\n\tconst defaults = defaultConfig(rootDir);\n\treturn {\n\t\t...defaults,\n\t\t...partial,\n\t\tenforce: {\n\t\t\t...defaults.enforce,\n\t\t\t...partial.enforce,\n\t\t\trules: { ...defaults.enforce.rules, ...partial.enforce?.rules },\n\t\t},\n\t\tdoctest: { ...defaults.doctest, ...partial.doctest },\n\t\tapi: { ...defaults.api, ...partial.api },\n\t\tgen: { ...defaults.gen, ...partial.gen },\n\t};\n}\n\n/**\n * Attempts to load a TypeScript or JavaScript config file via dynamic import.\n *\n * @param filePath - Absolute path to the config file.\n * @returns The default export of the config module, or `null` on failure.\n * @internal\n */\nasync function loadModuleConfig(filePath: string): Promise<Partial<ForgeConfig> | null> {\n\ttry {\n\t\tconst fileUrl = pathToFileURL(filePath).href;\n\t\tconst mod = (await import(fileUrl)) as {\n\t\t\tdefault?: Partial<ForgeConfig>;\n\t\t};\n\t\treturn mod.default ?? null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Minimal shape of a `package.json` file relevant to forge-ts config loading.\n * @internal\n */\ninterface PackageJson {\n\tname?: string;\n\tversion?: string;\n\t\"forge-ts\"?: Partial<ForgeConfig>;\n}\n\n/**\n * Attempts to read the `\"forge-ts\"` key from a `package.json` file.\n *\n * @param pkgPath - Absolute path to `package.json`.\n * @returns The value of the `\"forge-ts\"` key, or `null` if absent.\n * @internal\n */\nasync function loadPackageJsonConfig(pkgPath: string): Promise<Partial<ForgeConfig> | null> {\n\ttry {\n\t\tconst raw = await readFile(pkgPath, \"utf8\");\n\t\tconst pkg = JSON.parse(raw) as PackageJson;\n\t\tconst key = pkg[\"forge-ts\"];\n\t\tif (key) {\n\t\t\treturn key;\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Loads the forge-ts configuration for a project.\n *\n * Resolution order:\n * 1. `<rootDir>/forge-ts.config.ts`\n * 2. `<rootDir>/forge-ts.config.js`\n * 3. `\"forge-ts\"` key inside `<rootDir>/package.json`\n * 4. Built-in defaults (returned when none of the above is found)\n *\n * @param rootDir - The project root to search for config. Defaults to `process.cwd()`.\n * @returns A fully-resolved {@link ForgeConfig}.\n * @example\n * ```typescript\n * import { loadConfig } from \"@forge-ts/core\";\n * const config = await loadConfig(\"/path/to/project\");\n * // config is fully resolved with defaults\n * ```\n * @public\n */\nexport async function loadConfig(rootDir?: string): Promise<ForgeConfig> {\n\tconst root = resolve(rootDir ?? process.cwd());\n\n\tconst candidates = [join(root, \"forge-ts.config.ts\"), join(root, \"forge-ts.config.js\")];\n\n\tfor (const candidate of candidates) {\n\t\tif (existsSync(candidate)) {\n\t\t\tconst partial = await loadModuleConfig(candidate);\n\t\t\tif (partial) {\n\t\t\t\treturn mergeWithDefaults(root, partial);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst pkgPath = join(root, \"package.json\");\n\tif (existsSync(pkgPath)) {\n\t\tconst partial = await loadPackageJsonConfig(pkgPath);\n\t\tif (partial) {\n\t\t\treturn mergeWithDefaults(root, partial);\n\t\t}\n\t}\n\n\treturn defaultConfig(root);\n}\n","/**\n * Visibility levels for exported symbols.\n * Derived from TSDoc release tags (@public, @beta, @internal).\n * @public\n */\nexport enum Visibility {\n\tPublic = \"public\",\n\tBeta = \"beta\",\n\tInternal = \"internal\",\n\tPrivate = \"private\",\n}\n\n/**\n * A single extracted and annotated symbol from the TypeScript AST.\n * @public\n */\nexport interface ForgeSymbol {\n\t/** The declared name of the symbol. */\n\tname: string;\n\t/** The syntactic kind of the symbol. */\n\tkind: \"function\" | \"class\" | \"interface\" | \"type\" | \"enum\" | \"variable\" | \"method\" | \"property\";\n\t/** Resolved visibility from TSDoc release tags. */\n\tvisibility: Visibility;\n\t/** Absolute path to the source file. */\n\tfilePath: string;\n\t/** 1-based line number of the declaration. */\n\tline: number;\n\t/** 0-based column of the declaration. */\n\tcolumn: number;\n\t/** Parsed TSDoc documentation, if present. */\n\tdocumentation?: {\n\t\tsummary?: string;\n\t\tparams?: Array<{ name: string; description: string; type?: string }>;\n\t\treturns?: { description: string; type?: string };\n\t\tthrows?: Array<{ type?: string; description: string }>;\n\t\texamples?: Array<{ code: string; language: string; line: number }>;\n\t\ttags?: Record<string, string[]>;\n\t\tdeprecated?: string;\n\t\t/** {@link} cross-references found in this symbol's TSDoc. */\n\t\tlinks?: Array<{ target: string; line: number }>;\n\t};\n\t/** Human-readable type signature of the symbol. */\n\tsignature?: string;\n\t/** Child symbols (e.g., class members, enum values). */\n\tchildren?: ForgeSymbol[];\n\t/** Whether this symbol is part of the public module exports. */\n\texported: boolean;\n}\n\n/**\n * Severity level for an individual enforcement rule.\n * - `\"error\"` — violation fails the build.\n * - `\"warn\"` — violation is reported but does not fail the build.\n * - `\"off\"` — rule is disabled entirely.\n * @public\n */\nexport type RuleSeverity = \"error\" | \"warn\" | \"off\";\n\n/**\n * Per-rule severity configuration for the TSDoc enforcer.\n * Each key corresponds to one of the E001–E007 rule codes.\n * @public\n */\nexport interface EnforceRules {\n\t/** E001: Exported symbol missing TSDoc summary. */\n\t\"require-summary\": RuleSeverity;\n\t/** E002: Function parameter missing @param tag. */\n\t\"require-param\": RuleSeverity;\n\t/** E003: Non-void function missing @returns tag. */\n\t\"require-returns\": RuleSeverity;\n\t/** E004: Exported function missing @example block. */\n\t\"require-example\": RuleSeverity;\n\t/** E005: Entry point missing @packageDocumentation. */\n\t\"require-package-doc\": RuleSeverity;\n\t/** E006: Class member missing documentation. */\n\t\"require-class-member-doc\": RuleSeverity;\n\t/** E007: Interface/type member missing documentation. */\n\t\"require-interface-member-doc\": RuleSeverity;\n}\n\n/**\n * Full configuration for a forge-ts run.\n * Loaded from forge-ts.config.ts or the \"forge-ts\" key in package.json.\n * @public\n */\nexport interface ForgeConfig {\n\t/** Root directory of the project. */\n\trootDir: string;\n\t/** Path to the tsconfig.json to compile against. */\n\ttsconfig: string;\n\t/** Output directory for generated files. */\n\toutDir: string;\n\t/** Enforce TSDoc on all public exports. */\n\tenforce: {\n\t\tenabled: boolean;\n\t\t/** Minimum visibility level to enforce documentation on. */\n\t\tminVisibility: Visibility;\n\t\t/** Fail on warnings rather than only on errors. */\n\t\tstrict: boolean;\n\t\t/** Per-rule severity overrides. When strict is true, all \"warn\" become \"error\". */\n\t\trules: EnforceRules;\n\t};\n\t/** DocTest configuration. */\n\tdoctest: {\n\t\tenabled: boolean;\n\t\t/** Cache directory for virtual test files. */\n\t\tcacheDir: string;\n\t};\n\t/** API generation configuration. */\n\tapi: {\n\t\tenabled: boolean;\n\t\t/** Generate an OpenAPI spec from exported HTTP handlers. */\n\t\topenapi: boolean;\n\t\t/** Output path for the OpenAPI spec file. */\n\t\topenapiPath: string;\n\t};\n\t/** Output generation configuration. */\n\tgen: {\n\t\tenabled: boolean;\n\t\t/** Output formats to generate. */\n\t\tformats: Array<\"markdown\" | \"mdx\">;\n\t\t/** Generate an llms.txt companion file. */\n\t\tllmsTxt: boolean;\n\t\t/** Synchronise summaries back into README.md. */\n\t\treadmeSync: boolean;\n\t\t/** Static site generator to target for output format. */\n\t\tssgTarget?: \"docusaurus\" | \"mintlify\" | \"nextra\" | \"vitepress\";\n\t};\n}\n\n/**\n * The result of a forge-ts compilation pass.\n * @public\n */\nexport interface ForgeResult {\n\t/** Whether the run succeeded without errors. */\n\tsuccess: boolean;\n\t/** All symbols extracted during this run. */\n\tsymbols: ForgeSymbol[];\n\t/** Errors that caused or would cause failure. */\n\terrors: ForgeError[];\n\t/** Non-fatal warnings. */\n\twarnings: ForgeWarning[];\n\t/** Wall-clock duration of the run in milliseconds. */\n\tduration: number;\n}\n\n/**\n * A diagnostic error produced during a forge-ts run.\n * @public\n */\nexport interface ForgeError {\n\t/** Machine-readable error code (e.g. \"E001\"). */\n\tcode: string;\n\t/** Human-readable description of the error. */\n\tmessage: string;\n\t/** Absolute path of the file where the error occurred. */\n\tfilePath: string;\n\t/** 1-based line number. */\n\tline: number;\n\t/** 0-based column. */\n\tcolumn: number;\n\t/** Suggested fix for the agent — exact TSDoc block to add. */\n\tsuggestedFix?: string;\n\t/** The symbol name that needs fixing. */\n\tsymbolName?: string;\n\t/** The symbol kind (function, class, interface, etc.). */\n\tsymbolKind?: string;\n}\n\n/**\n * A diagnostic warning produced during a forge-ts run.\n * @public\n */\nexport interface ForgeWarning {\n\t/** Machine-readable warning code (e.g. \"W001\"). */\n\tcode: string;\n\t/** Human-readable description of the warning. */\n\tmessage: string;\n\t/** Absolute path of the file where the warning occurred. */\n\tfilePath: string;\n\t/** 1-based line number. */\n\tline: number;\n\t/** 0-based column. */\n\tcolumn: number;\n}\n","import { type ForgeSymbol, Visibility } from \"./types.js\";\n\n/**\n * Determines the visibility level of a symbol from its TSDoc release tags.\n *\n * The precedence order is:\n * 1. `@internal` → {@link Visibility.Internal}\n * 2. `@beta` → {@link Visibility.Beta}\n * 3. `@public` → {@link Visibility.Public}\n * 4. (no tag) → {@link Visibility.Public} (default for exports)\n *\n * @param tags - The parsed `tags` map from `ForgeSymbol.documentation`.\n * @returns The resolved {@link Visibility} value.\n * @example\n * ```typescript\n * import { resolveVisibility } from \"@forge-ts/core\";\n * const vis = resolveVisibility({ internal: [] });\n * // vis === Visibility.Internal\n * ```\n * @public\n */\nexport function resolveVisibility(tags: Record<string, string[]> | undefined): Visibility {\n\tif (!tags) return Visibility.Public;\n\n\tif (\"internal\" in tags) return Visibility.Internal;\n\tif (\"beta\" in tags) return Visibility.Beta;\n\tif (\"public\" in tags) return Visibility.Public;\n\n\treturn Visibility.Public;\n}\n\n/**\n * Numeric rank used for visibility comparisons.\n * Lower numbers are more restrictive.\n * @internal\n */\nconst VISIBILITY_RANK: Record<Visibility, number> = {\n\t[Visibility.Public]: 0,\n\t[Visibility.Beta]: 1,\n\t[Visibility.Internal]: 2,\n\t[Visibility.Private]: 3,\n};\n\n/**\n * Returns whether `candidate` meets or exceeds the required minimum visibility.\n *\n * \"Meets\" means the symbol is at least as visible as `minVisibility`.\n * For example, `Public` meets a minimum of `Public`, but `Internal` does not.\n *\n * @param candidate - The visibility of the symbol being tested.\n * @param minVisibility - The minimum visibility threshold.\n * @returns `true` if `candidate` is at least as visible as `minVisibility`.\n * @example\n * ```typescript\n * import { meetsVisibility, Visibility } from \"@forge-ts/core\";\n * meetsVisibility(Visibility.Public, Visibility.Public); // true\n * meetsVisibility(Visibility.Internal, Visibility.Public); // false\n * ```\n * @public\n */\nexport function meetsVisibility(candidate: Visibility, minVisibility: Visibility): boolean {\n\treturn VISIBILITY_RANK[candidate] <= VISIBILITY_RANK[minVisibility];\n}\n\n/**\n * Filters an array of {@link ForgeSymbol} objects to only include symbols\n * whose visibility meets or exceeds `minVisibility`.\n *\n * @param symbols - The full list of symbols to filter.\n * @param minVisibility - The minimum visibility threshold to keep.\n * @returns A new array containing only symbols that pass the visibility check.\n * @example\n * ```typescript\n * import { filterByVisibility, Visibility } from \"@forge-ts/core\";\n * const publicOnly = filterByVisibility(symbols, Visibility.Public);\n * ```\n * @public\n */\nexport function filterByVisibility(\n\tsymbols: ForgeSymbol[],\n\tminVisibility: Visibility,\n): ForgeSymbol[] {\n\treturn symbols.filter((s) => meetsVisibility(s.visibility, minVisibility));\n}\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport {\n\ttype DocBlock,\n\ttype DocCodeSpan,\n\ttype DocComment,\n\ttype DocFencedCode,\n\ttype DocLinkTag,\n\ttype DocNode,\n\tDocNodeKind,\n\ttype DocParagraph,\n\ttype DocPlainText,\n\ttype DocSection,\n\tStandardTags,\n\tTSDocConfiguration,\n\tTSDocParser,\n} from \"@microsoft/tsdoc\";\nimport ts from \"typescript\";\nimport type { ForgeConfig, ForgeSymbol } from \"./types.js\";\nimport { resolveVisibility } from \"./visibility.js\";\n\n// ---------------------------------------------------------------------------\n// Public API surface\n// ---------------------------------------------------------------------------\n\n/**\n * The return type of {@link createWalker}.\n * @public\n */\nexport interface ASTWalker {\n\t/**\n\t * Walk all source files referenced by the configured tsconfig and return\n\t * one {@link ForgeSymbol} per exported declaration.\n\t */\n\twalk(): ForgeSymbol[];\n}\n\n// ---------------------------------------------------------------------------\n// TSDoc helpers\n// ---------------------------------------------------------------------------\n\n/** Render inline nodes (PlainText, CodeSpan, SoftBreak) to a plain string. @internal */\nfunction renderInlineNodes(nodes: readonly DocNode[]): string {\n\tconst parts: string[] = [];\n\tfor (const node of nodes) {\n\t\tswitch (node.kind) {\n\t\t\tcase DocNodeKind.PlainText:\n\t\t\t\tparts.push((node as DocPlainText).text);\n\t\t\t\tbreak;\n\t\t\tcase DocNodeKind.CodeSpan:\n\t\t\t\tparts.push(`\\`${(node as DocCodeSpan).code}\\``);\n\t\t\t\tbreak;\n\t\t\tcase DocNodeKind.SoftBreak:\n\t\t\t\tparts.push(\" \");\n\t\t\t\tbreak;\n\t\t\tcase DocNodeKind.Paragraph:\n\t\t\t\t// Recurse into paragraph nodes to extract nested text\n\t\t\t\tparts.push(renderInlineNodes((node as DocParagraph).nodes));\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\treturn parts.join(\"\");\n}\n\n/** Render a `DocSection` (or similar node) to a plain string. @internal */\nfunction renderDocSection(section: DocSection | undefined): string {\n\tif (!section) return \"\";\n\treturn renderInlineNodes(section.nodes).trim();\n}\n\n/** Render a `DocBlock`'s content to a plain string. @internal */\nfunction renderBlock(block: DocBlock): string {\n\treturn renderDocSection(block.content);\n}\n\n/** Extract all `@example` fenced code blocks from a parsed comment. @internal */\nfunction extractExamples(\n\tcomment: DocComment,\n\tstartLine: number,\n): Array<{ code: string; language: string; line: number }> {\n\tconst examples: Array<{ code: string; language: string; line: number }> = [];\n\n\tfor (const block of comment.customBlocks) {\n\t\tif (block.blockTag.tagName.toLowerCase() !== \"@example\") continue;\n\n\t\tfor (const node of block.content.nodes) {\n\t\t\tif (node.kind === DocNodeKind.FencedCode) {\n\t\t\t\tconst fenced = node as DocFencedCode;\n\t\t\t\texamples.push({\n\t\t\t\t\tcode: fenced.code,\n\t\t\t\t\tlanguage: fenced.language || \"typescript\",\n\t\t\t\t\tline: startLine,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn examples;\n}\n\n/** Parse a raw JSDoc/TSDoc comment string into a structured documentation object. @internal */\nfunction parseTSDoc(rawComment: string, startLine: number): ForgeSymbol[\"documentation\"] {\n\tconst configuration = new TSDocConfiguration();\n\tconst parser = new TSDocParser(configuration);\n\tconst result = parser.parseString(rawComment);\n\tconst comment = result.docComment;\n\n\tconst tags: Record<string, string[]> = {};\n\n\t// Release tags\n\tif (comment.modifierTagSet.hasTag(StandardTags.public)) {\n\t\ttags.public = [];\n\t}\n\tif (comment.modifierTagSet.hasTag(StandardTags.beta)) {\n\t\ttags.beta = [];\n\t}\n\tif (comment.modifierTagSet.hasTag(StandardTags.internal)) {\n\t\ttags.internal = [];\n\t}\n\tif (comment.modifierTagSet.hasTag(StandardTags.alpha)) {\n\t\ttags.alpha = [];\n\t}\n\tif (comment.modifierTagSet.hasTag(StandardTags.packageDocumentation)) {\n\t\ttags.packageDocumentation = [];\n\t}\n\n\t// @deprecated\n\tlet deprecated: string | undefined;\n\tif (comment.deprecatedBlock) {\n\t\tdeprecated = renderBlock(comment.deprecatedBlock).trim() || \"true\";\n\t}\n\n\t// @param blocks\n\tconst params: Array<{ name: string; description: string; type?: string }> = [];\n\tfor (const paramBlock of comment.params.blocks) {\n\t\tparams.push({\n\t\t\tname: paramBlock.parameterName,\n\t\t\tdescription: renderBlock(paramBlock),\n\t\t});\n\t}\n\n\t// @returns block\n\tlet returns: { description: string; type?: string } | undefined;\n\tif (comment.returnsBlock) {\n\t\tconst desc = renderBlock(comment.returnsBlock);\n\t\tif (desc) returns = { description: desc };\n\t}\n\n\t// @throws blocks\n\tconst throws: Array<{ type?: string; description: string }> = [];\n\tfor (const block of comment.customBlocks) {\n\t\tif (block.blockTag.tagName.toLowerCase() === \"@throws\") {\n\t\t\tthrows.push({ description: renderBlock(block) });\n\t\t}\n\t}\n\n\t// @route blocks - format: \"METHOD /path\"\n\tfor (const block of comment.customBlocks) {\n\t\tif (block.blockTag.tagName.toLowerCase() === \"@route\") {\n\t\t\tconst routeText = renderBlock(block).trim();\n\t\t\tconst match = routeText.match(/^(GET|POST|PUT|DELETE|PATCH|OPTIONS|HEAD)\\s+(\\S+)/i);\n\t\t\tif (match) {\n\t\t\t\tif (!tags.route) tags.route = [];\n\t\t\t\ttags.route.push(`${match[1].toUpperCase()} ${match[2]}`);\n\t\t\t}\n\t\t}\n\t}\n\n\t// @example blocks\n\tconst examples = extractExamples(comment, startLine);\n\n\t// Extract {@link} references\n\tconst links: Array<{ target: string; line: number }> = [];\n\tfunction walkForLinks(node: DocNode): void {\n\t\tif (node.kind === DocNodeKind.LinkTag) {\n\t\t\tconst linkTag = node as DocLinkTag;\n\t\t\tif (linkTag.codeDestination) {\n\t\t\t\tconst target = linkTag.codeDestination.memberReferences\n\t\t\t\t\t.map((ref) => ref.memberIdentifier?.identifier ?? \"\")\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.join(\".\");\n\t\t\t\tif (target) {\n\t\t\t\t\tlinks.push({ target, line: startLine });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor (const child of node.getChildNodes()) {\n\t\t\twalkForLinks(child);\n\t\t}\n\t}\n\twalkForLinks(comment);\n\n\tconst summary = renderDocSection(comment.summarySection);\n\n\treturn {\n\t\tsummary: summary || undefined,\n\t\tparams: params.length > 0 ? params : undefined,\n\t\treturns,\n\t\tthrows: throws.length > 0 ? throws : undefined,\n\t\texamples: examples.length > 0 ? examples : undefined,\n\t\ttags: Object.keys(tags).length > 0 ? tags : undefined,\n\t\tdeprecated,\n\t\tlinks: links.length > 0 ? links : undefined,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// TypeScript AST helpers\n// ---------------------------------------------------------------------------\n\n/** Extract the leading JSDoc comment text for a node. @internal */\nfunction getLeadingComment(node: ts.Node, sourceFile: ts.SourceFile): string | undefined {\n\tconst fullText = sourceFile.getFullText();\n\tconst ranges = ts.getLeadingCommentRanges(fullText, node.getFullStart());\n\tif (!ranges || ranges.length === 0) return undefined;\n\n\t// Take the last leading comment (closest to the declaration)\n\tconst range = ranges[ranges.length - 1];\n\tif (\n\t\trange.kind !== ts.SyntaxKind.MultiLineCommentTrivia ||\n\t\t!fullText.slice(range.pos, range.end).startsWith(\"/**\")\n\t) {\n\t\treturn undefined;\n\t}\n\n\treturn fullText.slice(range.pos, range.end);\n}\n\n/** Map a TypeScript `SyntaxKind` to a `ForgeSymbol` kind string. @internal */\nfunction kindToString(kind: ts.SyntaxKind): ForgeSymbol[\"kind\"] | null {\n\tswitch (kind) {\n\t\tcase ts.SyntaxKind.FunctionDeclaration:\n\t\tcase ts.SyntaxKind.ArrowFunction:\n\t\tcase ts.SyntaxKind.FunctionExpression:\n\t\t\treturn \"function\";\n\t\tcase ts.SyntaxKind.ClassDeclaration:\n\t\t\treturn \"class\";\n\t\tcase ts.SyntaxKind.InterfaceDeclaration:\n\t\t\treturn \"interface\";\n\t\tcase ts.SyntaxKind.TypeAliasDeclaration:\n\t\t\treturn \"type\";\n\t\tcase ts.SyntaxKind.EnumDeclaration:\n\t\t\treturn \"enum\";\n\t\tcase ts.SyntaxKind.VariableDeclaration:\n\t\tcase ts.SyntaxKind.VariableStatement:\n\t\t\treturn \"variable\";\n\t\tcase ts.SyntaxKind.MethodDeclaration:\n\t\tcase ts.SyntaxKind.MethodSignature:\n\t\t\treturn \"method\";\n\t\tcase ts.SyntaxKind.PropertyDeclaration:\n\t\tcase ts.SyntaxKind.PropertySignature:\n\t\tcase ts.SyntaxKind.EnumMember:\n\t\t\treturn \"property\";\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\n/** Build a human-readable type signature string using the type checker. @internal */\nfunction buildSignature(node: ts.Declaration, checker: ts.TypeChecker): string | undefined {\n\ttry {\n\t\tconst symbol = checker.getSymbolAtLocation((node as ts.NamedDeclaration).name ?? node);\n\t\tif (!symbol) return undefined;\n\t\tconst type = checker.getTypeOfSymbolAtLocation(symbol, node);\n\t\treturn checker.typeToString(type);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Walker implementation\n// ---------------------------------------------------------------------------\n\n/** @internal */\nfunction extractSymbolsFromFile(\n\tsourceFile: ts.SourceFile,\n\tchecker: ts.TypeChecker,\n\t_tsdocParser: TSDocParser,\n): ForgeSymbol[] {\n\tconst symbols: ForgeSymbol[] = [];\n\tconst filePath = sourceFile.fileName;\n\n\tfunction visit(node: ts.Node, parentExported: boolean): void {\n\t\tconst isExported =\n\t\t\tparentExported ||\n\t\t\t(ts.getCombinedModifierFlags(node as ts.Declaration) & ts.ModifierFlags.Export) !== 0;\n\n\t\t// Handle export declarations: `export { Foo, Bar }`\n\t\tif (ts.isExportDeclaration(node)) {\n\t\t\tts.forEachChild(node, (child) => visit(child, true));\n\t\t\treturn;\n\t\t}\n\n\t\tconst kind = kindToString(node.kind);\n\n\t\t// Variable statements need special handling: `export const foo = ...`\n\t\tif (ts.isVariableStatement(node)) {\n\t\t\tif (!isExported) {\n\t\t\t\tts.forEachChild(node, (child) => visit(child, false));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const decl of node.declarationList.declarations) {\n\t\t\t\tconst name = decl.name.getText(sourceFile);\n\t\t\t\tconst pos = sourceFile.getLineAndCharacterOfPosition(decl.getStart());\n\t\t\t\tconst rawComment = getLeadingComment(node, sourceFile);\n\t\t\t\tconst documentation = rawComment ? parseTSDoc(rawComment, pos.line + 1) : undefined;\n\t\t\t\tconst tags = documentation?.tags;\n\t\t\t\tconst visibility = resolveVisibility(tags);\n\n\t\t\t\tsymbols.push({\n\t\t\t\t\tname,\n\t\t\t\t\tkind: \"variable\",\n\t\t\t\t\tvisibility,\n\t\t\t\t\tfilePath,\n\t\t\t\t\tline: pos.line + 1,\n\t\t\t\t\tcolumn: pos.character,\n\t\t\t\t\tdocumentation,\n\t\t\t\t\tsignature: buildSignature(decl, checker),\n\t\t\t\t\texported: true,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kind === null || !isExported) {\n\t\t\tts.forEachChild(node, (child) => visit(child, isExported));\n\t\t\treturn;\n\t\t}\n\n\t\tconst namedNode = node as ts.NamedDeclaration;\n\t\tconst nameNode = namedNode.name;\n\t\tif (!nameNode) {\n\t\t\tts.forEachChild(node, (child) => visit(child, isExported));\n\t\t\treturn;\n\t\t}\n\n\t\tconst name = nameNode.getText(sourceFile);\n\t\tconst pos = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n\t\tconst rawComment = getLeadingComment(node, sourceFile);\n\t\tconst documentation = rawComment ? parseTSDoc(rawComment, pos.line + 1) : undefined;\n\t\tconst tags = documentation?.tags;\n\t\tconst visibility = resolveVisibility(tags);\n\n\t\tconst children: ForgeSymbol[] = [];\n\n\t\t// Walk class members / interface members / enum members\n\t\tif (\n\t\t\tts.isClassDeclaration(node) ||\n\t\t\tts.isInterfaceDeclaration(node) ||\n\t\t\tts.isEnumDeclaration(node)\n\t\t) {\n\t\t\tfor (const member of node.members) {\n\t\t\t\tconst memberKind = kindToString(member.kind);\n\t\t\t\tif (!memberKind) continue;\n\t\t\t\tconst memberName = (member as ts.NamedDeclaration).name?.getText(sourceFile) ?? \"\";\n\t\t\t\tconst memberPos = sourceFile.getLineAndCharacterOfPosition(member.getStart());\n\t\t\t\tconst memberComment = getLeadingComment(member, sourceFile);\n\t\t\t\tconst memberDoc = memberComment ? parseTSDoc(memberComment, memberPos.line + 1) : undefined;\n\t\t\t\tconst memberTags = memberDoc?.tags;\n\t\t\t\tconst memberVisibility = resolveVisibility(memberTags);\n\n\t\t\t\tchildren.push({\n\t\t\t\t\tname: memberName,\n\t\t\t\t\tkind: memberKind,\n\t\t\t\t\tvisibility: memberVisibility,\n\t\t\t\t\tfilePath,\n\t\t\t\t\tline: memberPos.line + 1,\n\t\t\t\t\tcolumn: memberPos.character,\n\t\t\t\t\tdocumentation: memberDoc,\n\t\t\t\t\tsignature: buildSignature(member as ts.Declaration, checker),\n\t\t\t\t\texported: false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tsymbols.push({\n\t\t\tname,\n\t\t\tkind,\n\t\t\tvisibility,\n\t\t\tfilePath,\n\t\t\tline: pos.line + 1,\n\t\t\tcolumn: pos.character,\n\t\t\tdocumentation,\n\t\t\tsignature: buildSignature(namedNode as ts.Declaration, checker),\n\t\t\tchildren: children.length > 0 ? children : undefined,\n\t\t\texported: isExported,\n\t\t});\n\t}\n\n\tts.forEachChild(sourceFile, (node) => visit(node, false));\n\treturn symbols;\n}\n\n/**\n * Creates an {@link ASTWalker} configured for the given forge config.\n *\n * The walker uses the TypeScript Compiler API to create a `ts.Program` from\n * the project's tsconfig, then visits every source file to extract exported\n * declarations. TSDoc comments are parsed with `@microsoft/tsdoc` to\n * populate the `documentation` field on each {@link ForgeSymbol}.\n *\n * @param config - The resolved {@link ForgeConfig} for the project.\n * @returns An {@link ASTWalker} instance whose `walk()` method performs the extraction.\n * @example\n * ```typescript\n * import { loadConfig, createWalker } from \"@forge-ts/core\";\n * const config = await loadConfig();\n * const walker = createWalker(config);\n * const symbols = walker.walk();\n * console.log(`Found ${symbols.length} symbols`);\n * ```\n * @public\n */\nexport function createWalker(config: ForgeConfig): ASTWalker {\n\treturn {\n\t\twalk(): ForgeSymbol[] {\n\t\t\t// Load tsconfig\n\t\t\tconst tsconfigPath = resolve(config.tsconfig);\n\t\t\tconst configFile = ts.readConfigFile(tsconfigPath, (path) => readFileSync(path, \"utf8\"));\n\n\t\t\tif (configFile.error) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to read tsconfig at ${tsconfigPath}: ${ts.flattenDiagnosticMessageText(configFile.error.messageText, \"\\n\")}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst parsedCommandLine = ts.parseJsonConfigFileContent(\n\t\t\t\tconfigFile.config,\n\t\t\t\tts.sys,\n\t\t\t\tresolve(config.rootDir),\n\t\t\t);\n\n\t\t\tconst program = ts.createProgram({\n\t\t\t\trootNames: parsedCommandLine.fileNames,\n\t\t\t\toptions: parsedCommandLine.options,\n\t\t\t});\n\n\t\t\tconst checker = program.getTypeChecker();\n\n\t\t\tconst tsdocConfiguration = new TSDocConfiguration();\n\t\t\tconst tsdocParser = new TSDocParser(tsdocConfiguration);\n\n\t\t\tconst allSymbols: ForgeSymbol[] = [];\n\n\t\t\tfor (const sourceFile of program.getSourceFiles()) {\n\t\t\t\t// Skip declaration files and node_modules\n\t\t\t\tif (sourceFile.isDeclarationFile || sourceFile.fileName.includes(\"node_modules\")) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst fileSymbols = extractSymbolsFromFile(sourceFile, checker, tsdocParser);\n\t\t\t\tallSymbols.push(...fileSymbols);\n\t\t\t}\n\n\t\t\treturn allSymbols;\n\t\t},\n\t};\n}\n"],"mappings":"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","names":["Visibility","resolve","name","pos","rawComment","documentation","tags","visibility","resolve"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forge-ts/core",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Shared types, interfaces, and core AST walker for forge-ts",
6
6
  "license": "MIT",
@@ -29,9 +29,9 @@
29
29
  },
30
30
  "devDependencies": {
31
31
  "tsup": "^8.3.5",
32
- "@forge-ts/api": "0.3.0",
33
- "@forge-ts/enforcer": "0.3.0",
34
- "@forge-ts/gen": "0.3.0"
32
+ "@forge-ts/api": "0.4.0",
33
+ "@forge-ts/enforcer": "0.4.0",
34
+ "@forge-ts/gen": "0.4.0"
35
35
  },
36
36
  "scripts": {
37
37
  "build": "tsup",