eslint-doc-generator
Advanced tools
Comparing version 1.0.0 to 1.0.1
@@ -9,2 +9,3 @@ import { Command, Argument, Option } from 'commander'; | ||
import { getCurrentPackageVersion } from './package-json.js'; | ||
import { boolean, isBooleanable } from 'boolean'; | ||
/** | ||
@@ -32,3 +33,3 @@ * Used for collecting repeated CLI options into an array. | ||
function parseBoolean(value) { | ||
return ['true', undefined].includes(value); | ||
return value === undefined || (isBooleanable(value) && boolean(value)); | ||
} | ||
@@ -35,0 +36,0 @@ /** |
@@ -48,2 +48,4 @@ import { SEVERITY_TYPE } from './types.js'; | ||
export const EMOJI_DEPRECATED = '❌'; | ||
// The user is not allowed to specify a reserved emoji to represent their config because we use these emojis for other purposes. | ||
// Note that the default emojis for common configs are intentionally not reserved. | ||
export const RESERVED_EMOJIS = [ | ||
@@ -50,0 +52,0 @@ ...Object.values(EMOJI_CONFIG_FROM_SEVERITY), |
@@ -6,3 +6,3 @@ import { COLUMN_TYPE, NOTICE_TYPE } from './types.js'; | ||
*/ | ||
export declare function parseConfigEmojiOptions(plugin: Plugin, configEmoji?: readonly string[][]): ConfigEmojis; | ||
export declare function parseConfigEmojiOptions(plugin: Plugin, configEmoji?: readonly (readonly string[])[]): ConfigEmojis; | ||
/** | ||
@@ -9,0 +9,0 @@ * Parse the option, check for errors, and set defaults. |
@@ -14,3 +14,18 @@ import { BEGIN_RULE_LIST_MARKER, END_RULE_LIST_MARKER, } from './comment-markers.js'; | ||
import { getLinkToRule } from './rule-link.js'; | ||
import { camelCaseStringToTitle, isCamelCase } from './string.js'; | ||
import { capitalizeOnlyFirstLetter } from './string.js'; | ||
import { noCase } from 'no-case'; | ||
import { getProperty } from 'dot-prop'; | ||
import { boolean, isBooleanable } from 'boolean'; | ||
function isBooleanableTrue(value) { | ||
return isBooleanable(value) && boolean(value); | ||
} | ||
function isBooleanableFalse(value) { | ||
return isBooleanable(value) && !boolean(value); | ||
} | ||
function isConsideredFalse(value) { | ||
return (value === undefined || | ||
value === null || | ||
value === '' || | ||
isBooleanableFalse(value)); | ||
} | ||
function getPropertyFromRule(plugin, ruleName, property) { | ||
@@ -22,13 +37,3 @@ /* istanbul ignore next -- this shouldn't happen */ | ||
const rule = plugin.rules[ruleName]; | ||
// Loop through all the nested property parts. | ||
const parts = property.split('.'); | ||
// @ts-expect-error - Could be non-standard property on a function-style or object-style rule. | ||
let result = rule[parts[0]]; | ||
for (const part of parts.slice(1)) { | ||
if (typeof result !== 'object') { | ||
return undefined; // eslint-disable-line unicorn/no-useless-undefined -- Rule doesn't have this property. | ||
} | ||
result = result[part]; | ||
} | ||
return result; | ||
return getProperty(rule, property); // eslint-disable-line @typescript-eslint/no-explicit-any -- This could be any type, not just undefined (https://github.com/sindresorhus/dot-prop/issues/95). | ||
} | ||
@@ -88,5 +93,3 @@ function getConfigurationColumnValueForRule(rule, configsToRules, pluginPrefix, configEmojis, ignoreConfig, severityType) { | ||
listHeaderRow, | ||
...details.map((rule) => [ | ||
...buildRuleRow(columns, rule, configsToRules, pluginPrefix, pathPlugin, pathRuleDoc, pathRuleList, configEmojis, ignoreConfig, urlRuleDoc), | ||
]), | ||
...details.map((rule) => buildRuleRow(columns, rule, configsToRules, pluginPrefix, pathPlugin, pathRuleDoc, pathRuleList, configEmojis, ignoreConfig, urlRuleDoc)), | ||
], { align: 'l' } // Left-align headers. | ||
@@ -100,14 +103,4 @@ ); | ||
const values = new Set(details.map((detail) => getPropertyFromRule(plugin, detail.name, ruleListSplit))); | ||
// Common values for boolean properties. | ||
const ENABLED_VALUES = new Set([true, 'true', 'on', 'yes']); | ||
const DISABLED_VALUES = new Set([ | ||
undefined, | ||
null, | ||
false, | ||
'', | ||
'false', | ||
'no', | ||
'off', | ||
]); | ||
if (values.size === 1 && DISABLED_VALUES.has([...values.values()][0])) { | ||
const valuesAll = [...values.values()]; | ||
if (values.size === 1 && isConsideredFalse(valuesAll[0])) { | ||
throw new Error(`No rules found with --rule-list-split property "${ruleListSplit}".`); | ||
@@ -117,20 +110,26 @@ } | ||
// Show any rules that don't have a value for this rule-list-split property first, or for which the boolean property is off. | ||
if ([...DISABLED_VALUES.values()].some((val) => values.has(val))) { | ||
const rulesForThisValue = details.filter((detail) => DISABLED_VALUES.has(getPropertyFromRule(plugin, detail.name, ruleListSplit))); | ||
if (valuesAll.some((val) => isConsideredFalse(val))) { | ||
const rulesForThisValue = details.filter((detail) => isConsideredFalse(getPropertyFromRule(plugin, detail.name, ruleListSplit))); | ||
parts.push(generateRulesListMarkdown(columns, rulesForThisValue, configsToRules, pluginPrefix, pathPlugin, pathRuleDoc, pathRuleList, configEmojis, ignoreConfig, urlRuleDoc)); | ||
} | ||
// For each possible non-disabled value, show a header and list of corresponding rules. | ||
for (const value of [...values.values()] | ||
.filter((value) => !DISABLED_VALUES.has(value)) | ||
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))) { | ||
const rulesForThisValue = details.filter((detail) => getPropertyFromRule(plugin, detail.name, ruleListSplit) === value); | ||
const valuesNotFalseAndNotTrue = valuesAll.filter((val) => !isConsideredFalse(val) && !isBooleanableTrue(val)); | ||
const valuesTrue = valuesAll.filter((val) => isBooleanableTrue(val)); | ||
const valuesNew = [ | ||
...valuesNotFalseAndNotTrue, | ||
...(valuesTrue.length > 0 ? [true] : []), // If there are multiple true values, combine them all into one. | ||
]; | ||
for (const value of valuesNew.sort((a, b) => String(a).toLowerCase().localeCompare(String(b).toLowerCase()))) { | ||
const rulesForThisValue = details.filter((detail) => { | ||
const property = getPropertyFromRule(plugin, detail.name, ruleListSplit); | ||
return (property === value || (value === true && isBooleanableTrue(property))); | ||
}); | ||
// Turn ruleListSplit into a title. | ||
// E.g. meta.docs.requiresTypeChecking to "Requires Type Checking". | ||
// TODO: handle other types of variable casing. | ||
const ruleListSplitParts = ruleListSplit.split('.'); | ||
const ruleListSplitFinalPart = ruleListSplitParts[ruleListSplitParts.length - 1]; | ||
const ruleListSplitTitle = isCamelCase(ruleListSplitFinalPart) | ||
? camelCaseStringToTitle(ruleListSplitParts[ruleListSplitParts.length - 1]) | ||
: ruleListSplitFinalPart; | ||
parts.push(`${'#'.repeat(headerLevel)} ${ENABLED_VALUES.has(value) ? ruleListSplitTitle : value}`, generateRulesListMarkdown(columns, rulesForThisValue, configsToRules, pluginPrefix, pathPlugin, pathRuleDoc, pathRuleList, configEmojis, ignoreConfig, urlRuleDoc)); | ||
const ruleListSplitTitle = noCase(ruleListSplitFinalPart, { | ||
transform: (str) => capitalizeOnlyFirstLetter(str), | ||
}); | ||
parts.push(`${'#'.repeat(headerLevel)} ${isBooleanableTrue(value) ? ruleListSplitTitle : value}`, generateRulesListMarkdown(columns, rulesForThisValue, configsToRules, pluginPrefix, pathPlugin, pathRuleDoc, pathRuleList, configEmojis, ignoreConfig, urlRuleDoc)); | ||
} | ||
@@ -137,0 +136,0 @@ return parts.join('\n\n'); |
@@ -5,5 +5,4 @@ export declare function countOccurrencesInString(str: string, substring: string): number; | ||
/** | ||
* Example: theWeatherIsNice => The Weather Is Nice | ||
* Example: FOO => Foo, foo => Foo | ||
*/ | ||
export declare function camelCaseStringToTitle(str: string): string; | ||
export declare function isCamelCase(str: string): boolean; | ||
export declare function capitalizeOnlyFirstLetter(str: string): string; |
@@ -1,2 +0,1 @@ | ||
import camelCase from 'camelcase'; | ||
export function countOccurrencesInString(str, substring) { | ||
@@ -14,10 +13,6 @@ return str.split(substring).length - 1; | ||
/** | ||
* Example: theWeatherIsNice => The Weather Is Nice | ||
* Example: FOO => Foo, foo => Foo | ||
*/ | ||
export function camelCaseStringToTitle(str) { | ||
const text = str.replace(/([A-Z])/gu, ' $1'); | ||
return text.charAt(0).toUpperCase() + text.slice(1); | ||
export function capitalizeOnlyFirstLetter(str) { | ||
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); | ||
} | ||
export function isCamelCase(str) { | ||
return camelCase(str) === str; | ||
} |
@@ -67,2 +67,5 @@ import type { RuleDocTitleFormat } from './rule-doc-title-format.js'; | ||
} | ||
/** | ||
* CLI/config file options. | ||
*/ | ||
export declare enum OPTION_TYPE { | ||
@@ -97,3 +100,3 @@ CHECK = "check", | ||
*/ | ||
readonly configEmoji?: readonly string[][]; | ||
readonly configEmoji?: readonly (readonly string[])[]; | ||
/** Configs to ignore from being displayed. Often used for an `all` config. */ | ||
@@ -112,2 +115,3 @@ readonly ignoreConfig?: readonly string[]; | ||
* Useful for applying custom transformations such as formatting with tools like prettier. | ||
* Only available via a JavaScript config file. | ||
*/ | ||
@@ -114,0 +118,0 @@ readonly postprocess?: (content: string, pathToFile: string) => string | Promise<string>; |
@@ -48,2 +48,5 @@ // Custom types. | ||
})(COLUMN_TYPE || (COLUMN_TYPE = {})); | ||
/** | ||
* CLI/config file options. | ||
*/ | ||
export var OPTION_TYPE; | ||
@@ -50,0 +53,0 @@ (function (OPTION_TYPE) { |
{ | ||
"name": "eslint-doc-generator", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"description": "Automatic documentation generator for ESLint plugins and rules.", | ||
@@ -50,8 +50,10 @@ "keywords": [ | ||
"ajv": "^8.11.2", | ||
"camelcase": "^7.0.0", | ||
"boolean": "^3.2.0", | ||
"commander": "^9.4.0", | ||
"cosmiconfig": "^8.0.0", | ||
"deepmerge": "^4.2.2", | ||
"dot-prop": "^7.2.0", | ||
"jest-diff": "^29.2.1", | ||
"markdown-table": "^3.0.2", | ||
"markdown-table": "^3.0.3", | ||
"no-case": "^3.0.4", | ||
"type-fest": "^3.0.0" | ||
@@ -79,3 +81,3 @@ }, | ||
"release-it-lerna-changelog": "^5.0.0", | ||
"sinon": "^14.0.0", | ||
"sinon": "^15.0.0", | ||
"sort-package-json": "^2.0.0", | ||
@@ -82,0 +84,0 @@ "ts-jest": "^29.0.3", |
@@ -216,2 +216,17 @@ # eslint-doc-generator | ||
## Semantic versioning policy | ||
This tool follows [semantic versioning](https://semver.org/). | ||
New features will be released as a minor version, while bug fixes will be released as a patch version. | ||
Breaking changes will be released as a major version and include: | ||
- Changing an option default | ||
- Renaming or removing an option | ||
- Other backwards-incompatible changes to the CLI / API | ||
- Raising Node or ESLint version requirements | ||
Tweaks to the generated documentation output can take place in any type of release including minor and patch versions. This can break your build, as even a small formatting change will cause a diff, but you can simply re-run the tool to fix. | ||
## Related | ||
@@ -218,0 +233,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
115205
2039
238
12
+ Addedboolean@^3.2.0
+ Addeddot-prop@^7.2.0
+ Addedno-case@^3.0.4
+ Addedboolean@3.2.0(transitive)
+ Addeddot-prop@7.2.0(transitive)
+ Addedlower-case@2.0.2(transitive)
+ Addedno-case@3.0.4(transitive)
+ Addedtslib@2.8.1(transitive)
+ Addedtype-fest@2.19.0(transitive)
- Removedcamelcase@^7.0.0
- Removedcamelcase@7.0.1(transitive)
Updatedmarkdown-table@^3.0.3