mirror of
https://github.com/JamesIves/github-pages-deploy-action.git
synced 2023-12-15 20:03:39 +08:00
359 lines
13 KiB
JavaScript
359 lines
13 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
Object.defineProperty(exports, "__esModule", {
|
||
|
value: true
|
||
|
});
|
||
|
exports.default = void 0;
|
||
|
|
||
|
var _eslint = require("eslint");
|
||
|
|
||
|
var _iterateJsdoc = _interopRequireDefault(require("../iterateJsdoc"));
|
||
|
|
||
|
var _warnRemovedSettings = _interopRequireDefault(require("../warnRemovedSettings"));
|
||
|
|
||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
|
||
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
||
|
|
||
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
||
|
|
||
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||
|
|
||
|
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
|
||
|
|
||
|
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
|
||
|
|
||
|
function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { return; } var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
|
||
|
|
||
|
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
||
|
|
||
|
const zeroBasedLineIndexAdjust = -1;
|
||
|
const likelyNestedJSDocIndentSpace = 1;
|
||
|
const preTagSpaceLength = 1; // If a space is present, we should ignore it
|
||
|
|
||
|
const firstLinePrefixLength = preTagSpaceLength;
|
||
|
const hasCaptionRegex = /^\s*<caption>(.*?)<\/caption>/u;
|
||
|
|
||
|
const escapeStringRegexp = str => {
|
||
|
return str.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
||
|
};
|
||
|
|
||
|
const countChars = (str, ch) => {
|
||
|
return (str.match(new RegExp(escapeStringRegexp(ch), 'gu')) || []).length;
|
||
|
};
|
||
|
|
||
|
const getRegexFromString = regexString => {
|
||
|
const match = regexString.match(/^\/(.*)\/([gimyus]*)$/u);
|
||
|
let flags = 'u';
|
||
|
let regex = regexString;
|
||
|
|
||
|
if (match) {
|
||
|
var _match = _slicedToArray(match, 3);
|
||
|
|
||
|
regex = _match[1];
|
||
|
flags = _match[2];
|
||
|
|
||
|
if (!flags) {
|
||
|
flags = 'u';
|
||
|
}
|
||
|
|
||
|
const uniqueFlags = [...new Set(flags)];
|
||
|
flags = uniqueFlags.join('');
|
||
|
}
|
||
|
|
||
|
return new RegExp(regex, flags);
|
||
|
};
|
||
|
|
||
|
var _default = (0, _iterateJsdoc.default)(({
|
||
|
report,
|
||
|
utils,
|
||
|
context,
|
||
|
globalState
|
||
|
}) => {
|
||
|
(0, _warnRemovedSettings.default)(context, 'check-examples');
|
||
|
const tagName = utils.getPreferredTagName({
|
||
|
tagName: 'example'
|
||
|
});
|
||
|
|
||
|
if (!utils.hasTag(tagName)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!globalState.has('checkExamples-matchingFileName')) {
|
||
|
globalState.set('checkExamples-matchingFileName', new Map());
|
||
|
}
|
||
|
|
||
|
const matchingFileNameMap = globalState.get('checkExamples-matchingFileName');
|
||
|
const options = context.options[0] || {};
|
||
|
let _options$exampleCodeR = options.exampleCodeRegex,
|
||
|
exampleCodeRegex = _options$exampleCodeR === void 0 ? null : _options$exampleCodeR,
|
||
|
_options$rejectExampl = options.rejectExampleCodeRegex,
|
||
|
rejectExampleCodeRegex = _options$rejectExampl === void 0 ? null : _options$rejectExampl;
|
||
|
const _options$noDefaultExa = options.noDefaultExampleRules,
|
||
|
noDefaultExampleRules = _options$noDefaultExa === void 0 ? false : _options$noDefaultExa,
|
||
|
_options$checkEslintr = options.checkEslintrc,
|
||
|
checkEslintrc = _options$checkEslintr === void 0 ? true : _options$checkEslintr,
|
||
|
_options$matchingFile = options.matchingFileName,
|
||
|
filename = _options$matchingFile === void 0 ? null : _options$matchingFile,
|
||
|
_options$paddedIndent = options.paddedIndent,
|
||
|
paddedIndent = _options$paddedIndent === void 0 ? 0 : _options$paddedIndent,
|
||
|
_options$baseConfig = options.baseConfig,
|
||
|
baseConfig = _options$baseConfig === void 0 ? {} : _options$baseConfig,
|
||
|
configFile = options.configFile,
|
||
|
_options$allowInlineC = options.allowInlineConfig,
|
||
|
allowInlineConfig = _options$allowInlineC === void 0 ? true : _options$allowInlineC,
|
||
|
_options$reportUnused = options.reportUnusedDisableDirectives,
|
||
|
reportUnusedDisableDirectives = _options$reportUnused === void 0 ? true : _options$reportUnused,
|
||
|
_options$captionRequi = options.captionRequired,
|
||
|
captionRequired = _options$captionRequi === void 0 ? false : _options$captionRequi;
|
||
|
let defaultFileName;
|
||
|
|
||
|
if (!filename) {
|
||
|
const jsFileName = context.getFilename();
|
||
|
|
||
|
if (typeof jsFileName === 'string' && jsFileName.includes('.')) {
|
||
|
defaultFileName = jsFileName.replace(/\..*?$/, '.md');
|
||
|
} else {
|
||
|
defaultFileName = 'dummy.md';
|
||
|
}
|
||
|
} // Make this configurable?
|
||
|
|
||
|
|
||
|
const rulePaths = [];
|
||
|
const rules = noDefaultExampleRules ? undefined : {
|
||
|
// "always" newline rule at end unlikely in sample code
|
||
|
'eol-last': 0,
|
||
|
// Wouldn't generally expect example paths to resolve relative to JS file
|
||
|
'import/no-unresolved': 0,
|
||
|
// Snippets likely too short to always include import/export info
|
||
|
'import/unambiguous': 0,
|
||
|
// Unlikely to have inadvertent debugging within examples
|
||
|
'no-console': 0,
|
||
|
// Often wish to start `@example` code after newline; also may use
|
||
|
// empty lines for spacing
|
||
|
'no-multiple-empty-lines': 0,
|
||
|
// Many variables in examples will be `undefined`
|
||
|
'no-undef': 0,
|
||
|
// Common to define variables for clarity without always using them
|
||
|
'no-unused-vars': 0,
|
||
|
// See import/no-unresolved
|
||
|
'node/no-missing-import': 0,
|
||
|
'node/no-missing-require': 0,
|
||
|
// Can generally look nicer to pad a little even if code imposes more stringency
|
||
|
'padded-blocks': 0
|
||
|
};
|
||
|
|
||
|
if (exampleCodeRegex) {
|
||
|
exampleCodeRegex = getRegexFromString(exampleCodeRegex);
|
||
|
}
|
||
|
|
||
|
if (rejectExampleCodeRegex) {
|
||
|
rejectExampleCodeRegex = getRegexFromString(rejectExampleCodeRegex);
|
||
|
}
|
||
|
|
||
|
utils.forEachPreferredTag('example', (tag, targetTagName) => {
|
||
|
let source = tag.description;
|
||
|
const match = source.match(hasCaptionRegex);
|
||
|
|
||
|
if (captionRequired && (!match || !match[1].trim())) {
|
||
|
report('Caption is expected for examples.', null, tag);
|
||
|
} // If we allow newlines in hasCaptionRegex, we should add to line count
|
||
|
|
||
|
|
||
|
source = source.replace(hasCaptionRegex, '');
|
||
|
|
||
|
if (exampleCodeRegex && !exampleCodeRegex.test(source) || rejectExampleCodeRegex && rejectExampleCodeRegex.test(source)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const sources = [];
|
||
|
|
||
|
if (exampleCodeRegex) {
|
||
|
let nonJSPrefacingCols = 0;
|
||
|
let nonJSPrefacingLines = 0;
|
||
|
let startingIndex = 0;
|
||
|
let lastStringCount = 0;
|
||
|
let exampleCode;
|
||
|
exampleCodeRegex.lastIndex = 0;
|
||
|
|
||
|
while ((exampleCode = exampleCodeRegex.exec(source)) !== null) {
|
||
|
const _exampleCode = exampleCode,
|
||
|
index = _exampleCode.index,
|
||
|
n0 = _exampleCode[0],
|
||
|
n1 = _exampleCode[1]; // Count anything preceding user regex match (can affect line numbering)
|
||
|
|
||
|
const preMatch = source.slice(startingIndex, index);
|
||
|
const preMatchLines = countChars(preMatch, '\n');
|
||
|
const colDelta = preMatchLines ? preMatch.slice(preMatch.lastIndexOf('\n') + 1).length : preMatch.length;
|
||
|
let nonJSPreface;
|
||
|
let nonJSPrefaceLineCount;
|
||
|
|
||
|
if (n1) {
|
||
|
const idx = n0.indexOf(n1);
|
||
|
nonJSPreface = n0.slice(0, idx);
|
||
|
nonJSPrefaceLineCount = countChars(nonJSPreface, '\n');
|
||
|
} else {
|
||
|
nonJSPreface = '';
|
||
|
nonJSPrefaceLineCount = 0;
|
||
|
}
|
||
|
|
||
|
nonJSPrefacingLines += lastStringCount + preMatchLines + nonJSPrefaceLineCount; // Ignore `preMatch` delta if newlines here
|
||
|
|
||
|
if (nonJSPrefaceLineCount) {
|
||
|
const charsInLastLine = nonJSPreface.slice(nonJSPreface.lastIndexOf('\n') + 1).length;
|
||
|
nonJSPrefacingCols += charsInLastLine;
|
||
|
} else {
|
||
|
nonJSPrefacingCols += colDelta + nonJSPreface.length;
|
||
|
}
|
||
|
|
||
|
const string = n1 || n0;
|
||
|
sources.push({
|
||
|
nonJSPrefacingCols,
|
||
|
nonJSPrefacingLines,
|
||
|
string
|
||
|
});
|
||
|
startingIndex = exampleCodeRegex.lastIndex;
|
||
|
lastStringCount = countChars(string, '\n');
|
||
|
|
||
|
if (!exampleCodeRegex.global) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
sources.push({
|
||
|
nonJSPrefacingCols: 0,
|
||
|
nonJSPrefacingLines: 0,
|
||
|
string: source
|
||
|
});
|
||
|
} // Todo: Make fixable
|
||
|
// Todo: Fix whitespace indent
|
||
|
|
||
|
|
||
|
const checkRules = function checkRules({
|
||
|
nonJSPrefacingCols,
|
||
|
nonJSPrefacingLines,
|
||
|
string
|
||
|
}) {
|
||
|
const cliConfig = {
|
||
|
allowInlineConfig,
|
||
|
baseConfig,
|
||
|
configFile,
|
||
|
reportUnusedDisableDirectives,
|
||
|
rulePaths,
|
||
|
rules,
|
||
|
useEslintrc: checkEslintrc
|
||
|
};
|
||
|
const cliConfigStr = JSON.stringify(cliConfig);
|
||
|
const src = paddedIndent ? string.replace(new RegExp(`(^|\n) {${paddedIndent}}(?!$)`, 'gu'), '\n') : string; // Programmatic ESLint API: https://eslint.org/docs/developer-guide/nodejs-api
|
||
|
|
||
|
const fileNameMapKey = filename ? 'a' + cliConfigStr + filename : 'b' + cliConfigStr + defaultFileName;
|
||
|
const file = filename || defaultFileName;
|
||
|
let cliFile;
|
||
|
|
||
|
if (matchingFileNameMap.has(fileNameMapKey)) {
|
||
|
cliFile = matchingFileNameMap.get(fileNameMapKey);
|
||
|
} else {
|
||
|
const cli = new _eslint.CLIEngine(cliConfig);
|
||
|
let config;
|
||
|
|
||
|
if (filename || checkEslintrc) {
|
||
|
config = cli.getConfigForFile(file);
|
||
|
} // We need a new instance to ensure that the rules that may only
|
||
|
// be available to `file` (if it has its own `.eslintrc`),
|
||
|
// will be defined.
|
||
|
|
||
|
|
||
|
cliFile = new _eslint.CLIEngine({
|
||
|
allowInlineConfig,
|
||
|
baseConfig: _objectSpread({}, baseConfig, {}, config),
|
||
|
configFile,
|
||
|
reportUnusedDisableDirectives,
|
||
|
rulePaths,
|
||
|
rules,
|
||
|
useEslintrc: false
|
||
|
});
|
||
|
matchingFileNameMap.set(fileNameMapKey, cliFile);
|
||
|
}
|
||
|
|
||
|
const _cliFile$executeOnTex = cliFile.executeOnText(src),
|
||
|
_cliFile$executeOnTex2 = _slicedToArray(_cliFile$executeOnTex.results, 1),
|
||
|
messages = _cliFile$executeOnTex2[0].messages; // NOTE: `tag.line` can be 0 if of form `/** @tag ... */`
|
||
|
|
||
|
|
||
|
const codeStartLine = tag.line + nonJSPrefacingLines;
|
||
|
const codeStartCol = likelyNestedJSDocIndentSpace;
|
||
|
messages.forEach(({
|
||
|
message,
|
||
|
line,
|
||
|
column,
|
||
|
severity,
|
||
|
ruleId
|
||
|
}) => {
|
||
|
const startLine = codeStartLine + line + zeroBasedLineIndexAdjust;
|
||
|
const startCol = codeStartCol + ( // This might not work for line 0, but line 0 is unlikely for examples
|
||
|
line <= 1 ? nonJSPrefacingCols + firstLinePrefixLength : preTagSpaceLength) + column;
|
||
|
report('@' + targetTagName + ' ' + (severity === 2 ? 'error' : 'warning') + (ruleId ? ' (' + ruleId + ')' : '') + ': ' + message, null, {
|
||
|
column: startCol,
|
||
|
line: startLine
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
|
||
|
sources.forEach(checkRules);
|
||
|
});
|
||
|
}, {
|
||
|
iterateAllJsdocs: true,
|
||
|
meta: {
|
||
|
schema: [{
|
||
|
additionalProperties: false,
|
||
|
properties: {
|
||
|
allowInlineConfig: {
|
||
|
default: true,
|
||
|
type: 'boolean'
|
||
|
},
|
||
|
baseConfig: {
|
||
|
type: 'object'
|
||
|
},
|
||
|
captionRequired: {
|
||
|
default: false,
|
||
|
type: 'boolean'
|
||
|
},
|
||
|
checkEslintrc: {
|
||
|
default: true,
|
||
|
type: 'boolean'
|
||
|
},
|
||
|
configFile: {
|
||
|
type: 'string'
|
||
|
},
|
||
|
exampleCodeRegex: {
|
||
|
type: 'string'
|
||
|
},
|
||
|
matchingFileName: {
|
||
|
type: 'string'
|
||
|
},
|
||
|
noDefaultExampleRules: {
|
||
|
default: false,
|
||
|
type: 'boolean'
|
||
|
},
|
||
|
paddedIndent: {
|
||
|
default: 0,
|
||
|
type: 'integer'
|
||
|
},
|
||
|
rejectExampleCodeRegex: {
|
||
|
type: 'string'
|
||
|
},
|
||
|
reportUnusedDisableDirectives: {
|
||
|
default: true,
|
||
|
type: 'boolean'
|
||
|
}
|
||
|
},
|
||
|
type: 'object'
|
||
|
}],
|
||
|
type: 'suggestion'
|
||
|
},
|
||
|
noTrim: true
|
||
|
});
|
||
|
|
||
|
exports.default = _default;
|
||
|
module.exports = exports.default;
|
||
|
//# sourceMappingURL=checkExamples.js.map
|