Skip to content

fix: validate-jsdoc-codeblock handles union symbols regardless of order#1345

Closed
taiyakihitotsu wants to merge 1 commit intosindresorhus:mainfrom
taiyakihitotsu:fix/jsdoc-lint-20260203
Closed

fix: validate-jsdoc-codeblock handles union symbols regardless of order#1345
taiyakihitotsu wants to merge 1 commit intosindresorhus:mainfrom
taiyakihitotsu:fix/jsdoc-lint-20260203

Conversation

@taiyakihitotsu
Copy link
Contributor

@taiyakihitotsu taiyakihitotsu commented Feb 3, 2026

In the current (before this PR) validate-jsdoc-codeblocks.js doesn't sort union types including symbols.
And TypeScript doesn't ensure the order or unions, whether it's placed in actualComment or expectedComment.

This PR sorts both, keeps the original comments to pass a report.

Background

The union order error doesn't occur in the current main, 051325a including the commit to fix path, 8f0419c, but in my PR: #1338

Error log

npm test

> type-fest@5.4.3 test
> run-p test:*


> type-fest@5.4.3 test:linter
> node --test


> type-fest@5.4.3 test:tsd
> node --max-old-space-size=6144 ./node_modules/.bin/tsd


> type-fest@5.4.3 test:xo
> node --max-old-space-size=6144 ./node_modules/.bin/xo --ignores=lint-processors/fixtures/**/*.d.ts


> type-fest@5.4.3 test:tsc
> node --max-old-space-size=6144 ./node_modules/.bin/tsc

▶ jsdoc-codeblocks processor
  ✔ valid - No JSDoc (690.561768ms)
  ✔ valid - JSDoc without code block (690.678318ms)
  ✔ valid - Valid code block (690.788088ms)
  ✔ valid - With text before and after (690.823118ms)
  ✔ valid - With line breaks before and after (690.994059ms)
  ✔ valid - With @example tag (691.139441ms)
  ✔ valid - With ts language specifier (691.288462ms)
  ✔ valid - With typescript language specifier (691.587244ms)
  ✔ valid - Multiple code blocks (691.242572ms)
  ✔ valid - Multiple exports and multiple properties (691.630694ms)
  ✔ valid - Indented code blocks (691.762755ms)
  ✔ valid - Ignore codeblocks with inconsistent indentation (691.947576ms)
  ✔ invalid - With text before and after (855.647256ms)
  ✔ invalid - With line breaks before and after (855.894208ms)
  ✔ invalid - With @example tag (856.027278ms)
  ✔ invalid - With language specifiers (856.162729ms)
  ✔ invalid - With typescript language specifiers (856.278529ms)
  ✔ invalid - Multiple code blocks (856.39915ms)
  ✔ invalid - Multiple exports and multiple properties (856.496211ms)
  ✔ invalid - Indented code blocks (856.587461ms)
  ✔ invalid - Error and fix starting at the first character of the codeblock (856.706621ms)
  ✔ invalid - Error and fix in the middle of the codeblock (856.844393ms)
  ✔ invalid - Error and fix ending at the last character of the codeblock (857.064254ms)
  ✔ invalid - Error spanning multiple lines (857.208505ms)
  ✔ invalid - Multiline fix (857.367806ms)
  ✔ invalid - Multiple errors (857.533086ms)
  ✔ invalid - Overlapping errors (857.674898ms)
  ✔ invalid - Error reporting location different from fix location (857.764178ms)
  ✔ invalid - Non fixable error (857.91842ms)
  ✔ invalid - Error outside JSDoc (858.0627ms)
  ✔ invalid - Error ending at first column (858.234671ms)
