File size: 5,350 Bytes
1f5f1cc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
const Handlebars = require("handlebars");
const fs = require("fs");

const COLOR_KEYS = ["color", "bgColor", "fillcolor"];
const FRAGMENTS_PATH = "src/fragments";

// Transform the color names into colors defined in colors.mjs
const transformDataColors = async (data, path) => {
    const {getNamedColor} = await import('./src/colors.mjs');
    // if not json file, return
    if (!path.endsWith(".json")) {
        return data;
    }
    const parsedData = JSON.parse(data);
    // Change the color of the data
    const deepIterateAndSetColor = (key, val) => {
        if (val === null) {
            return null;
        }
        if (val == undefined) {
            return undefined;
        }
        if (Array.isArray(val)) {
            return val.map(item => deepIterateAndSetColor(key, item));
        }
        if (typeof val === "object") {
            return Object.entries(val).reduce((newObj, [key, value]) => {
                newObj[key] = deepIterateAndSetColor(key, value);
                return newObj;
            }, {});
        }
        if (COLOR_KEYS.includes(key)) {
            const [colorName, opacity, ...rest] = val.trim().split(/\s+/);
            const floatOpacity = parseFloat(opacity);
            const newColor = getNamedColor(colorName, floatOpacity);
            if (newColor !== undefined && rest.length === 0 && !isNaN(floatOpacity)) {
                console.log(`key: ${key} in file ${path} changed from ${val} to ${newColor}`);
                return newColor;
            } else {
                return val;
            }
        }
        return val;
    };
    return JSON.stringify(deepIterateAndSetColor(undefined, parsedData))
};


// Load the fragments from the fragments directory and caches it
const loadFragmentsMap = (() => {
    let cachedFragments = null;
    return async () => {
        if (cachedFragments === null) {
            cachedFragments = {};
            const walkDir = (dir, basePath = '') => {
                const files = fs.readdirSync(dir);
                files.forEach(file => {
                    const filePath = path.join(dir, file);
                    const relativePath = path.join(basePath, file);
                    if (fs.statSync(filePath).isDirectory()) {
                        walkDir(filePath, relativePath);
                    } else {
                        const dottedPath = relativePath.replace(/\\/g, '-').replace(/\//g, '-').replace(/\./g, '-');
                        cachedFragments[dottedPath] = fs.readFileSync(filePath, "utf8");
                    }
                });
            };
            walkDir(FRAGMENTS_PATH);
        }
        return cachedFragments;
    };
})();


const transformHandlebars = async (data, path) => {
    const fragments = await loadFragmentsMap();
    console.log(`Available fragments: ${Object.keys(fragments).join(', ')}`);
    // Load the template file
    const template = Handlebars.compile(data.toString('utf8'));
    const html = template(fragments);
    return html;
};

module.exports = {
    entry: {
        distill: "./src/distill.js",
        main: "./src/index.js",
    },
    output: {
        filename: "[name].bundle.js", // The output file
        path: path.resolve(__dirname, "dist"), // Output directory
    },
    module: {
        rules: [
            // { test: /\.css$/, use: ["style-loader", "css-loader"] },
            {
                test: /\.(js|mjs)$/,
                exclude: /node_modules/,
                use: {
                    loader: "babel-loader",
                    options: {
                        presets: ["@babel/preset-env"],
                    },
                },
            },
        ],
    },
    plugins: [
        new CleanWebpackPlugin(),
        new CopyPlugin({
            patterns: [
                {
                    from: "assets",
                    to: "assets",
                    transform: transformDataColors,
                },
                { from: "src/style.css", to: "style.css" },
                { from: "src/bibliography.bib", to: "bibliography.bib" },
                { 
                    from: "src/**/*.html.handlebars", 
                    to: ({context, absoluteFilename}) => {
                        const contextWithSrc = `${context}/src`;
                        const relativePath = absoluteFilename.replace(contextWithSrc, '').replace(/^\//, '');
                        const htmlPath = relativePath.replace(/\.handlebars$/, '');
                        return htmlPath;
                    },
                    transform: transformHandlebars, 
                    noErrorOnMissing: true
                },
            ],
        }),
    ],
    devtool: process.env.NODE_ENV === 'production' ? 'source-map' : 'eval-source-map',
    devServer: {
        static: "./dist", // Serve files from the 'dist' directory
        open: process.env.NODE_ENV !== 'production', // Automatically open the browser unless in production
        hot: process.env.NODE_ENV !== 'production', // Enable hot module replacement unless in production
    },
    mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
};

console.log(process.env.NODE_ENV)