/** * Shared lib between rule and tests */ const _ = require("lodash"), fs = require("fs"), findRoot = require("find-root"), path = require("path"); const COULD_NOT_FIND = `Missing notice header`; const REPORT_AND_SKIP = `Found a header comment which did not have a notice header, skipping fix and reporting`; const OUTSIDE_TOLERANCE = `Found a header comment which was too different from the required notice header (similarity={{ similarity }})`; const DEFAULT_MESSAGE_CONFIG = { whenFailedToMatch: COULD_NOT_FIND, reportAndSkip: REPORT_AND_SKIP, whenOutsideTolerance: OUTSIDE_TOLERANCE }; const ESCAPE = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g; const YEAR_REGEXP = /20\d{2}/; const NON_MATCHING_HEADER_ACTIONS = ["prepend", "replace", "report"]; function escapeRegExp(str) { return String(str).replace(ESCAPE, "\\$&"); } function stringifyRegexp(regexp) { return regexp instanceof RegExp ? regexp.source : String(regexp); } function regexpizeTemplate({ template, varRegexps }) { const allRegexpVars = Object.assign({}, { YEAR: YEAR_REGEXP }, varRegexps); const allPatternVars = _.mapValues(allRegexpVars, stringifyRegexp); return new RegExp(_.template(escapeRegExp(template))(allPatternVars)); } function resolveTemplate({ templateFile, template, fileName }) { if (template) return template; //No template file, so move foward and disable --fix if (!templateFile) return null; //Naively look for the templateFile first if (fs.existsSync(templateFile)) { return fs.readFileSync(templateFile, "utf8"); } if (!fs.existsSync(fileName)) { throw new Error(`Could not find the file name ${fileName}. This is necessary to find the root`); } const root = findRoot(fileName); const rootTemplateFile = path.join(root, templateFile); if (fs.existsSync(rootTemplateFile)) { return fs.readFileSync(rootTemplateFile, "utf8"); } const absRootTemplateFile = path.resolve(rootTemplateFile); if (fs.existsSync(absRootTemplateFile)) { return fs.readFileSync(absRootTemplateFile, "utf8"); } throw new Error(`Can't find templateFile @ ${absRootTemplateFile}`); } function resolveOptions( { mustMatch, templateFile, template, templateVars, chars, onNonMatchingHeader, varRegexps, nonMatchingTolerance, messages }, fileName ) { onNonMatchingHeader = onNonMatchingHeader || "prepend"; templateVars = templateVars || {}; varRegexps = varRegexps || {}; chars = chars || 1000; nonMatchingTolerance = nonMatchingTolerance || null; messages = _.assign({}, DEFAULT_MESSAGE_CONFIG, messages || {}); let mustMatchTemplate = false; if (!mustMatch) { mustMatchTemplate = true; } else if (!(mustMatch instanceof RegExp)) { mustMatch = new RegExp(mustMatch); } template = resolveTemplate({ templateFile, template, fileName }); if(typeof template === 'string'){ template = template.replace(/\r\n/g, "\n"); } const YEAR = new Date().getFullYear(); const allVars = Object.assign({}, { YEAR }, templateVars); if (mustMatchTemplate && template) { //create mustMatch from varRegexps and template mustMatch = regexpizeTemplate({ template, varRegexps }); } else if (!template && mustMatchTemplate) { throw new Error("Either mustMatch, template, or templateFile must be set"); } const resolvedTemplate = _.template(template)(allVars).replace(/\r\n/g, "\n"); return { resolvedTemplate, mustMatch, chars, onNonMatchingHeader, nonMatchingTolerance, messages }; } function createFixer({ resolvedTemplate, hasHeaderComment, topNode, onNonMatchingHeader }) { if (!resolvedTemplate) { return undefined; } if (!hasHeaderComment || (hasHeaderComment && onNonMatchingHeader === "prepend")) { return fixer => fixer.insertTextBeforeRange([0, 0], resolvedTemplate); } if (hasHeaderComment && onNonMatchingHeader === "replace") { return fixer => fixer.replaceText(topNode, resolvedTemplate); } } module.exports = { createFixer, regexpizeTemplate, COULD_NOT_FIND, REPORT_AND_SKIP, resolveOptions };