✔ jsdoc-codeblocks processor (863.804412ms)
✔ lint-rules/import-path.test.js (719.636064ms)
✔ lint-rules/require-export.test.js (641.388524ms)
✔ lint-rules/require-exported-types.test.js (1234.725503ms)
✔ lint-rules/source-files-extension.test.js (643.330826ms)
✔ lint-rules/test-utils.js (557.495563ms)
[baseline-browser-mapping] The data in this module is over two months old.  To ensure accurate Baseline data, please update: `npm i baseline-browser-mapping@latest -D`

  test-d/jsonify.ts:2:1
  ⚠    2:1   Unexpected todo comment: TODO: Convert the `interface`'s to....                                                                                                                                                   no-warning-comments
  ⚠   70:1   Unexpected todo comment: TODO: Convert this to a `type`..                                                                                                                                                         no-warning-comments

  source/arrayable.d.ts:28:1
  ⚠   28:1   Unexpected todo comment: TODO: Use `readonly T[]` when this issue....                                                                                                                                             no-warning-comments

  source/merge-deep.d.ts:17:94
  ⚠   17:94  Unexpected todo comment: TODO: Remove this.                                                                                                                                                                       no-warning-comments

  source/subtract.d.ts:37:1
  ⚠   37:1   Unexpected todo comment: TODO: Support big integer..                                                                                                                                                              no-warning-comments

  source/sum.d.ts:34:1
  ⚠   34:1   Unexpected todo comment: TODO: Support big integer..                                                                                                                                                              no-warning-comments

  test-d/conditional-simplify-deep.ts:27:1
  ⚠   27:1   Unexpected todo comment: TODO: Convert this to a `type`..                                                                                                                                                         no-warning-comments

  test-d/set-parameter-type.ts:43:1
  ⚠   43:1   Unexpected todo comment: TODO: Fix. The `this` is reported as....                                                                                                                                                 no-warning-comments

  test-d/undefined-on-partial-deep.ts:1:1
  ⚠    1:1   Unexpected todo comment: TODO: Test equality.                                                                                                                                                                     no-warning-comments

  source/internal/array.d.ts:18:1
  ⚠   18:1   Unexpected todo comment: TODO: should unknown-array be updated?.                                                                                                                                                  no-warning-comments

  test-d/internal/has-multiple-call-signatures.ts:11:2
  ⚠   11:2   Unused eslint-disable directive (no problems were reported from @typescript-eslint/unified-signatures).                                                                                  

  test-d/internal/union-max.ts:10:1
  ⚠   10:1   Unexpected todo comment: TODO: push `negative-union-max-min`....                                                                                                                                                  no-warning-comments

  test-d/internal/union-min.ts:10:1
  ⚠   10:1   Unexpected todo comment: TODO: push `negative-union-max-min`....                                                                                                                                                  no-warning-comments

  test-d/internal/unique-union-deep.ts:21:1
  ⚠   21:1   This line has a length of 260. Maximum allowed is 200.                                                                                                                                                            @stylistic/max-len

  test-d/internal/unique-union.ts:18:1
  ⚠   18:1   This line has a length of 256. Maximum allowed is 200.                                                                                                                                                            @stylistic/max-len

  source/paths.d.ts:80:2
  ✖   80:2   Expected twoslash comment to be: //=> id | author | author.name | author.name.first | author.name.last | author.id, but found: //=> id | author | author.id | author.name | author.name.first | author.name.last  type-fest/validate-jsdoc-codeblocks
  ✖   83:2   Expected twoslash comment to be: //=> id | author.name.first | author.name.last | author.id, but found: //=> id | author.id | author.name.first | author.name.last                                                type-fest/validate-jsdoc-codeblocks
  ✖  130:2   Expected twoslash comment to be: //=> author.name | author.id, but found: //=> author.id | author.name                                                                                                            type-fest/validate-jsdoc-codeblocks

  15 warnings
  3 errors

✖ lint-rules/validate-jsdoc-codeblocks.test.js (6969.422889ms)
ℹ tests 37
ℹ suites 1
ℹ pass 36
ℹ fail 0
ℹ cancelled 1
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 7026.163875

✖ failing tests:

test at lint-rules/validate-jsdoc-codeblocks.test.js:1:1
✖ lint-rules/validate-jsdoc-codeblocks.test.js (6969.422889ms)
  'Promise resolution is still pending but the event loop has already resolved'
ERROR: "test:xo" exited with 1.

PS

Changed this PR #1338 to draft because of this PR.

@taiyakihitotsu taiyakihitotsu marked this pull request as draft February 3, 2026 14:43
@taiyakihitotsu taiyakihitotsu force-pushed the fix/jsdoc-lint-20260203 branch from 95811ea to c08db43 Compare February 3, 2026 14:59
@taiyakihitotsu taiyakihitotsu force-pushed the fix/jsdoc-lint-20260203 branch from c08db43 to eeb9889 Compare February 3, 2026 15:13
@taiyakihitotsu taiyakihitotsu marked this pull request as ready for review February 3, 2026 15:23
@taiyakihitotsu
Copy link
Contributor Author

@som-sm
Hi!

I am not entirely confident in my approach, particularly here:

https://github.com/sindresorhus/type-fest/pull/1345/changes#diff-e8b043e91a0916ef1a0281b7d350f9915ec81cffeac533891e45fd25b03d9844R340

