"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
const pluginutils_1 = require("@rollup/pluginutils");
const fs_1 = require("fs");
const path_1 = __importDefault(require("path"));
const compiler_1 = require("svelte/compiler");
const svgo_1 = require("svgo");
const { readFile } = fs_1.promises;
function isCompileError(err) {
    return err instanceof Error && 'code' in err && 'frame' in err;
}
const svgRegex = /<svg(.*?)>(.*)<\/svg>/s;
function color(start, end = '\u001b[0m') {
    return (text) => `${start}${text}${end}`;
}
// const green = color('\u001b[32m')
const yellow = color('\u001b[33m');
const blue = color('\u001b[34m');
function toComponent(svg) {
    const parts = svgRegex.exec(svg);
    if (!parts) {
        throw new Error('Invalid SVG');
    }
    const [, attributes, content] = parts;
    // JSON.stringify escapes any characters that need to be escaped and
    // surrounds `content` with double quotes
    const contentStrLiteral = JSON.stringify(content);
    const component = `<svg ${attributes} {...$$props}>{@html ${contentStrLiteral}}</svg>`;
    return {
        attributes,
        content,
        component,
    };
}
function isSvgoOptimizeError(obj) {
    return typeof obj === 'object' && obj !== null && !('data' in obj);
}
function hasCdata(code) {
    return code.includes('<![CDATA[');
}
function isDevelopmentMode() {
    return process.env['NODE_ENV'] === 'development';
}
function readSvg(options = { type: 'component' }) {
    const resvg = /\.svg(?:\?(src|url|component|dataurl)(=(base64|(un)?enc))?)?$/;
    if (options.includePaths) {
        // Normalize the include paths prefixes ahead of time
        options.includePaths = options.includePaths.map((pattern) => {
            const filepath = path_1.default.resolve(path_1.default.normalize(pattern));
            return (0, pluginutils_1.normalizePath)(filepath);
        });
    }
    const isType = (str, type) => {
        return (!str && options.type === type) || str === type;
    };
    const handlePath = (id) => {
        if (!resvg.test(id)) {
            return false;
        }
        if (options.includePaths) {
            return options.includePaths.some((pattern) => {
                return id.startsWith(pattern);
            });
        }
        return true;
    };
    const hook = options.preCompileHook;
    /**
     * This contains URLs of generated static assets, that is SVGs that are
     * imported as URLs, so we can optimize them before they are written to disk.
     */
    const optmizeUrls = new Set();
    const plugin = {
        name: 'sveltekit-svg',
        // NOTE: This will only run in production mode
        renderChunk(_code, chunk) {
            var _a;
            // Check if this chunk is an SVG imported as an URL...
            const mods = chunk.moduleIds.filter((id) => { var _a; return (_a = this.getModuleInfo(id)) === null || _a === void 0 ? void 0 : _a.meta['isSvgUrl']; });
            // ...if so, we should have 1 module and one importAssets...
            if (mods.length !== 1 || ((_a = chunk.viteMetadata) === null || _a === void 0 ? void 0 : _a.importedAssets.size) !== 1) {
                return undefined;
            }
            // ...and store the output filename in the lookup so we can verify in
            //    `generateBundle()` that the SVG should be optimized before written
            //    to disk
            const outputId = Array.from(chunk.viteMetadata.importedAssets)[0];
            if (outputId) {
                optmizeUrls.add(outputId);
            }
        },
        // NOTE: This will only run in production mode
        async generateBundle(_options, bundle) {
            // Resolve assets that should be SVGO optimized before written to disk.
            // Such assets should exist in the `optimizeUrl` lookup data structure.
            for (const [k, v] of Object.entries(bundle)) {
                if (!optmizeUrls.has(k) || v.type !== 'asset') {
                    continue;
                }
                const optSvg = (0, svgo_1.optimize)(v.source.toString(), options.svgoOptions || undefined);
                v.source = Buffer.from(optSvg.data);
            }
        },
        async transform(source, id, transformOptions) {
            var _a, _b;
            if (!handlePath(id)) {
                return undefined;
            }
            const match = id.match(resvg);
            if (!match) {
                return undefined;
            }
            const isBuild = (_a = transformOptions === null || transformOptions === void 0 ? void 0 : transformOptions.ssr) !== null && _a !== void 0 ? _a : false;
            const type = match[1];
            if (isType(type, 'url')) {
                if (isDevelopmentMode()) {
                    const msg = `"url" imports are not optimized in development mode`;
                    this.info({
                        id,
                        message: msg,
                    });
                }
                return { code: source, map: null, meta: { isSvgUrl: true } };
            }
            let svgo = options.svgoOptions;
            let isSvgoDataUri = false;
            if (svgo && typeof svgo === 'object') {
                if (svgo.datauri) {
                    isSvgoDataUri = true;
                }
            }
            if (isSvgoDataUri && type === 'component') {
                console.warn(`%s Type %O can not be imported as a Svelte component ` +
                    `since "datauri" is set in vite.config`, yellow('[WARNING]'), id);
            }
            else if (type === 'dataurl') {
                const t = (_b = match[3]) !== null && _b !== void 0 ? _b : 'base64';
                if (!svgo) {
                    svgo = {};
                }
                svgo.datauri = t;
                isSvgoDataUri = true;
            }
            try {
                const filename = id.replace(/\.svg(\?.*)$/, '.svg');
                const data = (await readFile(filename)).toString('utf-8');
                const opt = svgo !== false
                    ? (0, svgo_1.optimize)(data, { path: filename, ...svgo })
                    : { data };
                if (isSvgoOptimizeError(opt)) {
                    console.error('Got optimize error from SVGO:', opt);
                    return undefined;
                }
                if (isType(type, 'src') || isSvgoDataUri) {
                    return {
                        code: `\nexport default \`${opt.data}\`;`,
                        map: null,
                    };
                }
                const comp = toComponent(opt.data);
                opt.data = hook ? hook(opt.data, comp) : comp.component;
                const { js } = (0, compiler_1.compile)(opt.data, {
                    css: 'none',
                    filename: id,
                    hydratable: !isBuild,
                    namespace: 'svg',
                    generate: isBuild ? 'ssr' : 'dom',
                });
                return js;
            }
            catch (err) {
                if (isCompileError(err) && hasCdata(err.frame)) {
                    const msg = `\n%s The SVG file %O contains a %s section which is not ` +
                        `supported by Svelte. To make this SVG work with the %s ` +
                        `plugin, you need to remove all %s sections from the SVG.\n`;
                    console.warn(msg, yellow('[WARNING]'), id, blue('<![CDATA[...]]>'), blue('@poppanator/sveltekit-svg'), blue('<![CDATA[...]]>'));
                }
                else {
                    console.error('Failed reading SVG "%s": %s', id, err.message, err);
                }
                return undefined;
            }
        },
    };
    if (isDevelopmentMode()) {
        delete plugin.renderChunk;
        delete plugin.generateBundle;
    }
    return plugin;
}
module.exports = readSvg;
