svelte-docinfo 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +20 -9
  2. package/dist/analyze-core.d.ts +55 -27
  3. package/dist/analyze-core.d.ts.map +1 -1
  4. package/dist/analyze-core.js +51 -45
  5. package/dist/analyze.d.ts +12 -31
  6. package/dist/analyze.d.ts.map +1 -1
  7. package/dist/analyze.js +5 -3
  8. package/dist/cli.d.ts +4 -7
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +4 -3
  11. package/dist/concurrency.d.ts +6 -3
  12. package/dist/concurrency.d.ts.map +1 -1
  13. package/dist/concurrency.js +6 -3
  14. package/dist/dep-resolver.d.ts +6 -3
  15. package/dist/dep-resolver.d.ts.map +1 -1
  16. package/dist/dep-resolver.js +6 -3
  17. package/dist/diagnostics.d.ts +18 -9
  18. package/dist/diagnostics.d.ts.map +1 -1
  19. package/dist/diagnostics.js +20 -9
  20. package/dist/discovery.d.ts +16 -21
  21. package/dist/discovery.d.ts.map +1 -1
  22. package/dist/discovery.js +9 -17
  23. package/dist/error.d.ts +3 -4
  24. package/dist/error.d.ts.map +1 -1
  25. package/dist/error.js +3 -4
  26. package/dist/exports.d.ts +7 -7
  27. package/dist/exports.d.ts.map +1 -1
  28. package/dist/exports.js +8 -8
  29. package/dist/files.d.ts +0 -3
  30. package/dist/files.d.ts.map +1 -1
  31. package/dist/files.js +5 -5
  32. package/dist/index.js +1 -1
  33. package/dist/postprocess.d.ts +13 -6
  34. package/dist/postprocess.d.ts.map +1 -1
  35. package/dist/postprocess.js +13 -6
  36. package/dist/session.d.ts +36 -12
  37. package/dist/session.d.ts.map +1 -1
  38. package/dist/session.js +39 -24
  39. package/dist/source-config.d.ts +22 -19
  40. package/dist/source-config.d.ts.map +1 -1
  41. package/dist/source-config.js +14 -12
  42. package/dist/source.d.ts +17 -13
  43. package/dist/source.d.ts.map +1 -1
  44. package/dist/source.js +4 -7
  45. package/dist/svelte.d.ts +21 -4
  46. package/dist/svelte.d.ts.map +1 -1
  47. package/dist/svelte.js +48 -15
  48. package/dist/tsdoc.d.ts +16 -13
  49. package/dist/tsdoc.d.ts.map +1 -1
  50. package/dist/tsdoc.js +75 -35
  51. package/dist/types.d.ts +607 -171
  52. package/dist/types.d.ts.map +1 -1
  53. package/dist/types.js +75 -30
  54. package/dist/typescript-exports.d.ts +7 -7
  55. package/dist/typescript-exports.d.ts.map +1 -1
  56. package/dist/typescript-exports.js +15 -13
  57. package/dist/typescript-extract-class.d.ts +2 -1
  58. package/dist/typescript-extract-class.d.ts.map +1 -1
  59. package/dist/typescript-extract-class.js +7 -7
  60. package/dist/typescript-extract-function.js +3 -3
  61. package/dist/typescript-extract-shared.d.ts +32 -12
  62. package/dist/typescript-extract-shared.d.ts.map +1 -1
  63. package/dist/typescript-extract-shared.js +55 -34
  64. package/dist/typescript-extract-type-json.d.ts +11 -3
  65. package/dist/typescript-extract-type-json.d.ts.map +1 -1
  66. package/dist/typescript-extract-type-json.js +12 -9
  67. package/dist/typescript-extract-type-properties.js +3 -3
  68. package/dist/typescript-extract-type.js +7 -7
  69. package/dist/typescript-program.d.ts +23 -8
  70. package/dist/typescript-program.d.ts.map +1 -1
  71. package/dist/typescript-program.js +23 -14
  72. package/dist/vite.d.ts +12 -35
  73. package/dist/vite.d.ts.map +1 -1
  74. package/dist/vite.js +7 -6
  75. package/package.json +9 -29
  76. package/virtual-svelte-docinfo.d.ts +9 -7
