mirror of
https://github.com/JamesIves/github-pages-deploy-action.git
synced 2023-12-15 20:03:39 +08:00
464 lines
14 KiB
JavaScript
464 lines
14 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.default = void 0;
|
|
|
|
var _lodash = _interopRequireDefault(require("lodash"));
|
|
|
|
var _tagNames = require("./tagNames");
|
|
|
|
var _WarnSettings = _interopRequireDefault(require("./WarnSettings"));
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
const getFunctionParameterNames = functionNode => {
|
|
const getParamName = param => {
|
|
if (_lodash.default.has(param, 'name')) {
|
|
return param.name;
|
|
}
|
|
|
|
if (_lodash.default.has(param, 'left.name')) {
|
|
return param.left.name;
|
|
}
|
|
|
|
if (param.type === 'ObjectPattern' || _lodash.default.get(param, 'left.type') === 'ObjectPattern') {
|
|
return '<ObjectPattern>';
|
|
}
|
|
|
|
if (param.type === 'ArrayPattern' || _lodash.default.get(param, 'left.type') === 'ArrayPattern') {
|
|
return '<ArrayPattern>';
|
|
}
|
|
|
|
if (param.type === 'RestElement') {
|
|
return param.argument.name;
|
|
}
|
|
|
|
if (param.type === 'TSParameterProperty') {
|
|
return getParamName(param.parameter);
|
|
}
|
|
|
|
throw new Error('Unsupported function signature format.');
|
|
};
|
|
|
|
return functionNode.params.map(getParamName);
|
|
};
|
|
/**
|
|
* 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) => {
|
|
return (jsdoc.tags || []).reduce((arr, {
|
|
name,
|
|
tag
|
|
}, idx) => {
|
|
if (tag !== targetTagName) {
|
|
return arr;
|
|
}
|
|
|
|
arr.push({
|
|
idx,
|
|
name
|
|
});
|
|
return arr;
|
|
}, []);
|
|
};
|
|
|
|
const getJsdocTags = (jsdoc, targetTagName) => {
|
|
let jsdocNames;
|
|
jsdocNames = getJsdocTagsDeep(jsdoc, targetTagName);
|
|
jsdocNames = jsdocNames.filter(({
|
|
name
|
|
}) => {
|
|
return !name.includes('.');
|
|
});
|
|
return jsdocNames;
|
|
};
|
|
|
|
const modeWarnSettings = (0, _WarnSettings.default)();
|
|
|
|
const getTagNamesForMode = (mode, context) => {
|
|
switch (mode) {
|
|
case 'jsdoc':
|
|
return _tagNames.jsdocTags;
|
|
|
|
case 'typescript':
|
|
return _tagNames.typeScriptTags;
|
|
|
|
case 'closure':
|
|
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 = {}) => {
|
|
const prefValues = _lodash.default.values(tagPreference);
|
|
|
|
if (prefValues.includes(name) || prefValues.some(prefVal => {
|
|
return prefVal && typeof prefVal === 'object' && prefVal.replacement === name;
|
|
})) {
|
|
return name;
|
|
}
|
|
|
|
if (_lodash.default.has(tagPreference, name)) {
|
|
return tagPreference[name];
|
|
}
|
|
|
|
const tagNames = getTagNamesForMode(mode, context);
|
|
|
|
const preferredTagName = _lodash.default.findKey(tagNames, aliases => {
|
|
return aliases.includes(name);
|
|
});
|
|
|
|
if (preferredTagName) {
|
|
return preferredTagName;
|
|
}
|
|
|
|
return name;
|
|
};
|
|
|
|
const isValidTag = (context, mode, name, definedTags) => {
|
|
const tagNames = getTagNamesForMode(mode, context);
|
|
|
|
const validTagNames = _lodash.default.keys(tagNames).concat(_lodash.default.flatten(_lodash.default.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 return value.
|
|
*
|
|
* @param {JsDocTag} tag
|
|
* the tag which should be checked.
|
|
* @returns {boolean}
|
|
* true in case a return value is declared; otherwise false.
|
|
*/
|
|
|
|
|
|
const hasDefinedTypeReturnTag = tag => {
|
|
// The function should not continue in the event @returns is not defined...
|
|
if (typeof tag === 'undefined' || tag === null) {
|
|
return false;
|
|
} // .. same applies if it declares `@returns {undefined}` or `@returns {void}`
|
|
|
|
|
|
const tagType = tag.type.trim();
|
|
|
|
if (tagType === 'undefined' || tagType === 'void') {
|
|
return false;
|
|
} // In any other case, something must be returned, and
|
|
// a return statement is expected
|
|
|
|
|
|
return true;
|
|
};
|
|
|
|
const tagsWithMandatoryTypePosition = [// These both show curly brackets in the doc signature and examples
|
|
// "typeExpression"
|
|
'implements', // "typeName"
|
|
'type'];
|
|
const tagsWithMandatoryTypePositionClosure = [...tagsWithMandatoryTypePosition, 'this', 'define']; // All of these have a signature with "type" except for
|
|
// `augments`/`extends` ("namepath")
|
|
// `param`/`arg`/`argument` (no signature)
|
|
// `property`/`prop` (no signature)
|
|
// `modifies` (undocumented)
|
|
|
|
const tagsWithOptionalTypePosition = [// These have the example showing curly brackets but not in their doc signature, e.g.: https://jsdoc.app/tags-enum.html
|
|
'enum', 'member', 'var', 'typedef', // These do not show curly brackets in either the signature or examples
|
|
'augments', 'extends', 'class', 'constructor', 'constant', 'const', // These show the signature with curly brackets but not in the example
|
|
'module', 'namespace', // These have no formal signature in the docs but show curly brackets
|
|
// in the examples
|
|
'param', 'arg', 'argument', 'property', 'prop', // These show curly brackets in the signature and in the examples
|
|
'returns', 'return', 'throws', 'exception', 'yields', 'yield', // Has no documentation, but test example has curly brackets, and
|
|
// "name" would be suggested rather than "namepath" based on example; not
|
|
// sure if name is required
|
|
'modifies'];
|
|
const tagsWithOptionalTypePositionClosure = [...tagsWithOptionalTypePosition, 'export', // Shows the signature with curly brackets but not in the example
|
|
// "typeExpression"
|
|
'package', 'private', 'protected', // These do not show a signature nor show curly brackets in the example
|
|
'public', 'static']; // None of these show as having curly brackets for their name/namepath
|
|
|
|
const namepathDefiningTags = [// These appear to require a "name" in their signature, albeit these
|
|
// are somewhat different from other "name"'s (including as described
|
|
// at https://jsdoc.app/about-namepaths.html )
|
|
'external', 'host', 'event', // These allow for "name"'s in their signature, but indicate as optional
|
|
'class', 'constructor', 'constant', 'const', 'function', 'func', 'method', 'interface', 'member', 'var', 'mixin', 'namespace', // Todo: Should add `module` here (with optional "name" and no curly brackets);
|
|
// this block impacts `no-undefined-types` and `valid-types` (search for
|
|
// "isNamepathDefiningTag|tagMightHaveNamePosition|tagMightHaveEitherTypeOrNamePosition")
|
|
// These seem to all require a "namepath" in their signatures (with no counter-examples)
|
|
'name', 'typedef', 'callback']; // The following do not seem to allow curly brackets in their doc
|
|
// signature or examples (besides `modifies`)
|
|
|
|
const tagsWithOptionalNamePosition = [...namepathDefiningTags, // `borrows` has a different format, however, so needs special parsing;
|
|
// seems to require both, and as "namepath"'s
|
|
'borrows', // Signature seems to require a "name" (of an event) and no counter-examples
|
|
'emits', 'fires', 'listens', // Signature seems to require a "namepath" (and no counter-examples)
|
|
'alias', 'augments', 'extends', 'lends', 'this', // Signature seems to require a "namepath" (and no counter-examples),
|
|
// though it allows an incomplete namepath ending with connecting symbol
|
|
'memberof', 'memberof!', // Signature seems to require a "OtherObjectPath" with no counter-examples
|
|
'mixes', // Signature allows for "namepath" or text
|
|
'see']; // Todo: `@link` seems to require a namepath OR URL and might be checked as such.
|
|
// The doc signature of `event` seems to require a "name"
|
|
|
|
const tagsWithMandatoryNamePosition = [// "name" (and a special syntax for the `external` name)
|
|
'external', 'host', // "namepath"
|
|
'callback', 'name', 'typedef'];
|
|
const tagsWithMandatoryTypeOrNamePosition = [// "namepath"
|
|
'alias', 'augments', 'extends', 'borrows', 'lends', 'memberof', 'memberof!', 'name', 'this', 'typedef', // "name"
|
|
'external', 'host', // "OtherObjectPath"
|
|
'mixes'];
|
|
|
|
const isNamepathDefiningTag = tagName => {
|
|
return namepathDefiningTags.includes(tagName);
|
|
};
|
|
|
|
const tagMightHaveTypePosition = (mode, tag) => {
|
|
if (mode === 'closure') {
|
|
return tagsWithMandatoryTypePositionClosure.includes(tag) || tagsWithOptionalTypePositionClosure.includes(tag);
|
|
}
|
|
|
|
return tagsWithMandatoryTypePosition.includes(tag) || tagsWithOptionalTypePosition.includes(tag);
|
|
};
|
|
|
|
const tagMustHaveTypePosition = (mode, tag) => {
|
|
if (mode === 'closure') {
|
|
return tagsWithMandatoryTypePositionClosure.includes(tag);
|
|
}
|
|
|
|
return tagsWithMandatoryTypePosition.includes(tag);
|
|
};
|
|
|
|
const tagMightHaveNamePosition = tag => {
|
|
return tagsWithOptionalNamePosition.includes(tag);
|
|
};
|
|
|
|
const tagMustHaveNamePosition = tag => {
|
|
return tagsWithMandatoryNamePosition.includes(tag);
|
|
};
|
|
|
|
const tagMightHaveEitherTypeOrNamePosition = (mode, tag) => {
|
|
return tagMightHaveTypePosition(mode, tag) || tagMightHaveNamePosition(tag);
|
|
};
|
|
|
|
const tagMustHaveEitherTypeOrNamePosition = tag => {
|
|
return tagsWithMandatoryTypeOrNamePosition.includes(tag);
|
|
};
|
|
/**
|
|
* Checks if a node has a return statement. Void return does not count.
|
|
*
|
|
* @param {object} node
|
|
* @returns {boolean}
|
|
*/
|
|
// eslint-disable-next-line complexity
|
|
|
|
|
|
const hasReturnValue = node => {
|
|
if (!node) {
|
|
return false;
|
|
}
|
|
|
|
switch (node.type) {
|
|
case 'FunctionExpression':
|
|
case 'FunctionDeclaration':
|
|
case 'ArrowFunctionExpression':
|
|
{
|
|
return node.expression || hasReturnValue(node.body);
|
|
}
|
|
|
|
case 'BlockStatement':
|
|
{
|
|
return node.body.some(bodyNode => {
|
|
return bodyNode.type !== 'FunctionDeclaration' && hasReturnValue(bodyNode);
|
|
});
|
|
}
|
|
|
|
case 'WhileStatement':
|
|
case 'DoWhileStatement':
|
|
case 'ForStatement':
|
|
case 'ForInStatement':
|
|
case 'ForOfStatement':
|
|
case 'WithStatement':
|
|
{
|
|
return hasReturnValue(node.body);
|
|
}
|
|
|
|
case 'IfStatement':
|
|
{
|
|
return hasReturnValue(node.consequent) || hasReturnValue(node.alternate);
|
|
}
|
|
|
|
case 'TryStatement':
|
|
{
|
|
return hasReturnValue(node.block) || hasReturnValue(node.handler && node.handler.body) || hasReturnValue(node.finalizer);
|
|
}
|
|
|
|
case 'SwitchStatement':
|
|
{
|
|
return node.cases.some(someCase => {
|
|
return someCase.consequent.some(hasReturnValue);
|
|
});
|
|
}
|
|
|
|
case 'ReturnStatement':
|
|
{
|
|
// void return does not count.
|
|
if (node.argument === null) {
|
|
return false;
|
|
}
|
|
|
|
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}
|
|
* @param {JsDocTag} tag
|
|
* @returns {Array<string>}
|
|
*/
|
|
|
|
|
|
const parseClosureTemplateTag = tag => {
|
|
return (tag.name + ' ' + tag.description).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 _ref = context.options[0] || {},
|
|
_ref$contexts = _ref.contexts,
|
|
contexts = _ref$contexts === void 0 ? defaultContexts === true ? ['ArrowFunctionExpression', 'FunctionDeclaration', 'FunctionExpression'] : defaultContexts : _ref$contexts;
|
|
|
|
return contexts;
|
|
};
|
|
/**
|
|
* @param {string[]} contexts
|
|
* @param {Function} checkJsdoc
|
|
*/
|
|
|
|
|
|
const getContextObject = (contexts, checkJsdoc) => {
|
|
return contexts.reduce((obj, prop) => {
|
|
obj[prop] = checkJsdoc;
|
|
return obj;
|
|
}, {});
|
|
};
|
|
|
|
const filterTags = (tags = [], filter) => {
|
|
return tags.filter(filter);
|
|
};
|
|
|
|
const tagsWithNamesAndDescriptions = ['param', 'arg', 'argument', 'property', 'prop', // 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 tagName = tag.tag;
|
|
const tagWithName = tagsWithNamesAndDescriptions.includes(tagName);
|
|
|
|
if (!tagWithName && tagName !== descName) {
|
|
tagsWithoutNames.push(tag);
|
|
}
|
|
|
|
return tagWithName;
|
|
});
|
|
return {
|
|
tagsWithNames,
|
|
tagsWithoutNames
|
|
};
|
|
};
|
|
|
|
const getIndent = sourceCode => {
|
|
let indent = sourceCode.text.match(/^\n*([ \t]+)/u);
|
|
/* istanbul ignore next */
|
|
|
|
indent = indent ? indent[1] + indent[1].charAt() : ' ';
|
|
return indent;
|
|
};
|
|
|
|
var _default = {
|
|
enforcedContexts,
|
|
filterTags,
|
|
getContextObject,
|
|
getFunctionParameterNames,
|
|
getIndent,
|
|
getJsdocTags,
|
|
getJsdocTagsDeep,
|
|
getPreferredTagName,
|
|
getTagsByType,
|
|
hasATag,
|
|
hasDefinedTypeReturnTag,
|
|
hasReturnValue,
|
|
hasTag,
|
|
isNamepathDefiningTag,
|
|
isValidTag,
|
|
parseClosureTemplateTag,
|
|
tagMightHaveEitherTypeOrNamePosition,
|
|
tagMightHaveNamePosition,
|
|
tagMightHaveTypePosition,
|
|
tagMustHaveEitherTypeOrNamePosition,
|
|
tagMustHaveNamePosition,
|
|
tagMustHaveTypePosition
|
|
};
|
|
exports.default = _default;
|
|
module.exports = exports.default;
|
|
//# sourceMappingURL=jsdocUtils.js.map
|