Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Add option for organize imports case sensitivity#51733

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Conversation

andrewbranch
Copy link
Member

Fixes#51616
Related:#51579

A new user preference (editor PR to follow) allows setting the case sensitivity for import sorting. By default, we detect.

SlurpTheo reacted with eyes emoji
@jakebailey
Copy link
Member

I'm finding it hard to deduce from the tests, but what is the behavior when you have bothHasDecorator andhasDecorator, in various orders? Does it always output the same thing?

This is something that frustrates me currently about the eslint plugin; it doesn't care which order you have, which leaves a hole where we can end up with conflicts when the result should not depend on the input ordering at all.

@andrewbranch
Copy link
MemberAuthor

andrewbranch commentedDec 6, 2022
edited
Loading

Currently, case-insensitive is truly case-insensitive like eslint, which means any order between specifiers that differ only in case is allowed, and a reshuffle will preserve the pre-existing relative order (eslint doesn’t use a stable sort, which means pre-existing order between case-different specifiers is not preserved, resulting in sorts that look totally random). This is something we can definitely change or improve on over the eslint behavior, but if we change back to case sensitive sorting, I wasn’t sure if anyone would end up caring about it.

jakebailey reacted with thumbs up emoji

}

/** @internal */
export function getImportDeclarationInsertionIndex(sortedImports: SortedReadonlyArray<AnyImportOrRequireStatement>, newImport: AnyImportOrRequireStatement) {
const index = binarySearch(sortedImports, newImport, identity, compareImportsOrRequireStatements);
export const detectImportSpecifierSorting = memoizeWeak((specifiers: readonly ImportSpecifier[]): SortKind => {
Copy link
Member

Choose a reason for hiding this comment

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

Is there a particular reason why this one is cached but others aren't? Would everything benefit from being cached like this?

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

As it stands now, this is the only one that benefits from being cached. It gets called several times from auto-imports in ways that are cumbersome to cache locally.

jakebailey reacted with thumbs up emoji
let prevElement = array[0];
for (const element of array.slice(1)) {
if (comparer(prevElement, element) === Comparison.GreaterThan) {
for (let i = 1, len = array.length; i < len; i++) {
Copy link
Member

Choose a reason for hiding this comment

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

:yikes: nice catch

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

@DanielRosenwasser noticed this while I was screensharing working on this. Turns out I wrote it years ago, before I was terrified of allocations 🙈

DanielRosenwasser reacted with laugh emojiDanielRosenwasser reacted with heart emoji
for (let i = 1, len = array.length; i < len; i++) {
const prevElement = array[i - 1];
const element = array[i];
if (caseSensitiveComparer(prevElement, element) === Comparison.GreaterThan) {

Choose a reason for hiding this comment

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

It would be more obvious to me what was going on if this was something like!== Comparison.LessThanOrEqualTo

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

“less than or equal to” can’t be represented in a single value the way ourComparison system works:

exportconstenumComparison{LessThan=-1,EqualTo=0,GreaterThan=1}

Choose a reason for hiding this comment

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

Yeah - just an idle sort of "it would be nice".

Comment on lines 981 to 989
if (caseSensitiveComparer(prevElement, element) === Comparison.GreaterThan) {
kind &= ~SortKind.CaseSensitive;
}
if (caseInsensitiveComparer(prevElement, element) === Comparison.GreaterThan) {
kind &= ~SortKind.CaseInsensitive;
}
if (kind === SortKind.None) {
return kind;
}
Copy link
Member

@DanielRosenwasserDanielRosenwasserDec 13, 2022
edited
Loading

Choose a reason for hiding this comment

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

I think that you can optimize this.

  1. If you know that you're not case-sensitively sorted, you never have to check again; you can just always check the case-insensitive branch.
  2. If you are not case-insensitively sorted, you can just bail out at that point. You won't be case-sensitively sorted.

That means the only times you ever have to do two checks for a pair of elements is the first pair that forces you to transition to only checking for case-insensitive comparison.

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

Good point on (1), but (2) is not true.['B', 'a'] is not case-insensitively sorted but is case-sensitively sorted. (That’s the entire reason this is bit flags.)

It sure sounds like the “case-insensitively sorted lists” ought to be a superset of “case-sensitively sorted lists,” doesn’t it? They’re actually a classic Venn diagram shape where there is a non-empty intersection but neither is a subset of the other. When Jake was first trying to explain the problem to me verbally, I made the same mistake.

DanielRosenwasser reacted with thumbs up emoji

Choose a reason for hiding this comment

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

Ugh, why was I so convinced this was true? But yes, I see that. At least you can avoid each kind of comparison after the first failure.

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

(Quiz ChatGPT about this for a good laugh)

}
return kind;
}

Choose a reason for hiding this comment

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

Suggested change

@DanielRosenwasser
Copy link
Member

@typescript-bot user test tsserver
@typescript-bot test tsserver top100
@typescript-bot perf test this

@typescript-bot
Copy link
Collaborator

typescript-bot commentedDec 13, 2022
edited
Loading

Heya@DanielRosenwasser, I've started to run the diff-based user code test suite (tsserver) on this PR at4257fe4. You can monitor the buildhere.

Update:The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commentedDec 13, 2022
edited
Loading

Heya@DanielRosenwasser, I've started to run the diff-based top-repos suite (tsserver) on this PR at4257fe4. You can monitor the buildhere.

Update:The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commentedDec 13, 2022
edited
Loading

Heya@DanielRosenwasser, I've started to run the perf test suite on this PR at4257fe4. You can monitor the buildhere.

@typescript-bot
Copy link
Collaborator

@DanielRosenwasser Here are the results of running the user test suite comparingmain andrefs/pull/51733/merge:

Everything looks good!

@andrewbranchandrewbranch merged commit4076ff8 intomicrosoft:mainDec 13, 2022
@andrewbranchandrewbranch deleted the bug/organize-imports-case-sensitivity branchDecember 13, 2022 22:37
@typescript-bot
Copy link
Collaborator

@DanielRosenwasser Here are the results of running the top-repos suite comparingmain andrefs/pull/51733/merge:

Something interesting changed - please have a look.

Details

backstage/backstage

⚠️ Note that built also had errors⚠️
Req #4960 - completionInfo    at hasCovariantVoidArgument (/typescript-main/built/local/tsserver.js:59960:91)    at relateVariances (/typescript-main/built/local/tsserver.js:59210:64)    at structuredTypeRelatedToWorker (/typescript-main/built/local/tsserver.js:58879:32)    at structuredTypeRelatedTo (/typescript-main/built/local/tsserver.js:58800:21)    at recursiveTypeRelatedTo (/typescript-main/built/local/tsserver.js:58770:19)    at isRelatedTo (/typescript-main/built/local/tsserver.js:58329:16)    at compareProperties2 (/typescript-main/built/local/tsserver.js:60116:12)    at propertiesIdenticalTo (/typescript-main/built/local/tsserver.js:59578:25)    at propertiesRelatedTo (/typescript-main/built/local/tsserver.js:59430:16)    at structuredTypeRelatedToWorker (/typescript-main/built/local/tsserver.js:59169:21)    at structuredTypeRelatedTo (/typescript-main/built/local/tsserver.js:58800:21)    at recursiveTypeRelatedTo (/typescript-main/built/local/tsserver.js:58770:19)    at isRelatedTo (/typescript-main/built/local/tsserver.js:58329:16)    at checkTypeRelatedTo (/typescript-main/built/local/tsserver.js:58063:20)    at isTypeRelatedTo (/typescript-main/built/local/tsserver.js:58018:14)    at isTypeIdenticalTo (/typescript-main/built/local/tsserver.js:57345:12)    at isTypeOrBaseIdenticalTo (/typescript-main/built/local/tsserver.js:61563:42)    at inferFromMatchingTypes (/typescript-main/built/local/tsserver.js:61233:15)    at inferFromTypes (/typescript-main/built/local/tsserver.js:61065:44)    at inferTypes (/typescript-main/built/local/tsserver.js:61040:5)    at inferReverseMappedType (/typescript-main/built/local/tsserver.js:60873:5)    at /typescript-main/built/local/tsserver.js:60852:65    at map (/typescript-main/built/local/tsserver.js:2921:19)    at createReverseMappedType (/typescript-main/built/local/tsserver.js:60852:28)    at inferTypeForHomomorphicMappedType (/typescript-main/built/local/tsserver.js:60836:18)    at inferToMappedType (/typescript-main/built/local/tsserver.js:61353:32)    at inferFromObjectTypes (/typescript-main/built/local/tsserver.js:61440:13)    at invokeOnce (/typescript-main/built/local/tsserver.js:61218:9)    at inferFromTypes (/typescript-main/built/local/tsserver.js:61176:11)    at inferWithPriority (/typescript-main/built/local/tsserver.js:61183:7)    at inferFromObjectTypes (/typescript-main/built/local/tsserver.js:61481:17)    at invokeOnce (/typescript-main/built/local/tsserver.js:61218:9)    at inferFromTypes (/typescript-main/built/local/tsserver.js:61176:11)    at inferToMultipleTypes (/typescript-main/built/local/tsserver.js:61303:15)    at inferFromTypes (/typescript-main/built/local/tsserver.js:61157:9)    at inferFromProperties (/typescript-main/built/local/tsserver.js:61510:11)    at inferFromObjectTypes (/typescript-main/built/local/tsserver.js:61499:9)    at invokeOnce (/typescript-main/built/local/tsserver.js:61218:9)    at inferFromTypes (/typescript-main/built/local/tsserver.js:61176:11)    at inferTypes (/typescript-main/built/local/tsserver.js:61040:5)    at inferTypeArguments (/typescript-main/built/local/tsserver.js:66805:11)    at chooseOverload (/typescript-main/built/local/tsserver.js:67426:33)    at resolveCall (/typescript-main/built/local/tsserver.js:67293:16)    at resolveCallExpression (/typescript-main/built/local/tsserver.js:67624:12)    at resolveSignature (/typescript-main/built/local/tsserver.js:67969:16)    at getResolvedSignature (/typescript-main/built/local/tsserver.js:67989:20)    at getContextualTypeForArgumentAtIndex (/typescript-main/built/local/tsserver.js:64299:112)    at getContextualTypeForArgument (/typescript-main/built/local/tsserver.js:64293:39)    at getContextualType2 (/typescript-main/built/local/tsserver.js:64673:16)    at getApparentTypeOfContextualType (/typescript-main/built/local/tsserver.js:64615:120)    at getContextualTypeForObjectLiteralElement (/typescript-main/built/local/tsserver.js:64495:18)    at getContextualType2 (/typescript-main/built/local/tsserver.js:64681:16)    at getApparentTypeOfContextualType (/typescript-main/built/local/tsserver.js:64615:120)    at getContextualType2 (/typescript-main/built/local/tsserver.js:64686:22)    at Object.getContextualType (/typescript-main/built/local/tsserver.js:44085:14)    at getContextualType (/typescript-main/built/local/tsserver.js:135744:348)    at getCompletionData (/typescript-main/built/local/tsserver.js:135968:43)    at Object.getCompletionsAtPosition (/typescript-main/built/local/tsserver.js:134376:26)    at Object.getCompletionsAtPosition2 [as getCompletionsAtPosition] (/typescript-main/built/local/tsserver.js:122893:35)    at IOSession.getCompletions (/typescript-main/built/local/tsserver.js:160896:54)    at completionInfo (/typescript-main/built/local/tsserver.js:159577:43)    at /typescript-main/built/local/tsserver.js:161606:69    at IOSession.executeWithRequestId (/typescript-main/built/local/tsserver.js:161598:14)    at IOSession.executeCommand (/typescript-main/built/local/tsserver.js:161606:29)    at IOSession.onMessage (/typescript-main/built/local/tsserver.js:161634:51)    at Interface.<anonymous> (/typescript-main/built/local/tsserver.js:163033:14)
Req #4960 - completionInfo    at hasCovariantVoidArgument (/typescript-51733/built/local/tsserver.js:60013:91)    at relateVariances (/typescript-51733/built/local/tsserver.js:59263:64)    at structuredTypeRelatedToWorker (/typescript-51733/built/local/tsserver.js:58932:32)    at structuredTypeRelatedTo (/typescript-51733/built/local/tsserver.js:58853:21)    at recursiveTypeRelatedTo (/typescript-51733/built/local/tsserver.js:58823:19)    at isRelatedTo (/typescript-51733/built/local/tsserver.js:58382:16)    at compareProperties2 (/typescript-51733/built/local/tsserver.js:60169:12)    at propertiesIdenticalTo (/typescript-51733/built/local/tsserver.js:59631:25)    at propertiesRelatedTo (/typescript-51733/built/local/tsserver.js:59483:16)    at structuredTypeRelatedToWorker (/typescript-51733/built/local/tsserver.js:59222:21)    at structuredTypeRelatedTo (/typescript-51733/built/local/tsserver.js:58853:21)    at recursiveTypeRelatedTo (/typescript-51733/built/local/tsserver.js:58823:19)    at isRelatedTo (/typescript-51733/built/local/tsserver.js:58382:16)    at checkTypeRelatedTo (/typescript-51733/built/local/tsserver.js:58116:20)    at isTypeRelatedTo (/typescript-51733/built/local/tsserver.js:58071:14)    at isTypeIdenticalTo (/typescript-51733/built/local/tsserver.js:57398:12)    at isTypeOrBaseIdenticalTo (/typescript-51733/built/local/tsserver.js:61616:42)    at inferFromMatchingTypes (/typescript-51733/built/local/tsserver.js:61286:15)    at inferFromTypes (/typescript-51733/built/local/tsserver.js:61118:44)    at inferTypes (/typescript-51733/built/local/tsserver.js:61093:5)    at inferReverseMappedType (/typescript-51733/built/local/tsserver.js:60926:5)    at /typescript-51733/built/local/tsserver.js:60905:65    at map (/typescript-51733/built/local/tsserver.js:2925:19)    at createReverseMappedType (/typescript-51733/built/local/tsserver.js:60905:28)    at inferTypeForHomomorphicMappedType (/typescript-51733/built/local/tsserver.js:60889:18)    at inferToMappedType (/typescript-51733/built/local/tsserver.js:61406:32)    at inferFromObjectTypes (/typescript-51733/built/local/tsserver.js:61493:13)    at invokeOnce (/typescript-51733/built/local/tsserver.js:61271:9)    at inferFromTypes (/typescript-51733/built/local/tsserver.js:61229:11)    at inferWithPriority (/typescript-51733/built/local/tsserver.js:61236:7)    at inferFromObjectTypes (/typescript-51733/built/local/tsserver.js:61534:17)    at invokeOnce (/typescript-51733/built/local/tsserver.js:61271:9)    at inferFromTypes (/typescript-51733/built/local/tsserver.js:61229:11)    at inferToMultipleTypes (/typescript-51733/built/local/tsserver.js:61356:15)    at inferFromTypes (/typescript-51733/built/local/tsserver.js:61210:9)    at inferFromProperties (/typescript-51733/built/local/tsserver.js:61563:11)    at inferFromObjectTypes (/typescript-51733/built/local/tsserver.js:61552:9)    at invokeOnce (/typescript-51733/built/local/tsserver.js:61271:9)    at inferFromTypes (/typescript-51733/built/local/tsserver.js:61229:11)    at inferTypes (/typescript-51733/built/local/tsserver.js:61093:5)    at inferTypeArguments (/typescript-51733/built/local/tsserver.js:66858:11)    at chooseOverload (/typescript-51733/built/local/tsserver.js:67479:33)    at resolveCall (/typescript-51733/built/local/tsserver.js:67346:16)    at resolveCallExpression (/typescript-51733/built/local/tsserver.js:67677:12)    at resolveSignature (/typescript-51733/built/local/tsserver.js:68022:16)    at getResolvedSignature (/typescript-51733/built/local/tsserver.js:68042:20)    at getContextualTypeForArgumentAtIndex (/typescript-51733/built/local/tsserver.js:64352:112)    at getContextualTypeForArgument (/typescript-51733/built/local/tsserver.js:64346:39)    at getContextualType2 (/typescript-51733/built/local/tsserver.js:64726:16)    at getApparentTypeOfContextualType (/typescript-51733/built/local/tsserver.js:64668:120)    at getContextualTypeForObjectLiteralElement (/typescript-51733/built/local/tsserver.js:64548:18)    at getContextualType2 (/typescript-51733/built/local/tsserver.js:64734:16)    at getApparentTypeOfContextualType (/typescript-51733/built/local/tsserver.js:64668:120)    at getContextualType2 (/typescript-51733/built/local/tsserver.js:64739:22)    at Object.getContextualType (/typescript-51733/built/local/tsserver.js:44138:14)    at getContextualType (/typescript-51733/built/local/tsserver.js:135817:348)    at getCompletionData (/typescript-51733/built/local/tsserver.js:136041:43)    at Object.getCompletionsAtPosition (/typescript-51733/built/local/tsserver.js:134449:26)    at Object.getCompletionsAtPosition2 [as getCompletionsAtPosition] (/typescript-51733/built/local/tsserver.js:122950:35)    at IOSession.getCompletions (/typescript-51733/built/local/tsserver.js:161016:54)    at completionInfo (/typescript-51733/built/local/tsserver.js:159697:43)    at /typescript-51733/built/local/tsserver.js:161726:69    at IOSession.executeWithRequestId (/typescript-51733/built/local/tsserver.js:161718:14)    at IOSession.executeCommand (/typescript-51733/built/local/tsserver.js:161726:29)    at IOSession.onMessage (/typescript-51733/built/local/tsserver.js:161754:51)    at Interface.<anonymous> (/typescript-51733/built/local/tsserver.js:163153:14)

That is a filtered view of the text. To see the raw error text, go to RepoResults4/backstage.backstage.rawError.txt in theartifact folder

Last few requests

{"seq":4957,"type":"request","command":"completionEntryDetails","arguments":{"file":"@PROJECT_ROOT@/plugins/catalog-backend-module-gitlab/src/service/GitlabDiscoveryEntityProviderCatalogModule.test.ts","line":25,"offset":50,"entryNames":["app-defaults"]}}{"seq":4958,"type":"request","command":"completionInfo","arguments":{"file":"@PROJECT_ROOT@/plugins/catalog-backend-module-gitlab/src/service/GitlabDiscoveryEntityProviderCatalogModule.test.ts","line":52,"offset":18,"includeExternalModuleExports":false,"includeInsertTextCompletions":true,"triggerKind":1}}{"seq":4959,"type":"request","command":"completionEntryDetails","arguments":{"file":"@PROJECT_ROOT@/plugins/catalog-backend-module-gitlab/src/service/GitlabDiscoveryEntityProviderCatalogModule.test.ts","line":52,"offset":18,"entryNames":["addedProviders"]}}{"seq":4960,"type":"request","command":"completionInfo","arguments":{"file":"@PROJECT_ROOT@/plugins/catalog-backend-module-gitlab/src/service/GitlabDiscoveryEntityProviderCatalogModule.test.ts","line":81,"offset":18,"includeExternalModuleExports":false,"includeInsertTextCompletions":true,"triggerKind":1}}

Repro Steps

  1. git clone https://github.com/backstage/backstage --recurse-submodules
  2. In dirbackstage, rungit reset --hard 5b0701ea1b1eaf16d505959f13977b2f3f757d88
  3. Install packages (exact steps are below, but it might be easier to follow the repo readme)
    1. In dirbackstage/cypress, runyarn install --no-immutable --mode=skip-build
    2. In dirbackstage/microsite-next, runyarn install --no-immutable --mode=skip-build
    3. In dirbackstage/microsite, runyarn install --no-immutable --mode=skip-build
    4. In dirbackstage, runyarn install --no-immutable --mode=skip-build
    5. In dirbackstage/storybook, runyarn install --no-immutable --mode=skip-build
  4. Back in the initial folder, downloadRepoResults4/backstage.backstage.replay.txt from theartifact folder
  5. npm install --no-save @typescript/server-replay
  6. npx tsreplay ./backstage ./backstage.backstage.replay.txt path/to/tsserver.js
  7. npx tsreplay --help to learn about helpful switches for debugging, logging, etc

felixrieseberg/windows95

⚠️ Note that built also had errors⚠️
Req #542 - references    at formatMessage2 (/typescript-main/built/local/tsserver.js:158985:21)    at IOSession.writeMessage (/typescript-main/built/local/tsserver.js:159992:21)    at IOSession.send (/typescript-main/built/local/tsserver.js:159989:10)    at IOSession.doOutput (/typescript-main/built/local/tsserver.js:160036:10)    at IOSession.onMessage (/typescript-main/built/local/tsserver.js:161647:14)    at Interface.<anonymous> (/typescript-main/built/local/tsserver.js:163033:14)
Req #542 - references    at formatMessage2 (/typescript-51733/built/local/tsserver.js:159105:21)    at IOSession.writeMessage (/typescript-51733/built/local/tsserver.js:160112:21)    at IOSession.send (/typescript-51733/built/local/tsserver.js:160109:10)    at IOSession.doOutput (/typescript-51733/built/local/tsserver.js:160156:10)    at IOSession.onMessage (/typescript-51733/built/local/tsserver.js:161767:14)    at Interface.<anonymous> (/typescript-51733/built/local/tsserver.js:163153:14)

That is a filtered view of the text. To see the raw error text, go to RepoResults4/felixrieseberg.windows95.rawError.txt in theartifact folder

Last few requests

{"seq":539,"type":"request","command":"definitionAndBoundSpan","arguments":{"file":"@PROJECT_ROOT@/src/renderer/lib/_libwabt.js","line":13,"offset":135424}}{"seq":540,"type":"request","command":"references","arguments":{"file":"@PROJECT_ROOT@/src/renderer/lib/_libwabt.js","line":13,"offset":135723}}{"seq":541,"type":"request","command":"definitionAndBoundSpan","arguments":{"file":"@PROJECT_ROOT@/src/renderer/lib/_libwabt.js","line":13,"offset":137242}}{"seq":542,"type":"request","command":"references","arguments":{"file":"@PROJECT_ROOT@/src/renderer/lib/_libwabt.js","line":13,"offset":138991}}

Repro Steps

  1. git clone https://github.com/felixrieseberg/windows95 --recurse-submodules
  2. In dirwindows95, rungit reset --hard 17a81393467e2668eb2eea291ab4b6a749756dad
  3. In dirwindows95, runyarn install --ignore-engines --ignore-scripts --silent
  4. Back in the initial folder, downloadRepoResults4/felixrieseberg.windows95.replay.txt from theartifact folder
  5. npm install --no-save @typescript/server-replay
  6. npx tsreplay ./windows95 ./felixrieseberg.windows95.replay.txt path/to/tsserver.js
  7. npx tsreplay --help to learn about helpful switches for debugging, logging, etc

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

@sandersnsandersnsandersn left review comments

@DanielRosenwasserDanielRosenwasserDanielRosenwasser left review comments

@jakebaileyjakebaileyjakebailey approved these changes

@sheetalkamatsheetalkamatsheetalkamat approved these changes

Labels
Author: TeamFor Milestone BugPRs that fix a bug with a specific milestone
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

Presence of underscore prefixed item in sorted import list causes auto-import to place new import at the end
6 participants
@andrewbranch@jakebailey@DanielRosenwasser@typescript-bot@sandersn@sheetalkamat

[8]ページ先頭

©2009-2025 Movatter.jp