package/dist/source.js CHANGED
@@ -1,12 +1,9 @@
1
1
  /**
2
- * Source file type predicates and path helpers.
3
- *
4
- * Pure functions for detecting file types by extension and extracting
5
- * component names from paths. No configuration dependency — these are
6
- * the building blocks used by `source-config.ts`.
2
+ * Source file shapes (`SourceFileInfo`, `AnalyzerType`), extension predicates,
3
+ * and svelte2tsx virtual-path and generated-name helpers. No configuration
4
+ * dependency; the building blocks under `source-config.ts`.
7
5
  *
8
6
  * @see `source-config.ts` for configuration-aware functions (`isSource`, `extractPath`, etc.)
9
- * @see `analyze.ts` for consumers (`analyze`, `analyzeFromFiles`)
10
7
  *
11
8
  * @module
12
9
  */
@@ -14,7 +11,7 @@
14
11
  * Default analyzer resolver based on file extension.
15
12
  *
16
13
  * - `.svelte` → `'svelte'`
17
- * - `.ts`, `.js` → `'typescript'`
14
+ * - `.ts` (not `.d.ts`), `.js` → `'typescript'`
18
15
  * - `.css` → `'css'`
19
16
  * - `.json` → `'json'`
20
17
  * - Other extensions → `null` (skip)
