Skip to content

Commit

Permalink
feat: add jsdocTagsOrder
Browse files Browse the repository at this point in the history
issue: #161
  • Loading branch information
hosseinmd committed Dec 22, 2023
1 parent 18dff67 commit 9f637aa
Show file tree
Hide file tree
Showing 10 changed files with 343 additions and 53 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ Description is formatting as Markdown, so you could use any features of Markdown
| tsdoc | Boolean | false |
| jsdocPrintWidth | Number | undefined | If You don't set value to jsdocPrintWidth, the printWidth will be use as jsdocPrintWidth. |
| jsdocLineWrappingStyle | String | "greedy" | "greedy": Lines wrap as soon as they reach the print width |
| jsdocTagsOrder | String (object) | "undefined" | [Custom Tags Order](doc/CUSTOM_TAGS_ORDER.md) |

Full up to date list and description of options can be found in Prettier help. First install plugin then run Prettier with "--help" option.

Expand Down
73 changes: 73 additions & 0 deletions doc/CUSTOM_TAGS_ORDER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# jsdocTagsOrder

Use this param for customizing tags order. To change tags order, Change the weight of them, for example the `default` tag has 22 weight for put that below of `returns` (42) we could change weight of it to 42.1

```json
{
"jsdocTagsOrder": "{\"default\":42.1}"
}
```

jsdocTagsOrder accepting json string

### plugin builtin order

```
remarks: 1,
privateRemarks: 2,
providesModule: 3,
module: 4,
license: 5,
flow: 6,
async: 7,
private: 8,
ignore: 9,
memberof: 10,
version: 11,
file: 12,
author: 13,
deprecated: 14,
since: 15,
category: 16,
description: 17,
example: 18,
abstract: 19,
augments: 20,
constant: 21,
default: 22,
defaultValue: 23,
external: 24,
overload: 25,
fires: 26,
template: 27,
typeParam: 28,
function: 29,
namespace: 30,
borrows: 31,
class: 32,
extends: 33,
member: 34,
typedef: 35,
type: 36,
satisfies: 37,
property: 38,
callback: 39,
param: 40,
yields: 41,
returns: 42,
throws: 43,
other: 44, // any other tags which is not listed here
see: 45,
todo: 46,
```

### example

```json
{
"jsdocTagsOrder": "{\"param\":28.1, \"return\":28.2, \"example\":70}"
}
```
12 changes: 12 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,13 @@ const options = {
default: "greedy",
description: `Strategy for wrapping lines for the given print width. More options may be added in the future.`,
},
jsdocTagsOrder: {
name: "jsdocTagsOrder",
type: "string",
category: "jsdoc",
default: undefined,
description: "How many spaces will be used to separate tag elements.",
},
} as const satisfies Record<keyof JsdocOptions, SupportOption>;

