2021-06-26 22:02:00 +02:00
|
|
|
// SPDX-FileCopyrightText: 2021 Johannes Loher
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
2021-03-17 12:15:25 +01:00
|
|
|
const { rollup } = require("rollup");
|
|
|
|
const argv = require("yargs").argv;
|
|
|
|
const chalk = require("chalk");
|
2021-01-06 01:31:23 +01:00
|
|
|
const fs = require("fs-extra");
|
2021-03-17 12:15:25 +01:00
|
|
|
const gulp = require("gulp");
|
2021-01-06 01:31:23 +01:00
|
|
|
const path = require("path");
|
2021-03-17 12:15:25 +01:00
|
|
|
const rollupConfig = require("./rollup.config");
|
|
|
|
const semver = require("semver");
|
2021-06-27 00:54:04 +02:00
|
|
|
const sass = require("gulp-sass")(require("sass"));
|
2021-09-21 01:12:17 +02:00
|
|
|
const Datastore = require("@seald-io/nedb");
|
|
|
|
const { Transform } = require("stream");
|
2021-01-06 01:31:23 +01:00
|
|
|
|
2021-03-17 12:15:25 +01:00
|
|
|
/********************/
|
|
|
|
/* CONFIGURATION */
|
|
|
|
/********************/
|
2021-01-06 01:31:23 +01:00
|
|
|
|
2021-03-17 12:15:25 +01:00
|
|
|
const name = path.basename(path.resolve("."));
|
|
|
|
const sourceDirectory = "./src";
|
|
|
|
const distDirectory = "./dist";
|
|
|
|
const stylesDirectory = path.join(sourceDirectory, "scss");
|
2021-09-21 01:12:17 +02:00
|
|
|
const packsDirectory = path.join(sourceDirectory, "packs");
|
2021-03-17 12:15:25 +01:00
|
|
|
const stylesExtension = ".scss";
|
|
|
|
const sourceFileExtension = ".ts";
|
2021-09-21 01:12:17 +02:00
|
|
|
const staticFiles = ["assets", "fonts", "lang", "templates", "system.json", "template.json"];
|
2021-09-14 11:16:43 +02:00
|
|
|
const getDownloadURL = (version) => `https://git.f3l.de/dungeonslayers/ds4/-/releases/${version}/downloads/ds4.zip`;
|
2021-09-17 19:46:36 +02:00
|
|
|
const getChangelogURL = (version) => `https://git.f3l.de/dungeonslayers/ds4/-/releases/${version}`;
|
2021-01-06 01:31:23 +01:00
|
|
|
|
|
|
|
/********************/
|
2021-03-17 12:15:25 +01:00
|
|
|
/* BUILD */
|
2021-01-06 01:31:23 +01:00
|
|
|
/********************/
|
|
|
|
|
|
|
|
/**
|
2021-03-17 12:15:25 +01:00
|
|
|
* Build the distributable JavaScript code
|
2021-01-06 01:31:23 +01:00
|
|
|
*/
|
2021-03-17 12:15:25 +01:00
|
|
|
async function buildCode() {
|
|
|
|
const build = await rollup({ input: rollupConfig.input, plugins: rollupConfig.plugins });
|
|
|
|
return build.write(rollupConfig.output);
|
2021-01-06 01:31:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-03-17 12:15:25 +01:00
|
|
|
* Build style sheets
|
2021-01-06 01:31:23 +01:00
|
|
|
*/
|
2021-03-17 12:15:25 +01:00
|
|
|
function buildStyles() {
|
|
|
|
return gulp
|
|
|
|
.src(path.join(stylesDirectory, `${name}${stylesExtension}`))
|
|
|
|
.pipe(sass().on("error", sass.logError))
|
|
|
|
.pipe(gulp.dest(path.join(distDirectory, "css")));
|
2021-01-06 01:31:23 +01:00
|
|
|
}
|
|
|
|
|
2021-09-22 02:33:20 +02:00
|
|
|
/**
|
|
|
|
* Remove unwanted data from a pack entry
|
|
|
|
*/
|
|
|
|
function cleanPackEntry(entry, cleanSourceId = true) {
|
|
|
|
if (cleanSourceId) {
|
|
|
|
delete entry.flags?.core?.sourceId;
|
|
|
|
}
|
2021-10-02 01:08:23 +02:00
|
|
|
Object.keys(entry.flags).forEach((scope) => {
|
|
|
|
if (Object.keys(entry.flags[scope]).length === 0) {
|
|
|
|
delete entry.flags[scope];
|
|
|
|
}
|
|
|
|
});
|
2021-09-22 02:33:20 +02:00
|
|
|
if (entry.permission) entry.permission = { default: 0 };
|
|
|
|
|
|
|
|
const embeddedDocumentCollections = [
|
|
|
|
"drawings",
|
|
|
|
"effects",
|
|
|
|
"items",
|
|
|
|
"lights",
|
|
|
|
"notes",
|
|
|
|
"results",
|
|
|
|
"sounds",
|
|
|
|
"templates",
|
|
|
|
"tiles",
|
|
|
|
"tokens",
|
|
|
|
"walls",
|
|
|
|
];
|
|
|
|
embeddedDocumentCollections
|
|
|
|
.flatMap((embeddedDocumentCollection) => entry[embeddedDocumentCollection] ?? [])
|
|
|
|
.forEach((embeddedEntry) => cleanPackEntry(embeddedEntry, false));
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
2021-09-21 01:12:17 +02:00
|
|
|
/**
|
|
|
|
* Convert a stream of JSON files to NeDB files
|
|
|
|
*/
|
|
|
|
const jsonToNeDB = () =>
|
|
|
|
new Transform({
|
|
|
|
transform(file, _, callback) {
|
|
|
|
try {
|
|
|
|
file.contents = Buffer.from(
|
|
|
|
JSON.parse(file.contents.toString())
|
2021-09-22 02:33:20 +02:00
|
|
|
.map(cleanPackEntry)
|
2021-09-21 01:12:17 +02:00
|
|
|
.map((entry) => JSON.stringify(entry))
|
|
|
|
.join("\n") + "\n",
|
|
|
|
);
|
|
|
|
file.path = path.join(
|
|
|
|
path.dirname(file.path),
|
|
|
|
path.basename(file.path, path.extname(file.path)) + ".db",
|
|
|
|
);
|
|
|
|
callback(undefined, file);
|
|
|
|
} catch (err) {
|
|
|
|
callback(err);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
objectMode: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* build compendium packs
|
|
|
|
*/
|
|
|
|
function buildPacks() {
|
|
|
|
return gulp
|
|
|
|
.src(path.join(packsDirectory, "*.json"))
|
|
|
|
.pipe(jsonToNeDB())
|
|
|
|
.pipe(gulp.dest(path.join(distDirectory, "packs")));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert a stream of NeDB files to JSON files
|
|
|
|
*/
|
|
|
|
const neDBToJSON = () =>
|
|
|
|
new Transform({
|
|
|
|
transform(file, _, callback) {
|
|
|
|
try {
|
|
|
|
const db = new Datastore({ filename: file.path, autoload: true });
|
|
|
|
db.find({}, (err, docs) => {
|
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
} else {
|
2021-09-22 02:33:20 +02:00
|
|
|
file.contents = Buffer.from(JSON.stringify(docs.map(cleanPackEntry), undefined, 4) + "\n");
|
2021-09-21 01:12:17 +02:00
|
|
|
file.path = path.join(
|
|
|
|
path.dirname(file.path),
|
|
|
|
path.basename(file.path, path.extname(file.path)) + ".json",
|
|
|
|
);
|
|
|
|
callback(undefined, file);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} catch (err) {
|
|
|
|
callback(err);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
objectMode: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate JSON files from the compendium packs in the distribution directory
|
|
|
|
*/
|
|
|
|
function generateJSONsFromPacks() {
|
|
|
|
return gulp
|
|
|
|
.src(path.join(distDirectory, "packs", "*.db"))
|
|
|
|
.pipe(neDBToJSON())
|
|
|
|
.pipe(gulp.dest(path.join(packsDirectory)));
|
|
|
|
}
|
|
|
|
|
2021-01-06 01:31:23 +01:00
|
|
|
/**
|
|
|
|
* Copy static files
|
|
|
|
*/
|
|
|
|
async function copyFiles() {
|
2021-03-17 12:15:25 +01:00
|
|
|
for (const file of staticFiles) {
|
|
|
|
if (fs.existsSync(path.join(sourceDirectory, file))) {
|
|
|
|
await fs.copy(path.join(sourceDirectory, file), path.join(distDirectory, file));
|
2021-01-06 01:31:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Watch for changes for each build step
|
|
|
|
*/
|
|
|
|
function buildWatch() {
|
2021-01-21 01:24:17 +01:00
|
|
|
gulp.watch(
|
2021-03-17 12:15:25 +01:00
|
|
|
path.join(sourceDirectory, "**", `*${sourceFileExtension}`).replace(/\\/g, "/"),
|
|
|
|
{ ignoreInitial: false },
|
|
|
|
buildCode,
|
|
|
|
);
|
|
|
|
gulp.watch(
|
|
|
|
path.join(stylesDirectory, "**", `*${stylesExtension}`).replace(/\\/g, "/"),
|
|
|
|
{ ignoreInitial: false },
|
|
|
|
buildStyles,
|
|
|
|
);
|
2021-09-21 01:12:17 +02:00
|
|
|
gulp.watch(path.join(packsDirectory, "**", "*.json").replace(/\\/g, "/"), { ignoreInitial: false }, buildPacks);
|
2021-03-17 12:15:25 +01:00
|
|
|
gulp.watch(
|
|
|
|
staticFiles.map((file) => path.join(sourceDirectory, file).replace(/\\/g, "/")),
|
2021-01-21 01:24:17 +01:00
|
|
|
{ ignoreInitial: false },
|
|
|
|
copyFiles,
|
|
|
|
);
|
2021-01-06 01:31:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/********************/
|
2021-03-17 12:15:25 +01:00
|
|
|
/* CLEAN */
|
2021-01-06 01:31:23 +01:00
|
|
|
/********************/
|
|
|
|
|
|
|
|
/**
|
2021-03-17 12:15:25 +01:00
|
|
|
* Remove built files from `dist` folder while ignoring source files
|
2021-01-06 01:31:23 +01:00
|
|
|
*/
|
|
|
|
async function clean() {
|
2021-09-21 01:12:17 +02:00
|
|
|
const files = [...staticFiles, "packs", "module"];
|
2021-01-06 01:31:23 +01:00
|
|
|
|
2021-03-17 12:15:25 +01:00
|
|
|
if (fs.existsSync(path.join(stylesDirectory, `${name}${stylesExtension}`))) {
|
|
|
|
files.push("css");
|
2021-01-06 01:31:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
console.log(" ", chalk.yellow("Files to clean:"));
|
|
|
|
console.log(" ", chalk.blueBright(files.join("\n ")));
|
|
|
|
|
2021-03-17 12:15:25 +01:00
|
|
|
for (const filePath of files) {
|
|
|
|
await fs.remove(path.join(distDirectory, filePath));
|
2021-01-06 01:31:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************/
|
2021-03-17 12:15:25 +01:00
|
|
|
/* LINK */
|
2021-01-06 01:31:23 +01:00
|
|
|
/********************/
|
|
|
|
|
|
|
|
/**
|
2021-03-17 12:15:25 +01:00
|
|
|
* Get the data path of Foundry VTT based on what is configured in `foundryconfig.json`
|
2021-01-06 01:31:23 +01:00
|
|
|
*/
|
2021-03-17 12:15:25 +01:00
|
|
|
function getDataPath() {
|
2021-01-06 01:31:23 +01:00
|
|
|
const config = fs.readJSONSync("foundryconfig.json");
|
|
|
|
|
2021-03-17 12:15:25 +01:00
|
|
|
if (config?.dataPath) {
|
|
|
|
if (!fs.existsSync(path.resolve(config.dataPath))) {
|
|
|
|
throw new Error("User Data path invalid, no Data directory found");
|
2021-01-06 01:31:23 +01:00
|
|
|
}
|
|
|
|
|
2021-03-17 12:15:25 +01:00
|
|
|
return path.resolve(config.dataPath);
|
|
|
|
} else {
|
|
|
|
throw new Error("No User Data path defined in foundryconfig.json");
|
|
|
|
}
|
|
|
|
}
|
2021-01-06 01:31:23 +01:00
|
|
|
|
2021-03-17 12:15:25 +01:00
|
|
|
/**
|
|
|
|
* Link build to User Data folder
|
|
|
|
*/
|
|
|
|
async function linkUserData() {
|
|
|
|
let destinationDirectory;
|
|
|
|
if (fs.existsSync(path.resolve(".", sourceDirectory, "system.json"))) {
|
|
|
|
destinationDirectory = "systems";
|
|
|
|
} else {
|
|
|
|
throw new Error(`Could not find ${chalk.blueBright("system.json")}`);
|
|
|
|
}
|
2021-01-06 01:31:23 +01:00
|
|
|
|
2021-03-17 12:15:25 +01:00
|
|
|
const linkDirectory = path.resolve(getDataPath(), destinationDirectory, name);
|
2021-01-06 01:31:23 +01:00
|
|
|
|
2021-03-17 12:15:25 +01:00
|
|
|
if (argv.clean || argv.c) {
|
|
|
|
console.log(chalk.yellow(`Removing build in ${chalk.blueBright(linkDirectory)}.`));
|
|
|
|
|
|
|
|
await fs.remove(linkDirectory);
|
|
|
|
} else if (!fs.existsSync(linkDirectory)) {
|
|
|
|
console.log(chalk.green(`Copying build to ${chalk.blueBright(linkDirectory)}.`));
|
|
|
|
await fs.ensureDir(path.resolve(linkDirectory, ".."));
|
|
|
|
await fs.symlink(path.resolve(".", distDirectory), linkDirectory);
|
2021-01-06 01:31:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-17 12:15:25 +01:00
|
|
|
/********************/
|
|
|
|
/* VERSIONING */
|
|
|
|
/********************/
|
2021-01-06 01:31:23 +01:00
|
|
|
|
|
|
|
/**
|
2021-03-17 12:15:25 +01:00
|
|
|
* Get the contents of the manifest file as object.
|
2021-01-06 01:31:23 +01:00
|
|
|
*/
|
2021-03-17 12:15:25 +01:00
|
|
|
function getManifest() {
|
|
|
|
const manifestPath = path.join(sourceDirectory, "system.json");
|
|
|
|
|
|
|
|
if (fs.existsSync(manifestPath)) {
|
|
|
|
return {
|
|
|
|
file: fs.readJSONSync(manifestPath),
|
|
|
|
name: "system.json",
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the target version based on on the current version and the argument passed as release.
|
|
|
|
*/
|
|
|
|
function getTargetVersion(currentVersion, release) {
|
|
|
|
if (["major", "premajor", "minor", "preminor", "patch", "prepatch", "prerelease"].includes(release)) {
|
|
|
|
return semver.inc(currentVersion, release);
|
|
|
|
} else {
|
|
|
|
return semver.valid(release);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update version and download URL.
|
|
|
|
*/
|
|
|
|
function bumpVersion(cb) {
|
2021-01-06 01:31:23 +01:00
|
|
|
const packageJson = fs.readJSONSync("package.json");
|
2021-01-09 18:08:24 +01:00
|
|
|
const manifest = getManifest();
|
2021-01-06 01:31:23 +01:00
|
|
|
|
|
|
|
if (!manifest) cb(Error(chalk.red("Manifest JSON not found")));
|
|
|
|
|
|
|
|
try {
|
2021-03-17 12:15:25 +01:00
|
|
|
const release = argv.release || argv.r;
|
2021-01-06 01:31:23 +01:00
|
|
|
|
2021-03-17 12:15:25 +01:00
|
|
|
const currentVersion = packageJson.version;
|
2021-01-06 01:31:23 +01:00
|
|
|
|
2021-03-17 12:15:25 +01:00
|
|
|
if (!release) {
|
|
|
|
return cb(Error("Missing release type"));
|
2021-01-06 01:31:23 +01:00
|
|
|
}
|
|
|
|
|
2021-03-17 12:15:25 +01:00
|
|
|
const targetVersion = getTargetVersion(currentVersion, release);
|
2021-01-06 01:31:23 +01:00
|
|
|
|
2021-03-17 12:15:25 +01:00
|
|
|
if (!targetVersion) {
|
|
|
|
return cb(new Error(chalk.red("Error: Incorrect version arguments")));
|
2021-01-06 01:31:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (targetVersion === currentVersion) {
|
2021-03-17 12:15:25 +01:00
|
|
|
return cb(new Error(chalk.red("Error: Target version is identical to current version")));
|
2021-01-06 01:31:23 +01:00
|
|
|
}
|
2021-03-17 12:15:25 +01:00
|
|
|
|
2021-01-06 01:31:23 +01:00
|
|
|
console.log(`Updating version number to '${targetVersion}'`);
|
|
|
|
|
|
|
|
packageJson.version = targetVersion;
|
2021-03-17 12:18:03 +01:00
|
|
|
fs.writeJSONSync("package.json", packageJson, { spaces: 4 });
|
2021-01-06 01:31:23 +01:00
|
|
|
|
2021-03-17 12:15:25 +01:00
|
|
|
manifest.file.version = targetVersion;
|
|
|
|
manifest.file.download = getDownloadURL(targetVersion);
|
2021-09-17 19:46:36 +02:00
|
|
|
manifest.file.changelog = getChangelogURL(targetVersion);
|
2021-03-17 12:18:03 +01:00
|
|
|
fs.writeJSONSync(path.join(sourceDirectory, manifest.name), manifest.file, { spaces: 4 });
|
2021-01-06 01:31:23 +01:00
|
|
|
|
|
|
|
return cb();
|
|
|
|
} catch (err) {
|
|
|
|
cb(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-21 01:12:17 +02:00
|
|
|
const execBuild = gulp.parallel(buildCode, buildStyles, buildPacks, copyFiles);
|
2021-01-06 01:31:23 +01:00
|
|
|
|
|
|
|
exports.build = gulp.series(clean, execBuild);
|
|
|
|
exports.watch = buildWatch;
|
|
|
|
exports.clean = clean;
|
|
|
|
exports.link = linkUserData;
|
2021-03-17 12:15:25 +01:00
|
|
|
exports.bumpVersion = bumpVersion;
|
2021-09-21 01:12:17 +02:00
|
|
|
exports.generateJSONsFromPacks = generateJSONsFromPacks;
|