/** * @fileoverview An eslint rule that checks the top of files and --fix them too! * @author Nick Deis */ "use strict"; const fs = require("fs"), _ = require("lodash"), utils = require("./utils"), metriclcs = require("metric-lcs"); const { regexpizeTemplate, resolveOptions, createFixer } = utils; module.exports = { rules: { notice: { meta: { docs: { description: "An eslint rule that checks the top of files and --fix them too!", category: "Stylistic Issues" }, fixable: "code" }, create(context) { const { resolvedTemplate, mustMatch, chars, onNonMatchingHeader, nonMatchingTolerance, messages } = resolveOptions(context.options[0], context.getFilename()); const sourceCode = context.getSourceCode(); const text = sourceCode.getText().substring(0, chars); const firstComment = sourceCode.getAllComments()[0]; return { Program(node) { let topNode; let hasHeaderComment = false; if (!firstComment) { topNode = node; } else if (firstComment.loc.start.line <= node.loc.start.line) { hasHeaderComment = true; topNode = firstComment; } else { topNode = node; } let headerMatches = false; if (!headerMatches && mustMatch && text) { headerMatches = !!(String(text).replace(/\r\n/g, "\n")).match(mustMatch); //If the header matches, return early if (headerMatches) return; } //If chars doesn't match, a header comment/template exists and nonMatchingTolerance is set, try calculating string distance if (!headerMatches && hasHeaderComment && resolvedTemplate && _.isNumber(nonMatchingTolerance)) { const dist = metriclcs(resolvedTemplate, firstComment.value); //Return early, mark as true for future work if needed if (nonMatchingTolerance <= dist) { headerMatches = true; return; } else { const fix = createFixer({ resolvedTemplate, hasHeaderComment, topNode, onNonMatchingHeader }); const report = { node, message: messages.whenOutsideTolerance, fix, data: { similarity: Math.round(dist * 1000) / 1000 } }; context.report(report); return; } } //report and skip if (hasHeaderComment && onNonMatchingHeader === "report" && !headerMatches) { const report = { node, message: messages.reportAndSkip }; context.report(report); return; } //Select fixer based off onNonMatchingHeader const fix = createFixer({ resolvedTemplate, hasHeaderComment, topNode, onNonMatchingHeader }); if (!headerMatches) { const report = { node, message: messages.whenFailedToMatch, fix }; context.report(report); return; } } }; } } } };