eslint-plugin-jsdoc
Version:
JSDoc linting rules for ESLint.
1 lines • 11.4 kB
Source Map (JSON)
{"version":3,"file":"generateRule.cjs","names":["fs","camelCase","existsSync","resolve","open"],"sources":["../src/bin/generateRule.js"],"sourcesContent":["/* eslint-disable no-console -- CLI */\n/**\n * @example\n * ```shell\n * pnpm run create-rule my-new-rule -- --recommended\n * ```\n */\n\nimport camelCase from 'camelcase';\nimport {\n existsSync,\n} from 'node:fs';\nimport fs from 'node:fs/promises';\nimport {\n resolve,\n} from 'node:path';\nimport open from 'open-editor';\n\n// Todo: Would ideally have prompts, e.g., to ask for whether\n// type was problem/layout, etc.\n\nconst [\n , , ruleName,\n ...options\n] = process.argv;\n\nconst recommended = options.includes('--recommended');\n\n(async () => {\n if (!ruleName) {\n console.error('Please supply a rule name');\n\n return;\n }\n\n if ((/[A-Z]/v).test(ruleName)) {\n console.error('Please ensure the rule has no capital letters');\n\n return;\n }\n\n const ruleNamesPath = './test/rules/ruleNames.json';\n const ruleNames = JSON.parse(await fs.readFile(\n // eslint-disable-next-line unicorn/prefer-json-parse-buffer -- TypeScript\n ruleNamesPath, 'utf8',\n ));\n if (!ruleNames.includes(ruleName)) {\n ruleNames.push(ruleName);\n ruleNames.sort();\n }\n\n await fs.writeFile(ruleNamesPath, JSON.stringify(ruleNames, null, 2) + '\\n');\n console.log('ruleNames', ruleNames);\n\n const ruleTemplate = `import iterateJsdoc from '../iterateJsdoc.js';\n\nexport default iterateJsdoc(({\n context,\n utils,\n}) => {\n // Rule here\n}, {\n iterateAllJsdocs: true,\n meta: {\n docs: {\n description: '',\n url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/${ruleName}.md#repos-sticky-header',\n },\n schema: [\n {\n additionalProperties: false,\n properties: {\n // Option properties here (or remove the object)\n },\n type: 'object',\n },\n ],\n type: 'suggestion',\n },\n});\n`;\n\n const camelCasedRuleName = camelCase(ruleName);\n\n const rulePath = `./src/rules/${camelCasedRuleName}.js`;\n\n if (!existsSync(rulePath)) {\n await fs.writeFile(rulePath, ruleTemplate);\n }\n\n const ruleTestTemplate = `export default {\n invalid: [\n {\n code: \\`\n \\`,\n errors: [\n {\n line: 2,\n message: '',\n },\n ],\n },\n ],\n valid: [\n {\n code: \\`\n \\`,\n },\n ],\n};\n`;\n\n const ruleTestPath = `./test/rules/assertions/${camelCasedRuleName}.js`;\n if (!existsSync(ruleTestPath)) {\n await fs.writeFile(ruleTestPath, ruleTestTemplate);\n }\n\n const ruleReadmeTemplate = `# \\`${ruleName}\\`\n\n## Options\n\n{\"gitdown\": \"options\"}\n\n|||\n|---|---|\n|Context|everywhere|\n|Tags|\\`\\`|\n|Recommended|${recommended ? 'true' : 'false'}|\n|Settings||\n|Options||\n\n## Failing examples\n\n<!-- assertions-failing ${camelCasedRuleName} -->\n\n## Passing examples\n\n<!-- assertions-passing ${camelCasedRuleName} -->\n`;\n\n const ruleReadmePath = `./.README/rules/${ruleName}.md`;\n if (!existsSync(ruleReadmePath)) {\n await fs.writeFile(ruleReadmePath, ruleReadmeTemplate);\n }\n\n /**\n * @param {object} cfg\n * @param {string} cfg.path\n * @param {RegExp} cfg.oldRegex\n * @param {string} cfg.checkName\n * @param {string} cfg.newLine\n * @param {boolean} [cfg.oldIsCamel]\n * @returns {Promise<void>}\n */\n const replaceInOrder = async ({\n checkName,\n newLine,\n oldIsCamel,\n oldRegex,\n path,\n }) => {\n /**\n * @typedef {number} Integer\n */\n /**\n * @typedef {{\n * matchedLine: string,\n * offset: Integer,\n * oldRule: string,\n * }} OffsetInfo\n */\n /**\n * @type {OffsetInfo[]}\n */\n const offsets = [];\n\n let readme = await fs.readFile(path, 'utf8');\n readme.replace(\n oldRegex,\n /**\n * @param {string} matchedLine\n * @param {string} n1\n * @param {Integer} offset\n * @param {string} str\n * @param {object} groups\n * @param {string} groups.oldRule\n * @returns {string}\n */\n (matchedLine, n1, offset, str, {\n oldRule,\n }) => {\n offsets.push({\n matchedLine,\n offset,\n oldRule,\n });\n\n return matchedLine;\n },\n );\n\n offsets.sort(({\n oldRule,\n }, {\n oldRule: oldRuleB,\n }) => {\n return oldRule < oldRuleB ? -1 : (oldRule > oldRuleB ? 1 : 0);\n });\n\n let alreadyIncluded = false;\n const itemIndex = offsets.findIndex(({\n oldRule,\n }) => {\n alreadyIncluded ||= oldIsCamel ? camelCasedRuleName === oldRule : ruleName === oldRule;\n\n return oldIsCamel ? camelCasedRuleName < oldRule : ruleName < oldRule;\n });\n let item = itemIndex !== undefined && offsets[itemIndex];\n if (item && itemIndex === 0 &&\n\n // This property would not always be sufficient but in this case it is.\n oldIsCamel\n ) {\n item.offset = 0;\n }\n\n if (!item) {\n item = /** @type {OffsetInfo} */ (offsets.pop());\n item.offset += item.matchedLine.length;\n }\n\n if (alreadyIncluded) {\n console.log(`Rule name is already present in ${checkName}.`);\n } else {\n readme = readme.slice(0, item.offset) +\n (item.offset ? '\\n' : '') +\n newLine +\n (item.offset ? '' : '\\n') +\n readme.slice(item.offset);\n\n await fs.writeFile(path, readme);\n }\n };\n\n // await replaceInOrder({\n // checkName: 'README',\n // newLine: `{\"gitdown\": \"include\", \"file\": \"./rules/${ruleName}.md\"}`,\n // oldRegex: /\\n\\{\"gitdown\": \"include\", \"file\": \".\\/rules\\/(?<oldRule>[^.]*).md\"\\}/gv,\n // path: './.README/README.md',\n // });\n\n await replaceInOrder({\n checkName: 'index import',\n newLine: `import ${camelCasedRuleName} from './rules/${camelCasedRuleName}.js';`,\n oldIsCamel: true,\n oldRegex: /\\nimport (?<oldRule>[^ ]*) from '.\\/rules\\/\\1\\.js';/gv,\n path: './src/index-cjs.js',\n });\n\n await replaceInOrder({\n checkName: 'index recommended',\n newLine: `${' '.repeat(6)}'jsdoc/${ruleName}': ${recommended ? 'warnOrError' : '\\'off\\''},`,\n oldRegex: /\\n\\s{6}'jsdoc\\/(?<oldRule>[^']*)': .*?,/gv,\n path: './src/index-cjs.js',\n });\n\n await replaceInOrder({\n checkName: 'index rules',\n newLine: `${' '.repeat(2)}'${ruleName}': ${camelCasedRuleName},`,\n oldRegex: /\\n\\s{2}'(?<oldRule>[^']*)': [^,]*,/gv,\n path: './src/index-cjs.js',\n });\n\n await import('./buildEntryFileForTS.js');\n\n await import('./generateDocs.js');\n\n /*\n console.log('Paths to open for further editing\\n');\n console.log(`open ${ruleReadmePath}`);\n console.log(`open ${rulePath}`);\n console.log(`open ${ruleTestPath}\\n`);\n */\n\n // Set chdir as somehow still in operation from other test\n process.chdir(resolve(import.meta.dirname, '../../'));\n await open([\n // Could even add editor line column numbers like `${rulePath}:1:1`\n ruleReadmePath,\n ruleTestPath,\n rulePath,\n ]);\n})();\n"],"mappings":"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","ignoreList":[]}