const isNotPassed = (/\/\/}/g.test(actualComment)) || (actualComment.length < 80 && (/\[{\n/g.test(actualComment)));

My logic assumes that both actualComment and expectedComment should be sorted, so, they cannot be directly compared with each other.

To simplify the implementation, I used regular expressions to exclude unsupported patterns.

Does this align with your intent, or is there any part of the implementation that seems off?
What do you think?

Thanks for reading.

@taiyakihitotsu taiyakihitotsu changed the title fix: validate-jsdoc-codeblock accepts union symbols fix: validate-jsdoc-codeblock handles union symbols regardless of order Feb 3, 2026
Comment on lines +810 to +825
namespace AAA {
export type aaa = {a: string};
}
namespace BBB {
export type aaa = {a: string};
}
namespace CCC {
export type aaa = {a: string};
export type bbb = {a: string};
}

type Symbols_0 = AAA.aaa | CCC.bbb | CCC.aaa | BBB.aaa;
//=> AAA.aaa | BBB.aaa | CCC.aaa | CCC.bbb

type Symbols_1 = AAA.aaa | CCC.bbb | CCC.aaa | BBB.aaa;
//=> BBB.aaa | AAA.aaa | CCC.aaa | CCC.bbb
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Umm...didn't get this. This example already works, and the result is already sorted.

namespace AAA {
	export type aaa = {a: string};
}
namespace BBB {
	export type aaa = {a: string};
}
namespace CCC {
	export type aaa = {a: string};
	export type bbb = {a: string};
}

type Symbols_0 = AAA.aaa | CCC.bbb | CCC.aaa | BBB.aaa;
//   ^? type Symbols_0 = AAA.aaa | BBB.aaa | CCC.aaa | CCC.bbb

type Symbols_1 = AAA.aaa | CCC.bbb | CCC.aaa | BBB.aaa;
//   ^? type Symbols_1 = AAA.aaa | BBB.aaa | CCC.aaa | CCC.bbb

Playground: https://tsplay.dev/W4oPAm

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry.
The goal was to verify that both actual and expected are sorted consistently even if they are Union types, allowing them to be compared via actualComment !== expectedComment regardless of their order.
However, I'm concerned that my test case might not be reproducing this scenario correctly.

This is what I want to fix:
https://github.com/sindresorhus/type-fest/actions/runs/21571234433/job/62150630102?pr=1338

If you pull this PR #1338 and run npm test, can you reproduce the same error?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@som-sm
Copy link
Collaborator

som-sm commented Feb 3, 2026

@taiyakihitotsu This error seems fine:

image

If you change something that alters the output of Paths, then the JSDoc should be updated accordingly.

The intent behind custom sorting was to only sort numbers, because unordered numbers can create confusion. For everything else, we want to stick to what shows up in the Quick Info tooltip. Custom sorting everything, will only make things more confusing.

So if the Quick Info tooltip shows id | author | author.name | author.name.first | author.name.last | author.id, we want the twoslash comment to match that. We should not change it to something else.

Also, at times you can tweak the implementation and get the desired order, so it's worth double-checking that as well.

@taiyakihitotsu
Copy link
Contributor Author

@som-sm

Thank for explanation!

So if the Quick Info tooltip shows id | author | author.name | author.name.first | author.name.last | author.id, we want the twoslash comment to match that. We should not change it to something else.

But in my environment, the main branch passes npm test but this PR #1338 doesn't.

My concern is that if we don't sort Unions, we might end up having to update (unrelated) documentation every time there's a change, just because the output order shifted.

(Regardless of whether my approach is the right way to go or not)

What do you think?

@som-sm
Copy link
Collaborator

som-sm commented Feb 3, 2026

But in my environment, the main branch passes npm test but this PR #1338 doesn't.

Because your PR most likely introduces some change that affects the order of Paths. Can you figure out why the order is changing?

My concern is that if we don't sort Unions, we might end up having to update (unrelated) documentation every time there's a change, just because the output order shifted.

But the order wouldn't change unless the underlying implementation changes. If the implementation is the same, the order should/would remain the same.


And, if you look at the example, the existing order is correct, because it follows the order in the input object.
image

id comes first in the object, then author, then author.name and so on. So, it shouldn't be changed.

@taiyakihitotsu
Copy link
Contributor Author

My concern is that if we don't sort Unions, we might end up having to update (unrelated) documentation every time there's a change, just because the output order shifted.

But the order wouldn't change unless the underlying implementation changes. If the implementation is the same, the order should/would remain the same.

Thank you for clarifying!
I see your point now.

I withdraw this PR (and reopen #1338).

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants