plugins_release_banner.js

/**
 * @file plugins/release/banner.js
 * @copyright Scott P Meesseman 2024
 * @author Scott Meesseman @spmeesseman
 *//** */

const WpwPlugin = require("../base");
const { extname } = require("@spmhome/cmn-utils");
const { apply, isObject } = require("@spmhome/type-utils");


/**
 * @augments WpwPlugin
 */
class WpwBannerPlugin extends WpwPlugin
{
    /**
     * @param {WpwPluginOptions} options Plugin options to be applied
     */
    constructor(options)
    {
        super(options);
        this.buildOptions = /** @type {WpwBuildOptionsPluginConfig<"banner">} */(this.buildOptions);
    }


	/**
     * @override
     * @param {WpwBuild} b
     */
	static create = (b) => WpwBannerPlugin.wrap.call(this, b, b.type === "app");


    /**
     * @override
     * @returns {WpwPluginTapOptions<any, void, false> | undefined}
     */
    onApply()
    {
        /** @type {WpwPluginTapOptions<any, void, false>} */
        const config =
        {
            addBannerToEntryAsset:
            {
                hook: "compilation",
                stage: "ADDITIONS",
                statsProperty: "banner",
                hookCompilation: "processAssets",
                // hookCompilation: "afterOptimizeAssets",
                callback: this.addBannerToEntryAsset.bind(this)
            }
        };

        return config;
    }


	/**
	 * @private
	 * @param {WebpackCompilationAssets} assets
	 */
    addBannerToEntryAsset = (assets) =>
    {
        const dt = new Date(), b = this.build, l = this.hookstart(),
              info = (/** @type {WebpackAssetInfo} */ info) => apply({ ...(info || {}) }, { banner: true }),
              author = (isObject(b.pkgJson.author) ? b.pkgJson.author.name : b.pkgJson.name);

        // const banner = (this.buildOptions.text || "Copyright \x00\xA9 #{COMPANY} #{DATE_STAMP_YEAR}")
        const banner = (this.buildOptions.text || "Copyright #{COMPANY} #{DATE_STAMP_YEAR}")
                       .replace(new RegExp("[#\\$]?\\{(?:DATE_STAMP_)?YEAR\\}", "g"), dt.getFullYear().toString())
                       .replace(new RegExp("[#\\$]?\\{(?:DATE_STAMP_)?MONTH\\}", "g"), (dt.getMonth() + 1).toString())
                       .replace(new RegExp("[#\\$]?\\{(?:DATE_STAMP_)?DAY\\}", "g"), (dt.getDay()).toString())
                       .replace(new RegExp("[#\\$]?{COMPANY\\}", "g"), b.wrapper.settings.project.company || "SPMHome")
                       .replace(new RegExp("[#\\$]?{AUTHOR\\}", "g"), author);

        Object.keys(assets).filter((f) => this.isOutputAsset(f, true) && !this._types_.isMediaExt(extname(f))).forEach((file) =>
        {
            l.write(`   add banner to '${file}'`, 1);
            this.compilation.updateAsset(file, (source) => this.addBannerToSource(file, banner, source), info.bind(this));
        });
        this.hookdone();
    };


    /**
     * @private
     * @param {string} file
     * @param {string} banner
     * @param {WebpackSource} sourceInfo
     * @returns {WebpackSource}
     */
    addBannerToSource(file, banner, sourceInfo)
    {
        const { source, map } = sourceInfo.sourceAndMap(),
              srcCode = `/* ${banner} */\n` + source.toString().trimStart().replace(/^.*?copyright.+?[\r\n]/i, "");
        return (map && this.build.options.devtool?.enabled) ?
               new this.build.wp.sources.SourceMapSource(srcCode, file, map, source) :
               new this.build.wp.sources.RawSource(srcCode);
    }
}


module.exports = WpwBannerPlugin.create;