diff options
| author | ST-DDT <[email protected]> | 2024-04-01 10:21:18 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-04-01 10:21:18 +0200 |
| commit | 6191a5d883048b694404dbf42527caba395828ea (patch) | |
| tree | d0f18f17789cb0bbdb5d6087f1a95772438dfe27 /test/scripts | |
| parent | 7dae52bfcd93c41ec9d2c4dd4d96a07f31c3dfc1 (diff) | |
| download | faker-6191a5d883048b694404dbf42527caba395828ea.tar.xz faker-6191a5d883048b694404dbf42527caba395828ea.zip | |
docs: rewrite api-docs generation using ts-morph (#2628)
Diffstat (limited to 'test/scripts')
16 files changed, 2209 insertions, 1281 deletions
diff --git a/test/scripts/apidoc/__snapshots__/module.spec.ts.snap b/test/scripts/apidoc/__snapshots__/module.spec.ts.snap deleted file mode 100644 index d4275860..00000000 --- a/test/scripts/apidoc/__snapshots__/module.spec.ts.snap +++ /dev/null @@ -1,54 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`module > analyzeModule() > ModuleDeprecationTest 1`] = ` -{ - "comment": "This is a description for a module with a code example.", - "deprecated": "Well, this is deprecated.", - "examples": undefined, -} -`; - -exports[`module > analyzeModule() > ModuleExampleTest 1`] = ` -{ - "comment": "This is a description for a module with a code example.", - "deprecated": undefined, - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">new</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> ModuleExampleTest</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">()</span></span></code></pre> -</div>", -} -`; - -exports[`module > analyzeModule() > ModuleFakerJsLinkTest 1`] = ` -{ - "comment": "Description with a link to our [website](/) -and [api docs](/api/).", - "deprecated": undefined, - "examples": undefined, -} -`; - -exports[`module > analyzeModule() > ModuleNextFakerJsLinkTest 1`] = ` -{ - "comment": "Description with a link to our [website](/) -and [api docs](/api/).", - "deprecated": undefined, - "examples": undefined, -} -`; - -exports[`module > analyzeModule() > ModuleSimpleTest 1`] = ` -{ - "comment": "A simple module without anything special.", - "deprecated": undefined, - "examples": undefined, -} -`; - -exports[`module > analyzeModule() > expected and actual modules are equal 1`] = ` -[ - "ModuleDeprecationTest", - "ModuleExampleTest", - "ModuleFakerJsLinkTest", - "ModuleNextFakerJsLinkTest", - "ModuleSimpleTest", -] -`; diff --git a/test/scripts/apidoc/__snapshots__/signature.spec.ts.snap b/test/scripts/apidoc/__snapshots__/signature.spec.ts.snap deleted file mode 100644 index 37a9f754..00000000 --- a/test/scripts/apidoc/__snapshots__/signature.spec.ts.snap +++ /dev/null @@ -1,768 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`signature > analyzeSignature() > complexArrayParameter 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Complex array parameter.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">complexArrayParameter</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"><</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">T</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">>(array: readonly </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Array</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"><{</span></span> -<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> value</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> T</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">,</span></span> -<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> weight</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> number</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}>): </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">T</span></span></code></pre> -</div>", - "name": "complexArrayParameter", - "parameters": [ - { - "description": "<p>The type of the entries to pick from.</p> -", - "name": "<T>", - "type": undefined, - }, - { - "default": undefined, - "description": "<p>Array to pick the value from.</p> -", - "name": "array", - "type": "Array<{ ... }>", - }, - { - "default": undefined, - "description": "<p>The value to pick.</p> -", - "name": "array[].value", - "type": "T", - }, - { - "default": undefined, - "description": "<p>The weight of the value.</p> -", - "name": "array[].weight", - "type": "number", - }, - ], - "returns": "T", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L377", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > defaultBooleanParamMethod 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with a default parameter.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">defaultBooleanParamMethod</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(c: boolean </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">): number</span></span></code></pre> -</div>", - "name": "defaultBooleanParamMethod", - "parameters": [ - { - "default": "true", - "description": "<p>The boolean parameter.</p> -", - "name": "c", - "type": "boolean", - }, - ], - "returns": "number", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L105", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > expected and actual methods are equal 1`] = ` -[ - "complexArrayParameter", - "defaultBooleanParamMethod", - "functionParamMethod", - "literalUnionParamMethod", - "methodWithDeprecated", - "methodWithDeprecatedOption", - "methodWithExample", - "methodWithMultipleSeeMarkers", - "methodWithMultipleSeeMarkersAndBackticks", - "methodWithMultipleThrows", - "methodWithSinceMarker", - "methodWithThrows", - "multiParamMethod", - "noParamMethod", - "optionalStringParamMethod", - "optionsInlineParamMethodWithDefaults", - "optionsInterfaceParamMethodWithDefaults", - "optionsParamMethod", - "optionsTypeParamMethodWithDefaults", - "recordParamMethod", - "requiredNumberParamMethod", - "stringUnionParamMethod", -] -`; - -exports[`signature > analyzeSignature() > functionParamMethod 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with a function parameters.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">functionParamMethod</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(fn: (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">a</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> number): number</span></span></code></pre> -</div>", - "name": "functionParamMethod", - "parameters": [ - { - "default": undefined, - "description": "<p>The function parameter.</p> -", - "name": "fn", - "type": "(a: string) => number", - }, - ], - "returns": "number", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L125", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > literalUnionParamMethod 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with LiteralUnion.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">literalUnionParamMethod</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(value: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">'a'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'b'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> ?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, namedValue</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'a'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'b'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> ?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, array</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> readonly Array</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"><</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">'a'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'b'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> ?></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, namedArray</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> readonly Array</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"><</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">'a'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'b'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> ?></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, mixed</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'a'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'b'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> ?</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> readonly Array</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"><</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">'a'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'b'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> ?></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, namedMixed</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'a'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'b'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> ?</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> readonly Array</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"><</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">'a'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'b'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> ?></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> string</span></span></code></pre> -</div>", - "name": "literalUnionParamMethod", - "parameters": [ - { - "default": undefined, - "description": "<p><code>'a'</code> or <code>'b'</code>.</p> -", - "name": "value", - "type": "'a' | 'b' | ?", - }, - { - "default": undefined, - "description": "<p><code>'a'</code> or <code>'b'</code>.</p> -", - "name": "namedValue", - "type": "'a' | 'b' | ?", - }, - { - "default": undefined, - "description": "<p>Array of <code>'a'</code> or <code>'b'</code>.</p> -", - "name": "array", - "type": "Array<'a' | 'b' | ?>", - }, - { - "default": undefined, - "description": "<p>Array of <code>'a'</code> or <code>'b'</code>.</p> -", - "name": "namedArray", - "type": "Array<'a' | 'b' | ?>", - }, - { - "default": undefined, - "description": "<p>Value <code>'a'</code> or <code>'b'</code> or an array thereof.</p> -", - "name": "mixed", - "type": "'a' | 'b' | ? | Array<'a' | 'b' | ?>", - }, - { - "default": undefined, - "description": "<p>Value <code>'a'</code> or <code>'b'</code> or an array thereof.</p> -", - "name": "namedMixed", - "type": "'a' | 'b' | ? | Array<'a' | 'b' | ?>", - }, - ], - "returns": "string", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L159", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > methodWithDeprecated 1`] = ` -{ - "deprecated": "<p>do something else</p> -", - "description": "<p>Test with deprecated and see marker.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">methodWithDeprecated</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(): number</span></span></code></pre> -</div>", - "name": "methodWithDeprecated", - "parameters": [], - "returns": "number", - "seeAlsos": [ - "test.apidoc.methodWithExample()", - ], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L287", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > methodWithDeprecatedOption 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with deprecated option.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">methodWithDeprecatedOption</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(option: {</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> a: string,</span></span> -<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> b</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> number,</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> c: number</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}): number</span></span></code></pre> -</div>", - "name": "methodWithDeprecatedOption", - "parameters": [ - { - "default": undefined, - "description": "<p>The options.</p> -", - "name": "option", - "type": "{ ... }", - }, - { - "default": undefined, - "description": "<p>Some deprecated option.</p> -<p><strong>DEPRECATED:</strong> do something else.</p> -", - "name": "option.a", - "type": "string", - }, - { - "default": undefined, - "description": "<p>Some other deprecated option.</p> -<p><strong>DEPRECATED:</strong> do something else.</p> -", - "name": "option.b", - "type": "() => number", - }, - { - "default": undefined, - "description": "<p>Some other option.</p> -", - "name": "option.c", - "type": "number", - }, - ], - "returns": "number", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L318", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > methodWithExample 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with example marker.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">methodWithExample</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(): number</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">test.apidoc.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">methodWithExample</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">() </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">// 0</span></span></code></pre> -</div>", - "name": "methodWithExample", - "parameters": [], - "returns": "number", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L276", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > methodWithMultipleSeeMarkers 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with multiple see markers.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">methodWithMultipleSeeMarkers</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(): number</span></span></code></pre> -</div>", - "name": "methodWithMultipleSeeMarkers", - "parameters": [], - "returns": "number", - "seeAlsos": [ - "test.apidoc.methodWithExample()", - "test.apidoc.methodWithDeprecated()", - ], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L345", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > methodWithMultipleSeeMarkersAndBackticks 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with multiple see markers and backticks.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">methodWithMultipleSeeMarkersAndBackticks</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(): number</span></span></code></pre> -</div>", - "name": "methodWithMultipleSeeMarkersAndBackticks", - "parameters": [], - "returns": "number", - "seeAlsos": [ - "test.apidoc.methodWithExample() with parameter <code>foo</code>.", - "test.apidoc.methodWithDeprecated() with parameter <code>bar</code> and <code>baz</code>.", - ], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L355", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > methodWithMultipleThrows 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with multiple throws.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">methodWithMultipleThrows</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(): number</span></span></code></pre> -</div>", - "name": "methodWithMultipleThrows", - "parameters": [], - "returns": "number", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L306", - "throws": "First error case. -Another error case.", -} -`; - -exports[`signature > analyzeSignature() > methodWithSinceMarker 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with since marker.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">methodWithSinceMarker</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(): number</span></span></code></pre> -</div>", - "name": "methodWithSinceMarker", - "parameters": [], - "returns": "number", - "seeAlsos": [], - "since": "1.0.0", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L364", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > methodWithThrows 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with throws.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">methodWithThrows</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(): number</span></span></code></pre> -</div>", - "name": "methodWithThrows", - "parameters": [], - "returns": "number", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L296", - "throws": "Everytime.", -} -`; - -exports[`signature > analyzeSignature() > multiParamMethod 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with multiple parameters.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">multiParamMethod</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(a: number, b</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">?:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> string, c: boolean </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">): number</span></span></code></pre> -</div>", - "name": "multiParamMethod", - "parameters": [ - { - "default": undefined, - "description": "<p>The number parameter.</p> -", - "name": "a", - "type": "number", - }, - { - "default": undefined, - "description": "<p>The string parameter.</p> -", - "name": "b?", - "type": "string", - }, - { - "default": "true", - "description": "<p>The boolean parameter.</p> -", - "name": "c", - "type": "boolean", - }, - ], - "returns": "number", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L116", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > noParamMethod 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with no parameters.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">noParamMethod</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(): number</span></span></code></pre> -</div>", - "name": "noParamMethod", - "parameters": [], - "returns": "number", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L78", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > optionalStringParamMethod 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with an optional parameter.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">optionalStringParamMethod</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(b</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">?:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> string): number</span></span></code></pre> -</div>", - "name": "optionalStringParamMethod", - "parameters": [ - { - "default": undefined, - "description": "<p>The string parameter.</p> -", - "name": "b?", - "type": "string", - }, - ], - "returns": "number", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L96", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > optionsInlineParamMethodWithDefaults 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with a function parameters (inline types) with defaults.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">optionsInlineParamMethodWithDefaults</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(a: {</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> value: number</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">} </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> { value: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> }, b: {</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> value: number</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">} </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> { value: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> }, c: {</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> value: number</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}): number</span></span></code></pre> -</div>", - "name": "optionsInlineParamMethodWithDefaults", - "parameters": [ - { - "default": "{ value: 1 }", - "description": "<p>Parameter with signature default. -It also has a more complex description.</p> -", - "name": "a", - "type": "{ ... }", - }, - { - "default": undefined, - "description": "<p>The number parameter.</p> -", - "name": "a.value?", - "type": "number", - }, - { - "default": "{ value: 1 }", - "description": "<p>Parameter with jsdocs default.</p> -<p>It also has a more complex description.</p> -", - "name": "b", - "type": "{ ... }", - }, - { - "default": undefined, - "description": "<p>The number parameter.</p> -", - "name": "b.value?", - "type": "number", - }, - { - "default": undefined, - "description": "<p>Parameter with inner jsdocs default.</p> -", - "name": "c", - "type": "{ ... }", - }, - { - "default": "2", - "description": "<p>The number parameter. It also has a more complex description.</p> -", - "name": "c.value?", - "type": "number", - }, - ], - "returns": "number", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L226", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > optionsInterfaceParamMethodWithDefaults 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with a function parameters with defaults.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">optionsInterfaceParamMethodWithDefaults</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(a: ParameterOptionsInterfaceA </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> { value: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> }, b: ParameterOptionsInterfaceB </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> { value: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> }, c: ParameterOptionsInterfaceC): number</span></span></code></pre> -</div>", - "name": "optionsInterfaceParamMethodWithDefaults", - "parameters": [ - { - "default": "{ value: 1 }", - "description": "<p>Parameter with signature default.</p> -", - "name": "a", - "type": "ParameterOptionsInterfaceA", - }, - { - "default": "{ value: 1 }", - "description": "<p>Parameter with jsdocs default.</p> -", - "name": "b", - "type": "ParameterOptionsInterfaceB", - }, - { - "default": undefined, - "description": "<p>Parameter with inner jsdocs default.</p> -", - "name": "c", - "type": "ParameterOptionsInterfaceC", - }, - ], - "returns": "number", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L262", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > optionsParamMethod 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with an options parameter.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">optionsParamMethod</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(options: {</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> a: number,</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> b: string,</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> c: boolean,</span></span> -<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> d</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> string,</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> e: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">'a'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'b'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> ?</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">})</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> number</span></span></code></pre> -</div>", - "name": "optionsParamMethod", - "parameters": [ - { - "default": undefined, - "description": "<p>The options parameter.</p> -", - "name": "options", - "type": "{ ... }", - }, - { - "default": undefined, - "description": "<p>The number parameter.</p> -", - "name": "options.a", - "type": "number", - }, - { - "default": undefined, - "description": "<p>The string parameter.</p> -", - "name": "options.b?", - "type": "string", - }, - { - "default": undefined, - "description": "<p>The boolean parameter.</p> -", - "name": "options.c", - "type": "boolean", - }, - { - "default": undefined, - "description": "<p>The method parameter.</p> -", - "name": "options.d", - "type": "() => string", - }, - { - "default": "'a'", - "description": "<p>A parameter with inline documentation.</p> -", - "name": "options.e", - "type": "'a' | 'b' | ?", - }, - ], - "returns": "number", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L196", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > optionsTypeParamMethodWithDefaults 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with a function parameters with defaults.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">optionsTypeParamMethodWithDefaults</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(a: ParameterOptionsTypeA </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> { value: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> }, b: ParameterOptionsTypeB </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> { value: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> }, c: ParameterOptionsTypeC): number</span></span></code></pre> -</div>", - "name": "optionsTypeParamMethodWithDefaults", - "parameters": [ - { - "default": "{ value: 1 }", - "description": "<p>Parameter with signature default.</p> -", - "name": "a", - "type": "ParameterOptionsTypeA", - }, - { - "default": "{ value: 1 }", - "description": "<p>Parameter with jsdocs default.</p> -", - "name": "b", - "type": "ParameterOptionsTypeB", - }, - { - "default": undefined, - "description": "<p>Parameter with inner jsdocs default.</p> -", - "name": "c", - "type": "ParameterOptionsTypeC", - }, - ], - "returns": "number", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L244", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > recordParamMethod 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with a Record parameter.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">recordParamMethod</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(object: Record</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"><</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">string, number</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">): number</span></span></code></pre> -</div>", - "name": "recordParamMethod", - "parameters": [ - { - "default": undefined, - "description": "<p>The Record parameter.</p> -", - "name": "object", - "type": "Record<string, number>", - }, - ], - "returns": "number", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L182", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > requiredNumberParamMethod 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with a required parameter.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">requiredNumberParamMethod</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(a: number): number</span></span></code></pre> -</div>", - "name": "requiredNumberParamMethod", - "parameters": [ - { - "default": undefined, - "description": "<p>The number parameter.</p> -", - "name": "a", - "type": "number", - }, - ], - "returns": "number", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L87", - "throws": undefined, -} -`; - -exports[`signature > analyzeSignature() > stringUnionParamMethod 1`] = ` -{ - "deprecated": undefined, - "description": "<p>Test with string union.</p> -", - "examples": "<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" v-pre><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">stringUnionParamMethod</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(value: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">'a'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'b'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, options</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">?:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> casing: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">'lower'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'mixed'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'upper'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">,</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> excludes: readonly AlphaNumericChar[],</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> format: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">'binary'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'css'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'decimal'</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'hex'</span></span> -<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}): string</span></span></code></pre> -</div>", - "name": "stringUnionParamMethod", - "parameters": [ - { - "default": undefined, - "description": "<p><code>'a'</code> or <code>'b'</code>.</p> -", - "name": "value", - "type": "'a' | 'b'", - }, - { - "default": undefined, - "description": "<p>The options parameter.</p> -", - "name": "options?", - "type": "{ ... }", - }, - { - "default": undefined, - "description": "<p>The casing parameter.</p> -", - "name": "options.casing?", - "type": "'lower' | 'mixed' | 'upper'", - }, - { - "default": undefined, - "description": "<p>The excludes parameter.</p> -", - "name": "options.excludes?", - "type": "readonly AlphaNumericChar[]", - }, - { - "default": undefined, - "description": "<p>The format parameter.</p> -", - "name": "options.format?", - "type": "'binary' | 'css' | 'decimal' | 'hex'", - }, - ], - "returns": "string", - "seeAlsos": [], - "since": "Missing", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L138", - "throws": undefined, -} -`; diff --git a/test/scripts/apidoc/module.spec.ts b/test/scripts/apidoc/module.spec.ts deleted file mode 100644 index 5e55afea..00000000 --- a/test/scripts/apidoc/module.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { beforeAll, describe, expect, it } from 'vitest'; -import { initMarkdownRenderer } from '../../../scripts/apidoc/markdown'; -import { analyzeModule } from '../../../scripts/apidoc/module-methods'; -import * as ModuleTests from './module.example'; -import { loadExampleModules } from './utils'; - -beforeAll(initMarkdownRenderer); -const modules = await loadExampleModules(); - -describe('module', () => { - describe('analyzeModule()', () => { - it('dummy dependency to rerun the test if the example changes', () => { - expect(Object.keys(ModuleTests)).not.toEqual([]); - }); - - it('expected and actual modules are equal', () => { - expect(Object.keys(modules).sort()).toMatchSnapshot(); - }); - - it.each(Object.entries(modules))('%s', (_, module) => { - const actual = analyzeModule(module); - - expect(actual).toMatchSnapshot(); - }); - }); -}); diff --git a/test/scripts/apidoc/signature.debug.ts b/test/scripts/apidoc/signature.debug.ts deleted file mode 100644 index 704b629c..00000000 --- a/test/scripts/apidoc/signature.debug.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * This file exists, because vitest doesn't allow me to debug code outside of src and test. - * And it's easier to test these features independently from the main project. - */ -import { initMarkdownRenderer } from '../../../scripts/apidoc/markdown'; -import { analyzeSignature } from '../../../scripts/apidoc/signature'; -import { loadExampleMethods } from './utils'; - -/* Run with `pnpm tsx test/scripts/apidoc/signature.debug.ts` */ - -await initMarkdownRenderer(); -const methods = await loadExampleMethods(); -for (const [name, method] of Object.entries(methods)) { - console.log('Analyzing:', name); - const result = await analyzeSignature(method, '', method.name); - console.log('Result:', result); -} diff --git a/test/scripts/apidoc/signature.spec.ts b/test/scripts/apidoc/signature.spec.ts deleted file mode 100644 index 51935fcf..00000000 --- a/test/scripts/apidoc/signature.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { beforeAll, describe, expect, it } from 'vitest'; -import { initMarkdownRenderer } from '../../../scripts/apidoc/markdown'; -import { analyzeSignature } from '../../../scripts/apidoc/signature'; -import { SignatureTest } from './signature.example'; -import { loadExampleMethods } from './utils'; - -beforeAll(initMarkdownRenderer); -const methods = await loadExampleMethods(); - -describe('signature', () => { - describe('analyzeSignature()', () => { - it('dummy dependency to rerun the test if the example changes', () => { - expect(new SignatureTest()).toBeTruthy(); - }); - - it('expected and actual methods are equal', () => { - expect(Object.keys(methods)).toMatchSnapshot(); - }); - - it.each(Object.entries(methods))('%s', async (name, signature) => { - const actual = await analyzeSignature(signature, '', name); - - expect(actual).toMatchSnapshot(); - }); - }); -}); diff --git a/test/scripts/apidoc/utils.ts b/test/scripts/apidoc/utils.ts deleted file mode 100644 index 2752f25b..00000000 --- a/test/scripts/apidoc/utils.ts +++ /dev/null @@ -1,66 +0,0 @@ -import type { - DeclarationReflection, - SignatureReflection, - TypeDocOptions, -} from 'typedoc'; -import { - loadProject, - selectApiMethodSignatures, - selectApiModules, -} from '../../../scripts/apidoc/typedoc'; -import { mapByName } from '../../../scripts/apidoc/utils'; - -/** - * Returns a record with the (Module-Name -> (Method-Name -> Method-Signature)) for the project. - * - * @param options The TypeDoc options. - * @param includeTestModules Whether to include the test modules. - */ -export async function loadProjectModules( - options?: Partial<TypeDocOptions>, - includeTestModules = false -): Promise< - Record<string, [DeclarationReflection, Record<string, SignatureReflection>]> -> { - const [, project] = await loadProject(options); - - const modules = selectApiModules(project, includeTestModules); - - return mapByName(modules, (m) => [m, selectApiMethodSignatures(m)]); -} - -/** - * Loads the example methods using TypeDoc. - */ -export async function loadExampleMethods(): Promise< - Record<string, SignatureReflection> -> { - const modules = await loadProjectModules( - { - entryPoints: ['test/scripts/apidoc/signature.example.ts'], - }, - true - ); - return modules['SignatureTest'][1]; -} - -/** - * Loads the example modules using TypeDoc. - */ -export async function loadExampleModules(): Promise< - Record<string, DeclarationReflection> -> { - const modules = await loadProjectModules( - { - entryPoints: ['test/scripts/apidoc/module.example.ts'], - }, - true - ); - - const result: Record<string, DeclarationReflection> = {}; - for (const key in modules) { - result[key] = modules[key][0]; - } - - return result; -} diff --git a/test/scripts/apidoc/verify-jsdoc-tags.spec.ts b/test/scripts/apidoc/verify-jsdoc-tags.spec.ts deleted file mode 100644 index da34316e..00000000 --- a/test/scripts/apidoc/verify-jsdoc-tags.spec.ts +++ /dev/null @@ -1,315 +0,0 @@ -import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'; -import { dirname, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; -import type { ReflectionType, SomeType } from 'typedoc'; -import validator from 'validator'; -import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'; -import { initMarkdownRenderer } from '../../../scripts/apidoc/markdown'; -import { analyzeSignature } from '../../../scripts/apidoc/signature'; -import { - MISSING_DESCRIPTION, - extractDeprecated, - extractDescription, - extractJoinedRawExamples, - extractModuleFieldName, - extractRawDefault, - extractSeeAlsos, - extractSince, - extractSummaryDefault, - extractTagContent, -} from '../../../scripts/apidoc/typedoc'; -import { loadProjectModules } from './utils'; - -// This test ensures, that every method -// - has working examples -// - running these do not log anything, unless the method is deprecated - -beforeAll(initMarkdownRenderer); - -const tempDir = resolve(dirname(fileURLToPath(import.meta.url)), 'temp'); - -afterAll(() => { - // Remove temp folder - if (existsSync(tempDir)) { - rmSync(tempDir, { recursive: true }); - } -}); - -const modules = await loadProjectModules(); - -function resolveDirToModule(moduleName: string): string { - return resolve(tempDir, moduleName); -} - -function resolvePathToMethodFile( - moduleName: string, - methodName: string -): string { - const dir = resolveDirToModule(moduleName); - return resolve(dir, `${methodName}.ts`); -} - -const allowedReferences = new Set( - Object.values(modules).flatMap(([module, methods]) => { - const moduleFieldName = extractModuleFieldName(module); - return Object.keys(methods).map( - (methodName) => `faker.${moduleFieldName}.${methodName}` - ); - }) -); -const allowedLinks = new Set( - Object.values(modules).flatMap(([module, methods]) => { - const moduleFieldName = extractModuleFieldName(module); - return [ - `/api/${moduleFieldName}.html`, - ...Object.keys(methods).map( - (methodName) => - `/api/${moduleFieldName}.html#${methodName.toLowerCase()}` - ), - ]; - }) -); - -function assertDescription(description: string, isHtml: boolean): void { - const linkRegexp = isHtml ? /(href)="([^"]+)"/g : /\[([^\]]+)\]\(([^)]+)\)/g; - const links = [...description.matchAll(linkRegexp)].map((m) => m[2]); - - for (const link of links) { - if (!isHtml) { - expect(link).toMatch(/^https?:\/\//); - expect(link).toSatisfy(validator.isURL); - } - - if (isHtml ? link.startsWith('/api/') : link.includes('fakerjs.dev/api/')) { - expect(allowedLinks, `${link} to point to a valid target`).toContain( - link.replace(/.*fakerjs.dev\//, '/') - ); - } - } -} - -// keep in sync with analyzeParameterOptions -function assertNestedParameterDefault( - name: string, - parameterType?: SomeType -): void { - if (!parameterType) { - return; - } - - switch (parameterType.type) { - case 'array': { - return assertNestedParameterDefault( - `${name}[]`, - parameterType.elementType - ); - } - - case 'union': { - for (const type of parameterType.types) { - assertNestedParameterDefault(name, type); - } - - return; - } - - case 'reflection': { - for (const property of parameterType.declaration.children ?? []) { - const reflection = property.comment - ? property - : (property.type as ReflectionType)?.declaration?.signatures?.[0]; - const comment = reflection?.comment; - const tagDefault = extractRawDefault({ comment }) || undefined; - const summaryDefault = extractSummaryDefault(comment, false); - - if (summaryDefault) { - expect( - tagDefault, - `Expect jsdoc summary default and @default for ${name}.${property.name} to be the same` - ).toBe(summaryDefault); - } - } - - return; - } - - case 'typeOperator': { - return assertNestedParameterDefault(name, parameterType.target); - } - - default: { - return; - } - } -} - -describe('verify JSDoc tags', () => { - describe.each(Object.entries(modules))( - '%s', - (moduleName, [module, methodsByName]) => { - describe('verify module', () => { - it('verify description', () => { - const description = extractDescription(module); - assertDescription(description, false); - }); - }); - - describe.each(Object.entries(methodsByName))( - '%s', - (methodName, signature) => { - beforeAll(() => { - // Write temp files to disk - - // Extract examples and make them runnable - const examples = extractJoinedRawExamples(signature) ?? ''; - - // Save examples to a file to run them later in the specific tests - const dir = resolveDirToModule(moduleName); - mkdirSync(dir, { recursive: true }); - - const path = resolvePathToMethodFile(moduleName, methodName); - const imports = [ - ...new Set(examples.match(/(?<!\.)faker[^.]*(?=\.)/g)), - ]; - writeFileSync( - path, - `import { ${imports.join( - ', ' - )} } from '../../../../../src';\n\n${examples}` - ); - }); - - it('verify description', () => { - const description = extractDescription(signature); - assertDescription(description, false); - }); - - it('verify @example tag', async () => { - // Extract the examples - const examples = extractJoinedRawExamples(signature); - - expect( - examples, - `${moduleName}.${methodName} to have examples` - ).not.toBe(''); - - // Grab path to example file - const path = resolvePathToMethodFile(moduleName, methodName); - - // Executing the examples should not throw - await expect( - import(`${path}?scope=example`) - ).resolves.toBeDefined(); - }); - - // This only checks whether the whole method is deprecated or not - // It does not check whether the method is deprecated for a specific set of arguments - it('verify @deprecated tag', async () => { - // Grab path to example file - const path = resolvePathToMethodFile(moduleName, methodName); - - const consoleWarnSpy = vi.spyOn(console, 'warn'); - - // Run the examples - await import(`${path}?scope=deprecated`); - - // Verify that deprecated methods log a warning - const deprecatedFlag = extractDeprecated(signature) !== undefined; - if (deprecatedFlag) { - expect(consoleWarnSpy).toHaveBeenCalled(); - expect( - extractTagContent('@deprecated', signature).join(''), - '@deprecated tag without message' - ).not.toBe(''); - } else { - expect(consoleWarnSpy).not.toHaveBeenCalled(); - } - }); - - it('verify @param tags', async () => { - // This must run before analyzeSignature - for (const param of signature.parameters ?? []) { - const type = param.type; - const paramDefault = param.defaultValue; - const commentDefault = extractSummaryDefault( - param.comment, - false - ); - if (paramDefault) { - if ( - /^{.*}$/.test(paramDefault) || - paramDefault.includes('\n') - ) { - expect(commentDefault).toBeUndefined(); - } else { - expect( - commentDefault, - `Expect '${param.name}'s js implementation default to be the same as the jsdoc summary default.` - ).toBe(paramDefault); - } - } - - assertNestedParameterDefault(param.name, type); - } - - for (const param of ( - await analyzeSignature(signature, '', methodName) - ).parameters) { - const { name, description } = param; - const plainDescription = description - .replaceAll(/<[^>]+>/g, '') - .trim(); - expect( - plainDescription, - `Expect param ${name} to have a description` - ).not.toBe(MISSING_DESCRIPTION); - assertDescription(description, true); - } - }); - - it('verify @see tags', () => { - for (const link of extractSeeAlsos(signature)) { - if (link.startsWith('faker.')) { - // Expected @see faker.xxx.yyy() - expect(link, 'Expect method reference to contain ()').toContain( - '(' - ); - expect(link, 'Expect method reference to contain ()').toContain( - ')' - ); - expect( - link, - "Expect method reference to have a ': ' after the parenthesis" - ).toContain('): '); - expect( - link, - 'Expect method reference to have a description starting with a capital letter' - ).toMatch(/\): [A-Z]/); - expect( - link, - 'Expect method reference to start with a standard description phrase' - ).toMatch( - /\): (?:For generating |For more information about |For using |For the replacement method)/ - ); - expect( - link, - 'Expect method reference to have a description ending with a dot' - ).toMatch(/\.$/); - expect(allowedReferences).toContain(link.replace(/\(.*/, '')); - } - } - }); - - it('verify @since tag', () => { - const since = extractSince(signature); - expect(since, '@since to be present').toBeTruthy(); - expect(since).not.toBe(MISSING_DESCRIPTION); - expect(since, '@since to be a valid semver').toSatisfy( - validator.isSemVer - ); - }); - } - ); - } - ); -}); diff --git a/test/scripts/apidoc/.gitignore b/test/scripts/apidocs/.gitignore index a6d7ecd9..a6d7ecd9 100644 --- a/test/scripts/apidoc/.gitignore +++ b/test/scripts/apidocs/.gitignore diff --git a/test/scripts/apidocs/__snapshots__/class.spec.ts.snap b/test/scripts/apidocs/__snapshots__/class.spec.ts.snap new file mode 100644 index 00000000..6461169d --- /dev/null +++ b/test/scripts/apidocs/__snapshots__/class.spec.ts.snap @@ -0,0 +1,75 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`class > expected and actual modules are equal 1`] = ` +[ + "ModuleDeprecationTest", + "ModuleExampleTest", + "ModuleFakerJsLinkTest", + "ModuleNextFakerJsLinkTest", + "ModuleSimpleTest", +] +`; + +exports[`class > processClass(ModuleDeprecationTest) 1`] = ` +{ + "camelTitle": "moduleDeprecationTest", + "category": undefined, + "deprecated": "Well, this is deprecated.", + "description": "This is a description for a module with a code example.", + "examples": [], + "methods": [], + "title": "ModuleDeprecationTest", +} +`; + +exports[`class > processClass(ModuleExampleTest) 1`] = ` +{ + "camelTitle": "moduleExampleTest", + "category": undefined, + "deprecated": undefined, + "description": "This is a description for a module with a code example.", + "examples": [ + "new ModuleExampleTest()", + ], + "methods": [], + "title": "ModuleExampleTest", +} +`; + +exports[`class > processClass(ModuleFakerJsLinkTest) 1`] = ` +{ + "camelTitle": "moduleFakerJsLinkTest", + "category": undefined, + "deprecated": undefined, + "description": "Description with a link to our [website](https://fakerjs.dev/) +and [api docs](https://fakerjs.dev/api/).", + "examples": [], + "methods": [], + "title": "ModuleFakerJsLinkTest", +} +`; + +exports[`class > processClass(ModuleNextFakerJsLinkTest) 1`] = ` +{ + "camelTitle": "moduleNextFakerJsLinkTest", + "category": undefined, + "deprecated": undefined, + "description": "Description with a link to our [website](https://next.fakerjs.dev/) +and [api docs](https://next.fakerjs.dev/api/).", + "examples": [], + "methods": [], + "title": "ModuleNextFakerJsLinkTest", +} +`; + +exports[`class > processClass(ModuleSimpleTest) 1`] = ` +{ + "camelTitle": "moduleSimpleTest", + "category": undefined, + "deprecated": undefined, + "description": "A simple module without anything special.", + "examples": [], + "methods": [], + "title": "ModuleSimpleTest", +} +`; diff --git a/test/scripts/apidocs/__snapshots__/method.spec.ts.snap b/test/scripts/apidocs/__snapshots__/method.spec.ts.snap new file mode 100644 index 00000000..5a5518e4 --- /dev/null +++ b/test/scripts/apidocs/__snapshots__/method.spec.ts.snap @@ -0,0 +1,1671 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`method > expected and actual methods are equal 1`] = ` +[ + "complexArrayParameter", + "defaultBooleanParamMethod", + "functionParamMethod", + "literalUnionParamMethod", + "methodWithDeprecated", + "methodWithDeprecatedOption", + "methodWithExample", + "methodWithMultipleSeeMarkers", + "methodWithMultipleSeeMarkersAndBackticks", + "methodWithMultipleThrows", + "methodWithSinceMarker", + "methodWithThrows", + "multiParamMethod", + "noParamMethod", + "optionalStringParamMethod", + "optionsInlineParamMethodWithDefaults", + "optionsInterfaceParamMethodWithDefaults", + "optionsParamMethod", + "optionsTypeParamMethodWithDefaults", + "recordParamMethod", + "requiredNumberParamMethod", + "stringUnionParamMethod", +] +`; + +exports[`method > processMethodLike(complexArrayParameter) 1`] = ` +{ + "name": "complexArrayParameter", + "signatures": [ + { + "deprecated": undefined, + "description": "Complex array parameter.", + "examples": [], + "parameters": [ + { + "default": undefined, + "description": "The type of the entries to pick from.", + "name": "<T>", + "type": { + "text": "any", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "Array to pick the value from.", + "name": "array", + "type": { + "text": "Array<{ ... }>", + "type": "generic", + "typeParameters": [ + { + "text": "{ ... }", + "type": "simple", + }, + ], + }, + }, + { + "default": undefined, + "description": "The value to pick.", + "name": "array[].value", + "type": { + "resolvedType": { + "text": "any", + "type": "simple", + }, + "text": "T", + "type": "shadow", + }, + }, + { + "default": undefined, + "description": "The weight of the value.", + "name": "array[].weight", + "type": { + "text": "number", + "type": "simple", + }, + }, + ], + "returns": { + "resolvedType": { + "text": "any", + "type": "simple", + }, + "text": "T", + "type": "shadow", + }, + "seeAlsos": [], + "signature": "function complexArrayParameter<T>( + array: ReadonlyArray<{ + weight: number; + value: T; + }> + ): T;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(defaultBooleanParamMethod) 1`] = ` +{ + "name": "defaultBooleanParamMethod", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with a default parameter.", + "examples": [], + "parameters": [ + { + "default": "true", + "description": "The boolean parameter.", + "name": "c", + "type": { + "text": "boolean", + "type": "simple", + }, + }, + ], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function defaultBooleanParamMethod(c: boolean = true): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(functionParamMethod) 1`] = ` +{ + "name": "functionParamMethod", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with a function parameters.", + "examples": [], + "parameters": [ + { + "default": undefined, + "description": "The function parameter.", + "name": "fn", + "type": { + "text": "(a: string) => number", + "type": "simple", + }, + }, + ], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function functionParamMethod(fn: (a: string) => number): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(literalUnionParamMethod) 1`] = ` +{ + "name": "literalUnionParamMethod", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with LiteralUnion.", + "examples": [], + "parameters": [ + { + "default": undefined, + "description": "\`'a'\` or \`'b'\`.", + "name": "value", + "type": { + "text": "'a' | 'b' | string", + "type": "union", + "types": [ + { + "text": "'a' | 'b'", + "type": "union", + "types": [ + { + "text": "'a'", + "type": "simple", + }, + { + "text": "'b'", + "type": "simple", + }, + ], + }, + { + "text": "string", + "type": "simple", + }, + ], + }, + }, + { + "default": undefined, + "description": "\`'a'\` or \`'b'\`.", + "name": "namedValue", + "type": { + "text": "AB | string", + "type": "union", + "types": [ + { + "resolvedType": { + "text": "'a' | 'b'", + "type": "union", + "types": [ + { + "text": "'a'", + "type": "simple", + }, + { + "text": "'b'", + "type": "simple", + }, + ], + }, + "text": "AB", + "type": "shadow", + }, + { + "text": "string", + "type": "simple", + }, + ], + }, + }, + { + "default": undefined, + "description": "Array of \`'a'\` or \`'b'\`.", + "name": "array", + "type": { + "text": "Array<'a' | 'b' | string>", + "type": "generic", + "typeParameters": [ + { + "text": "'a' | 'b' | string", + "type": "union", + "types": [ + { + "text": "'a' | 'b'", + "type": "union", + "types": [ + { + "text": "'a'", + "type": "simple", + }, + { + "text": "'b'", + "type": "simple", + }, + ], + }, + { + "text": "string", + "type": "simple", + }, + ], + }, + ], + }, + }, + { + "default": undefined, + "description": "Array of \`'a'\` or \`'b'\`.", + "name": "namedArray", + "type": { + "text": "Array<AB | string>", + "type": "generic", + "typeParameters": [ + { + "text": "AB | string", + "type": "union", + "types": [ + { + "resolvedType": { + "text": "'a' | 'b'", + "type": "union", + "types": [ + { + "text": "'a'", + "type": "simple", + }, + { + "text": "'b'", + "type": "simple", + }, + ], + }, + "text": "AB", + "type": "shadow", + }, + { + "text": "string", + "type": "simple", + }, + ], + }, + ], + }, + }, + { + "default": undefined, + "description": "Value \`'a'\` or \`'b'\` or an array thereof.", + "name": "mixed", + "type": { + "text": "'a' | 'b' | string | Array<'a' | 'b' | string>", + "type": "union", + "types": [ + { + "text": "'a'", + "type": "simple", + }, + { + "text": "'b'", + "type": "simple", + }, + { + "text": "string & { zz_IGNORE_ME?: undefined; }", + "type": "simple", + }, + { + "text": "Array<'a' | 'b' | string>", + "type": "generic", + "typeParameters": [ + { + "text": "'a' | 'b' | string", + "type": "union", + "types": [ + { + "text": "'a' | 'b'", + "type": "union", + "types": [ + { + "text": "'a'", + "type": "simple", + }, + { + "text": "'b'", + "type": "simple", + }, + ], + }, + { + "text": "string", + "type": "simple", + }, + ], + }, + ], + }, + ], + }, + }, + { + "default": undefined, + "description": "Value \`'a'\` or \`'b'\` or an array thereof.", + "name": "namedMixed", + "type": { + "text": "'a' | 'b' | string | Array<AB | string>", + "type": "union", + "types": [ + { + "text": "'a'", + "type": "simple", + }, + { + "text": "'b'", + "type": "simple", + }, + { + "text": "string & { zz_IGNORE_ME?: undefined; }", + "type": "simple", + }, + { + "text": "Array<AB | string>", + "type": "generic", + "typeParameters": [ + { + "text": "AB | string", + "type": "union", + "types": [ + { + "resolvedType": { + "text": "'a' | 'b'", + "type": "union", + "types": [ + { + "text": "'a'", + "type": "simple", + }, + { + "text": "'b'", + "type": "simple", + }, + ], + }, + "text": "AB", + "type": "shadow", + }, + { + "text": "string", + "type": "simple", + }, + ], + }, + ], + }, + ], + }, + }, + ], + "returns": { + "text": "string", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function literalUnionParamMethod( + value: LiteralUnion<'a' | 'b'>, + namedValue: LiteralUnion<AB>, + array: ReadonlyArray<LiteralUnion<'a' | 'b'>>, + namedArray: ReadonlyArray<LiteralUnion<AB>>, + mixed: LiteralUnion<'a' | 'b'> | ReadonlyArray<LiteralUnion<'a' | 'b'>>, + namedMixed: ReadonlyArray<LiteralUnion<AB>> | LiteralUnion<AB> + ): string;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(methodWithDeprecated) 1`] = ` +{ + "name": "methodWithDeprecated", + "signatures": [ + { + "deprecated": "do something else", + "description": "Test with deprecated and see marker.", + "examples": [], + "parameters": [], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [ + "test.apidocs.methodWithExample()", + ], + "signature": "function methodWithDeprecated(): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(methodWithDeprecatedOption) 1`] = ` +{ + "name": "methodWithDeprecatedOption", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with deprecated option.", + "examples": [], + "parameters": [ + { + "default": undefined, + "description": "The options.", + "name": "option", + "type": { + "text": "{ ... }", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "Some deprecated option. + +**DEPRECATED:** do something else.", + "name": "option.a", + "type": { + "text": "string", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "Some other deprecated option. + +**DEPRECATED:** do something else.", + "name": "option.b", + "type": { + "text": "() => number", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "Some other option.", + "name": "option.c", + "type": { + "text": "number", + "type": "simple", + }, + }, + ], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function methodWithDeprecatedOption(option: { + a: string; + b: () => number; + c: number; + }): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(methodWithExample) 1`] = ` +{ + "name": "methodWithExample", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with example marker.", + "examples": [ + "test.apidocs.methodWithExample() // 0", + ], + "parameters": [], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function methodWithExample(): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(methodWithMultipleSeeMarkers) 1`] = ` +{ + "name": "methodWithMultipleSeeMarkers", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with multiple see markers.", + "examples": [], + "parameters": [], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [ + "test.apidocsmethodWithExample()", + "test.apidocsmethodWithDeprecated()", + ], + "signature": "function methodWithMultipleSeeMarkers(): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(methodWithMultipleSeeMarkersAndBackticks) 1`] = ` +{ + "name": "methodWithMultipleSeeMarkersAndBackticks", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with multiple see markers and backticks.", + "examples": [], + "parameters": [], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [ + "test.apidocsmethodWithExample() with parameter \`foo\`.", + "test.apidocsmethodWithDeprecated() with parameter \`bar\` and \`baz\`.", + ], + "signature": "function methodWithMultipleSeeMarkersAndBackticks(): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(methodWithMultipleThrows) 1`] = ` +{ + "name": "methodWithMultipleThrows", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with multiple throws.", + "examples": [], + "parameters": [], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function methodWithMultipleThrows(): number;", + "since": "1.0.0", + "throws": [ + "First error case.", + "Another error case.", + ], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(methodWithSinceMarker) 1`] = ` +{ + "name": "methodWithSinceMarker", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with since marker.", + "examples": [], + "parameters": [], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function methodWithSinceMarker(): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(methodWithThrows) 1`] = ` +{ + "name": "methodWithThrows", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with throws.", + "examples": [], + "parameters": [], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function methodWithThrows(): number;", + "since": "1.0.0", + "throws": [ + "Everytime.", + ], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(multiParamMethod) 1`] = ` +{ + "name": "multiParamMethod", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with multiple parameters.", + "examples": [], + "parameters": [ + { + "default": undefined, + "description": "The number parameter.", + "name": "a", + "type": { + "text": "number", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "The string parameter.", + "name": "b?", + "type": { + "text": "string", + "type": "simple", + }, + }, + { + "default": "true", + "description": "The boolean parameter.", + "name": "c", + "type": { + "text": "boolean", + "type": "simple", + }, + }, + ], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function multiParamMethod(a: number, b?: string, c: boolean = true): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(noParamMethod) 1`] = ` +{ + "name": "noParamMethod", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with no parameters.", + "examples": [], + "parameters": [], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function noParamMethod(): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(optionalStringParamMethod) 1`] = ` +{ + "name": "optionalStringParamMethod", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with an optional parameter.", + "examples": [], + "parameters": [ + { + "default": undefined, + "description": "The string parameter.", + "name": "b?", + "type": { + "text": "string", + "type": "simple", + }, + }, + ], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function optionalStringParamMethod(b?: string): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(optionsInlineParamMethodWithDefaults) 1`] = ` +{ + "name": "optionsInlineParamMethodWithDefaults", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with a function parameters (inline types) with defaults.", + "examples": [], + "parameters": [ + { + "default": "{ value: 1 }", + "description": "Parameter with signature default. +It also has a more complex description.", + "name": "a", + "type": { + "text": "{ ... }", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "The number parameter.", + "name": "a.value?", + "type": { + "text": "number", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "Parameter with jsdocs default. + +It also has a more complex description. + +Defaults to \`{ value: 1 }\`.", + "name": "b", + "type": { + "text": "{ ... }", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "The number parameter.", + "name": "b.value?", + "type": { + "text": "number", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "Parameter with inner jsdocs default.", + "name": "c", + "type": { + "text": "{ ... }", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "The number parameter.", + "name": "c.value?", + "type": { + "text": "number", + "type": "simple", + }, + }, + ], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function optionsInlineParamMethodWithDefaults( + a: { + value?: number; + } = { value: 1 }, + b: { + value?: number; + }, + c: { + value?: number; + } + ): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(optionsInterfaceParamMethodWithDefaults) 1`] = ` +{ + "name": "optionsInterfaceParamMethodWithDefaults", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with a function parameters with defaults.", + "examples": [], + "parameters": [ + { + "default": "{ value: 1 }", + "description": "Parameter with signature default.", + "name": "a", + "type": { + "text": "ParameterOptionsInterfaceA", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "Parameter with jsdocs default. Defaults to \`{ value: 1 }\`.", + "name": "b", + "type": { + "text": "ParameterOptionsInterfaceB", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "Parameter with inner jsdocs default.", + "name": "c", + "type": { + "text": "ParameterOptionsInterfaceC", + "type": "simple", + }, + }, + ], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function optionsInterfaceParamMethodWithDefaults( + a: ParameterOptionsInterfaceA = { value: 1 }, + b: ParameterOptionsInterfaceB, + c: ParameterOptionsInterfaceC + ): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(optionsParamMethod) 1`] = ` +{ + "name": "optionsParamMethod", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with an options parameter.", + "examples": [], + "parameters": [ + { + "default": undefined, + "description": "The options parameter.", + "name": "options", + "type": { + "text": "{ ... }", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "The number parameter.", + "name": "options.a", + "type": { + "text": "number", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "The string parameter.", + "name": "options.b?", + "type": { + "text": "string", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "The boolean parameter.", + "name": "options.c", + "type": { + "text": "boolean", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "The method parameter.", + "name": "options.d", + "type": { + "text": "() => string", + "type": "simple", + }, + }, + { + "default": "'a'", + "description": "A parameter with inline documentation.", + "name": "options.e", + "type": { + "text": "'a' | 'b' | string", + "type": "union", + "types": [ + { + "text": "'a' | 'b'", + "type": "union", + "types": [ + { + "text": "'a'", + "type": "simple", + }, + { + "text": "'b'", + "type": "simple", + }, + ], + }, + { + "text": "string", + "type": "simple", + }, + ], + }, + }, + ], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function optionsParamMethod(options: { + a: number; + b?: string; + c: boolean; + d: () => string; + e: LiteralUnion<'a' | 'b'>; + }): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(optionsTypeParamMethodWithDefaults) 1`] = ` +{ + "name": "optionsTypeParamMethodWithDefaults", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with a function parameters with defaults.", + "examples": [], + "parameters": [ + { + "default": "{ value: 1 }", + "description": "Parameter with signature default.", + "name": "a", + "type": { + "text": "{ ... }", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "Options value.", + "name": "a.value?", + "type": { + "text": "number", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "Parameter with jsdocs default. Defaults to \`{ value: 1 }\`.", + "name": "b", + "type": { + "text": "{ ... }", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "Options value.", + "name": "b.value?", + "type": { + "text": "number", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "Parameter with inner jsdocs default.", + "name": "c", + "type": { + "text": "{ ... }", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "Options value. Defaults to \`0\`.", + "name": "c.value?", + "type": { + "text": "number", + "type": "simple", + }, + }, + ], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function optionsTypeParamMethodWithDefaults( + a: ParameterOptionsTypeA = { value: 1 }, + b: ParameterOptionsTypeB, + c: ParameterOptionsTypeC + ): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(recordParamMethod) 1`] = ` +{ + "name": "recordParamMethod", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with a Record parameter.", + "examples": [], + "parameters": [ + { + "default": undefined, + "description": "The Record parameter.", + "name": "object", + "type": { + "text": "Record<string, number>", + "type": "simple", + }, + }, + ], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function recordParamMethod(object: Record<string, number>): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(requiredNumberParamMethod) 1`] = ` +{ + "name": "requiredNumberParamMethod", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with a required parameter.", + "examples": [], + "parameters": [ + { + "default": undefined, + "description": "The number parameter.", + "name": "a", + "type": { + "text": "number", + "type": "simple", + }, + }, + ], + "returns": { + "text": "number", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function requiredNumberParamMethod(a: number): number;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; + +exports[`method > processMethodLike(stringUnionParamMethod) 1`] = ` +{ + "name": "stringUnionParamMethod", + "signatures": [ + { + "deprecated": undefined, + "description": "Test with string union.", + "examples": [], + "parameters": [ + { + "default": undefined, + "description": "\`'a'\` or \`'b'\`.", + "name": "value", + "type": { + "text": "'a' | 'b'", + "type": "union", + "types": [ + { + "text": "'a'", + "type": "simple", + }, + { + "text": "'b'", + "type": "simple", + }, + ], + }, + }, + { + "default": undefined, + "description": "The options parameter.", + "name": "options?", + "type": { + "text": "{ ... }", + "type": "simple", + }, + }, + { + "default": undefined, + "description": "The casing parameter.", + "name": "options.casing?", + "type": { + "resolvedType": { + "text": "'lower' | 'upper' | 'mixed'", + "type": "union", + "types": [ + { + "text": "'lower'", + "type": "simple", + }, + { + "text": "'upper'", + "type": "simple", + }, + { + "text": "'mixed'", + "type": "simple", + }, + ], + }, + "text": "Casing", + "type": "shadow", + }, + }, + { + "default": undefined, + "description": "The excludes parameter.", + "name": "options.excludes?", + "type": { + "text": "AlphaNumericChar[]", + "type": "generic", + "typeParameters": [ + { + "resolvedType": { + "text": "'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'", + "type": "union", + "types": [ + { + "text": "'a'", + "type": "simple", + }, + { + "text": "'b'", + "type": "simple", + }, + { + "text": "'c'", + "type": "simple", + }, + { + "text": "'d'", + "type": "simple", + }, + { + "text": "'e'", + "type": "simple", + }, + { + "text": "'f'", + "type": "simple", + }, + { + "text": "'g'", + "type": "simple", + }, + { + "text": "'h'", + "type": "simple", + }, + { + "text": "'i'", + "type": "simple", + }, + { + "text": "'j'", + "type": "simple", + }, + { + "text": "'k'", + "type": "simple", + }, + { + "text": "'l'", + "type": "simple", + }, + { + "text": "'m'", + "type": "simple", + }, + { + "text": "'n'", + "type": "simple", + }, + { + "text": "'o'", + "type": "simple", + }, + { + "text": "'p'", + "type": "simple", + }, + { + "text": "'q'", + "type": "simple", + }, + { + "text": "'r'", + "type": "simple", + }, + { + "text": "'s'", + "type": "simple", + }, + { + "text": "'t'", + "type": "simple", + }, + { + "text": "'u'", + "type": "simple", + }, + { + "text": "'v'", + "type": "simple", + }, + { + "text": "'w'", + "type": "simple", + }, + { + "text": "'x'", + "type": "simple", + }, + { + "text": "'y'", + "type": "simple", + }, + { + "text": "'z'", + "type": "simple", + }, + { + "text": "'A'", + "type": "simple", + }, + { + "text": "'B'", + "type": "simple", + }, + { + "text": "'C'", + "type": "simple", + }, + { + "text": "'D'", + "type": "simple", + }, + { + "text": "'E'", + "type": "simple", + }, + { + "text": "'F'", + "type": "simple", + }, + { + "text": "'G'", + "type": "simple", + }, + { + "text": "'H'", + "type": "simple", + }, + { + "text": "'I'", + "type": "simple", + }, + { + "text": "'J'", + "type": "simple", + }, + { + "text": "'K'", + "type": "simple", + }, + { + "text": "'L'", + "type": "simple", + }, + { + "text": "'M'", + "type": "simple", + }, + { + "text": "'N'", + "type": "simple", + }, + { + "text": "'O'", + "type": "simple", + }, + { + "text": "'P'", + "type": "simple", + }, + { + "text": "'Q'", + "type": "simple", + }, + { + "text": "'R'", + "type": "simple", + }, + { + "text": "'S'", + "type": "simple", + }, + { + "text": "'T'", + "type": "simple", + }, + { + "text": "'U'", + "type": "simple", + }, + { + "text": "'V'", + "type": "simple", + }, + { + "text": "'W'", + "type": "simple", + }, + { + "text": "'X'", + "type": "simple", + }, + { + "text": "'Y'", + "type": "simple", + }, + { + "text": "'Z'", + "type": "simple", + }, + { + "text": "'0'", + "type": "simple", + }, + { + "text": "'1'", + "type": "simple", + }, + { + "text": "'2'", + "type": "simple", + }, + { + "text": "'3'", + "type": "simple", + }, + { + "text": "'4'", + "type": "simple", + }, + { + "text": "'5'", + "type": "simple", + }, + { + "text": "'6'", + "type": "simple", + }, + { + "text": "'7'", + "type": "simple", + }, + { + "text": "'8'", + "type": "simple", + }, + { + "text": "'9'", + "type": "simple", + }, + ], + }, + "text": "AlphaNumericChar", + "type": "shadow", + }, + ], + }, + }, + { + "default": undefined, + "description": "The format parameter.", + "name": "options.format?", + "type": { + "text": "'hex' | 'css' | 'binary' | 'decimal'", + "type": "union", + "types": [ + { + "text": "'hex'", + "type": "simple", + }, + { + "text": "'css'", + "type": "simple", + }, + { + "text": "'binary'", + "type": "simple", + }, + { + "text": "'decimal'", + "type": "simple", + }, + ], + }, + }, + ], + "returns": { + "text": "string", + "type": "simple", + }, + "seeAlsos": [], + "signature": "function stringUnionParamMethod( + value: 'a' | 'b', + options?: { + casing?: Casing; + format?: 'hex' | ColorFormat; + excludes?: ReadonlyArray<AlphaNumericChar>; + } + ): string;", + "since": "1.0.0", + "throws": [], + }, + ], + "source": { + "column": -1, + "filePath": "test/scripts/apidocs/method.example.ts", + "line": -1, + }, +} +`; diff --git a/test/scripts/apidoc/module.example.ts b/test/scripts/apidocs/class.example.ts index 0e5d9d89..0e5d9d89 100644 --- a/test/scripts/apidoc/module.example.ts +++ b/test/scripts/apidocs/class.example.ts diff --git a/test/scripts/apidocs/class.spec.ts b/test/scripts/apidocs/class.spec.ts new file mode 100644 index 00000000..8ebce847 --- /dev/null +++ b/test/scripts/apidocs/class.spec.ts @@ -0,0 +1,22 @@ +import { describe, expect, it } from 'vitest'; +import { processClass } from '../../../scripts/apidocs/processing/class'; +import * as ModuleTests from './class.example'; +import { loadExampleClasses } from './utils'; + +const modules = loadExampleClasses(); + +describe('class', () => { + it('dummy dependency to rerun the test if the example changes', () => { + expect(Object.keys(ModuleTests)).not.toEqual([]); + }); + + it('expected and actual modules are equal', () => { + expect(Object.keys(modules).sort()).toMatchSnapshot(); + }); + + it.each(Object.entries(modules))('processClass(%s)', (_, module) => { + const actual = processClass(module); + + expect(actual).toMatchSnapshot(); + }); +}); diff --git a/test/scripts/apidoc/signature.example.ts b/test/scripts/apidocs/method.example.ts index c42d2d45..e72f5f3f 100644 --- a/test/scripts/apidoc/signature.example.ts +++ b/test/scripts/apidocs/method.example.ts @@ -74,6 +74,8 @@ export type AB = 'a' | 'b'; export class SignatureTest { /** * Test with no parameters. + * + * @since 1.0.0 */ noParamMethod(): number { return 0; @@ -83,6 +85,8 @@ export class SignatureTest { * Test with a required parameter. * * @param a The number parameter. + * + * @since 1.0.0 */ requiredNumberParamMethod(a: number): number { return a; @@ -92,6 +96,8 @@ export class SignatureTest { * Test with an optional parameter. * * @param b The string parameter. + * + * @since 1.0.0 */ optionalStringParamMethod(b?: string): number { return b ? 0 : 1; @@ -101,6 +107,8 @@ export class SignatureTest { * Test with a default parameter. * * @param c The boolean parameter. + * + * @since 1.0.0 */ defaultBooleanParamMethod(c: boolean = true): number { return c ? 1 : 0; @@ -112,6 +120,8 @@ export class SignatureTest { * @param a The number parameter. * @param b The string parameter. * @param c The boolean parameter. + * + * @since 1.0.0 */ multiParamMethod(a: number, b?: string, c: boolean = true): number { return c ? a : b ? 0 : 1; @@ -121,6 +131,8 @@ export class SignatureTest { * Test with a function parameters. * * @param fn The function parameter. + * + * @since 1.0.0 */ functionParamMethod(fn: (a: string) => number): number { return fn('a'); @@ -134,12 +146,23 @@ export class SignatureTest { * @param options.casing The casing parameter. * @param options.format The format parameter. * @param options.excludes The excludes parameter. + * + * @since 1.0.0 */ stringUnionParamMethod( value: 'a' | 'b', options?: { + /** + * The casing parameter. + */ casing?: Casing; + /** + * The format parameter. + */ format?: 'hex' | ColorFormat; + /** + * The excludes parameter. + */ excludes?: ReadonlyArray<AlphaNumericChar>; } ): string { @@ -155,6 +178,8 @@ export class SignatureTest { * @param namedArray Array of `'a'` or `'b'`. * @param mixed Value `'a'` or `'b'` or an array thereof. * @param namedMixed Value `'a'` or `'b'` or an array thereof. + * + * @since 1.0.0 */ literalUnionParamMethod( value: LiteralUnion<'a' | 'b'>, @@ -178,6 +203,8 @@ export class SignatureTest { * Test with a Record parameter. * * @param object The Record parameter. + * + * @since 1.0.0 */ recordParamMethod(object: Record<string, number>): number { return object.a; @@ -192,11 +219,25 @@ export class SignatureTest { * @param options.c The boolean parameter. * @param options.d The method parameter. * @param options.e The LiteralUnion parameter. + * + * @since 1.0.0 */ optionsParamMethod(options: { + /** + * The number parameter. + */ a: number; + /** + * The string parameter. + */ b?: string; + /** + * The boolean parameter. + */ c: boolean; + /** + * The method parameter. + */ d: () => string; /** * A parameter with inline documentation. @@ -222,11 +263,28 @@ export class SignatureTest { * @param b.value The number parameter. * @param c Parameter with inner jsdocs default. * @param c.value The number parameter. It also has a more complex description. Defaults to `2`. + * + * @since 1.0.0 */ optionsInlineParamMethodWithDefaults( - a: { value?: number } = { value: 1 }, - b: { value?: number }, - c: { value?: number } + a: { + /** + * The number parameter. + */ + value?: number; + } = { value: 1 }, + b: { + /** + * The number parameter. + */ + value?: number; + }, + c: { + /** + * The number parameter. + */ + value?: number; + } ): number { return a.value ?? b.value ?? c.value ?? -1; } @@ -240,6 +298,8 @@ export class SignatureTest { * @param b.value The number parameter. * @param c Parameter with inner jsdocs default. * @param c.value The number parameter. Defaults to `2`. + * + * @since 1.0.0 */ optionsTypeParamMethodWithDefaults( a: ParameterOptionsTypeA = { value: 1 }, @@ -258,6 +318,8 @@ export class SignatureTest { * @param b.value The number parameter. * @param c Parameter with inner jsdocs default. * @param c.value The number parameter. Defaults to `2`. + * + * @since 1.0.0 */ optionsInterfaceParamMethodWithDefaults( a: ParameterOptionsInterfaceA = { value: 1 }, @@ -271,7 +333,9 @@ export class SignatureTest { * Test with example marker. * * @example - * test.apidoc.methodWithExample() // 0 + * test.apidocs.methodWithExample() // 0 + * + * @since 1.0.0 */ methodWithExample(): number { return 0; @@ -280,7 +344,9 @@ export class SignatureTest { /** * Test with deprecated and see marker. * - * @see test.apidoc.methodWithExample() + * @see test.apidocs.methodWithExample() + * + * @since 1.0.0 * * @deprecated do something else */ @@ -292,6 +358,8 @@ export class SignatureTest { * Test with throws. * * @throws Everytime. + * + * @since 1.0.0 */ methodWithThrows(): number { throw new FakerError('Test error'); @@ -302,6 +370,8 @@ export class SignatureTest { * * @throws First error case. * @throws Another error case. + * + * @since 1.0.0 */ methodWithMultipleThrows(): number { throw new FakerError('Another test error'); @@ -314,6 +384,8 @@ export class SignatureTest { * @param option.a Some deprecated option. * @param option.b Some other deprecated option. * @param option.c Some other option. + * + * @since 1.0.0 */ methodWithDeprecatedOption(option: { /** @@ -339,8 +411,10 @@ export class SignatureTest { /** * Test with multiple see markers. * - * @see test.apidoc.methodWithExample() - * @see test.apidoc.methodWithDeprecated() + * @see test.apidocsmethodWithExample() + * @see test.apidocsmethodWithDeprecated() + * + * @since 1.0.0 */ methodWithMultipleSeeMarkers(): number { return 0; @@ -349,8 +423,10 @@ export class SignatureTest { /** * Test with multiple see markers and backticks. * - * @see test.apidoc.methodWithExample() with parameter `foo`. - * @see test.apidoc.methodWithDeprecated() with parameter `bar` and `baz`. + * @see test.apidocsmethodWithExample() with parameter `foo`. + * @see test.apidocsmethodWithDeprecated() with parameter `bar` and `baz`. + * + * @since 1.0.0 */ methodWithMultipleSeeMarkersAndBackticks(): number { return 0; @@ -373,6 +449,8 @@ export class SignatureTest { * @param array Array to pick the value from. * @param array[].weight The weight of the value. * @param array[].value The value to pick. + * + * @since 1.0.0 */ complexArrayParameter<T>( array: ReadonlyArray<{ diff --git a/test/scripts/apidocs/method.spec.ts b/test/scripts/apidocs/method.spec.ts new file mode 100644 index 00000000..14c9cfc0 --- /dev/null +++ b/test/scripts/apidocs/method.spec.ts @@ -0,0 +1,30 @@ +import { describe, expect, it } from 'vitest'; +import { processMethodLike } from '../../../scripts/apidocs/processing/method'; +import { SignatureTest } from './method.example'; +import { loadExampleMethods } from './utils'; + +const methods = loadExampleMethods(); + +describe('method', () => { + it('dummy dependency to rerun the test if the example changes', () => { + expect(new SignatureTest()).toBeTruthy(); + }); + + it('expected and actual methods are equal', () => { + expect(Object.keys(methods)).toMatchSnapshot(); + }); + + it.each(Object.entries(methods))( + 'processMethodLike(%s)', + (name, signature) => { + const actual = processMethodLike(name, signature); + actual.source = { + filePath: actual.source.filePath, + line: -1, + column: -1, + }; + + expect(actual).toMatchSnapshot(); + } + ); +}); diff --git a/test/scripts/apidocs/utils.ts b/test/scripts/apidocs/utils.ts new file mode 100644 index 00000000..e15bcd8f --- /dev/null +++ b/test/scripts/apidocs/utils.ts @@ -0,0 +1,38 @@ +import type { ClassDeclaration, MethodDeclaration, SourceFile } from 'ts-morph'; +import { getProject } from '../../../scripts/apidocs/project'; + +/** + * Loads the example methods. + */ +export function loadExampleMethods(): Record<string, MethodDeclaration> { + return Object.fromEntries( + loadProjectFile('test/scripts/apidocs/method.example.ts') + .getClassOrThrow('SignatureTest') + .getMethods() + .map((m) => [m.getName(), m] as const) + .sort(([a], [b]) => a.localeCompare(b)) // Relevant for Object.keys() order + ); +} + +/** + * Loads the example classes. + */ +export function loadExampleClasses(): Record<string, ClassDeclaration> { + return Object.fromEntries( + loadProjectFile('test/scripts/apidocs/class.example.ts') + .getClasses() + .map((m) => [m.getNameOrThrow(), m] as const) + .sort(([a], [b]) => a.localeCompare(b)) // Relevant for Object.keys() order + ); +} + +/** + * Loads the project. + * + * @param sourceFile The source file to load. + */ +function loadProjectFile(sourceFile: string): SourceFile { + const project = getProject(); + + return project.addSourceFileAtPath(sourceFile); +} diff --git a/test/scripts/apidocs/verify-jsdoc-tags.spec.ts b/test/scripts/apidocs/verify-jsdoc-tags.spec.ts new file mode 100644 index 00000000..16f0ea51 --- /dev/null +++ b/test/scripts/apidocs/verify-jsdoc-tags.spec.ts @@ -0,0 +1,286 @@ +import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import validator from 'validator'; +import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'; +import { processComponents } from '../../../scripts/apidocs/generate'; +import { extractSummaryDefault } from '../../../scripts/apidocs/output/page'; +import { getProject } from '../../../scripts/apidocs/project'; + +// This test suite ensures, that every method +// - has working examples +// - running these do not log anything, unless the method is deprecated +// - has a valid @since tag +// - has valid @see tags +// - has proper links in the description + +const tempDir = resolve(dirname(fileURLToPath(import.meta.url)), 'temp'); +const relativeImportPath = `${'../'.repeat(5)}src`; + +afterAll(() => { + // Remove temp folder + if (existsSync(tempDir)) { + rmSync(tempDir, { recursive: true }); + } +}); + +const modules = processComponents(getProject()); + +function resolveDirToModule(moduleName: string): string { + return resolve(tempDir, moduleName); +} + +function resolvePathToMethodFile( + moduleName: string, + methodName: string, + signature: number +): string { + const dir = resolveDirToModule(moduleName); + return resolve(dir, `${methodName}_${signature}.ts`); +} + +const allowedReferences = new Set( + modules.flatMap(({ camelTitle, methods, category }) => { + return methods.map(({ name }) => + category ? `faker.${camelTitle}.${name}` : `${camelTitle}.${name}` + ); + }) +); +const allowedLinks = new Set( + modules.flatMap(({ camelTitle, methods }) => { + return [ + `/api/${camelTitle}.html`, + ...methods.map( + ({ name }) => `/api/${camelTitle}.html#${name.toLowerCase()}` + ), + ]; + }) +); + +function assertDescription(description: string): void { + const linkRegexp = /\[([^\]]+)\]\(([^)]+)\)/g; + const links = [...description.matchAll(linkRegexp)].map((m) => m[2]); + + for (const link of links) { + expect(link).toMatch(/^https?:\/\//); + expect(link).toSatisfy(validator.isURL); + + if (link.includes('fakerjs.dev/api/')) { + expect(allowedLinks, `${link} to point to a valid target`).toContain( + link.replace(/.*fakerjs.dev\//, '/') + ); + } + } +} + +describe('verify JSDoc tags', () => { + describe.each(modules.map((m) => [m.camelTitle, m]))( + '%s', + (moduleName, module) => { + describe('verify module', () => { + it('verify description', () => { + assertDescription(module.description); + }); + }); + + describe.each(module.methods.map((m) => [m.name, m]))( + '%s', + (methodName, method) => { + describe.each(method.signatures.map((s, i) => [i, s]))( + '%i', + (signatureIndex, signature) => { + beforeAll(() => { + // Write temp files to disk + // By extracting the examples + // Guessing required imports + // And saving them to disk for later execution + + const dir = resolveDirToModule(moduleName); + mkdirSync(dir, { recursive: true }); + const path = resolvePathToMethodFile( + moduleName, + methodName, + signatureIndex + ); + + let examples = signature.examples.join('\n'); + if (moduleName === 'faker' && methodName === 'constructor') { + // That case should demonstrate an error and is thus not suitable for testing + examples = examples.replace( + 'customFaker.music.genre()', + '// customFaker.music.genre()' + ); + } + + // Replace imports for users with our source path + examples = examples.replaceAll( + " from '@faker-js/faker'", + ` from '${relativeImportPath}'` + ); + + if (moduleName === 'randomizer') { + examples = `import { generateMersenne32Randomizer } from '${relativeImportPath}/internal/mersenne'; + +const randomizer = generateMersenne32Randomizer(); + +${examples}`; + } + + // If imports are present, we expect them to be complete + if (!examples.includes('import ')) { + const imports = [ + // collect the imports for the various locales e.g. fakerDE_CH + ...new Set(examples.match(/(?<!\.)faker[^.]*(?=\.)/g)), + ]; + + if (imports.length > 0) { + examples = `import { ${imports.join( + ', ' + )} } from '${relativeImportPath}';\n\n${examples}`; + } + } + + writeFileSync(path, examples); + }); + + it('verify description', () => { + assertDescription(signature.description); + }); + + it('verify @example tag', async () => { + const examples = signature.examples.join('\n'); + + expect( + examples, + `${moduleName}.${methodName} to have examples` + ).not.toBe(''); + + // Grab path to example file + const path = resolvePathToMethodFile( + moduleName, + methodName, + signatureIndex + ); + + // Executing the examples should not throw + await expect( + import(`${path}?scope=example`), + examples + ).resolves.toBeDefined(); + }); + + // This only checks whether the whole method is deprecated or not + // It does not check whether the method is deprecated for a specific set of arguments + it('verify @deprecated tag', async () => { + // Grab path to example file + const path = resolvePathToMethodFile( + moduleName, + methodName, + signatureIndex + ); + + const consoleWarnSpy = vi.spyOn(console, 'warn'); + + // Run the examples + await import(`${path}?scope=deprecated`); + + // Verify that deprecated methods log a warning + const { deprecated } = signature; + if (deprecated == null) { + expect(consoleWarnSpy).not.toHaveBeenCalled(); + } else { + expect(consoleWarnSpy).toHaveBeenCalled(); + expect(deprecated).not.toBe(''); + } + }); + + describe.each(signature.parameters.map((p) => [p.name, p]))( + '%s', + (_, parameter) => { + it('verify default value', () => { + const { + name, + default: paramDefault, + description, + } = parameter; + + const commentDefault = extractSummaryDefault(description); + if (paramDefault) { + if ( + /^{.*}$/.test(paramDefault) || + paramDefault.includes('\n') + ) { + expect(commentDefault).toBeUndefined(); + } else if ( + !name.includes('.') && + // Skip check of defaults in descriptions if it is a paraphrased function call + (commentDefault || + (!description.includes('Defaults to') && + !paramDefault.includes('('))) + ) { + expect( + commentDefault, + `Expect '${name}'s js implementation default to be the same as the jsdoc summary default` + ).toBe(paramDefault); + } + } + }); + + it('verify description', () => { + assertDescription(parameter.description); + }); + } + ); + + it('verify @see tags', () => { + for (const link of signature.seeAlsos) { + if (link.startsWith('faker.')) { + // Expected @see faker.xxx.yyy() + expect( + link, + 'Expect method reference to contain ()' + ).toContain('('); + expect( + link, + 'Expect method reference to contain ()' + ).toContain(')'); + expect( + link, + "Expect method reference to have a ': ' after the parenthesis" + ).toContain('): '); + expect( + link, + 'Expect method reference to have a description starting with a capital letter' + ).toMatch(/\): [A-Z]/); + expect( + link, + 'Expect method reference to start with a standard description phrase' + ).toMatch( + /\): (?:For generating |For more information about |For using |For the replacement method)/ + ); + expect( + link, + 'Expect method reference to have a description ending with a dot' + ).toMatch(/\.$/); + expect(allowedReferences).toContain( + link.replace(/\(.*/, '') + ); + } + } + }); + + it('verify @since tag', () => { + const { since } = signature; + expect(since, '@since to be present').toBeTruthy(); + expect(since).not.toBe(''); + expect(since, '@since to be a valid semver').toSatisfy( + validator.isSemVer + ); + }); + } + ); + } + ); + } + ); +}); |