package/dist/svelte.d.ts CHANGED
@@ -74,8 +74,9 @@ export interface TransformResult {
74
74
  *
75
75
  * Produces a `SvelteVirtualFile` containing the transformed TypeScript content
76
76
  * and source map. The virtual file can be included in a TypeScript program
77
- * (via `createAnalysisProgram({ virtualFiles })`) so that the checker can
78
- * resolve imported types, `<script module>` exports, and re-exports.
77
+ * (via `createAnalysisProgram({ virtualFiles })`, or the language service's
78
+ * `setFile` in sessions) so that the checker can resolve imported types,
79
+ * `<script module>` exports, and re-exports.
79
80
  *
80
81
  * Errors at ingest are returned via `diagnostics` rather than thrown:
81
82
  * - svelte2tsx throws → `transform_failed`, `virtual: undefined`
@@ -153,7 +154,7 @@ export declare const extractSvelteModuleComment: (scriptContent: string) => stri
153
154
  * assembling modules themselves through `analyzeModule` /
154
155
  * `analyzeSvelteModule`.
155
156
  *
156
- * @mutates diagnostics — rewrites `line`/`column` on virtual-file entries
157
+ * @mutates diagnostics - rewrites `line`/`column` on virtual-file entries
157
158
  */
158
159
  export declare const remapVirtualDiagnosticPositions: (diagnostics: Array<Diagnostic>, virtualFiles: Iterable<SvelteVirtualFile>) => void;
159
160
  /**
@@ -224,11 +225,27 @@ export declare const synthesizeSnippetTypeSignature: (parameters: Array<Paramete
224
225
  * Analyze a Svelte module using checker-backed analysis.
225
226
  *
226
227
  * Requires the svelte2tsx virtual output to be included in the TypeScript program
227
- * (via `createAnalysisProgram({ virtualFiles })`). Provides full type resolution for:
228
+ * (via `createAnalysisProgram({ virtualFiles })`, or the language service's
229
+ * `setFile` in sessions). Provides full type resolution for:
228
230
  * - Imported prop types (`let {x}: ImportedProps = $props()`)
229
231
  * - `<script module>` exports (constants, types, re-exports)
230
232
  * - Star exports and re-exports from Svelte files
231
233
  *
234
+ * Mirrors the numbered steps in the body:
235
+ *
236
+ * 1. `analyzeExports` on the virtual collects `<script module>` exports,
237
+ * re-exports, and star exports
238
+ * 2. svelte2tsx internals are filtered (`isSvelte2tsxGeneratedExport`) and
239
+ * exported snippets reclassified to `kind: 'snippet'` (`isSnippetReturnType`);
240
+ * 2b remaps module-level `sourceLine`s to the original `.svelte` source
241
+ * 3. the component declaration is synthesized: props via `extractPropsViaChecker`,
242
+ * `acceptsChildren` from a `Snippet`-typed `children` prop or, failing that,
243
+ * template use (`__sveltets_2_ensureSnippet`), plus generics, doc comment, and
244
+ * source line from the landmarks `findComponentNodes` locates
245
+ * 4. the module comment is read from the original source
246
+ * 5. declarations combine, component first
247
+ * 6. dependencies are extracted
248
+ *
232
249
  * @param sourceFile - the original Svelte source file
233
250
  * @param modulePath - module path relative to source root; feeds
234
251
  * `ModuleJson.path` and the component name, never `Diagnostic.file` (which
@@ -1 +1 @@
1
- {"version":3,"file":"svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/svelte.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/svelte.ts"],"names":[],"mappings":"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"}
package/dist/svelte.js CHANGED
@@ -34,15 +34,16 @@ import { getComponentName, isSvelte2tsxGeneratedExport, SVELTE_COMPONENT_ALIAS_S
34
34
  import { extractDependencies } from './source-config.js';
35
35
  import { compareStrings } from './postprocess.js';
36
36
  import {} from './diagnostics.js';
37
- import { to_error_message } from './error.js';
37
+ import { toErrorMessage } from './error.js';
38
38
  import { toPosixPath } from './paths.js';
39
39
  /**
40
40
  * Pre-transform a Svelte source file via svelte2tsx.
41
41
  *
42
42
  * Produces a `SvelteVirtualFile` containing the transformed TypeScript content
43
43
  * and source map. The virtual file can be included in a TypeScript program
44
- * (via `createAnalysisProgram({ virtualFiles })`) so that the checker can
45
- * resolve imported types, `<script module>` exports, and re-exports.
44
+ * (via `createAnalysisProgram({ virtualFiles })`, or the language service's
45
+ * `setFile` in sessions) so that the checker can resolve imported types,
46
+ * `<script module>` exports, and re-exports.
46
47
  *
47
48
  * Errors at ingest are returned via `diagnostics` rather than thrown:
48
49
  * - svelte2tsx throws → `transform_failed`, `virtual: undefined`
@@ -85,7 +86,7 @@ export const transformSvelteSource = (sourceFile) => {
85
86
  diagnostics.push({
86
87
  kind: 'transform_failed',
87
88
  file: posixId,
88
- message: `svelte2tsx failed to transform Svelte source: ${to_error_message(err)}`,
89
+ message: `svelte2tsx failed to transform Svelte source: ${toErrorMessage(err)}`,
89
90
  severity: 'error'
90
91
  });
91
92
  return { virtual: undefined, diagnostics };
@@ -99,7 +100,7 @@ export const transformSvelteSource = (sourceFile) => {
99
100
  diagnostics.push({
100
101
  kind: 'source_map_failed',
101
102
  file: posixId,
102
- message: `Failed to parse svelte2tsx source map: ${to_error_message(err)}. Line/column positions for this file will reference virtual TypeScript output instead of the original Svelte source.`,
103
+ message: `Failed to parse svelte2tsx source map: ${toErrorMessage(err)}. Line/column positions for this file will reference virtual TypeScript output instead of the original Svelte source.`,
103
104
  severity: 'warning'
104
105
  });
105
106
  }
@@ -491,6 +492,9 @@ const extractComponentTsdoc = (nodes, sourceFile) => {
491
492
  * documented statement in a propless runes component or a legacy `export let`
492
493
  * component is some local's doc, not the component's). The HTML `@component`
493
494
  * comment is the authoring path for anchorless components.
495
+ *
496
+ * A JSDoc above the instance script's first import is missed: svelte2tsx
497
+ * hoists imports out of `$$render`, taking their leading comments with them.
494
498
  */
495
499
  const findInstanceTsdoc = (renderBody, sourceFile) => {
496
500
  const { statements } = renderBody;
@@ -521,6 +525,13 @@ const isPropsDeclaration = (statement) => ts.isVariableStatement(statement) &&
521
525
  * annotation (or the one svelte2tsx synthesizes for untyped `$props()`)
522
526
  * parses to an empty result and would otherwise claim the doc slot, masking
523
527
  * the HTML `@component` fallback.
528
+ *
529
+ * Two JS-component caveats: a description block written above a separate
530
+ * `/** @type {...} *\/` block never attaches (TypeScript binds only the last
531
+ * block — write docs in the HTML comment, or inside the `@type` block), and
532
+ * svelte2tsx consumes descriptions merged into an inline `@type {{...}}`
533
+ * literal when it rewrites it into a synthesized typedef (the HTML fallback
534
+ * still applies).
524
535
  */
525
536
  const findComponentTsdoc = (root, sourceFile) => {
526
537
  let foundTsdoc = undefined;
@@ -566,7 +577,7 @@ const findComponentTsdoc = (root, sourceFile) => {
566
577
  * assembling modules themselves through `analyzeModule` /
567
578
  * `analyzeSvelteModule`.
568
579
  *
569
- * @mutates diagnostics — rewrites `line`/`column` on virtual-file entries
580
+ * @mutates diagnostics - rewrites `line`/`column` on virtual-file entries
570
581
  */
571
582
  export const remapVirtualDiagnosticPositions = (diagnostics, virtualFiles) => {
572
583
  if (diagnostics.length === 0)
@@ -825,7 +836,7 @@ const detectChildrenSnippet = (propsType, propsTypeNode, ctx, componentName, dia
825
836
  ctx.diagnostics.push({
826
837
  kind: 'svelte_prop_failed',
827
838
  file: diagnosticFile,
828
- message: `Failed to resolve type for "children" in ${componentName} while detecting acceptsChildren: ${to_error_message(err)}`,
839
+ message: `Failed to resolve type for "children" in ${componentName} while detecting acceptsChildren: ${toErrorMessage(err)}`,
829
840
  severity: 'warning',
830
841
  componentName,
831
842
  propName: 'children'
@@ -888,15 +899,18 @@ const extractPropsViaChecker = (virtualSource, ctx, componentName, diagnosticFil
888
899
  }
889
900
  const { type: propsType, node: propsTypeNode } = resolvedProps;
890
901
  // Detect `acceptsChildren` via type inference: `children` must resolve to a
891
- // `Snippet<...>` type. Checking the symbol name alone (the previous approach)
892
- // misreports a non-Snippet `children` (e.g. `children: string`) as accepting
893
- // children. The lookup runs on the unfiltered props type so inherited
894
- // `children` from `SvelteHTMLElements`/`DOMAttributes` (declared as `Snippet`)
895
- // is honored even when its declaration lives in node_modules.
902
+ // `Snippet<...>` type. Checking the symbol name alone would misreport a
903
+ // non-Snippet `children` (e.g. `children: string`) as accepting children.
904
+ // The lookup runs on the unfiltered props type so inherited `children` from
905
+ // `SvelteHTMLElements`/`DOMAttributes` (declared as `Snippet`) is honored
906
+ // even when its declaration lives in node_modules.
896
907
  const acceptsChildren = detectChildrenSnippet(propsType, propsTypeNode, ctx, componentName, diagnosticFile);
897
908
  // Drop properties contributed by external types (node_modules / svelte's
898
909
  // element-attribute bags like `SvelteHTMLElements['li']`); those external
899
910
  // types are summarized in `externalTypes` rather than enumerated as props.
911
+ // No `hasExtractableProperties` gate here, unlike the type-alias path, so
912
+ // union prop types (`HTMLButtonAttributes | HTMLAnchorAttributes`) still get
913
+ // `externalTypes`.
900
914
  const { properties, externalTypes } = filterDocumentedProperties(propsType, propsTypeNode, checker, ctx.isExternalFile);
901
915
  // One pick rule for "which declaration represents this prop": the symbol's
902
916
  // declaration in the component's own file when one exists, else the usual
@@ -996,7 +1010,7 @@ const extractPropsViaChecker = (virtualSource, ctx, componentName, diagnosticFil
996
1010
  file: diagnosticFile,
997
1011
  line: finalLine,
998
1012
  column: finalColumn,
999
- message: `Failed to resolve type for prop "${prop.name}" in ${componentName}, falling back to 'any': ${to_error_message(err)}`,
1013
+ message: `Failed to resolve type for prop "${prop.name}" in ${componentName}, falling back to 'any': ${toErrorMessage(err)}`,
1000
1014
  severity: 'warning',
1001
1015
  componentName,
1002
1016
  propName: prop.name
@@ -1010,11 +1024,27 @@ const extractPropsViaChecker = (virtualSource, ctx, componentName, diagnosticFil
1010
1024
  * Analyze a Svelte module using checker-backed analysis.
1011
1025
  *
1012
1026
  * Requires the svelte2tsx virtual output to be included in the TypeScript program
1013
- * (via `createAnalysisProgram({ virtualFiles })`). Provides full type resolution for:
1027
+ * (via `createAnalysisProgram({ virtualFiles })`, or the language service's
1028
+ * `setFile` in sessions). Provides full type resolution for:
1014
1029
  * - Imported prop types (`let {x}: ImportedProps = $props()`)
1015
1030
  * - `<script module>` exports (constants, types, re-exports)
1016
1031
  * - Star exports and re-exports from Svelte files
1017
1032
  *
1033
+ * Mirrors the numbered steps in the body:
1034
+ *
1035
+ * 1. `analyzeExports` on the virtual collects `<script module>` exports,
1036
+ * re-exports, and star exports
1037
+ * 2. svelte2tsx internals are filtered (`isSvelte2tsxGeneratedExport`) and
1038
+ * exported snippets reclassified to `kind: 'snippet'` (`isSnippetReturnType`);
1039
+ * 2b remaps module-level `sourceLine`s to the original `.svelte` source
1040
+ * 3. the component declaration is synthesized: props via `extractPropsViaChecker`,
1041
+ * `acceptsChildren` from a `Snippet`-typed `children` prop or, failing that,
1042
+ * template use (`__sveltets_2_ensureSnippet`), plus generics, doc comment, and
1043
+ * source line from the landmarks `findComponentNodes` locates
1044
+ * 4. the module comment is read from the original source
1045
+ * 5. declarations combine, component first
1046
+ * 6. dependencies are extracted
1047
+ *
1018
1048
  * @param sourceFile - the original Svelte source file
1019
1049
  * @param modulePath - module path relative to source root; feeds
1020
1050
  * `ModuleJson.path` and the component name, never `Diagnostic.file` (which
@@ -1275,7 +1305,10 @@ export const analyzeSvelteModule = (sourceFile, modulePath, checker, options, di
1275
1305
  severity: 'warning'
1276
1306
  });
1277
1307
  }
1278
- // 5. Combine: component declaration first (primary export), then <script module> exports
1308
+ // 5. Combine: component declaration first (primary export), then <script module> exports;
1309
+ // `@nodocs` is read from whichever doc source won (in-script JSDoc over the
1310
+ // HTML `@component` comment), so an HTML `@nodocs` is ignored when in-script
1311
+ // JSDoc supplies the doc
1279
1312
  const allDeclarations = [
1280
1313
  { declaration: componentDecl, nodocs: componentTsdoc?.tsdoc.nodocs === true },
1281
1314
  ...moduleDeclarations
package/dist/tsdoc.d.ts CHANGED
@@ -22,25 +22,23 @@
22
22
  *
23
23
  * `@internal` is a marker, not an exclusion: it means "not stable public API"
24
24
  * and lands as `internalMessage` (with any trailing prose; empty string for a
25
- * bare tag) while the declaration stays documented. Use `@nodocs` to exclude
26
- * a declaration from output entirely.
27
- *
28
- * The `@nodocs` tag excludes exports from documentation and flat namespace validation.
29
- * The declaration is still exported and usable, just not documented.
25
+ * bare tag) while the declaration stays documented. `@nodocs` excludes a
26
+ * declaration from documentation and flat-namespace validation — it's still
27
+ * exported and usable, just not documented.
30
28
  *
31
29
  * Also supports `@mutates` (non-standard) for documenting mutations to parameters or external state.
32
- * Uses same format as `@param`: `@mutates key - description of mutation`. The key is
33
- * unvalidated — typically a parameter name, but compound paths (`this.foo`, `obj.field`)
34
- * and external state references are accepted as-is.
30
+ * Format: `@mutates target - description of mutation` — the target is everything before the
31
+ * first ` - ` separator. It is unvalidated: typically a parameter name, but compound paths
32
+ * (`this.foo`, `obj.field`) and multi-word external references are accepted; backticks are
33
+ * stripped from the target so `` `a` `` and `a` are one key. Without a separator the first
34
+ * line is a bare target (empty description) and any continuation lines are the description.
35
35
  *
36
36
  * The `@see` tag supports multiple formats: plain URLs (`https://...`), `{@link}` syntax, and module names.
37
37
  * Relative/absolute path support in `@see` is TBD.
38
38
  *
39
39
  * ## Behavioral notes
40
40
  *
41
- * JSDoc blocks tagged `@module` are excluded from `parseComment` entirely (text
42
- * and tags) — module comments attach to the file's first statement in the AST
43
- * and are owned by `extractModuleComment` instead.
41
+ * `@module` blocks are excluded from `parseComment` (see there).
44
42
  *
45
43
  * `JSDocPropertyLikeTag` nodes (`@property`/`@param` declaring a symbol in a
46
44
  * typedef or callback) parse to their own tag description — the only doc such
@@ -48,7 +46,8 @@
48
46
  *
49
47
  * Due to TS Compiler API limitations:
50
48
  * - TS API includes dash separator in `@param` tag text; we strip the leading `- ` as it's syntax, not content
51
- * - `@throws` tags have `{Type}` stripped by TS API; fallback regex extracts first word as error type
49
+ * - `@throws` braced types (`{TypeError}`) parse into the tag's typeExpression, not its text —
50
+ * the type is read from there; unbraced text falls back to a first-word-as-type regex
52
51
  * - TS API strips URL protocols from `@see` tag text; we use `getText()` to preserve original format including `{@link}` syntax
53
52
  *
54
53
  * @see `declaration-build.ts` for `DeclarationJsonBuild`
@@ -93,7 +92,11 @@ export interface TsdocParsedComment {
93
92
  since?: string;
94
93
  /** Default value from `@default` (or its `@defaultValue`/`@defaultvalue` spellings). */
95
94
  defaultValue?: string;
96
- /** Mutation documentation from `@mutates` (non-standard), mapped by parameter name. */
95
+ /**
96
+ * Mutation documentation from `@mutates` (non-standard), mapped by target —
97
+ * typically a parameter name, possibly a compound path (`this.foo`) or a
98
+ * multi-word external reference. Empty string for a bare tag with no description.
99
+ */
97
100
  mutates?: Record<string, string>;
98
101
  /** Whether to exclude from documentation. From `@nodocs` tag. */
99
102
  nodocs?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"tsdoc.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/tsdoc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEpF;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IAClC,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvD,qCAAqC;IACrC,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACzB,8CAA8C;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxB,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wFAAwF;IACxF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB;AAgCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,eAAO,MAAM,YAAY,GACxB,MAAM,EAAE,CAAC,IAAI,EACb,aAAY,EAAE,CAAC,UAAiC,KAC9C,kBAAkB,GAAG,SA8HvB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,GAAI,2BAA2B,kBAAkB,KAAG,OAGrB,CAAC;AAE1D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,GAC9B,aAAa,oBAAoB,GAAG,eAAe,EACnD,OAAO,kBAAkB,GAAG,SAAS,EACrC,WAAU,OAAe,KACvB,IAwCF,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY,GAAI,aAAa,MAAM,KAAG,MAAM,GAAG,SAW3D,CAAC"}
1
+ {"version":3,"file":"tsdoc.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/tsdoc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEpF;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IAClC,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvD,qCAAqC;IACrC,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACzB,8CAA8C;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxB,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wFAAwF;IACxF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB;AA+DD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,eAAO,MAAM,YAAY,GACxB,MAAM,EAAE,CAAC,IAAI,EACb,aAAY,EAAE,CAAC,UAAiC,KAC9C,kBAAkB,GAAG,SAqIvB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,GAAI,2BAA2B,kBAAkB,KAAG,OAGrB,CAAC;AAE1D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,GAC9B,aAAa,oBAAoB,GAAG,eAAe,EACnD,OAAO,kBAAkB,GAAG,SAAS,EACrC,WAAU,OAAe,KACvB,IAwCF,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY,GAAI,aAAa,MAAM,KAAG,MAAM,GAAG,SAW3D,CAAC"}
package/dist/tsdoc.js CHANGED
@@ -22,25 +22,23 @@
22
22
  *
23
23
  * `@internal` is a marker, not an exclusion: it means "not stable public API"
24
24
  * and lands as `internalMessage` (with any trailing prose; empty string for a
25
- * bare tag) while the declaration stays documented. Use `@nodocs` to exclude
26
- * a declaration from output entirely.
27
- *
28
- * The `@nodocs` tag excludes exports from documentation and flat namespace validation.
29
- * The declaration is still exported and usable, just not documented.
25
+ * bare tag) while the declaration stays documented. `@nodocs` excludes a
26
+ * declaration from documentation and flat-namespace validation — it's still
27
+ * exported and usable, just not documented.
30
28
  *
31
29
  * Also supports `@mutates` (non-standard) for documenting mutations to parameters or external state.
32
- * Uses same format as `@param`: `@mutates key - description of mutation`. The key is
33
- * unvalidated — typically a parameter name, but compound paths (`this.foo`, `obj.field`)
34
- * and external state references are accepted as-is.
30
+ * Format: `@mutates target - description of mutation` — the target is everything before the
31
+ * first ` - ` separator. It is unvalidated: typically a parameter name, but compound paths
32
+ * (`this.foo`, `obj.field`) and multi-word external references are accepted; backticks are
33
+ * stripped from the target so `` `a` `` and `a` are one key. Without a separator the first
34
+ * line is a bare target (empty description) and any continuation lines are the description.
35
35
  *
36
36
  * The `@see` tag supports multiple formats: plain URLs (`https://...`), `{@link}` syntax, and module names.
37
37
  * Relative/absolute path support in `@see` is TBD.
38
38
  *
39
39
  * ## Behavioral notes
40
40
  *
41
- * JSDoc blocks tagged `@module` are excluded from `parseComment` entirely (text
42
- * and tags) — module comments attach to the file's first statement in the AST
43
- * and are owned by `extractModuleComment` instead.
41
+ * `@module` blocks are excluded from `parseComment` (see there).
44
42
  *
45
43
  * `JSDocPropertyLikeTag` nodes (`@property`/`@param` declaring a symbol in a
46
44
  * typedef or callback) parse to their own tag description — the only doc such
@@ -48,7 +46,8 @@
48
46
  *
49
47
  * Due to TS Compiler API limitations:
50
48
  * - TS API includes dash separator in `@param` tag text; we strip the leading `- ` as it's syntax, not content
51
- * - `@throws` tags have `{Type}` stripped by TS API; fallback regex extracts first word as error type
49
+ * - `@throws` braced types (`{TypeError}`) parse into the tag's typeExpression, not its text —
50
+ * the type is read from there; unbraced text falls back to a first-word-as-type regex
52
51
  * - TS API strips URL protocols from `@see` tag text; we use `getText()` to preserve original format including `{@link}` syntax
53
52
  *
54
53
  * @see `declaration-build.ts` for `DeclarationJsonBuild`
@@ -66,6 +65,37 @@ import ts from 'typescript';
66
65
  * @returns cleaned text with leading `- ` removed if present
67
66
  */
68
67
  const cleanTagDescription = (text) => text.trim().replace(/^-\s+/, '');
68
+ /**
69
+ * Parse an `@mutates` tag's text into target and description.
70
+ *
71
+ * The target is everything before the first ` - ` separator — a parameter
72
+ * name, a compound path (`this.foo`, `obj.field`), or a multi-word external
73
+ * reference — with backticks stripped so `` `a` `` and `a` normalize to one
74
+ * key (matching `params` keys) and renderers apply their own code styling.
75
+ * Without a separator the first line is a bare target (empty description)
76
+ * and any continuation lines are the description.
77
+ *
78
+ * @returns target and description, or undefined when no target remains after stripping
79
+ */
80
+ const parseMutatesTag = (text) => {
81
+ const cleaned = text.trim();
82
+ const match = /^(.+?)\s+-\s+([\s\S]+)$/.exec(cleaned);
83
+ let rawTarget;
84
+ let description;
85
+ if (match) {
86
+ rawTarget = match[1];
87
+ // the regex consumed the separator, so a leading `- ` here is
88
+ // content (a markdown list bullet) — trim only, no strip
89
+ description = match[2].trim();
90
+ }
91
+ else {
92
+ const newlineIndex = cleaned.indexOf('\n');
93
+ rawTarget = newlineIndex === -1 ? cleaned : cleaned.slice(0, newlineIndex);
94
+ description = newlineIndex === -1 ? '' : cleaned.slice(newlineIndex + 1).trim();
95
+ }
96
+ const target = rawTarget.replaceAll('`', '').trim();
97
+ return target ? { target, description } : undefined;
98
+ };
69
99
  /**
70
100
  * Whether a JSDoc block is a module-level comment (carries a `@module` tag).
71
101
  */
@@ -149,19 +179,21 @@ export const parseComment = (node, sourceFile = node.getSourceFile()) => {
149
179
  let defaultValue;
150
180
  let mutates;
151
181
  let nodocs;
152
- // Extract main comment text
182
+ // Extract main comment text. `getTextOfJSDocComment` keeps inline `{@link}`
183
+ // tags — a link node carries its target in `name`, not `text`, so a manual
184
+ // `.map((c) => c.text)` join would silently drop it.
153
185
  for (const comment of tsdocComments) {
154
186
  if (ts.isJSDoc(comment) && comment.comment) {
155
- const text = typeof comment.comment === 'string'
156
- ? comment.comment
157
- : comment.comment.map((c) => c.text).join('');
158
- fullText += text + '\n';
187
+ const text = ts.getTextOfJSDocComment(comment.comment);
188
+ if (text) {
189
+ fullText += text + '\n';
190
+ }
159
191
  }
160
192
  }
161
193
  // Extract tags (module-block tags filtered like their text above)
162
194
  const tags = ts.getJSDocTags(node).filter((tag) => !belongsToModuleBlock(tag));
163
195
  for (const tag of tags) {
164
- const tagText = typeof tag.comment === 'string' ? tag.comment : tag.comment?.map((c) => c.text).join('');
196
+ const tagText = ts.getTextOfJSDocComment(tag.comment);
165
197
  const tagName = tag.tagName.text;
166
198
  if (tagName === 'param' && ts.isJSDocParameterTag(tag)) {
167
199
  // Extract parameter name and description
@@ -173,14 +205,26 @@ export const parseComment = (node, sourceFile = node.getSourceFile()) => {
173
205
  else if ((tagName === 'returns' || tagName === 'return') && tagText) {
174
206
  returns = tagText.trim();
175
207
  }
176
- else if (tagName === 'throws' && tagText) {
177
- // Try to extract error type and description
178
- const match = /^\{?(\w+)\}?\s+(.+)/.exec(tagText);
179
- if (match) {
180
- (throws ??= []).push({ type: match[1], description: cleanTagDescription(match[2]) });
208
+ else if (tagName === 'throws') {
209
+ // The standard braced form (`@throws {TypeError} - description`) parses
210
+ // its type into the tag's typeExpression — the comment text carries only
211
+ // the description (or nothing at all, for a bare `@throws {TypeError}`)
212
+ const typeNode = ts.isJSDocThrowsTag(tag) ? tag.typeExpression?.type : undefined;
213
+ if (typeNode) {
214
+ (throws ??= []).push({
215
+ type: typeNode.getText(sourceFile),
216
+ description: tagText ? cleanTagDescription(tagText) : ''
217
+ });
181
218
  }
182
- else {
183
- (throws ??= []).push({ description: cleanTagDescription(tagText) });
219
+ else if (tagText) {
220
+ // Unbraced text: heuristically extract a leading word as the error type
221
+ const match = /^\{?(\w+)\}?\s+([\s\S]+)/.exec(tagText);
222
+ if (match) {
223
+ (throws ??= []).push({ type: match[1], description: cleanTagDescription(match[2]) });
224
+ }
225
+ else {
226
+ (throws ??= []).push({ description: cleanTagDescription(tagText) });
227
+ }
184
228
  }
185
229
  }
186
230
  else if (tagName === 'example' && tagText) {
@@ -213,16 +257,12 @@ export const parseComment = (node, sourceFile = node.getSourceFile()) => {
213
257
  defaultValue = tagText.trim();
214
258
  }
215
259
  else if (tagName === 'mutates' && tagText) {
216
- // Extract parameter name and description (format: @mutates paramName - description)
217
- const cleanedText = cleanTagDescription(tagText);
218
- const match = /^(\w+)\s+-?\s*(.+)/.exec(cleanedText);
219
- if (match) {
220
- const paramName = match[1];
221
- const description = match[2].trim();
222
- // Null-prototype map: `paramName` comes from source (`\w+` matches
223
- // `__proto__`, `constructor`, …); a plain object would let such a key
224
- // pollute the prototype on write and read back later by key.
225
- (mutates ??= Object.create(null))[paramName] = description;
260
+ const parsed = parseMutatesTag(tagText);
261
+ if (parsed) {
262
+ // Null-prototype map: the target comes from source (it can be
263
+ // `__proto__`, `constructor`, …); a plain object would let such a
264
+ // key pollute the prototype on write and read back later by key.
265
+ (mutates ??= Object.create(null))[parsed.target] = parsed.description;
226
266
  }
227
267
  }
228
268
  else if (tagName === 'nodocs') {