WLED/tools/cdata.js
2020-05-17 21:14:56 +03:00

329 lines
7.8 KiB
JavaScript

/**
* Writes compressed C arrays of data files (web interface)
* How to use it?
*
* 1) Install Node 11+ and npm
* 2) npm install
* 3) npm run build
*
* If you change data folder often, you can run it in monitoring mode (it will recompile and update *.h on every file change)
*
* > npm run dev
*
* How it works?
*
* It uses NodeJS packages to inline, minify and GZIP files. See writeHtmlGzipped and writeChunks invocations at the bottom of the page.
*/
const fs = require("fs");
/**
*
*/
function hexdump(buffer) {
let lines = [];
for (let i = 0; i < buffer.length; i += 16) {
let block = buffer.slice(i, i + 16); // cut buffer into blocks of 16
let hexArray = [];
for (let value of block) {
hexArray.push("0x" + value.toString(16).padStart(2, "0"));
}
let hexString = hexArray.join(", ");
let line = ` ${hexString}`;
lines.push(line);
}
return lines.join(",\n");
}
const inliner = require("inliner");
const zlib = require("zlib");
function writeHtmlGzipped(sourceFile, resultFile) {
console.info("Reading " + sourceFile);
new inliner(sourceFile, function(error, html) {
console.info("Inlined " + html.length + " characters");
if (error) {
console.warn(error);
throw error;
}
zlib.gzip(html, function(error, result) {
if (error) {
console.warn(error);
throw error;
}
console.info("Compressed " + result.length + " bytes");
const array = hexdump(result);
const src = `
// Autogenerated from ${sourceFile}, do not edit!!
const uint16_t PAGE_index_L = ${result.length};
const uint8_t PAGE_index[] PROGMEM = {
${array}
};
`;
console.info("Writing " + resultFile);
fs.writeFileSync(resultFile, src);
});
});
}
const CleanCSS = require("clean-css");
const MinifyHTML = require("html-minifier").minify;
function filter(str, type) {
if (type === undefined) {
return str;
} else if (type == "css-minify") {
return new CleanCSS({}).minify(str).styles;
} else if (type == "html-minify") {
return MinifyHTML(str, {
collapseWhitespace: true,
maxLineLength: 80,
minifyCSS: true,
minifyJS: true,
continueOnParseError: false
});
} else {
console.warn("Unknown filter: " + type);
return str;
}
}
function specToChunk(srcDir, s) {
if (s.method == "plaintext") {
const buf = fs.readFileSync(srcDir + "/" + s.file);
const str = buf.toString("ascii");
const chunk = `
// Autogenerated from ${srcDir}/${s.file}, do not edit!!
const char ${s.name}[] PROGMEM = R"${s.prepend || ""}${filter(
str,
s.filter
)}${s.append || ""}";
`;
return s.mangle ? s.mangle(chunk) : chunk;
} else if (s.method == "binary") {
const buf = fs.readFileSync(srcDir + "/" + s.file);
const result = hexdump(buf);
const chunk = `
// Autogenerated from ${srcDir}/${s.file}, do not edit!!
const uint16_t ${s.name}_length = ${result.length};
const uint8_t ${s.name}[] PROGMEM = {
${result}
};
`;
return s.mangle ? s.mangle(chunk) : chunk;
} else {
console.warn("Unknown method: " + s.method);
return undefined;
}
}
function writeChunks(srcDir, specs, resultFile) {
let src = "";
specs.forEach(s => {
try {
console.info("Reading " + srcDir + "/" + s.file + " as " + s.name);
src += specToChunk(srcDir, s);
} catch (e) {
console.warn(
"Failed " + s.name + " from " + srcDir + "/" + s.file,
e.message.length > 60 ? e.message.substring(0, 60) : e.message
);
}
});
console.info("Writing " + src.length + " characters into " + resultFile);
fs.writeFileSync(resultFile, src);
}
writeHtmlGzipped("wled00/data/index.htm", "wled00/html_ui.h");
writeChunks(
"wled00/data",
[
{
file: "style.css",
name: "PAGE_settingsCss",
prepend: "=====(<style>",
append: "</style>)=====",
method: "plaintext",
filter: "css-minify"
},
{
file: "settings.htm",
name: "PAGE_settings",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify"
},
{
file: "settings_wifi.htm",
name: "PAGE_settings_wifi",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: str =>
str
.replace(/\<link rel="stylesheet".*\>/gms, "")
.replace(/\<style\>.*\<\/style\>/gms, "%CSS%%SCSS%")
},
{
file: "settings_leds.htm",
name: "PAGE_settings_leds",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: str =>
str
.replace(/\<link rel="stylesheet".*\>/gms, "")
.replace(/\<style\>.*\<\/style\>/gms, "%CSS%%SCSS%")
},
{
file: "settings_dmx.htm",
name: "PAGE_settings_dmx",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: str => {
const nocss = str
.replace(/\<link rel="stylesheet".*\>/gms, "")
.replace(/\<style\>.*\<\/style\>/gms, "%CSS%%SCSS%");
return `
#ifdef WLED_ENABLE_DMX
${nocss}
#else
const char PAGE_settings_dmx[] PROGMEM = R"=====()=====";
#endif
`;
}
},
{
file: "settings_ui.htm",
name: "PAGE_settings_ui",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: str =>
str
.replace(/\<link rel="stylesheet".*\>/gms, "")
.replace(/\<style\>.*\<\/style\>/gms, "%CSS%%SCSS%")
},
{
file: "settings_sync.htm",
name: "PAGE_settings_sync",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: str =>
str
.replace(/\<link rel="stylesheet".*\>/gms, "")
.replace(/\<style\>.*\<\/style\>/gms, "%CSS%%SCSS%")
},
{
file: "settings_time.htm",
name: "PAGE_settings_time",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: str =>
str
.replace(/\<link rel="stylesheet".*\>/gms, "")
.replace(/\<style\>.*\<\/style\>/gms, "%CSS%%SCSS%")
},
{
file: "settings_sec.htm",
name: "PAGE_settings_sec",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: str =>
str
.replace(/\<link rel="stylesheet".*\>/gms, "")
.replace(/\<style\>.*\<\/style\>/gms, "%CSS%%SCSS%")
}
],
"wled00/html_settings.h"
);
writeChunks(
"wled00/data",
[
{
file: "usermod.htm",
name: "PAGE_usermod",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify"
},
{
file: "msg.htm",
name: "PAGE_msg",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify"
},
{
file: "dmxmap.htm",
name: "PAGE_dmxmap",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: str => `
#ifdef WLED_ENABLE_DMX
${str}
#else
const char PAGE_dmxmap[] PROGMEM = R"=====()=====";
#endif
`
},
{
file: "update.htm",
name: "PAGE_update",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify"
},
{
file: "welcome.htm",
name: "PAGE_welcome",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify"
},
{
file: "liveview.htm",
name: "PAGE_liveview",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify"
},
{
file: "favicon.ico",
name: "favicon",
method: "binary"
}
],
"wled00/html_other.h"
);