PHP WebShell
Текущая директория: /opt/BitGoJS/node_modules/eslint-plugin-jsdoc/dist
Просмотр файла: jsdocUtils.js
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _lodash = _interopRequireDefault(require("lodash"));
var _WarnSettings = _interopRequireDefault(require("./WarnSettings"));
var _getDefaultTagStructureForMode = _interopRequireDefault(require("./getDefaultTagStructureForMode"));
var _tagNames = require("./tagNames");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
let tagStructure;
const setTagStructure = mode => {
tagStructure = (0, _getDefaultTagStructureForMode.default)(mode);
}; // Given a nested array of property names, reduce them to a single array,
// appending the name of the root element along the way if present.
const flattenRoots = (params, root = '') => {
let hasRestElement = false;
let hasPropertyRest = false;
const rests = [];
const names = params.reduce((acc, cur) => {
if (Array.isArray(cur)) {
let nms;
if (Array.isArray(cur[1])) {
nms = cur[1];
} else {
if (cur[1].hasRestElement) {
hasRestElement = true;
}
if (cur[1].hasPropertyRest) {
hasPropertyRest = true;
}
nms = cur[1].names;
}
const flattened = flattenRoots(nms, root ? `${root}.${cur[0]}` : cur[0]);
if (flattened.hasRestElement) {
hasRestElement = true;
}
if (flattened.hasPropertyRest) {
hasPropertyRest = true;
}
const inner = [root ? `${root}.${cur[0]}` : cur[0], ...flattened.names].filter(Boolean);
rests.push(false, ...flattened.rests);
return acc.concat(inner);
}
if (typeof cur === 'object') {
if (cur.isRestProperty) {
hasPropertyRest = true;
rests.push(true);
} else {
rests.push(false);
}
if (cur.restElement) {
hasRestElement = true;
}
acc.push(root ? `${root}.${cur.name}` : cur.name);
} else if (typeof cur !== 'undefined') {
rests.push(false);
acc.push(root ? `${root}.${cur}` : cur);
}
return acc;
}, []);
return {
hasPropertyRest,
hasRestElement,
names,
rests
};
};
const getPropertiesFromPropertySignature = propSignature => {
if (propSignature.type === 'TSIndexSignature' || propSignature.type === 'TSConstructSignatureDeclaration' || propSignature.type === 'TSCallSignatureDeclaration') {
return undefined;
}
if (propSignature.typeAnnotation && propSignature.typeAnnotation.typeAnnotation.type === 'TSTypeLiteral') {
return [propSignature.key.name, propSignature.typeAnnotation.typeAnnotation.members.map(member => {
return getPropertiesFromPropertySignature(member);
})];
}
return propSignature.key.name;
};
const getFunctionParameterNames = (functionNode, checkDefaultObjects) => {
// eslint-disable-next-line complexity
const getParamName = (param, isProperty) => {
var _param$left, _param$left3;
if (_lodash.default.has(param, 'typeAnnotation') || _lodash.default.has(param, 'left.typeAnnotation')) {
const typeAnnotation = _lodash.default.has(param, 'left.typeAnnotation') ? param.left.typeAnnotation : param.typeAnnotation;
if (typeAnnotation.typeAnnotation.type === 'TSTypeLiteral') {
const propertyNames = typeAnnotation.typeAnnotation.members.map(member => {
return getPropertiesFromPropertySignature(member);
});
const flattened = { ...flattenRoots(propertyNames),
annotationParamName: param.name
};
if (_lodash.default.has(param, 'name') || _lodash.default.has(param, 'left.name')) {
return [_lodash.default.has(param, 'left.name') ? param.left.name : param.name, flattened];
}
return [undefined, flattened];
}
}
if (_lodash.default.has(param, 'name')) {
return param.name;
}
if (_lodash.default.has(param, 'left.name')) {
return param.left.name;
}
if (param.type === 'ObjectPattern' || ((_param$left = param.left) === null || _param$left === void 0 ? void 0 : _param$left.type) === 'ObjectPattern') {
var _param$left2;
const properties = param.properties || ((_param$left2 = param.left) === null || _param$left2 === void 0 ? void 0 : _param$left2.properties);
const roots = properties.map(prop => {
return getParamName(prop, true);
});
return [undefined, flattenRoots(roots)];
}
if (param.type === 'Property') {
switch (param.value.type) {
case 'ArrayPattern':
return [param.key.name, param.value.elements.map((prop, idx) => {
return {
name: idx,
restElement: prop.type === 'RestElement'
};
})];
case 'ObjectPattern':
return [param.key.name, param.value.properties.map(prop => {
return getParamName(prop, isProperty);
})];
case 'AssignmentPattern':
{
switch (param.value.left.type) {
case 'Identifier':
// Default parameter
if (checkDefaultObjects && param.value.right.type === 'ObjectExpression') {
return [param.key.name, param.value.right.properties.map(prop => {
return getParamName(prop, isProperty);
})];
}
break;
case 'ObjectPattern':
return [param.key.name, param.value.left.properties.map(prop => {
return getParamName(prop, isProperty);
})];
case 'ArrayPattern':
return [param.key.name, param.value.left.elements.map((prop, idx) => {
return {
name: idx,
restElement: prop.type === 'RestElement'
};
})];
}
}
}
switch (param.key.type) {
case 'Identifier':
return param.key.name;
// The key of an object could also be a string or number
case 'Literal':
return param.key.raw || // istanbul ignore next -- `raw` may not be present in all parsers
param.key.value;
// case 'MemberExpression':
default:
// Todo: We should really create a structure (and a corresponding
// option analogous to `checkRestProperty`) which allows for
// (and optionally requires) dynamic properties to have a single
// line of documentation
return undefined;
}
}
if (param.type === 'ArrayPattern' || ((_param$left3 = param.left) === null || _param$left3 === void 0 ? void 0 : _param$left3.type) === 'ArrayPattern') {
var _param$left4;
const elements = param.elements || ((_param$left4 = param.left) === null || _param$left4 === void 0 ? void 0 : _param$left4.elements);
const roots = elements.map((prop, idx) => {
return {
name: `"${idx}"`,
restElement: (prop === null || prop === void 0 ? void 0 : prop.type) === 'RestElement'
};
});
return [undefined, flattenRoots(roots)];
}
if (['RestElement', 'ExperimentalRestProperty'].includes(param.type)) {
return {
isRestProperty: isProperty,
name: param.argument.name,
restElement: true
};
}
if (param.type === 'TSParameterProperty') {
return getParamName(param.parameter, true);
}
throw new Error(`Unsupported function signature format: \`${param.type}\`.`);
};
return (functionNode.params || functionNode.value.params).map(param => {
return getParamName(param);
});
};
const hasParams = functionNode => {
// Should also check `functionNode.value.params` if supporting `MethodDefinition`
return functionNode.params.length;
};
/**
* Gets all names of the target type, including those that refer to a path, e.g.
* "@param foo; @param foo.bar".
*/
const getJsdocTagsDeep = (jsdoc, targetTagName) => {
const ret = [];
jsdoc.tags.forEach(({
name,
tag,
type
}, idx) => {
if (tag !== targetTagName) {
return;
}
ret.push({
idx,
name,
type
});
});
return ret;
};
const modeWarnSettings = (0, _WarnSettings.default)();
const getTagNamesForMode = (mode, context) => {
switch (mode) {
case 'jsdoc':
return _tagNames.jsdocTags;
case 'typescript':
return _tagNames.typeScriptTags;
case 'closure':
case 'permissive':
return _tagNames.closureTags;
default:
if (!modeWarnSettings.hasBeenWarned(context, 'mode')) {
context.report({
loc: {
start: {
column: 1,
line: 1
}
},
message: `Unrecognized value \`${mode}\` for \`settings.jsdoc.mode\`.`
});
modeWarnSettings.markSettingAsWarned(context, 'mode');
} // We'll avoid breaking too many other rules
return _tagNames.jsdocTags;
}
};
const getPreferredTagName = (context, mode, name, tagPreference = {}) => {
var _Object$entries$find;
const prefValues = Object.values(tagPreference);
if (prefValues.includes(name) || prefValues.some(prefVal => {
return prefVal && typeof prefVal === 'object' && prefVal.replacement === name;
})) {
return name;
} // Allow keys to have a 'tag ' prefix to avoid upstream bug in ESLint
// that disallows keys that conflict with Object.prototype,
// e.g. 'tag constructor' for 'constructor':
// https://github.com/eslint/eslint/issues/13289
// https://github.com/gajus/eslint-plugin-jsdoc/issues/537
const tagPreferenceFixed = _lodash.default.mapKeys(tagPreference, (_value, key) => {
return key.replace('tag ', '');
});
if (_lodash.default.has(tagPreferenceFixed, name)) {
return tagPreferenceFixed[name];
}
const tagNames = getTagNamesForMode(mode, context);
const preferredTagName = (_Object$entries$find = Object.entries(tagNames).find(([, aliases]) => {
return aliases.includes(name);
})) === null || _Object$entries$find === void 0 ? void 0 : _Object$entries$find[0];
if (preferredTagName) {
return preferredTagName;
}
return name;
};
const isValidTag = (context, mode, name, definedTags) => {
const tagNames = getTagNamesForMode(mode, context); // Todo[engine:node@>=12]: Switch to flatten
// eslint-disable-next-line unicorn/prefer-array-flat -- Not yet supported
const validTagNames = Object.keys(tagNames).concat(_lodash.default.flatten(Object.values(tagNames)));
const additionalTags = definedTags;
const allTags = validTagNames.concat(additionalTags);
return allTags.includes(name);
};
const hasTag = (jsdoc, targetTagName) => {
const targetTagLower = targetTagName.toLowerCase();
return _lodash.default.some(jsdoc.tags, doc => {
return doc.tag.toLowerCase() === targetTagLower;
});
};
const hasATag = (jsdoc, targetTagNames) => {
return targetTagNames.some(targetTagName => {
return hasTag(jsdoc, targetTagName);
});
};
/**
* Checks if the JSDoc comment declares a defined type.
*
* @param {JsDocTag} tag
* the tag which should be checked.
* @returns {boolean}
* true in case a defined type is declared; otherwise false.
*/
const hasDefinedTypeTag = tag => {
// The function should not continue in the event the type is not defined...
if (typeof tag === 'undefined' || tag === null) {
return false;
} // .. same applies if it declares an `{undefined}` or `{void}` type
const tagType = tag.type.trim();
if (tagType === 'undefined' || tagType === 'void') {
return false;
} // In any other case, a type is present
return true;
};
const ensureMap = (map, tag) => {
if (!map.has(tag)) {
map.set(tag, new Map());
}
return map.get(tag);
};
const overrideTagStructure = (structuredTags, tagMap = tagStructure) => {
Object.entries(structuredTags).forEach(([tag, {
name,
type,
required = []
}]) => {
const tagStruct = ensureMap(tagMap, tag);
tagStruct.set('nameContents', name);
tagStruct.set('typeAllowed', type);
const requiredName = required.includes('name');
if (requiredName && name === false) {
throw new Error('Cannot add "name" to `require` with the tag\'s `name` set to `false`');
}
tagStruct.set('nameRequired', requiredName);
const requiredType = required.includes('type');
if (requiredType && type === false) {
throw new Error('Cannot add "type" to `require` with the tag\'s `type` set to `false`');
}
tagStruct.set('typeRequired', requiredType);
const typeOrNameRequired = required.includes('typeOrNameRequired');
if (typeOrNameRequired && name === false) {
throw new Error('Cannot add "typeOrNameRequired" to `require` with the tag\'s `name` set to `false`');
}
if (typeOrNameRequired && type === false) {
throw new Error('Cannot add "typeOrNameRequired" to `require` with the tag\'s `type` set to `false`');
}
tagStruct.set('typeOrNameRequired', typeOrNameRequired);
});
};
const getTagStructureForMode = (mode, structuredTags) => {
const tagStruct = (0, _getDefaultTagStructureForMode.default)(mode);
try {
overrideTagStructure(structuredTags, tagStruct);
} catch {//
}
return tagStruct;
};
const isNamepathDefiningTag = (tag, tagMap = tagStructure) => {
const tagStruct = ensureMap(tagMap, tag);
return tagStruct.get('nameContents') === 'namepath-defining';
};
const tagMustHaveTypePosition = (tag, tagMap = tagStructure) => {
const tagStruct = ensureMap(tagMap, tag);
return tagStruct.get('typeRequired');
};
const tagMightHaveTypePosition = (tag, tagMap = tagStructure) => {
if (tagMustHaveTypePosition(tag, tagMap)) {
return true;
}
const tagStruct = ensureMap(tagMap, tag);
const ret = tagStruct.get('typeAllowed');
return ret === undefined ? true : ret;
};
const namepathTypes = new Set(['namepath-defining', 'namepath-referencing']);
const tagMightHaveNamePosition = (tag, tagMap = tagStructure) => {
const tagStruct = ensureMap(tagMap, tag);
const ret = tagStruct.get('nameContents');
return ret === undefined ? true : Boolean(ret);
};
const tagMightHaveNamepath = (tag, tagMap = tagStructure) => {
const tagStruct = ensureMap(tagMap, tag);
return namepathTypes.has(tagStruct.get('nameContents'));
};
const tagMustHaveNamePosition = (tag, tagMap = tagStructure) => {
const tagStruct = ensureMap(tagMap, tag);
return tagStruct.get('nameRequired');
};
const tagMightHaveEitherTypeOrNamePosition = (tag, tagMap) => {
return tagMightHaveTypePosition(tag, tagMap) || tagMightHaveNamepath(tag, tagMap);
};
const tagMustHaveEitherTypeOrNamePosition = (tag, tagMap) => {
const tagStruct = ensureMap(tagMap, tag);
return tagStruct.get('typeOrNameRequired');
};
const tagMissingRequiredTypeOrNamepath = (tag, tagMap = tagStructure) => {
const mustHaveTypePosition = tagMustHaveTypePosition(tag.tag, tagMap);
const mightHaveTypePosition = tagMightHaveTypePosition(tag.tag, tagMap);
const hasTypePosition = mightHaveTypePosition && Boolean(tag.type);
const hasNameOrNamepathPosition = (tagMustHaveNamePosition(tag.tag, tagMap) || tagMightHaveNamepath(tag.tag, tagMap)) && Boolean(tag.name);
const mustHaveEither = tagMustHaveEitherTypeOrNamePosition(tag.tag, tagMap);
const hasEither = tagMightHaveEitherTypeOrNamePosition(tag.tag, tagMap) && (hasTypePosition || hasNameOrNamepathPosition);
return mustHaveEither && !hasEither && !mustHaveTypePosition;
};
/**
* Checks if a node is a promise but has no resolve value or an empty value.
* An `undefined` resolve does not count.
*
* @param {object} node
* @returns {boolean}
*/
const isNewPromiseExpression = node => {
return node.type === 'NewExpression' && node.callee.type === 'Identifier' && node.callee.name === 'Promise';
};
/**
* Checks if a node has a return statement. Void return does not count.
*
* @param {object} node
* @returns {boolean|Node}
*/
// eslint-disable-next-line complexity
const hasReturnValue = (node, promFilter) => {
if (!node) {
return false;
}
switch (node.type) {
case 'FunctionExpression':
case 'FunctionDeclaration':
case 'ArrowFunctionExpression':
{
return node.expression || hasReturnValue(node.body, promFilter);
}
case 'BlockStatement':
{
return node.body.some(bodyNode => {
return bodyNode.type !== 'FunctionDeclaration' && hasReturnValue(bodyNode, promFilter);
});
}
case 'LabeledStatement':
case 'WhileStatement':
case 'DoWhileStatement':
case 'ForStatement':
case 'ForInStatement':
case 'ForOfStatement':
case 'WithStatement':
{
return hasReturnValue(node.body, promFilter);
}
case 'IfStatement':
{
return hasReturnValue(node.consequent, promFilter) || hasReturnValue(node.alternate, promFilter);
}
case 'TryStatement':
{
return hasReturnValue(node.block, promFilter) || hasReturnValue(node.handler && node.handler.body, promFilter) || hasReturnValue(node.finalizer, promFilter);
}
case 'SwitchStatement':
{
return node.cases.some(someCase => {
return someCase.consequent.some(nde => {
return hasReturnValue(nde, promFilter);
});
});
}
case 'ReturnStatement':
{
// void return does not count.
if (node.argument === null) {
return false;
}
if (promFilter && isNewPromiseExpression(node.argument)) {
// Let caller decide how to filter, but this is, at the least,
// a return of sorts and truthy
return promFilter(node.argument);
}
return true;
}
default:
{
return false;
}
}
};
/**
* Avoids further checking child nodes if a nested function shadows the
* resolver, but otherwise, if name is used (by call or passed in as an
* argument to another function), will be considered as non-empty.
*
* This could check for redeclaration of the resolver, but as such is
* unlikely, we avoid the performance cost of checking everywhere for
* (re)declarations or assignments.
*
* @param {AST} node
* @param {string} resolverName
* @returns {boolean}
*/
// eslint-disable-next-line complexity
const hasNonEmptyResolverCall = (node, resolverName) => {
if (!node) {
return false;
} // Arrow function without block
switch (node.type) {
// istanbul ignore next -- In Babel?
case 'OptionalCallExpression':
case 'CallExpression':
return node.callee.name === resolverName && ( // Implicit or expliit undefined
node.arguments.length > 1 || node.arguments[0] !== undefined) || node.arguments.some(nde => {
// Being passed in to another function (which might invoke it)
return nde.type === 'Identifier' && nde.name === resolverName || // Handle nested items
hasNonEmptyResolverCall(nde, resolverName);
});
case 'ChainExpression':
case 'Decorator':
case 'ExpressionStatement':
return hasNonEmptyResolverCall(node.expression, resolverName);
case 'ClassBody':
case 'BlockStatement':
return node.body.some(bodyNode => {
return hasNonEmptyResolverCall(bodyNode, resolverName);
});
case 'FunctionExpression':
case 'FunctionDeclaration':
case 'ArrowFunctionExpression':
{
var _node$params$;
// Shadowing
if (((_node$params$ = node.params[0]) === null || _node$params$ === void 0 ? void 0 : _node$params$.name) === resolverName) {
return false;
}
return hasNonEmptyResolverCall(node.body, resolverName);
}
case 'LabeledStatement':
case 'WhileStatement':
case 'DoWhileStatement':
case 'ForStatement':
case 'ForInStatement':
case 'ForOfStatement':
case 'WithStatement':
{
return hasNonEmptyResolverCall(node.body, resolverName);
}
case 'ConditionalExpression':
case 'IfStatement':
{
return hasNonEmptyResolverCall(node.test, resolverName) || hasNonEmptyResolverCall(node.consequent, resolverName) || hasNonEmptyResolverCall(node.alternate, resolverName);
}
case 'TryStatement':
{
return hasNonEmptyResolverCall(node.block, resolverName) || hasNonEmptyResolverCall(node.handler && node.handler.body, resolverName) || hasNonEmptyResolverCall(node.finalizer, resolverName);
}
case 'SwitchStatement':
{
return node.cases.some(someCase => {
return someCase.consequent.some(nde => {
return hasNonEmptyResolverCall(nde, resolverName);
});
});
}
case 'ArrayPattern':
case 'ArrayExpression':
return node.elements.some(element => {
return hasNonEmptyResolverCall(element, resolverName);
});
case 'AssignmentPattern':
return hasNonEmptyResolverCall(node.right, resolverName);
case 'AssignmentExpression':
case 'BinaryExpression':
case 'LogicalExpression':
{
return hasNonEmptyResolverCall(node.left, resolverName) || hasNonEmptyResolverCall(node.right, resolverName);
}
// Comma
case 'SequenceExpression':
case 'TemplateLiteral':
return node.expressions.some(subExpression => {
return hasNonEmptyResolverCall(subExpression, resolverName);
});
case 'ObjectPattern':
case 'ObjectExpression':
return node.properties.some(property => {
return hasNonEmptyResolverCall(property, resolverName);
});
// istanbul ignore next -- In Babel?
case 'ClassMethod':
case 'MethodDefinition':
return node.decorators && node.decorators.some(decorator => {
return hasNonEmptyResolverCall(decorator, resolverName);
}) || node.computed && hasNonEmptyResolverCall(node.key, resolverName) || hasNonEmptyResolverCall(node.value, resolverName);
// istanbul ignore next -- In Babel?
case 'ObjectProperty':
/* eslint-disable no-fallthrough */
// istanbul ignore next -- In Babel?
case 'ClassProperty':
/* eslint-enable no-fallthrough */
case 'Property':
return node.computed && hasNonEmptyResolverCall(node.key, resolverName) || hasNonEmptyResolverCall(node.value, resolverName);
// istanbul ignore next -- In Babel?
case 'ObjectMethod':
// istanbul ignore next -- In Babel?
return node.computed && hasNonEmptyResolverCall(node.key, resolverName) || node.arguments.some(nde => {
return hasNonEmptyResolverCall(nde, resolverName);
});
case 'ClassExpression':
case 'ClassDeclaration':
return hasNonEmptyResolverCall(node.body, resolverName);
case 'AwaitExpression':
case 'SpreadElement':
case 'UnaryExpression':
case 'YieldExpression':
return hasNonEmptyResolverCall(node.argument, resolverName);
case 'VariableDeclaration':
{
return node.declarations.some(nde => {
return hasNonEmptyResolverCall(nde, resolverName);
});
}
case 'VariableDeclarator':
{
return hasNonEmptyResolverCall(node.id, resolverName) || hasNonEmptyResolverCall(node.init, resolverName);
}
case 'TaggedTemplateExpression':
return hasNonEmptyResolverCall(node.quasi, resolverName);
// ?.
// istanbul ignore next -- In Babel?
case 'OptionalMemberExpression':
case 'MemberExpression':
return hasNonEmptyResolverCall(node.object, resolverName) || hasNonEmptyResolverCall(node.property, resolverName);
// istanbul ignore next -- In Babel?
case 'Import':
case 'ImportExpression':
return hasNonEmptyResolverCall(node.source, resolverName);
case 'ReturnStatement':
{
if (node.argument === null) {
return false;
}
return hasNonEmptyResolverCall(node.argument, resolverName);
}
/*
// Shouldn't need to parse literals/literal components, etc.
case 'Identifier':
case 'TemplateElement':
case 'Super':
// Exports not relevant in this context
*/
default:
return false;
}
};
/**
* Checks if a Promise executor has no resolve value or an empty value.
* An `undefined` resolve does not count.
*
* @param {object} node
* @param {boolean} anyPromiseAsReturn
* @returns {boolean}
*/
const hasValueOrExecutorHasNonEmptyResolveValue = (node, anyPromiseAsReturn) => {
return hasReturnValue(node, prom => {
if (anyPromiseAsReturn) {
return true;
}
const [{
params,
body
} = {}] = prom.arguments;
if (!(params !== null && params !== void 0 && params.length)) {
return false;
}
const [{
name: resolverName
}] = params;
return hasNonEmptyResolverCall(body, resolverName);
});
}; // eslint-disable-next-line complexity
const hasNonFunctionYield = (node, checkYieldReturnValue) => {
if (!node) {
return false;
}
switch (node.type) {
case 'BlockStatement':
{
return node.body.some(bodyNode => {
return !['ArrowFunctionExpression', 'FunctionDeclaration', 'FunctionExpression'].includes(bodyNode.type) && hasNonFunctionYield(bodyNode, checkYieldReturnValue);
});
}
// istanbul ignore next -- In Babel?
case 'OptionalCallExpression':
case 'CallExpression':
return node.arguments.some(element => {
return hasNonFunctionYield(element, checkYieldReturnValue);
});
case 'ChainExpression':
case 'ExpressionStatement':
{
return hasNonFunctionYield(node.expression, checkYieldReturnValue);
}
case 'LabeledStatement':
case 'WhileStatement':
case 'DoWhileStatement':
case 'ForStatement':
case 'ForInStatement':
case 'ForOfStatement':
case 'WithStatement':
{
return hasNonFunctionYield(node.body, checkYieldReturnValue);
}
case 'ConditionalExpression':
case 'IfStatement':
{
return hasNonFunctionYield(node.test, checkYieldReturnValue) || hasNonFunctionYield(node.consequent, checkYieldReturnValue) || hasNonFunctionYield(node.alternate, checkYieldReturnValue);
}
case 'TryStatement':
{
return hasNonFunctionYield(node.block, checkYieldReturnValue) || hasNonFunctionYield(node.handler && node.handler.body, checkYieldReturnValue) || hasNonFunctionYield(node.finalizer, checkYieldReturnValue);
}
case 'SwitchStatement':
{
return node.cases.some(someCase => {
return someCase.consequent.some(nde => {
return hasNonFunctionYield(nde, checkYieldReturnValue);
});
});
}
case 'ArrayPattern':
case 'ArrayExpression':
return node.elements.some(element => {
return hasNonFunctionYield(element, checkYieldReturnValue);
});
case 'AssignmentPattern':
return hasNonFunctionYield(node.right, checkYieldReturnValue);
case 'VariableDeclaration':
{
return node.declarations.some(nde => {
return hasNonFunctionYield(nde, checkYieldReturnValue);
});
}
case 'VariableDeclarator':
{
return hasNonFunctionYield(node.id, checkYieldReturnValue) || hasNonFunctionYield(node.init, checkYieldReturnValue);
}
case 'AssignmentExpression':
case 'BinaryExpression':
case 'LogicalExpression':
{
return hasNonFunctionYield(node.left, checkYieldReturnValue) || hasNonFunctionYield(node.right, checkYieldReturnValue);
}
// Comma
case 'SequenceExpression':
case 'TemplateLiteral':
return node.expressions.some(subExpression => {
return hasNonFunctionYield(subExpression, checkYieldReturnValue);
});
case 'ObjectPattern':
case 'ObjectExpression':
return node.properties.some(property => {
return hasNonFunctionYield(property, checkYieldReturnValue);
});
// istanbul ignore next -- In Babel?
case 'ObjectProperty':
/* eslint-disable no-fallthrough */
// istanbul ignore next -- In Babel?
case 'ClassProperty':
/* eslint-enable no-fallthrough */
case 'Property':
return node.computed && hasNonFunctionYield(node.key, checkYieldReturnValue) || hasNonFunctionYield(node.value, checkYieldReturnValue);
// istanbul ignore next -- In Babel?
case 'ObjectMethod':
// istanbul ignore next -- In Babel?
return node.computed && hasNonFunctionYield(node.key, checkYieldReturnValue) || node.arguments.some(nde => {
return hasNonFunctionYield(nde, checkYieldReturnValue);
});
case 'SpreadElement':
case 'UnaryExpression':
return hasNonFunctionYield(node.argument, checkYieldReturnValue);
case 'TaggedTemplateExpression':
return hasNonFunctionYield(node.quasi, checkYieldReturnValue);
// ?.
// istanbul ignore next -- In Babel?
case 'OptionalMemberExpression':
case 'MemberExpression':
return hasNonFunctionYield(node.object, checkYieldReturnValue) || hasNonFunctionYield(node.property, checkYieldReturnValue);
// istanbul ignore next -- In Babel?
case 'Import':
case 'ImportExpression':
return hasNonFunctionYield(node.source, checkYieldReturnValue);
case 'ReturnStatement':
{
if (node.argument === null) {
return false;
}
return hasNonFunctionYield(node.argument, checkYieldReturnValue);
}
case 'YieldExpression':
{
if (checkYieldReturnValue) {
if (node.parent.type === 'VariableDeclarator') {
return true;
}
return false;
} // void return does not count.
if (node.argument === null) {
return false;
}
return true;
}
default:
{
return false;
}
}
};
/**
* Checks if a node has a return statement. Void return does not count.
*
* @param {object} node
* @returns {boolean}
*/
const hasYieldValue = (node, checkYieldReturnValue) => {
return node.generator && (node.expression || hasNonFunctionYield(node.body, checkYieldReturnValue));
};
/**
* Checks if a node has a throws statement.
*
* @param {object} node
* @param {boolean} innerFunction
* @returns {boolean}
*/
// eslint-disable-next-line complexity
const hasThrowValue = (node, innerFunction) => {
if (!node) {
return false;
} // There are cases where a function may execute its inner function which
// throws, but we're treating functions atomically rather than trying to
// follow them
switch (node.type) {
case 'FunctionExpression':
case 'FunctionDeclaration':
case 'ArrowFunctionExpression':
{
return !innerFunction && hasThrowValue(node.body, true);
}
case 'BlockStatement':
{
return node.body.some(bodyNode => {
return bodyNode.type !== 'FunctionDeclaration' && hasThrowValue(bodyNode);
});
}
case 'LabeledStatement':
case 'WhileStatement':
case 'DoWhileStatement':
case 'ForStatement':
case 'ForInStatement':
case 'ForOfStatement':
case 'WithStatement':
{
return hasThrowValue(node.body);
}
case 'IfStatement':
{
return hasThrowValue(node.consequent) || hasThrowValue(node.alternate);
}
// We only consider it to throw an error if the catch or finally blocks throw an error.
case 'TryStatement':
{
return hasThrowValue(node.handler && node.handler.body) || hasThrowValue(node.finalizer);
}
case 'SwitchStatement':
{
return node.cases.some(someCase => {
return someCase.consequent.some(nde => {
return hasThrowValue(nde);
});
});
}
case 'ThrowStatement':
{
return true;
}
default:
{
return false;
}
}
};
/** @param {string} tag */
/*
const isInlineTag = (tag) => {
return /^(@link|@linkcode|@linkplain|@tutorial) /u.test(tag);
};
*/
/**
* Parses GCC Generic/Template types
*
* @see {https://github.com/google/closure-compiler/wiki/Generic-Types}
* @see {https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#template}
* @param {JsDocTag} tag
* @returns {Array<string>}
*/
const parseClosureTemplateTag = tag => {
return tag.name.split(',').map(type => {
return type.trim();
});
};
/**
* Checks user option for `contexts` array, defaulting to
* contexts designated by the rule. Returns an array of
* ESTree AST types, indicating allowable contexts.
*
* @param {*} context
* @param {true|string[]} defaultContexts
* @returns {string[]}
*/
const enforcedContexts = (context, defaultContexts) => {
const {
contexts = defaultContexts === true ? ['ArrowFunctionExpression', 'FunctionDeclaration', 'FunctionExpression'] : defaultContexts
} = context.options[0] || {};
return contexts;
};
/**
* @param {string[]} contexts
* @param {Function} checkJsdoc
* @param {Function} handler
*/
const getContextObject = (contexts, checkJsdoc, handler) => {
const properties = {};
contexts.forEach(prop => {
if (typeof prop === 'object') {
const selInfo = {
selector: prop.context
};
if (prop.comment) {
properties[prop.context] = checkJsdoc.bind(null, { ...selInfo,
comment: prop.comment
}, handler.bind(null, prop.comment));
} else {
properties[prop.context] = checkJsdoc.bind(null, selInfo, null);
}
} else {
const selInfo = {
selector: prop
};
properties[prop] = checkJsdoc.bind(null, selInfo, null);
}
});
return properties;
};
const filterTags = (tags, filter) => {
return tags.filter(filter);
};
const tagsWithNamesAndDescriptions = new Set(['param', 'arg', 'argument', 'property', 'prop', 'template', // These two are parsed by our custom parser as though having a `name`
'returns', 'return']);
const getTagsByType = (context, mode, tags, tagPreference) => {
const descName = getPreferredTagName(context, mode, 'description', tagPreference);
const tagsWithoutNames = [];
const tagsWithNames = filterTags(tags, tag => {
const {
tag: tagName
} = tag;
const tagWithName = tagsWithNamesAndDescriptions.has(tagName);
if (!tagWithName && tagName !== descName) {
tagsWithoutNames.push(tag);
}
return tagWithName;
});
return {
tagsWithNames,
tagsWithoutNames
};
};
const getIndent = sourceCode => {
var _sourceCode$text$matc, _sourceCode$text$matc2;
return ((_sourceCode$text$matc = (_sourceCode$text$matc2 = sourceCode.text.match(/^\n*([ \t]+)/u)) === null || _sourceCode$text$matc2 === void 0 ? void 0 : _sourceCode$text$matc2[1]) !== null && _sourceCode$text$matc !== void 0 ? _sourceCode$text$matc : '') + ' ';
};
const isConstructor = node => {
var _node$parent;
return (node === null || node === void 0 ? void 0 : node.type) === 'MethodDefinition' && node.kind === 'constructor' || (node === null || node === void 0 ? void 0 : (_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.kind) === 'constructor';
};
const isGetter = node => {
return node && node.parent.kind === 'get';
};
const isSetter = node => {
return node && node.parent.kind === 'set';
};
const hasAccessorPair = node => {
const {
type,
kind: sourceKind,
key: {
name: sourceName
}
} = node;
const oppositeKind = sourceKind === 'get' ? 'set' : 'get';
const children = type === 'MethodDefinition' ? 'body' : 'properties';
return node.parent[children].some(({
kind,
key: {
name
}
}) => {
return kind === oppositeKind && name === sourceName;
});
};
const exemptSpeciaMethods = (jsdoc, node, context, schema) => {
const hasSchemaOption = prop => {
var _context$options$0$pr, _context$options$;
const schemaProperties = schema[0].properties;
return (_context$options$0$pr = (_context$options$ = context.options[0]) === null || _context$options$ === void 0 ? void 0 : _context$options$[prop]) !== null && _context$options$0$pr !== void 0 ? _context$options$0$pr : schemaProperties[prop] && schemaProperties[prop].default;
};
const checkGetters = hasSchemaOption('checkGetters');
const checkSetters = hasSchemaOption('checkSetters');
return !hasSchemaOption('checkConstructors') && (isConstructor(node) || hasATag(jsdoc, ['class', 'constructor'])) || isGetter(node) && (!checkGetters || checkGetters === 'no-setter' && hasAccessorPair(node.parent)) || isSetter(node) && (!checkSetters || checkSetters === 'no-getter' && hasAccessorPair(node.parent));
};
/**
* Since path segments may be unquoted (if matching a reserved word,
* identifier or numeric literal) or single or double quoted, in either
* the `@param` or in source, we need to strip the quotes to give a fair
* comparison.
*
* @param {string} str
* @returns {string}
*/
const dropPathSegmentQuotes = str => {
return str.replace(/\.(['"])(.*)\1/gu, '.$2');
};
const comparePaths = name => {
return otherPathName => {
return otherPathName === name || dropPathSegmentQuotes(otherPathName) === dropPathSegmentQuotes(name);
};
};
const getRegexFromString = (regexString, requiredFlags) => {
const match = regexString.match(/^\/(.*)\/([gimyus]*)$/us);
let flags = 'u';
let regex = regexString;
if (match) {
[, regex, flags] = match;
if (!flags) {
flags = 'u';
}
}
const uniqueFlags = [...new Set(flags + (requiredFlags || ''))];
flags = uniqueFlags.join('');
return new RegExp(regex, flags);
};
var _default = {
comparePaths,
dropPathSegmentQuotes,
enforcedContexts,
exemptSpeciaMethods,
filterTags,
flattenRoots,
getContextObject,
getFunctionParameterNames,
getIndent,
getJsdocTagsDeep,
getPreferredTagName,
getRegexFromString,
getTagsByType,
getTagStructureForMode,
hasATag,
hasDefinedTypeTag,
hasParams,
hasReturnValue,
hasTag,
hasThrowValue,
hasValueOrExecutorHasNonEmptyResolveValue,
hasYieldValue,
isConstructor,
isGetter,
isNamepathDefiningTag,
isSetter,
isValidTag,
overrideTagStructure,
parseClosureTemplateTag,
setTagStructure,
tagMightHaveNamepath,
tagMightHaveNamePosition,
tagMightHaveTypePosition,
tagMissingRequiredTypeOrNamepath,
tagMustHaveNamePosition,
tagMustHaveTypePosition
};
exports.default = _default;
module.exports = exports.default;
//# sourceMappingURL=jsdocUtils.js.mapВыполнить команду
Для локальной разработки. Не используйте в интернете!