const defaultOptions: JsdocOptions = {
Expand All @@ -158,6 +165,7 @@ const defaultOptions: JsdocOptions = {
jsdocPreferCodeFences: options.jsdocPreferCodeFences.default,
tsdoc: options.tsdoc.default,
jsdocLineWrappingStyle: options.jsdocLineWrappingStyle.default,
jsdocTagsOrder: options.jsdocTagsOrder.default,
};

const parsers = {
Expand Down Expand Up @@ -232,6 +240,10 @@ export { options, parsers, defaultOptions };
export type Options = Partial<JsdocOptions>;

function normalizeOptions(options: prettier.ParserOptions & JsdocOptions) {
if (options.jsdocTagsOrder) {
options.jsdocTagsOrder = JSON.parse(options.jsdocTagsOrder as any);
}

if (options.jsdocCommentLineStrategy) {
return;
}
Expand Down
19 changes: 14 additions & 5 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,15 @@ function getTagOrderWeight(tag: string, options: AllOptions): number {
if (tag === DESCRIPTION && !options.jsdocDescriptionTag) {
return -1;
}
const index = TAGS_ORDER.indexOf(tag);
return index === -1 ? TAGS_ORDER.indexOf("other") : index;
let index;

if (options.jsdocTagsOrder?.[tag] !== undefined) {
index = options.jsdocTagsOrder[tag];
} else {
index = TAGS_ORDER[tag as keyof typeof TAGS_ORDER];
}

return index === undefined ? TAGS_ORDER.other : index;
}

function isBlockComment(comment: PrettierComment): boolean {
Expand Down Expand Up @@ -352,7 +359,7 @@ function getIndentationWidth(
return options.printWidth - (spaces + tabs * options.tabWidth) - " * ".length;
}

const TAGS_ORDER_LOWER = TAGS_ORDER.map((tagOrder) => tagOrder.toLowerCase());
const TAGS_ORDER_ENTRIES = Object.entries(TAGS_ORDER);
/**
* This will adjust the casing of tag titles, resolve synonyms, fix
* incorrectly parsed tags, correct incorrectly assigned names and types, and
Expand All @@ -378,9 +385,11 @@ function normalizeTags(parsed: Block): void {

tag = tag.trim();
const lower = tag.toLowerCase();
const tagIndex = TAGS_ORDER_LOWER.indexOf(lower);
const tagIndex = TAGS_ORDER_ENTRIES.findIndex(
([key]) => key.toLowerCase() === lower,
);
if (tagIndex >= 0) {
tag = TAGS_ORDER[tagIndex];
tag = TAGS_ORDER_ENTRIES[tagIndex][0];
} else if (lower in TAGS_SYNONYMS) {
// resolve synonyms
tag = TAGS_SYNONYMS[lower as keyof typeof TAGS_SYNONYMS];
Expand Down
95 changes: 48 additions & 47 deletions src/roles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,53 +173,54 @@ const TAGS_GROUP_CONDITION = [
THROWS,
];

const TAGS_ORDER = [
REMARKS,
PRIVATE_REMARKS,
PROVIDES_MODULE,
MODULE,
LICENSE,
FLOW,
ASYNC,
PRIVATE,
IGNORE,
MEMBEROF,
VERSION,
FILE,
AUTHOR,
DEPRECATED,
SINCE,
CATEGORY,
DESCRIPTION,
EXAMPLE,
ABSTRACT,
AUGMENTS,
CONSTANT,
...TAGS_DEFAULT,
EXTERNAL,
OVERLOAD,
FIRES,
TEMPLATE,
TYPE_PARAM,
FUNCTION,
NAMESPACE,
BORROWS,
CLASS,
EXTENDS,
MEMBER,
TYPEDEF,
TYPE,
SATISFIES,
PROPERTY,
CALLBACK,
PARAM,
YIELDS,
RETURNS,
THROWS,
"other",
SEE,
TODO,
];
const TAGS_ORDER = {
[REMARKS]: 1,
[PRIVATE_REMARKS]: 2,
[PROVIDES_MODULE]: 3,
[MODULE]: 4,
[LICENSE]: 5,
[FLOW]: 6,
[ASYNC]: 7,
[PRIVATE]: 8,
[IGNORE]: 9,
[MEMBEROF]: 10,
[VERSION]: 11,
[FILE]: 12,
[AUTHOR]: 13,
[DEPRECATED]: 14,
[SINCE]: 15,
[CATEGORY]: 16,
[DESCRIPTION]: 17,
[EXAMPLE]: 18,
[ABSTRACT]: 19,
[AUGMENTS]: 20,
[CONSTANT]: 21,
[DEFAULT]: 22,
[DEFAULT_VALUE]: 23,
[EXTERNAL]: 24,
[OVERLOAD]: 25,
[FIRES]: 26,
[TEMPLATE]: 27,
[TYPE_PARAM]: 28,
[FUNCTION]: 29,
[NAMESPACE]: 30,
[BORROWS]: 31,
[CLASS]: 32,
[EXTENDS]: 33,
[MEMBER]: 34,
[TYPEDEF]: 35,
[TYPE]: 36,
[SATISFIES]: 37,
[PROPERTY]: 38,
[CALLBACK]: 39,
[PARAM]: 40,
[YIELDS]: 41,
[RETURNS]: 42,
[THROWS]: 43,
other: 44,
[SEE]: 45,
[TODO]: 46,
};

export {
TAGS_PEV_FORMATE_DESCRIPTION,
Expand Down
2 changes: 1 addition & 1 deletion src/stringify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ const stringify = async (
if (useTagTitle) tagString += gap + " ".repeat(descGapAdj);
if (
TAGS_PEV_FORMATE_DESCRIPTION.includes(tag) ||
!TAGS_ORDER.includes(tag)
!TAGS_ORDER[tag as keyof typeof TAGS_ORDER]
) {
// Avoid wrapping
descriptionString = description;
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface JsdocOptions {
jsdocPreferCodeFences: boolean;
tsdoc: boolean;
jsdocLineWrappingStyle: "greedy";
jsdocTagsOrder?: Record<string, number>;
}

export interface AllOptions extends ParserOptions, JsdocOptions {}
Expand Down
98 changes: 98 additions & 0 deletions tests/__snapshots__/files/order-custom.jsx.shot
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`File: order-custom.jsx 1`] = `
"/**
* @property {string} language
* @property {string} type
* @property {string} content
* @param {string} className
* @param {string} language
* @param {ClassAdderEnvironment} env
* @example
* let foo = \\"foo\\"
*
* @see http://github.com/hosseinmd/prettier-plugin-jsdoc
* @returns {undefined | string | string[]}
*/

/**
* Returns an object which provides methods to get the ids of the components
* which have to be loaded (\`getIds\`) and a way to efficiently load them in
* synchronously and asynchronous contexts (\`load\`).
*
* The set of ids to be loaded is a superset of \`load\`. If some of these ids
* are in \`loaded\`, the corresponding components will have to reloaded.
*
* The ids in \`load\` and \`loaded\` may be in any order and can contain
* duplicates.
*
* @param {Components} components
* @param {string[]} load
* @param {string[]} [loaded=[]] A list of already loaded components.
*
* If a component is in this list, then all of its requirements will also be
* assumed to be in the list. Default is \`[]\`
* @returns {Loader}
*
* @typedef Loader
* @property {() => string[]} getIds A function to get all ids of the
* components to load.
*
* The returned ids will be duplicate-free, alias-free and in load order.
* @property {LoadFunction} load A functional interface to load components.
*
* @typedef {<T>(
* loadComponent: (id: string) => T,
* chainer?: LoadChainer<T>,
* ) => T} LoadFunction
* A functional interface to load components.
*
* The \`loadComponent\` function will be called for every component in the
* order in which they have to be loaded.
*
* The \`chainer\` is useful for asynchronous loading and its \`series\` and
* \`parallel\` functions can be thought of as \`Promise#then\` and
* \`Promise.all\`.
* @example
* load(id => { loadComponent(id); }); // returns undefined
*
* await load(
* id => loadComponentAsync(id), // returns a Promise for each id
* {
* series: async (before, after) => {
* await before;
* await after();
* },
* parallel: async (values) => {
* await Promise.all(values);
* }
* }
* );
*/

/**
* Function example description that was wrapped by hand so it have more then
* one line and don't end with a dot REPEATED TWO TIMES BECAUSE IT WAS EASIER to
* copy function example description that was wrapped by hand so it have more
* then one line.
*
* @async
* @private
* @memberof test
* @param {String | Number} text - Some text description that is very long and
* needs to be wrapped
* @param {String} [defaultValue=\\"defaultTest\\"] TODO. Default is \`\\"defaultTest\\"\`
* @param {Number | Null} [optionalNumber]
* @example
* var one = 5
* var two = 10
*
* if(one > 2) { two += one }
*
* @undefiendTag\${\\" \\"}
* @undefiendTag {number} name des
* @returns {Boolean} Description for @returns with s
*/
const testFunction = (text, defaultValue, optionalNumber) => true;
"
`;
9 changes: 9 additions & 0 deletions tests/files.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ const files: {
tsdoc: true,
},
},
{
name: "order-custom.jsx",
options: {
jsdocTagsOrder: '{"example":43, "typedef":0, "returns": 46}' as any,
// {
// example: 70,
// } as any,
},
},
];

for (let i = 0; i < files.length; i++) {
Expand Down

0 comments on commit 9f637aa

Please sign in to comment.