const mkdirp = require("mkdirp"); const usercssMeta = require("usercss-meta"); const fs = require("fs"); const path = require("path"); /****/ const inputFile = process.argv[1]; const outputDir = process.argv[2]; if (!fs.existsSync(inputFile)) { console.log("input does not exist"); process.exit(1); } if (!fs.existsSync(outputDir)) mkdirp.sync(outputDir); const css = fs.readFileSync(inputFile, "utf8"); const files = {}; const preprocessors = { default: true, uso: true, }; const usercssParser = usercssMeta.createParser({ mandatoryKeys: [], validateKey: { preprocessor: (state) => { const preprocessor = state.value ?? "default"; if (!preprocessors[preprocessor]) throw new usercssMeta.ParseError({ message: `Unsupported preprocessor: ${preprocessor}`, code: "unknownPreprocessor", args: [state.value], index: state.valueIndex, }); }, }, validateVar: { select: (state) => { if (state.varResult.options.every((o) => o.name !== state.value)) { throw new usercssMeta.ParseError({ code: "invalidSelectValueMismatch", index: state.valueIndex, }); } }, }, }); /****/ try { //parser won't parse \r const cssUnixEndings = css.replace(/\r/g, ""); const parsed = usercssParser.parse(cssUnixEndings); if (!parsed?.metadata || Object.keys(parsed.metadata).length == 0) { console.log("UserCSS file has no valid metadata."); process.exit(1); } if (parsed.errors.length > 0) { console.log("UserCSS parsed with errors:"); for (const error of parsed.errors) { console.log(error); } } const sections = cssUnixEndings.match(/@-moz-document(.*?){\n(.*?\n)}/gs); if (sections) { for (const index in sections) { const section = sections[index]; const content = section.match(/@-moz-document(.*?){\n(.*?\n)}/s)[2]; if (sections.length > 1) { files["section-" + index] = content; } else { files["base"] = content; } } } for (const key of Object.keys(parsed.metadata.vars)) { const setting = parsed.metadata.vars[key]; if (setting.type != "select") continue; const options = setting.options.filter((x) => x.value != ""); if (options.length > 1) { for (const option of options) { files[ key.replace("xmc_", "") + "/" + option.name.toLowerCase().replace(/ /g, "_") ] = option.value; } } else { files[key.replace("xmc_", "")] = options[0].value; } } } catch (err) { console.log("UserCSS parsing failed: " + err); process.exit(1); } /****/ try { for (const filePath of Object.keys(files)) { const contents = files[filePath]; if (filePath.indexOf("/") > -1) { const [subfolder, name] = filePath.split("/"); if (!fs.existsSync(path.join(outputDir, subfolder))) mkdirp.sync(path.join(outputDir, subfolder)); fs.writeFileSync( path.join(outputDir, subfolder, name + ".css"), contents ); } else { fs.writeFileSync(path.join(outputDir, name + ".css"), contents); } } } catch (err) { console.log("Failed to write files: " + err); process.exit(1); }