UNPKG

add-dist-header

Version:

Prepend a one-line banner comment (with license notice) to distribution files

94 lines (92 loc) 4.38 kB
//! add-dist-header v1.4.4 ~~ https://github.com/center-key/add-dist-header ~~ MIT License import { isBinary } from 'istextorbinary'; import chalk from 'chalk'; import fs from 'fs'; import log from 'fancy-log'; import path from 'path'; import slash from 'slash'; const addDistHeader = { prepend(filename, options) { const defaults = { allFiles: false, dist: 'dist', extension: null, delimiter: '~~', replaceComment: true, setVersion: true, }; const settings = { ...defaults, ...options }; if (!filename) throw new Error('[add-dist-header] Must specify the "filename" option.'); const doctypeLine = /^<(!doctype|\?xml).*\n/i; const commentStyle = { js: { start: '//! ', end: '' }, ml: { start: '<!-- ', end: ' -->' }, other: { start: '/*! ', end: ' */' }, }; const firstLine = { js: /^(\/\/[^!].*|\/[*][^!].*[*]\/)\n/, ml: /^<!--.*-->\n/, other: /^\/[*][^!].*[*]\/\n/, }; const pkg = JSON.parse(fs.readFileSync('package.json', 'utf-8')); const inputFile = path.parse(filename); const fileExt = settings.extension ?? inputFile.ext; const jsStyle = /\.(js|ts|cjs|mjs)$/.test(fileExt); const mlStyle = /\.(html|htm|sgml|xml|php)$/.test(fileExt); const type = jsStyle ? 'js' : mlStyle ? 'ml' : 'other'; const isTextFile = !isBinary(filename); const input = fs.readFileSync(filename, 'utf-8').trimStart(); const normalizeEol = /\r/g; const normalizeEof = /\s*$(?!\n)/; const out1 = input.replace(normalizeEol, '').replace(normalizeEof, '\n'); const out2 = settings.replaceComment ? out1.replace(firstLine[type], '') : out1; const doctype = mlStyle && out2.match(doctypeLine)?.[0] || ''; const out3 = mlStyle && doctype ? out2.replace(doctype, '') : out2; const versionPattern = /{{package[.]version}}/g; const out4 = settings.setVersion ? out3.replace(versionPattern, pkg.version) : out3; const info = pkg.homepage ?? pkg.docs ?? pkg.repository; const unlicensed = !pkg.license || pkg.license === 'UNLICENSED'; const license = unlicensed ? 'All Rights Reserved' : `${pkg.license} License`; const delimiter = ' ' + settings.delimiter + ' '; const banner = [`${pkg.name} v${pkg.version}`, info, license].join(delimiter); const header = commentStyle[type].start + banner + commentStyle[type].end; const fixedDigits = { minimumFractionDigits: 2, maximumFractionDigits: 2 }; const distFolder = fs.mkdirSync(settings.dist, { recursive: true }) ?? settings.dist; const formatOptions = { dir: settings.dist, name: inputFile.name, ext: fileExt }; const outputPath = slash(path.format(formatOptions)); const isMinified = outputPath.includes('.min.') || out4.indexOf('\n') === out4.length - 1; const spacerLines = isMinified || mlStyle ? '\n' : '\n\n'; const leadingBlanks = /^\s*\n/; const final = doctype + header + spacerLines + out4.replace(leadingBlanks, ''); if (isTextFile) fs.writeFileSync(outputPath, final); else if (settings.allFiles) fs.copyFileSync(filename, outputPath); return { valid: isTextFile || settings.allFiles, text: isTextFile, dist: distFolder, header: isTextFile ? header : null, source: slash(filename), file: outputPath, length: isTextFile ? final.length : null, size: isTextFile ? (final.length / 1024).toLocaleString([], fixedDigits) + ' KB' : null, }; }, reporter(result, options) { const defaults = { quiet: false, }; const settings = { ...defaults, ...options }; const name = chalk.gray('add-dist-header'); const arrow = chalk.gray.bold('→'); const source = chalk.blue.bold(result.source); const target = chalk.magenta(result.file); const size = chalk.white('(' + (result.size || 'binary') + ')'); if (!settings.quiet && result.valid) log(name, source, arrow, target, size); return result; }, }; export { addDistHeader };