Koha/gulpfile.js
Koha Development Team d659526b5a
Bug 38664: Tidy the whole codebase
This commit is generated using:
  % perl misc/devel/tidy.pl
*within* ktd, to get the same version of perltidy than what will be used
by our CI (currently v20230309).

Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
2025-02-11 14:58:24 +01:00

570 lines
16 KiB
JavaScript

/* eslint-env node */
/* eslint no-console:"off" */
const { dest, parallel, series, src, watch } = require("gulp");
const child_process = require("child_process");
const fs = require("fs");
const os = require("os");
const path = require("path");
const util = require("util");
const stream = require("stream/promises");
const sass = require("gulp-sass")(require("sass"));
const tildeImporter = require("node-sass-tilde-importer");
const rtlcss = require("gulp-rtlcss");
const sourcemaps = require("gulp-sourcemaps");
const autoprefixer = require("gulp-autoprefixer");
const concatPo = require("gulp-concat-po");
const exec = require("gulp-exec");
const merge = require("merge-stream");
const through2 = require("through2");
const Vinyl = require("vinyl");
const args = require("minimist")(process.argv.slice(2), {
default: { "generate-pot": "always" },
});
const rename = require("gulp-rename");
const STAFF_CSS_BASE = "koha-tmpl/intranet-tmpl/prog/css";
const OPAC_CSS_BASE = "koha-tmpl/opac-tmpl/bootstrap/css";
var CSS_BASE = args.view == "opac" ? OPAC_CSS_BASE : STAFF_CSS_BASE;
var sassOptions = {
importer: tildeImporter,
includePaths: [__dirname + "/node_modules", __dirname + "/../node_modules"],
};
// CSS processing for development
function css(css_base) {
css_base = css_base || CSS_BASE;
var stream = src(css_base + "/src/**/*.scss", { sourcemaps: true });
if (args.view == "opac") {
stream = stream
.pipe(sass(sassOptions).on("error", sass.logError))
.pipe(autoprefixer())
.pipe(dest(css_base))
.pipe(rtlcss())
.pipe(
rename({
suffix: "-rtl",
})
) // Append "-rtl" to the filename.
.pipe(dest(css_base, { sourcemaps: "./maps" }));
} else {
stream = stream
.pipe(sass(sassOptions).on("error", sass.logError))
.pipe(autoprefixer())
.pipe(dest(css_base))
.pipe(rtlcss())
.pipe(
rename({
suffix: "-rtl",
})
) // Append "-rtl" to the filename.
.pipe(dest(css_base, { sourcemaps: "./maps" }));
}
return stream;
}
// CSS processing for production
function build(css_base) {
css_base = css_base || CSS_BASE;
sassOptions.outputStyle = "compressed";
var stream = src(css_base + "/src/**/*.scss")
.pipe(sass(sassOptions).on("error", sass.logError))
.pipe(autoprefixer())
.pipe(dest(css_base))
.pipe(rtlcss())
.pipe(
rename({
suffix: "-rtl",
})
) // Append "-rtl" to the filename.
.pipe(dest(css_base));
return stream;
}
function opac_css() {
return css(OPAC_CSS_BASE);
}
function staff_css() {
return css(STAFF_CSS_BASE);
}
const poTasks = {
"marc-MARC21": {
extract: po_extract_marc_marc21,
create: po_create_marc_marc21,
update: po_update_marc_marc21,
},
"marc-UNIMARC": {
extract: po_extract_marc_unimarc,
create: po_create_marc_unimarc,
update: po_update_marc_unimarc,
},
"staff-prog": {
extract: po_extract_staff,
create: po_create_staff,
update: po_update_staff,
},
"opac-bootstrap": {
extract: po_extract_opac,
create: po_create_opac,
update: po_update_opac,
},
pref: {
extract: po_extract_pref,
create: po_create_pref,
update: po_update_pref,
},
messages: {
extract: po_extract_messages,
create: po_create_messages,
update: po_update_messages,
},
"messages-js": {
extract: po_extract_messages_js,
create: po_create_messages_js,
update: po_update_messages_js,
},
installer: {
extract: po_extract_installer,
create: po_create_installer,
update: po_update_installer,
},
"installer-MARC21": {
extract: po_extract_installer_marc21,
create: po_create_installer_marc21,
update: po_update_installer_marc21,
},
"installer-UNIMARC": {
extract: po_extract_installer_unimarc,
create: po_create_installer_unimarc,
update: po_update_installer_unimarc,
},
};
function getPoTasks() {
let tasks = [];
let all_tasks = Object.keys(poTasks);
if (args.task) {
tasks = [args.task].flat(Infinity);
} else {
return all_tasks;
}
let invalid_tasks = tasks.filter(function (el) {
return all_tasks.indexOf(el) < 0;
});
if (invalid_tasks.length) {
console.error("Invalid task");
return [];
}
return tasks;
}
const poTypes = getPoTasks();
function po_extract_marc(type) {
return src(`koha-tmpl/*-tmpl/*/en/**/*${type}*`, {
read: false,
nocase: true,
})
.pipe(
xgettext(
"misc/translator/xgettext.pl --charset=UTF-8 -F",
`Koha-marc-${type}.pot`
)
)
.pipe(dest("misc/translator"));
}
function po_extract_marc_marc21() {
return po_extract_marc("MARC21");
}
function po_extract_marc_unimarc() {
return po_extract_marc("UNIMARC");
}
function po_extract_staff() {
const globs = [
"koha-tmpl/intranet-tmpl/prog/en/**/*.tt",
"koha-tmpl/intranet-tmpl/prog/en/**/*.inc",
"koha-tmpl/intranet-tmpl/prog/en/xslt/*.xsl",
"!koha-tmpl/intranet-tmpl/prog/en/**/*MARC21*",
"!koha-tmpl/intranet-tmpl/prog/en/**/*UNIMARC*",
"!koha-tmpl/intranet-tmpl/prog/en/**/*marc21*",
"!koha-tmpl/intranet-tmpl/prog/en/**/*unimarc*",
];
return src(globs, { read: false, nocase: true })
.pipe(
xgettext(
"misc/translator/xgettext.pl --charset=UTF-8 -F",
"Koha-staff-prog.pot"
)
)
.pipe(dest("misc/translator"));
}
function po_extract_opac() {
const globs = [
"koha-tmpl/opac-tmpl/bootstrap/en/**/*.tt",
"koha-tmpl/opac-tmpl/bootstrap/en/**/*.inc",
"koha-tmpl/opac-tmpl/bootstrap/en/xslt/*.xsl",
"!koha-tmpl/opac-tmpl/bootstrap/en/**/*MARC21*",
"!koha-tmpl/opac-tmpl/bootstrap/en/**/*UNIMARC*",
"!koha-tmpl/opac-tmpl/bootstrap/en/**/*marc21*",
"!koha-tmpl/opac-tmpl/bootstrap/en/**/*unimarc*",
];
return src(globs, { read: false, nocase: true })
.pipe(
xgettext(
"misc/translator/xgettext.pl --charset=UTF-8 -F",
"Koha-opac-bootstrap.pot"
)
)
.pipe(dest("misc/translator"));
}
const xgettext_options =
"--from-code=UTF-8 --package-name Koha " +
"--package-version= -k -k__ -k__x -k__n:1,2 -k__nx:1,2 -k__xn:1,2 " +
"-k__p:1c,2 -k__px:1c,2 -k__np:1c,2,3 -k__npx:1c,2,3 -kN__ " +
"-kN__n:1,2 -kN__p:1c,2 -kN__np:1c,2,3 " +
"-k -k$__ -k$__x -k$__n:1,2 -k$__nx:1,2 -k$__xn:1,2 " +
"--force-po";
function po_extract_messages_js() {
const globs = [
"koha-tmpl/intranet-tmpl/prog/js/vue/**/*.vue",
"koha-tmpl/intranet-tmpl/prog/js/**/*.js",
"koha-tmpl/opac-tmpl/bootstrap/js/**/*.js",
];
return src(globs, { read: false, nocase: true })
.pipe(
xgettext(
`xgettext -L JavaScript ${xgettext_options}`,
"Koha-messages-js.pot"
)
)
.pipe(dest("misc/translator"));
}
function po_extract_messages() {
const perlStream = src(["**/*.pl", "**/*.pm"], {
read: false,
nocase: true,
}).pipe(xgettext(`xgettext -L Perl ${xgettext_options}`, "Koha-perl.pot"));
const ttStream = src(
[
"koha-tmpl/intranet-tmpl/prog/en/**/*.tt",
"koha-tmpl/intranet-tmpl/prog/en/**/*.inc",
"koha-tmpl/opac-tmpl/bootstrap/en/**/*.tt",
"koha-tmpl/opac-tmpl/bootstrap/en/**/*.inc",
],
{ read: false, nocase: true }
).pipe(
xgettext(
"misc/translator/xgettext-tt2 --from-code=UTF-8",
"Koha-tt.pot"
)
);
const headers = {
"Project-Id-Version": "Koha",
"Content-Type": "text/plain; charset=UTF-8",
};
return merge(perlStream, ttStream)
.pipe(concatPo("Koha-messages.pot", { headers }))
.pipe(dest("misc/translator"));
}
function po_extract_pref() {
return src(
"koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/*.pref",
{ read: false }
)
.pipe(xgettext("misc/translator/xgettext-pref", "Koha-pref.pot"))
.pipe(dest("misc/translator"));
}
function po_extract_installer() {
const globs = [
"installer/data/mysql/en/mandatory/*.yml",
"installer/data/mysql/en/optional/*.yml",
];
return src(globs, { read: false, nocase: true })
.pipe(
xgettext("misc/translator/xgettext-installer", "Koha-installer.pot")
)
.pipe(dest("misc/translator"));
}
function po_extract_installer_marc(type) {
const globs = `installer/data/mysql/en/marcflavour/${type}/**/*.yml`;
return src(globs, { read: false, nocase: true })
.pipe(
xgettext(
"misc/translator/xgettext-installer",
`Koha-installer-${type}.pot`
)
)
.pipe(dest("misc/translator"));
}
function po_extract_installer_marc21() {
return po_extract_installer_marc("MARC21");
}
function po_extract_installer_unimarc() {
return po_extract_installer_marc("UNIMARC");
}
function po_create_type(type) {
const access = util.promisify(fs.access);
const exec = util.promisify(child_process.exec);
const pot = `misc/translator/Koha-${type}.pot`;
// Generate .pot only if it doesn't exist or --force-extract is given
const extract = () => stream.finished(poTasks[type].extract());
const p =
args["generate-pot"] === "always"
? extract()
: args["generate-pot"] === "auto"
? access(pot).catch(extract)
: args["generate-pot"] === "never"
? Promise.resolve(0)
: Promise.reject(
new Error(
"Invalid value for option --generate-pot: " +
args["generate-pot"]
)
);
return p.then(function () {
const languages = getLanguages();
const promises = [];
for (const language of languages) {
const locale = language
.split("-")
.filter(s => s.length !== 4)
.join("_");
const po = `misc/translator/po/${language}-${type}.po`;
const promise = access(po).catch(() =>
exec(`msginit -o ${po} -i ${pot} -l ${locale} --no-translator`)
);
promises.push(promise);
}
return Promise.all(promises);
});
}
function po_create_marc_marc21() {
return po_create_type("marc-MARC21");
}
function po_create_marc_unimarc() {
return po_create_type("marc-UNIMARC");
}
function po_create_staff() {
return po_create_type("staff-prog");
}
function po_create_opac() {
return po_create_type("opac-bootstrap");
}
function po_create_pref() {
return po_create_type("pref");
}
function po_create_messages() {
return po_create_type("messages");
}
function po_create_messages_js() {
return po_create_type("messages-js");
}
function po_create_installer() {
return po_create_type("installer");
}
function po_create_installer_marc21() {
return po_create_type("installer-MARC21");
}
function po_create_installer_unimarc() {
return po_create_type("installer-UNIMARC");
}
function po_update_type(type) {
const access = util.promisify(fs.access);
const exec = util.promisify(child_process.exec);
const pot = `misc/translator/Koha-${type}.pot`;
// Generate .pot only if it doesn't exist or --force-extract is given
const extract = () => stream.finished(poTasks[type].extract());
const p =
args["generate-pot"] === "always"
? extract()
: args["generate-pot"] === "auto"
? access(pot).catch(extract)
: args["generate-pot"] === "never"
? Promise.resolve(0)
: Promise.reject(
new Error(
"Invalid value for option --generate-pot: " +
args["generate-pot"]
)
);
return p.then(function () {
const languages = getLanguages();
const promises = [];
for (const language of languages) {
const po = `misc/translator/po/${language}-${type}.po`;
promises.push(
exec(
`msgmerge --backup=off --no-wrap --quiet -F --update ${po} ${pot}`
)
);
}
return Promise.all(promises);
});
}
function po_update_marc_marc21() {
return po_update_type("marc-MARC21");
}
function po_update_marc_unimarc() {
return po_update_type("marc-UNIMARC");
}
function po_update_staff() {
return po_update_type("staff-prog");
}
function po_update_opac() {
return po_update_type("opac-bootstrap");
}
function po_update_pref() {
return po_update_type("pref");
}
function po_update_messages() {
return po_update_type("messages");
}
function po_update_messages_js() {
return po_update_type("messages-js");
}
function po_update_installer() {
return po_update_type("installer");
}
function po_update_installer_marc21() {
return po_update_type("installer-MARC21");
}
function po_update_installer_unimarc() {
return po_update_type("installer-UNIMARC");
}
/**
* Gulp plugin that executes xgettext-like command `cmd` on all files given as
* input, and then outputs the result as a POT file named `filename`.
* `cmd` should accept -o and -f options
*/
function xgettext(cmd, filename) {
const filenames = [];
function transform(file, encoding, callback) {
filenames.push(path.relative(file.cwd, file.path));
callback();
}
function flush(callback) {
fs.mkdtemp(path.join(os.tmpdir(), "koha-"), (err, folder) => {
const outputFilename = path.join(folder, filename);
const filesFilename = path.join(folder, "files");
fs.writeFile(filesFilename, filenames.join(os.EOL), err => {
if (err) return callback(err);
const command = `${cmd} -o ${outputFilename} -f ${filesFilename}`;
child_process.exec(command, err => {
if (err) return callback(err);
fs.readFile(outputFilename, (err, data) => {
if (err) return callback(err);
const file = new Vinyl();
file.path = path.join(file.base, filename);
file.contents = data;
callback(null, file);
fs.rmSync(folder, { recursive: true });
});
});
});
});
}
return through2.obj(transform, flush);
}
/**
* Return languages selected for PO-related tasks
*
* This can be either languages given on command-line with --lang option, or
* all the languages found in misc/translator/po otherwise
*/
function getLanguages() {
if (Array.isArray(args.lang)) {
return args.lang;
}
if (args.lang) {
return [args.lang];
}
const filenames = fs
.readdirSync("misc/translator/po/")
.filter(filename => filename.endsWith("-installer.po"))
.filter(filename => !filename.startsWith("."));
const re = new RegExp("-installer.po");
languages = filenames.map(filename => filename.replace(re, ""));
return Array.from(new Set(languages));
}
exports.build = function (next) {
build();
next();
};
exports.css = function (next) {
css();
next();
};
exports.opac_css = opac_css;
exports.staff_css = staff_css;
exports.watch = function () {
watch(OPAC_CSS_BASE + "/src/**/*.scss", series("opac_css"));
watch(STAFF_CSS_BASE + "/src/**/*.scss", series("staff_css"));
};
if (args["_"][0].match("po:") && !fs.existsSync("misc/translator/po")) {
console.log(
"misc/translator/po does not exist. You should clone koha-l10n there. See https://wiki.koha-community.org/wiki/Translation_files for more details."
);
process.exit(1);
}
exports["po:create"] = parallel(...poTypes.map(type => poTasks[type].create));
exports["po:update"] = parallel(...poTypes.map(type => poTasks[type].update));
exports["po:extract"] = parallel(...poTypes.map(type => poTasks[type].extract));