mirror of
https://github.com/JamesIves/github-pages-deploy-action.git
synced 2023-12-15 20:03:39 +08:00
230 lines
7.2 KiB
JavaScript
230 lines
7.2 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
Object.defineProperty(exports, "__esModule", {
|
||
|
value: true
|
||
|
});
|
||
|
exports.default = void 0;
|
||
|
|
||
|
var _lodash = _interopRequireDefault(require("lodash"));
|
||
|
|
||
|
var _mainUmd = require("regextras/dist/main-umd");
|
||
|
|
||
|
var _iterateJsdoc = _interopRequireDefault(require("../iterateJsdoc"));
|
||
|
|
||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
|
||
|
const otherDescriptiveTags = [// 'copyright' and 'see' might be good addition, but as the former may be
|
||
|
// sensitive text, and the latter may have just a link, they are not
|
||
|
// included by default
|
||
|
'summary', 'file', 'fileoverview', 'overview', 'classdesc', 'todo', 'deprecated', 'throws', 'exception', 'yields', 'yield'];
|
||
|
|
||
|
const extractParagraphs = text => {
|
||
|
// Todo [engine:node@>8.11.0]: Uncomment following line with neg. lookbehind instead
|
||
|
// return text.split(/(?<![;:])\n\n/u);
|
||
|
return [...text].reverse().join('').split(/\n\n(?![;:])/u).map(par => {
|
||
|
return [...par].reverse().join('');
|
||
|
}).reverse();
|
||
|
};
|
||
|
|
||
|
const extractSentences = (text, abbreviationsRegex) => {
|
||
|
const txt = text // Remove all {} tags.
|
||
|
.replace(/\{[\s\S]*?\}\s*/gu, '') // Remove custom abbreviations
|
||
|
.replace(abbreviationsRegex, '');
|
||
|
const sentenceEndGrouping = /([.?!])(?:\s+|$)/u;
|
||
|
const puncts = (0, _mainUmd.RegExtras)(sentenceEndGrouping).map(txt, punct => {
|
||
|
return punct;
|
||
|
});
|
||
|
return txt.split(/[.?!](?:\s+|$)/u) // Re-add the dot.
|
||
|
.map((sentence, idx) => {
|
||
|
return /^\s*$/u.test(sentence) ? sentence : `${sentence}${puncts[idx] || ''}`;
|
||
|
});
|
||
|
};
|
||
|
|
||
|
const isNewLinePrecededByAPeriod = text => {
|
||
|
let lastLineEndsSentence;
|
||
|
const lines = text.split('\n');
|
||
|
return !lines.some(line => {
|
||
|
if (lastLineEndsSentence === false && /^[A-Z][a-z]/u.test(line)) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
lastLineEndsSentence = /[.:?!|]$/u.test(line);
|
||
|
return false;
|
||
|
});
|
||
|
};
|
||
|
|
||
|
const isCapitalized = str => {
|
||
|
return str[0] === str[0].toUpperCase();
|
||
|
};
|
||
|
|
||
|
const isTable = str => {
|
||
|
return str.charAt() === '|';
|
||
|
};
|
||
|
|
||
|
const capitalize = str => {
|
||
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
||
|
};
|
||
|
|
||
|
const validateDescription = (description, reportOrig, jsdocNode, abbreviationsRegex, sourceCode, tag) => {
|
||
|
if (!description) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
const paragraphs = extractParagraphs(description);
|
||
|
return paragraphs.some((paragraph, parIdx) => {
|
||
|
const sentences = extractSentences(paragraph, abbreviationsRegex);
|
||
|
|
||
|
const fix = fixer => {
|
||
|
let text = sourceCode.getText(jsdocNode);
|
||
|
|
||
|
if (!/[.:?!]$/u.test(paragraph)) {
|
||
|
const line = _lodash.default.last(paragraph.split('\n'));
|
||
|
|
||
|
text = text.replace(new RegExp(`${_lodash.default.escapeRegExp(line)}$`, 'mu'), `${line}.`);
|
||
|
}
|
||
|
|
||
|
var _iteratorNormalCompletion = true;
|
||
|
var _didIteratorError = false;
|
||
|
var _iteratorError = undefined;
|
||
|
|
||
|
try {
|
||
|
for (var _iterator = sentences.filter(sentence_ => {
|
||
|
return !/^\s*$/u.test(sentence_) && !isCapitalized(sentence_) && !isTable(sentence_);
|
||
|
})[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||
|
const sentence = _step.value;
|
||
|
const beginning = sentence.split('\n')[0];
|
||
|
|
||
|
if (tag.tag) {
|
||
|
const reg = new RegExp(`(@${_lodash.default.escapeRegExp(tag.tag)}.*)${_lodash.default.escapeRegExp(beginning)}`, 'u');
|
||
|
text = text.replace(reg, ($0, $1) => {
|
||
|
return $1 + capitalize(beginning);
|
||
|
});
|
||
|
} else {
|
||
|
text = text.replace(beginning, capitalize(beginning));
|
||
|
}
|
||
|
}
|
||
|
} catch (err) {
|
||
|
_didIteratorError = true;
|
||
|
_iteratorError = err;
|
||
|
} finally {
|
||
|
try {
|
||
|
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
||
|
_iterator.return();
|
||
|
}
|
||
|
} finally {
|
||
|
if (_didIteratorError) {
|
||
|
throw _iteratorError;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return fixer.replaceText(jsdocNode, text);
|
||
|
};
|
||
|
|
||
|
const report = (msg, fixer, tagObj) => {
|
||
|
tagObj.line += parIdx * 2; // Avoid errors if old column doesn't exist here
|
||
|
|
||
|
tagObj.column = 0;
|
||
|
reportOrig(msg, fixer, tagObj);
|
||
|
};
|
||
|
|
||
|
if (sentences.some(sentence => {
|
||
|
return !/^\s*$/u.test(sentence) && !isCapitalized(sentence) && !isTable(sentence);
|
||
|
})) {
|
||
|
report('Sentence should start with an uppercase character.', fix, tag);
|
||
|
}
|
||
|
|
||
|
const paragraphNoAbbreviations = paragraph.replace(abbreviationsRegex, '');
|
||
|
|
||
|
if (!/[.!?|]$/u.test(paragraphNoAbbreviations)) {
|
||
|
report('Sentence must end with a period.', fix, tag);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (!isNewLinePrecededByAPeriod(paragraphNoAbbreviations)) {
|
||
|
report('A line of text is started with an uppercase character, but preceding line does not end the sentence.', null, tag);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
});
|
||
|
};
|
||
|
|
||
|
var _default = (0, _iterateJsdoc.default)(({
|
||
|
sourceCode,
|
||
|
context,
|
||
|
jsdoc,
|
||
|
report,
|
||
|
jsdocNode,
|
||
|
utils
|
||
|
}) => {
|
||
|
const options = context.options[0] || {};
|
||
|
const _options$abbreviation = options.abbreviations,
|
||
|
abbreviations = _options$abbreviation === void 0 ? [] : _options$abbreviation;
|
||
|
const abbreviationsRegex = abbreviations.length ? new RegExp('\\b' + abbreviations.map(abbreviation => {
|
||
|
return _lodash.default.escapeRegExp(abbreviation.replace(/\.$/g, '') + '.');
|
||
|
}).join('|') + '(?:$|\\s)', 'gu') : '';
|
||
|
|
||
|
if (!jsdoc.tags || validateDescription(jsdoc.description, report, jsdocNode, abbreviationsRegex, sourceCode, {
|
||
|
line: jsdoc.line + 1
|
||
|
})) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
utils.forEachPreferredTag('description', matchingJsdocTag => {
|
||
|
const description = `${matchingJsdocTag.name} ${matchingJsdocTag.description}`.trim();
|
||
|
validateDescription(description, report, jsdocNode, abbreviationsRegex, sourceCode, matchingJsdocTag);
|
||
|
}, true);
|
||
|
|
||
|
const _utils$getTagsByType = utils.getTagsByType(jsdoc.tags),
|
||
|
tagsWithNames = _utils$getTagsByType.tagsWithNames;
|
||
|
|
||
|
const tagsWithoutNames = utils.filterTags(({
|
||
|
tag: tagName
|
||
|
}) => {
|
||
|
return otherDescriptiveTags.includes(tagName) || utils.hasOptionTag(tagName) && !tagsWithNames.some(({
|
||
|
tag
|
||
|
}) => {
|
||
|
// If user accidentally adds tags with names (or like `returns`
|
||
|
// get parsed as having names), do not add to this list
|
||
|
return tag === tagName;
|
||
|
});
|
||
|
});
|
||
|
tagsWithNames.some(tag => {
|
||
|
const description = _lodash.default.trimStart(tag.description, '- ');
|
||
|
|
||
|
return validateDescription(description, report, jsdocNode, abbreviationsRegex, sourceCode, tag);
|
||
|
});
|
||
|
tagsWithoutNames.some(tag => {
|
||
|
const description = `${tag.name} ${tag.description}`.trim();
|
||
|
return validateDescription(description, report, jsdocNode, abbreviationsRegex, sourceCode, tag);
|
||
|
});
|
||
|
}, {
|
||
|
iterateAllJsdocs: true,
|
||
|
meta: {
|
||
|
fixable: 'code',
|
||
|
schema: [{
|
||
|
additionalProperties: false,
|
||
|
properties: {
|
||
|
abbreviations: {
|
||
|
items: {
|
||
|
type: 'string'
|
||
|
},
|
||
|
type: 'array'
|
||
|
},
|
||
|
tags: {
|
||
|
items: {
|
||
|
type: 'string'
|
||
|
},
|
||
|
type: 'array'
|
||
|
}
|
||
|
},
|
||
|
type: 'object'
|
||
|
}],
|
||
|
type: 'suggestion'
|
||
|
}
|
||
|
});
|
||
|
|
||
|
exports.default = _default;
|
||
|
module.exports = exports.default;
|
||
|
//# sourceMappingURL=requireDescriptionCompleteSentence.js.map
|