123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501 |
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- var _exportParser = _interopRequireDefault(require("../exportParser.js"));
- var _iterateJsdoc = require("../iterateJsdoc.js");
- var _jsdocUtils = _interopRequireDefault(require("../jsdocUtils.js"));
- var _jsdoccomment = require("@es-joy/jsdoccomment");
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- /**
- * @typedef {{
- * ancestorsOnly: boolean,
- * esm: boolean,
- * initModuleExports: boolean,
- * initWindow: boolean
- * }} RequireJsdocOpts
- */
- /** @type {import('json-schema').JSONSchema4} */
- const OPTIONS_SCHEMA = {
- additionalProperties: false,
- properties: {
- checkConstructors: {
- default: true,
- type: 'boolean'
- },
- checkGetters: {
- anyOf: [{
- type: 'boolean'
- }, {
- enum: ['no-setter'],
- type: 'string'
- }],
- default: true
- },
- checkSetters: {
- anyOf: [{
- type: 'boolean'
- }, {
- enum: ['no-getter'],
- type: 'string'
- }],
- default: true
- },
- contexts: {
- items: {
- anyOf: [{
- type: 'string'
- }, {
- additionalProperties: false,
- properties: {
- context: {
- type: 'string'
- },
- inlineCommentBlock: {
- type: 'boolean'
- },
- minLineCount: {
- type: 'integer'
- }
- },
- type: 'object'
- }]
- },
- type: 'array'
- },
- enableFixer: {
- default: true,
- type: 'boolean'
- },
- exemptEmptyConstructors: {
- default: false,
- type: 'boolean'
- },
- exemptEmptyFunctions: {
- default: false,
- type: 'boolean'
- },
- fixerMessage: {
- default: '',
- type: 'string'
- },
- minLineCount: {
- type: 'integer'
- },
- publicOnly: {
- oneOf: [{
- default: false,
- type: 'boolean'
- }, {
- additionalProperties: false,
- default: {},
- properties: {
- ancestorsOnly: {
- type: 'boolean'
- },
- cjs: {
- type: 'boolean'
- },
- esm: {
- type: 'boolean'
- },
- window: {
- type: 'boolean'
- }
- },
- type: 'object'
- }]
- },
- require: {
- additionalProperties: false,
- default: {},
- properties: {
- ArrowFunctionExpression: {
- default: false,
- type: 'boolean'
- },
- ClassDeclaration: {
- default: false,
- type: 'boolean'
- },
- ClassExpression: {
- default: false,
- type: 'boolean'
- },
- FunctionDeclaration: {
- default: true,
- type: 'boolean'
- },
- FunctionExpression: {
- default: false,
- type: 'boolean'
- },
- MethodDefinition: {
- default: false,
- type: 'boolean'
- }
- },
- type: 'object'
- }
- },
- type: 'object'
- };
- /**
- * @param {import('eslint').Rule.RuleContext} context
- * @param {import('json-schema').JSONSchema4Object} baseObject
- * @param {string} option
- * @param {string} key
- * @returns {boolean|undefined}
- */
- const getOption = (context, baseObject, option, key) => {
- if (context.options[0] && option in context.options[0] && (
- // Todo: boolean shouldn't be returning property, but
- // tests currently require
- typeof context.options[0][option] === 'boolean' || key in context.options[0][option])) {
- return context.options[0][option][key];
- }
- return /** @type {{[key: string]: {default?: boolean|undefined}}} */baseObject.properties[key].default;
- };
- /**
- * @param {import('eslint').Rule.RuleContext} context
- * @param {import('../iterateJsdoc.js').Settings} settings
- * @returns {{
- * contexts: (string|{
- * context: string,
- * inlineCommentBlock: boolean,
- * minLineCount: import('../iterateJsdoc.js').Integer
- * })[],
- * enableFixer: boolean,
- * exemptEmptyConstructors: boolean,
- * exemptEmptyFunctions: boolean,
- * fixerMessage: string,
- * minLineCount: undefined|import('../iterateJsdoc.js').Integer,
- * publicOnly: boolean|{[key: string]: boolean|undefined}
- * require: {[key: string]: boolean|undefined}
- * }}
- */
- const getOptions = (context, settings) => {
- const {
- publicOnly,
- contexts = settings.contexts || [],
- exemptEmptyConstructors = true,
- exemptEmptyFunctions = false,
- enableFixer = true,
- fixerMessage = '',
- minLineCount = undefined
- } = context.options[0] || {};
- return {
- contexts,
- enableFixer,
- exemptEmptyConstructors,
- exemptEmptyFunctions,
- fixerMessage,
- minLineCount,
- publicOnly: (baseObj => {
- if (!publicOnly) {
- return false;
- }
- /** @type {{[key: string]: boolean|undefined}} */
- const properties = {};
- for (const prop of Object.keys( /** @type {import('json-schema').JSONSchema4Object} */
- /** @type {import('json-schema').JSONSchema4Object} */baseObj.properties)) {
- const opt = getOption(context, /** @type {import('json-schema').JSONSchema4Object} */baseObj, 'publicOnly', prop);
- properties[prop] = opt;
- }
- return properties;
- })( /** @type {import('json-schema').JSONSchema4Object} */
- ( /** @type {import('json-schema').JSONSchema4Object} */
- ( /** @type {import('json-schema').JSONSchema4Object} */
- OPTIONS_SCHEMA.properties.publicOnly).oneOf)[1]),
- require: (baseObj => {
- /** @type {{[key: string]: boolean|undefined}} */
- const properties = {};
- for (const prop of Object.keys( /** @type {import('json-schema').JSONSchema4Object} */
- /** @type {import('json-schema').JSONSchema4Object} */baseObj.properties)) {
- const opt = getOption(context, /** @type {import('json-schema').JSONSchema4Object} */
- baseObj, 'require', prop);
- properties[prop] = opt;
- }
- return properties;
- })( /** @type {import('json-schema').JSONSchema4Object} */
- OPTIONS_SCHEMA.properties.require)
- };
- };
- /** @type {import('eslint').Rule.RuleModule} */
- var _default = exports.default = {
- create(context) {
- // istanbul ignore next -- Fallback to deprecated method
- const {
- sourceCode = context.getSourceCode()
- } = context;
- const settings = (0, _iterateJsdoc.getSettings)(context);
- if (!settings) {
- return {};
- }
- const opts = getOptions(context, settings);
- const {
- require: requireOption,
- contexts,
- exemptEmptyFunctions,
- exemptEmptyConstructors,
- enableFixer,
- fixerMessage,
- minLineCount
- } = opts;
- const publicOnly =
- /**
- * @type {{
- * [key: string]: boolean | undefined;
- * }}
- */
- opts.publicOnly;
- /**
- * @type {import('../iterateJsdoc.js').CheckJsdoc}
- */
- const checkJsDoc = (info, _handler, node) => {
- if (
- // Optimize
- minLineCount !== undefined || contexts.some(ctxt => {
- if (typeof ctxt === 'string') {
- return false;
- }
- const {
- minLineCount: count
- } = ctxt;
- return count !== undefined;
- })) {
- /**
- * @param {undefined|import('../iterateJsdoc.js').Integer} count
- */
- const underMinLine = count => {
- var _sourceCode$getText$m;
- return count !== undefined && count > (((_sourceCode$getText$m = sourceCode.getText(node).match(/\n/gu)) === null || _sourceCode$getText$m === void 0 ? void 0 : _sourceCode$getText$m.length) ?? 0) + 1;
- };
- if (underMinLine(minLineCount)) {
- return;
- }
- const {
- minLineCount: contextMinLineCount
- } =
- /**
- * @type {{
- * context: string;
- * inlineCommentBlock: boolean;
- * minLineCount: number;
- * }}
- */
- contexts.find(ctxt => {
- if (typeof ctxt === 'string') {
- return false;
- }
- const {
- context: ctx
- } = ctxt;
- return ctx === (info.selector || node.type);
- }) || {};
- if (underMinLine(contextMinLineCount)) {
- return;
- }
- }
- const jsDocNode = (0, _jsdoccomment.getJSDocComment)(sourceCode, node, settings);
- if (jsDocNode) {
- return;
- }
- // For those who have options configured against ANY constructors (or
- // setters or getters) being reported
- if (_jsdocUtils.default.exemptSpeciaMethods({
- description: '',
- inlineTags: [],
- problems: [],
- source: [],
- tags: []
- }, node, context, [OPTIONS_SCHEMA])) {
- return;
- }
- if (
- // Avoid reporting param-less, return-less functions (when
- // `exemptEmptyFunctions` option is set)
- exemptEmptyFunctions && info.isFunctionContext ||
- // Avoid reporting param-less, return-less constructor methods (when
- // `exemptEmptyConstructors` option is set)
- exemptEmptyConstructors && _jsdocUtils.default.isConstructor(node)) {
- const functionParameterNames = _jsdocUtils.default.getFunctionParameterNames(node);
- if (!functionParameterNames.length && !_jsdocUtils.default.hasReturnValue(node)) {
- return;
- }
- }
- const fix = /** @type {import('eslint').Rule.ReportFixer} */fixer => {
- // Default to one line break if the `minLines`/`maxLines` settings allow
- const lines = settings.minLines === 0 && settings.maxLines >= 1 ? 1 : settings.minLines;
- /** @type {import('eslint').Rule.Node|import('@typescript-eslint/types').TSESTree.Decorator} */
- let baseNode = (0, _jsdoccomment.getReducedASTNode)(node, sourceCode);
- const decorator = (0, _jsdoccomment.getDecorator)(baseNode);
- if (decorator) {
- baseNode = decorator;
- }
- const indent = _jsdocUtils.default.getIndent({
- text: sourceCode.getText( /** @type {import('eslint').Rule.Node} */baseNode, /** @type {import('eslint').AST.SourceLocation} */
- ( /** @type {import('eslint').Rule.Node} */baseNode.loc).start.column)
- });
- const {
- inlineCommentBlock
- } =
- /**
- * @type {{
- * context: string,
- * inlineCommentBlock: boolean,
- * minLineCount: import('../iterateJsdoc.js').Integer
- * }}
- */
- contexts.find(contxt => {
- if (typeof contxt === 'string') {
- return false;
- }
- const {
- context: ctxt
- } = contxt;
- return ctxt === node.type;
- }) || {};
- const insertion = (inlineCommentBlock ? `/** ${fixerMessage}` : `/**\n${indent}*${fixerMessage}\n${indent}`) + `*/${'\n'.repeat(lines)}${indent.slice(0, -1)}`;
- return fixer.insertTextBefore( /** @type {import('eslint').Rule.Node} */
- baseNode, insertion);
- };
- const report = () => {
- const {
- start
- } = /** @type {import('eslint').AST.SourceLocation} */node.loc;
- const loc = {
- end: {
- column: 0,
- line: start.line + 1
- },
- start
- };
- context.report({
- fix: enableFixer ? fix : null,
- loc,
- messageId: 'missingJsDoc',
- node
- });
- };
- if (publicOnly) {
- /** @type {RequireJsdocOpts} */
- const opt = {
- ancestorsOnly: Boolean((publicOnly === null || publicOnly === void 0 ? void 0 : publicOnly.ancestorsOnly) ?? false),
- esm: Boolean((publicOnly === null || publicOnly === void 0 ? void 0 : publicOnly.esm) ?? true),
- initModuleExports: Boolean((publicOnly === null || publicOnly === void 0 ? void 0 : publicOnly.cjs) ?? true),
- initWindow: Boolean((publicOnly === null || publicOnly === void 0 ? void 0 : publicOnly.window) ?? false)
- };
- const exported = _exportParser.default.isUncommentedExport(node, sourceCode, opt, settings);
- if (exported) {
- report();
- }
- } else {
- report();
- }
- };
- /**
- * @param {string} prop
- * @returns {boolean}
- */
- const hasOption = prop => {
- return requireOption[prop] || contexts.some(ctxt => {
- return typeof ctxt === 'object' ? ctxt.context === prop : ctxt === prop;
- });
- };
- return {
- ..._jsdocUtils.default.getContextObject(_jsdocUtils.default.enforcedContexts(context, [], settings), checkJsDoc),
- ArrowFunctionExpression(node) {
- if (!hasOption('ArrowFunctionExpression')) {
- return;
- }
- if (['VariableDeclarator', 'AssignmentExpression', 'ExportDefaultDeclaration'].includes(node.parent.type) || ['Property', 'ObjectProperty', 'ClassProperty', 'PropertyDefinition'].includes(node.parent.type) && node ===
- /**
- * @type {import('@typescript-eslint/types').TSESTree.Property|
- * import('@typescript-eslint/types').TSESTree.PropertyDefinition
- * }
- */
- node.parent.value) {
- checkJsDoc({
- isFunctionContext: true
- }, null, node);
- }
- },
- ClassDeclaration(node) {
- if (!hasOption('ClassDeclaration')) {
- return;
- }
- checkJsDoc({
- isFunctionContext: false
- }, null, node);
- },
- ClassExpression(node) {
- if (!hasOption('ClassExpression')) {
- return;
- }
- checkJsDoc({
- isFunctionContext: false
- }, null, node);
- },
- FunctionDeclaration(node) {
- if (!hasOption('FunctionDeclaration')) {
- return;
- }
- checkJsDoc({
- isFunctionContext: true
- }, null, node);
- },
- FunctionExpression(node) {
- if (!hasOption('FunctionExpression')) {
- return;
- }
- if (['VariableDeclarator', 'AssignmentExpression', 'ExportDefaultDeclaration'].includes(node.parent.type) || ['Property', 'ObjectProperty', 'ClassProperty', 'PropertyDefinition'].includes(node.parent.type) && node ===
- /**
- * @type {import('@typescript-eslint/types').TSESTree.Property|
- * import('@typescript-eslint/types').TSESTree.PropertyDefinition
- * }
- */
- node.parent.value) {
- checkJsDoc({
- isFunctionContext: true
- }, null, node);
- }
- },
- MethodDefinition(node) {
- if (!hasOption('MethodDefinition')) {
- return;
- }
- checkJsDoc({
- isFunctionContext: true,
- selector: 'MethodDefinition'
- }, null, /** @type {import('eslint').Rule.Node} */node.value);
- }
- };
- },
- meta: {
- docs: {
- category: 'Stylistic Issues',
- description: 'Require JSDoc comments',
- recommended: true,
- url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-jsdoc.md#repos-sticky-header'
- },
- fixable: 'code',
- messages: {
- missingJsDoc: 'Missing JSDoc comment.'
- },
- schema: [OPTIONS_SCHEMA],
- type: 'suggestion'
- }
- };
- module.exports = exports.default;
- //# sourceMappingURL=requireJsdoc.js.map
|