UNPKG

@softwareventures/maintain-project

Version:

Automatically create and maintain TypeScript projects with standard settings for Software Ventures Limited

77 lines 3.67 kB
import { EOL } from "os"; import { chain } from "@softwareventures/chain"; import { concat, first, map, mapFn, maximum, minimum, partitionWhile, partitionWhileFn, sortByDescendingFn, sortByFn, tail, unshiftFn } from "@softwareventures/array"; import { mapNullableFn } from "@softwareventures/nullable"; import { insert } from "../fs-stage/fs-stage.js"; import { readProjectText } from "../project/read-text.js"; import { textFile } from "../fs-stage/file.js"; import { chainAsyncResultsFn, toNullable } from "../result/result.js"; import { asyncExcludeNull, asyncMapFn, combineAsync } from "../collections/async-iterable.js"; export async function updateCopyrightYear(project) { const copyrightLineRegExp = /^\s*($|((Copyright|\(C\)|©)\s*)+.*\d{4})/iu; return chain(["LICENSE.md", "LICENSE.txt", "LICENSE"]) .map(mapFn(async (filename) => readProjectText(project, filename) .then(toNullable) .then(mapNullableFn(text => ({ filename, text }))))) .map(asyncExcludeNull) .map(asyncMapFn(({ filename, text }) => { const [titleLines, copyrightLines, followingLines] = chain(text) .map(license => license.split("\n")) .map(mapFn(line => line.replace(/\r$/u, ""))) .map(partitionWhileFn(line => line.match(copyrightLineRegExp) == null)) .map(([titleLines, followingLines]) => [ titleLines, ...partitionWhile(followingLines, line => Boolean(line.match(copyrightLineRegExp))) ]).value; const copyrights = chain(copyrightLines) .map(mapFn((text, index) => ({ index, text, years: map(text.match(/\d{4,}/gu) ?? [], year => parseInt(year, 10)) }))) .map(mapFn(({ index, text, years }) => ({ index, text, startYear: minimum(years), endYear: maximum(years) }))) .map(sortByDescendingFn(({ endYear }) => endYear ?? -Infinity)).value; const copyright = first(copyrights); const currentYear = project.license.year; if (copyright == null || (copyright.endYear ?? 0) >= currentYear) { return null; } const assignee = copyright.text .replace(/^\s*((Copyright|\(C\)|©)\s*)+/iu, "") .replace(/\d{4,}(\s*[-,]?\s*\d{4,})*/gu, "") .replace(/\s+/gu, " ") .trim(); if (assignee === "") { return null; } const updatedCopyright = { index: copyright.index, text: `Copyright ${copyright.startYear == null ? "" : `${copyright.startYear}-`}${currentYear} ${assignee}` }; const updatedCopyrightLines = chain(tail(copyrights)) .map(mapFn(({ index, text }) => ({ index, text }))) .map(unshiftFn(updatedCopyright)) .map(sortByFn(({ index }) => index)) .map(mapFn(({ text }) => text)).value; return { filename, text: concat([titleLines, updatedCopyrightLines, followingLines]).join(EOL) }; })) .map(asyncExcludeNull) .map(asyncMapFn(({ filename, text }) => ({ filename, file: textFile(text) }))) .map(asyncMapFn(({ filename, file }) => async (stage) => insert(stage, filename, file))) .map(combineAsync) .value.then(insertions => (insertions.length === 0 ? null : insertions)) .then(mapNullableFn(insertions => ({ type: "fs-stage-update", log: "docs(license): update copyright year", apply: chainAsyncResultsFn(insertions) }))); } //# sourceMappingURL=update-copyright-year.js.map