Skip to content

Commit 7b3a194

Browse files
authored
chore(repo): Add eslint-plugin-jsdoc (#5697)
1 parent 136a2a1 commit 7b3a194

File tree

7 files changed

+155
-23
lines changed

7 files changed

+155
-23
lines changed

.changeset/tasty-parrots-teach.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

.typedoc/__tests__/__snapshots__/file-structure.test.ts.snap

+6
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ exports[`Typedoc output > should have a deliberate file structure 1`] = `
6767
"types/user-organization-invitation-resource.mdx",
6868
"types/user-resource.mdx",
6969
"types/without.mdx",
70+
"shared/api-url-from-publishable-key.mdx",
7071
"shared/build-clerk-js-script-attributes.mdx",
72+
"shared/camel-to-snake.mdx",
7173
"shared/clerk-js-script-url.mdx",
7274
"shared/clerk-runtime-error.mdx",
7375
"shared/create-path-matcher.mdx",
@@ -79,11 +81,13 @@ exports[`Typedoc output > should have a deliberate file structure 1`] = `
7981
"shared/fast-deep-merge-and-replace.mdx",
8082
"shared/get-clerk-js-major-version-or-tag.mdx",
8183
"shared/get-env-variable.mdx",
84+
"shared/get-non-undefined-values.mdx",
8285
"shared/get-script-url.mdx",
8386
"shared/icon-image-url.mdx",
8487
"shared/in-browser.mdx",
8588
"shared/is-browser-online.mdx",
8689
"shared/is-clerk-runtime-error.mdx",
90+
"shared/is-ipv4-address.mdx",
8791
"shared/is-publishable-key.mdx",
8892
"shared/is-staging.mdx",
8993
"shared/is-truthy.mdx",
@@ -96,6 +100,8 @@ exports[`Typedoc output > should have a deliberate file structure 1`] = `
96100
"shared/paginated-resources.mdx",
97101
"shared/read-json-file.mdx",
98102
"shared/set-clerk-js-loading-error-package-name.mdx",
103+
"shared/snake-to-camel.mdx",
104+
"shared/titleize.mdx",
99105
"shared/to-sentence.mdx",
100106
"shared/use-clerk.mdx",
101107
"shared/use-organization-list-params.mdx",

eslint.config.mjs

+26-14
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import pluginSimpleImportSort from 'eslint-plugin-simple-import-sort';
1111
import pluginTurbo from 'eslint-plugin-turbo';
1212
import pluginUnusedImports from 'eslint-plugin-unused-imports';
1313
import pluginYml from 'eslint-plugin-yml';
14+
import pluginJsDoc from 'eslint-plugin-jsdoc';
1415
import globals from 'globals';
1516
import tseslint from 'typescript-eslint';
1617

@@ -419,21 +420,32 @@ export default tseslint.config([
419420
'turbo/no-undeclared-env-vars': 'off',
420421
},
421422
},
422-
...pluginYml.configs['flat/recommended'],
423423
{
424-
name: 'repo/.github',
425-
// rules: {
426-
// 'regex/invalid': [
427-
// 'error',
428-
// [
429-
// {
430-
// regex: '^(?!.*\\$TURBO_ARGS( |$)).*turbo \\S+',
431-
// message: 'Invalid turbo CI command. Must contain `$TURBO_ARGS`',
432-
// },
433-
// ],
434-
// ],
435-
// },
424+
name: 'repo/jsdoc',
425+
...pluginJsDoc.configs['flat/recommended-typescript'],
426+
files: ['packages/shared/src/**/*.{ts,tsx}'],
427+
ignores: ['**/__tests__/**'],
428+
plugins: {
429+
jsdoc: pluginJsDoc,
430+
},
431+
rules: {
432+
...pluginJsDoc.configs['flat/recommended-typescript'].rules,
433+
'jsdoc/check-examples': 'off',
434+
'jsdoc/informative-docs': 'warn',
435+
'jsdoc/check-tag-names': ['warn', { definedTags: ['inline', 'unionReturnHeadings'], typed: false }],
436+
'jsdoc/require-hyphen-before-param-description': 'warn',
437+
'jsdoc/require-description': 'warn',
438+
'jsdoc/require-description-complete-sentence': 'warn',
439+
'jsdoc/require-param': ['warn', { ignoreWhenAllParamsMissing: true }],
440+
'jsdoc/require-param-description': 'warn',
441+
'jsdoc/require-returns': 'off',
442+
'jsdoc/tag-lines': [
443+
'warn',
444+
'always',
445+
{ count: 1, applyToEndTag: false, startLines: 1, tags: { param: { lines: 'never' } } },
446+
],
447+
},
436448
},
437-
449+
...pluginYml.configs['flat/recommended'],
438450
configPrettier,
439451
]);

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
"eslint-import-resolver-typescript": "3.10.0",
9595
"eslint-plugin-import": "2.31.0",
9696
"eslint-plugin-jest": "28.11.0",
97+
"eslint-plugin-jsdoc": "50.6.9",
9798
"eslint-plugin-jsx-a11y": "6.10.2",
9899
"eslint-plugin-playwright": "2.2.0",
99100
"eslint-plugin-react": "7.37.5",

packages/shared/src/apiUrlFromPublishableKey.ts

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ import {
88
} from './constants';
99
import { parsePublishableKey } from './keys';
1010

11+
/**
12+
* Get the correct API url based on the publishable key.
13+
*
14+
* @param publishableKey - The publishable key to parse.
15+
* @returns One of Clerk's API URLs.
16+
*/
1117
export const apiUrlFromPublishableKey = (publishableKey: string) => {
1218
const frontendApi = parsePublishableKey(publishableKey)?.frontendApi;
1319

packages/shared/src/underscore.ts

+34-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/**
2-
* Converts an array of strings to a comma-separated sentence
3-
* @param items {Array<string>}
4-
* @returns {string} Returns a string with the items joined by a comma and the last item joined by ", or"
2+
* Convert words to a sentence.
3+
*
4+
* @param items - An array of words to be joined.
5+
* @returns A string with the items joined by a comma and the last item joined by ", or".
56
*/
67
export const toSentence = (items: string[]): string => {
78
// TODO: Once Safari supports it, use Intl.ListFormat
@@ -19,19 +20,41 @@ export const toSentence = (items: string[]): string => {
1920
const IP_V4_ADDRESS_REGEX =
2021
/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
2122

23+
/**
24+
* Checks if a string is a valid IPv4 address.
25+
*
26+
* @returns True if the string is a valid IPv4 address, false otherwise.
27+
*/
2228
export function isIPV4Address(str: string | undefined | null): boolean {
2329
return IP_V4_ADDRESS_REGEX.test(str || '');
2430
}
2531

32+
/**
33+
* Converts the first character of a string to uppercase.
34+
*
35+
* @param str - The string to be converted.
36+
* @returns The modified string with the rest of the string unchanged.
37+
*
38+
* @example
39+
* ```ts
40+
* titleize('hello world') // 'Hello world'
41+
* ```
42+
*/
2643
export function titleize(str: string | undefined | null): string {
2744
const s = str || '';
2845
return s.charAt(0).toUpperCase() + s.slice(1);
2946
}
3047

48+
/**
49+
* Converts a string from snake_case to camelCase.
50+
*/
3151
export function snakeToCamel(str: string | undefined): string {
3252
return str ? str.replace(/([-_][a-z])/g, match => match.toUpperCase().replace(/-|_/, '')) : '';
3353
}
3454

55+
/**
56+
* Converts a string from camelCase to snake_case.
57+
*/
3558
export function camelToSnake(str: string | undefined): string {
3659
return str ? str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`) : '';
3760
}
@@ -73,6 +96,7 @@ const createDeepObjectTransformer = (transform: any) => {
7396
* Transforms camelCased objects/ arrays to snake_cased.
7497
* This function recursively traverses all objects and arrays of the passed value
7598
* camelCased keys are removed.
99+
*
76100
* @function
77101
*/
78102
export const deepCamelToSnake = createDeepObjectTransformer(camelToSnake);
@@ -81,13 +105,15 @@ export const deepCamelToSnake = createDeepObjectTransformer(camelToSnake);
81105
* Transforms snake_cased objects/ arrays to camelCased.
82106
* This function recursively traverses all objects and arrays of the passed value
83107
* camelCased keys are removed.
108+
*
84109
* @function
85110
*/
86111
export const deepSnakeToCamel = createDeepObjectTransformer(snakeToCamel);
87112

88113
/**
89-
* Returns true for `true`, true, positive numbers.
90-
* Returns false for `false`, false, 0, negative integers and anything else.
114+
* A function to determine if a value is truthy.
115+
*
116+
* @returns True for `true`, true, positive numbers. False for `false`, false, 0, negative integers and anything else.
91117
*/
92118
export function isTruthy(value: unknown): boolean {
93119
// Return if Boolean
@@ -125,6 +151,9 @@ export function isTruthy(value: unknown): boolean {
125151
return false;
126152
}
127153

154+
/**
155+
* Get all non-undefined values from an object.
156+
*/
128157
export function getNonUndefinedValues<T extends object>(obj: T): Partial<T> {
129158
return Object.entries(obj).reduce((acc, [key, value]) => {
130159
if (value !== undefined) {

0 commit comments

Comments
 (0)