UNPKG

eslint-plugin-pii

Version:

PII linting rules for ESLint

144 lines (127 loc) 4.09 kB
"use strict"; const escapeStringRegexp = require("escape-string-regexp"); const LINE_PATTERN = /[^\r\n\u2028\u2029]*(?:\r\n|[\r\n\u2028\u2029]|$)/gu; const DIRECTIVE_PATTERN = /^(eslint(?:-env|-enable|-disable(?:(?:-next)?-line)?)?|exported|globals?)(?:\s|$)/u; const LINE_COMMENT_PATTERN = /^eslint-disable-(next-)?line$/u; module.exports = { /** * Make the location ignoring `eslint-disable` comments. * * @param {object} location - The location to convert. * @returns {object} Converted location. */ toForceLocation(location) { return { start: { line: location.start.line, column: -1, }, end: location.end, }; }, /** * Calculate the location of the given rule in the given comment token. * * @param {Token} comment - The comment token to calculate. * @param {string|null} ruleId - The rule name to calculate. * @returns {object} The location of the given information. */ toRuleIdLocation(comment, ruleId) { if (ruleId == null) { return module.exports.toForceLocation(comment.loc); } const lines = comment.value.match(LINE_PATTERN); //eslint-disable-next-line require-unicode-regexp const ruleIdPattern = new RegExp( `([\\s,]|^)${escapeStringRegexp(ruleId)}(?:[\\s,]|$)` ); { const m = ruleIdPattern.exec(lines[0]); if (m != null) { const start = comment.loc.start; return { start: { line: start.line, column: 2 + start.column + m.index + m[1].length, }, end: { line: start.line, column: 2 + start.column + m.index + m[1].length + ruleId.length, }, }; } } for (let i = 1; i < lines.length; ++i) { const m = ruleIdPattern.exec(lines[i]); if (m != null) { const start = comment.loc.start; return { start: { line: start.line + i, column: m.index + m[1].length, }, end: { line: start.line + i, column: m.index + m[1].length + ruleId.length, }, }; } } /*istanbul ignore next : foolproof */ return comment.loc; }, /** * Checks `a` is less than `b` or `a` equals `b`. * * @param {{line: number, column: number}} a - A location to compare. * @param {{line: number, column: number}} b - Another location to compare. * @returns {boolean} `true` if `a` is less than `b` or `a` equals `b`. */ lte(a, b) { return a.line < b.line || (a.line === b.line && a.column <= b.column); }, /** * Parse the given comment token as a directive comment. * * @param {Token} comment - The comment token to parse. * @returns {{kind: string, value: string, description: string | null}|null} The parsed data of the given comment. If `null`, it is not a directive comment. */ parseDirectiveComment(comment) { const { text, description } = divideDirectiveComment(comment.value); const match = DIRECTIVE_PATTERN.exec(text); if (!match) { return null; } const directiveText = match[1]; const lineCommentSupported = LINE_COMMENT_PATTERN.test(directiveText); if (comment.type === "Line" && !lineCommentSupported) { return null; } if ( lineCommentSupported && comment.loc.start.line !== comment.loc.end.line ) { // disable-line comment should not span multiple lines. return null; } const directiveValue = text.slice(match.index + directiveText.length); return { kind: directiveText, value: directiveValue.trim(), description, }; }, }; /** * Divides and trims description text and directive comments. * @param {string} value The comment text to strip. * @returns {{text: string, description: string | null}} The stripped text. */ function divideDirectiveComment(value) { const divided = value.split(/\s-{2,}\s/u); const text = divided[0].trim(); return { text, description: divided.length > 1 ? divided[1].trim() : null, }; }