From 87db85434cf077b936076676af9fee061326dc8e Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Thu, 2 May 2024 14:32:44 +0200 Subject: [PATCH] Sort destructured arguments by source position (#128) This is a repeat of #101 which we dropped when rewriting in typescript. This time I added a test. --- sphinx_js/js/convertTopLevel.ts | 14 +++++++++ tests/test_typedoc_analysis/source/types.ts | 8 ++--- .../test_typedoc_analysis.py | 29 +++++++++++-------- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/sphinx_js/js/convertTopLevel.ts b/sphinx_js/js/convertTopLevel.ts index 174fece1..459727c4 100644 --- a/sphinx_js/js/convertTopLevel.ts +++ b/sphinx_js/js/convertTopLevel.ts @@ -684,6 +684,20 @@ export class Converter { } const decl = type.declaration; const children = decl.children!; + // Sort destructured parameter by order in the type declaration in the + // source file. Before we sort they are in alphabetical order by name. Maybe + // we should have a way to pick the desired behavior? There are three + // reasonable orders: + // + // 1. alphabetical by name + // 2. In order of the @options.b annotations + // 3. In order of their declarations in the type + // + // This does order 3 + children.sort( + ({ sources: a }, { sources: b }) => + a![0].line - b![0].line || a![0].character - b![0].character, + ); const result: ParamReflSubset[] = []; for (const child of children) { result.push({ diff --git a/tests/test_typedoc_analysis/source/types.ts b/tests/test_typedoc_analysis/source/types.ts index b4dc304b..bea598a1 100644 --- a/tests/test_typedoc_analysis/source/types.ts +++ b/tests/test_typedoc_analysis/source/types.ts @@ -146,7 +146,7 @@ export function codeInDescription() {} * @param options.b - The 'b' string. * @destructure options */ -export function destructureTest({ a, b }: { a: string; b: { c: string } }) {} +export function destructureTest({ a, b }: { b: { c: string }; a: string }) {} /** * An example with destructured args 2 @@ -158,14 +158,14 @@ export function destructureTest2({ a, b, }: { - /** The 'a' string. */ - a: string; /** The 'b' object. */ b: { c: string }; + /** The 'a' string. */ + a: string; }) {} /** - * An example with destructured args 3 + * An example with no destructured args 3 * * @param options - The options. * @param options.a - The 'a' string. diff --git a/tests/test_typedoc_analysis/test_typedoc_analysis.py b/tests/test_typedoc_analysis/test_typedoc_analysis.py index d9bf1122..eb013f74 100644 --- a/tests/test_typedoc_analysis/test_typedoc_analysis.py +++ b/tests/test_typedoc_analysis/test_typedoc_analysis.py @@ -569,22 +569,27 @@ def test_code_in_description(self): def test_destructured(self): obj = self.analyzer.get_object(["destructureTest"]) - assert obj.params[0].name == "options.a" - assert join_type(obj.params[0].type) == "string" - assert obj.params[0].description == [DescriptionText(text="The 'a' string.")] - assert obj.params[1].name == "options.b" - assert join_type(obj.params[1].type) == "{ c: string; }" - assert obj.params[1].description == [DescriptionText(text="The 'b' string.")] + # Parameters should be sorted by source position in the type annotation not by name. + assert obj.params[0].name == "options.b" + assert join_type(obj.params[0].type) == "{ c: string; }" + assert obj.params[0].description == [DescriptionText(text="The 'b' string.")] + assert obj.params[1].name == "options.a" + assert join_type(obj.params[1].type) == "string" + assert obj.params[1].description == [DescriptionText(text="The 'a' string.")] + obj = self.analyzer.get_object(["destructureTest2"]) - assert obj.params[0].name == "options.a" - assert join_type(obj.params[0].type) == "string" - assert obj.params[0].description == [DescriptionText(text="The 'a' string.")] - assert obj.params[1].name == "options.b" - assert join_type(obj.params[1].type) == "{ c: string; }" - assert obj.params[1].description == [DescriptionText(text="The 'b' object.")] + assert obj.params[0].name == "options.b" + assert join_type(obj.params[0].type) == "{ c: string; }" + assert obj.params[0].description == [DescriptionText(text="The 'b' object.")] + + assert obj.params[1].name == "options.a" + assert join_type(obj.params[1].type) == "string" + assert obj.params[1].description == [DescriptionText(text="The 'a' string.")] + obj = self.analyzer.get_object(["destructureTest3"]) assert obj.params[0].name == "options" assert join_type(obj.params[0].type) == "{ a: string; b: { c: string; }; }" + obj = self.analyzer.get_object(["destructureTest4"]) assert obj.params[0].name == "destructureThisPlease.a" assert join_type(obj.params[0].type) == "string"