2021-01-06 01:31:23 +01:00
|
|
|
const gulp = require("gulp");
|
|
|
|
const fs = require("fs-extra");
|
|
|
|
const path = require("path");
|
|
|
|
const chalk = require("chalk");
|
|
|
|
const stringify = require("json-stringify-pretty-compact");
|
|
|
|
const typescript = require("typescript");
|
|
|
|
|
|
|
|
const ts = require("gulp-typescript");
|
|
|
|
const sass = require("gulp-sass");
|
|
|
|
|
|
|
|
const argv = require("yargs").argv;
|
|
|
|
|
|
|
|
sass.compiler = require("sass");
|
|
|
|
|
|
|
|
function getConfig() {
|
|
|
|
const configPath = path.resolve(process.cwd(), "foundryconfig.json");
|
|
|
|
let config;
|
|
|
|
|
|
|
|
if (fs.existsSync(configPath)) {
|
|
|
|
config = fs.readJSONSync(configPath);
|
|
|
|
return config;
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function getManifest() {
|
|
|
|
const json = {};
|
|
|
|
|
|
|
|
if (fs.existsSync("src")) {
|
|
|
|
json.root = "src";
|
|
|
|
} else {
|
|
|
|
json.root = "dist";
|
|
|
|
}
|
|
|
|
|
|
|
|
const modulePath = path.join(json.root, "module.json");
|
|
|
|
const systemPath = path.join(json.root, "system.json");
|
|
|
|
|
|
|
|
if (fs.existsSync(modulePath)) {
|
|
|
|
json.file = fs.readJSONSync(modulePath);
|
|
|
|
json.name = "module.json";
|
|
|
|
} else if (fs.existsSync(systemPath)) {
|
|
|
|
json.file = fs.readJSONSync(systemPath);
|
|
|
|
json.name = "system.json";
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return json;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* TypeScript transformers
|
|
|
|
* @returns {typescript.TransformerFactory<typescript.SourceFile>}
|
|
|
|
*/
|
|
|
|
function createTransformer() {
|
|
|
|
/**
|
|
|
|
* @param {typescript.Node} node
|
|
|
|
*/
|
|
|
|
function shouldMutateModuleSpecifier(node) {
|
|
|
|
if (!typescript.isImportDeclaration(node) && !typescript.isExportDeclaration(node)) return false;
|
|
|
|
if (node.moduleSpecifier === undefined) return false;
|
|
|
|
if (!typescript.isStringLiteral(node.moduleSpecifier)) return false;
|
|
|
|
if (!node.moduleSpecifier.text.startsWith("./") && !node.moduleSpecifier.text.startsWith("../")) return false;
|
|
|
|
if (path.extname(node.moduleSpecifier.text) !== "") return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Transforms import/export declarations to append `.js` extension
|
|
|
|
* @param {typescript.TransformationContext} context
|
|
|
|
*/
|
|
|
|
function importTransformer(context) {
|
|
|
|
return (node) => {
|
|
|
|
/**
|
|
|
|
* @param {typescript.Node} node
|
|
|
|
*/
|
|
|
|
function visitor(node) {
|
|
|
|
if (shouldMutateModuleSpecifier(node)) {
|
|
|
|
if (typescript.isImportDeclaration(node)) {
|
|
|
|
const newModuleSpecifier = typescript.createLiteral(`${node.moduleSpecifier.text}.js`);
|
|
|
|
return typescript.updateImportDeclaration(
|
|
|
|
node,
|
|
|
|
node.decorators,
|
|
|
|
node.modifiers,
|
|
|
|
node.importClause,
|
|
|
|
newModuleSpecifier,
|
|
|
|
);
|
|
|
|
} else if (typescript.isExportDeclaration(node)) {
|
|
|
|
const newModuleSpecifier = typescript.createLiteral(`${node.moduleSpecifier.text}.js`);
|
|
|
|
return typescript.updateExportDeclaration(
|
|
|
|
node,
|
|
|
|
node.decorators,
|
|
|
|
node.modifiers,
|
|
|
|
node.exportClause,
|
|
|
|
newModuleSpecifier,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return typescript.visitEachChild(node, visitor, context);
|
|
|
|
}
|
|
|
|
|
|
|
|
return typescript.visitNode(node, visitor);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return importTransformer;
|
|
|
|
}
|
|
|
|
|
|
|
|
const tsConfig = ts.createProject("tsconfig.json", {
|
|
|
|
getCustomTransformers: (_program) => ({
|
|
|
|
after: [createTransformer()],
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
|
|
|
|
/********************/
|
|
|
|
/* BUILD */
|
|
|
|
/********************/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Build TypeScript
|
|
|
|
*/
|
|
|
|
function buildTS() {
|
|
|
|
return gulp.src("src/**/*.ts").pipe(tsConfig()).pipe(gulp.dest("dist"));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Build SASS
|
|
|
|
*/
|
|
|
|
function buildSASS() {
|
|
|
|
return gulp.src("src/*.scss").pipe(sass().on("error", sass.logError)).pipe(gulp.dest("dist"));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Copy static files
|
|
|
|
*/
|
|
|
|
async function copyFiles() {
|
2021-01-20 00:42:13 +01:00
|
|
|
const statics = ["lang", "fonts", "assets", "templates", "packs", "module.json", "system.json", "template.json"];
|
2021-01-06 01:31:23 +01:00
|
|
|
try {
|
|
|
|
for (const file of statics) {
|
|
|
|
if (fs.existsSync(path.join("src", file))) {
|
|
|
|
await fs.copy(path.join("src", file), path.join("dist", file));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Promise.resolve();
|
|
|
|
} catch (err) {
|
|
|
|
Promise.reject(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Watch for changes for each build step
|
|
|
|
*/
|
|
|
|
function buildWatch() {
|
|
|
|
gulp.watch("src/**/*.ts", { ignoreInitial: false }, buildTS);
|
|
|
|
gulp.watch("src/**/*.scss", { ignoreInitial: false }, buildSASS);
|
2021-01-21 01:24:17 +01:00
|
|
|
gulp.watch(
|
|
|
|
["src/fonts", "src/lang", "src/templates", "src/*.json", "src/packs"],
|
|
|
|
{ ignoreInitial: false },
|
|
|
|
copyFiles,
|
|
|
|
);
|
2021-01-06 01:31:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/********************/
|
|
|
|
/* CLEAN */
|
|
|
|
/********************/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove built files from `dist` folder
|
|
|
|
* while ignoring source files
|
|
|
|
*/
|
|
|
|
async function clean() {
|
|
|
|
const name = path.basename(path.resolve("."));
|
|
|
|
const files = [];
|
|
|
|
|
|
|
|
// If the project uses TypeScript
|
2021-01-20 00:42:13 +01:00
|
|
|
if (fs.existsSync(path.join("src", "module", `${name}.ts`))) {
|
2021-01-06 01:31:23 +01:00
|
|
|
files.push(
|
|
|
|
"lang",
|
|
|
|
"templates",
|
|
|
|
"assets",
|
|
|
|
"module",
|
2021-01-20 00:42:13 +01:00
|
|
|
"packs",
|
2021-01-06 01:31:23 +01:00
|
|
|
`${name}.js`,
|
|
|
|
"module.json",
|
|
|
|
"system.json",
|
|
|
|
"template.json",
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-01-09 18:08:24 +01:00
|
|
|
// If the project uses SASS
|
|
|
|
if (fs.existsSync(path.join("src", `${name}.scss`))) {
|
2021-01-06 01:31:23 +01:00
|
|
|
files.push("fonts", `${name}.css`);
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log(" ", chalk.yellow("Files to clean:"));
|
|
|
|
console.log(" ", chalk.blueBright(files.join("\n ")));
|
|
|
|
|
|
|
|
// Attempt to remove the files
|
|
|
|
try {
|
|
|
|
for (const filePath of files) {
|
|
|
|
await fs.remove(path.join("dist", filePath));
|
|
|
|
}
|
|
|
|
return Promise.resolve();
|
|
|
|
} catch (err) {
|
|
|
|
Promise.reject(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************/
|
|
|
|
/* LINK */
|
|
|
|
/********************/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Link build to User Data folder
|
|
|
|
*/
|
|
|
|
async function linkUserData() {
|
|
|
|
const name = path.basename(path.resolve("."));
|
|
|
|
const config = fs.readJSONSync("foundryconfig.json");
|
|
|
|
|
|
|
|
let destDir;
|
|
|
|
try {
|
|
|
|
if (
|
|
|
|
fs.existsSync(path.resolve(".", "dist", "module.json")) ||
|
|
|
|
fs.existsSync(path.resolve(".", "src", "module.json"))
|
|
|
|
) {
|
|
|
|
destDir = "modules";
|
|
|
|
} else if (
|
|
|
|
fs.existsSync(path.resolve(".", "dist", "system.json")) ||
|
|
|
|
fs.existsSync(path.resolve(".", "src", "system.json"))
|
|
|
|
) {
|
|
|
|
destDir = "systems";
|
|
|
|
} else {
|
|
|
|
throw Error(`Could not find ${chalk.blueBright("module.json")} or ${chalk.blueBright("system.json")}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
let linkDir;
|
|
|
|
if (config.dataPath) {
|
|
|
|
if (!fs.existsSync(path.join(config.dataPath, "Data")))
|
|
|
|
throw Error("User Data path invalid, no Data directory found");
|
|
|
|
|
|
|
|
linkDir = path.join(config.dataPath, "Data", destDir, name);
|
|
|
|
} else {
|
|
|
|
throw Error("No User Data path defined in foundryconfig.json");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argv.clean || argv.c) {
|
|
|
|
console.log(chalk.yellow(`Removing build in ${chalk.blueBright(linkDir)}`));
|
|
|
|
|
|
|
|
await fs.remove(linkDir);
|
|
|
|
} else if (!fs.existsSync(linkDir)) {
|
|
|
|
console.log(chalk.green(`Copying build to ${chalk.blueBright(linkDir)}`));
|
|
|
|
await fs.symlink(path.resolve("./dist"), linkDir);
|
|
|
|
}
|
|
|
|
return Promise.resolve();
|
|
|
|
} catch (err) {
|
|
|
|
Promise.reject(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*********************/
|
|
|
|
/* PACKAGE */
|
|
|
|
/*********************/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update version and URLs in the manifest JSON
|
|
|
|
*/
|
|
|
|
function updateManifest(cb) {
|
|
|
|
const packageJson = fs.readJSONSync("package.json");
|
2021-01-09 18:40:52 +01:00
|
|
|
const packageLockJson = fs.readJSONSync("package-lock.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 {
|
|
|
|
const version = argv.update || argv.u;
|
|
|
|
|
|
|
|
/* Update version */
|
|
|
|
|
|
|
|
const versionMatch = /^(\d{1,}).(\d{1,}).(\d{1,})$/;
|
|
|
|
const currentVersion = manifest.file.version;
|
|
|
|
let targetVersion = "";
|
|
|
|
|
|
|
|
if (!version) {
|
|
|
|
cb(Error("Missing version number"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (versionMatch.test(version)) {
|
|
|
|
targetVersion = version;
|
|
|
|
} else {
|
|
|
|
targetVersion = currentVersion.replace(versionMatch, (substring, major, minor, patch) => {
|
|
|
|
console.log(substring, Number(major) + 1, Number(minor) + 1, Number(patch) + 1);
|
|
|
|
if (version === "major") {
|
|
|
|
return `${Number(major) + 1}.0.0`;
|
|
|
|
} else if (version === "minor") {
|
|
|
|
return `${major}.${Number(minor) + 1}.0`;
|
|
|
|
} else if (version === "patch") {
|
|
|
|
return `${major}.${minor}.${Number(patch) + 1}`;
|
|
|
|
} else {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (targetVersion === "") {
|
|
|
|
return cb(Error(chalk.red("Error: Incorrect version arguments.")));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (targetVersion === currentVersion) {
|
|
|
|
return cb(Error(chalk.red("Error: Target version is identical to current version.")));
|
|
|
|
}
|
|
|
|
console.log(`Updating version number to '${targetVersion}'`);
|
|
|
|
|
|
|
|
packageJson.version = targetVersion;
|
2021-01-09 18:40:52 +01:00
|
|
|
packageLockJson.version = targetVersion;
|
2021-01-06 01:31:23 +01:00
|
|
|
manifest.file.version = targetVersion;
|
|
|
|
|
2021-01-09 18:08:24 +01:00
|
|
|
/* Update URL */
|
|
|
|
const result = `https://git.f3l.de/dungeonslayers/ds4/-/jobs/artifacts/${targetVersion}/download?job=build`;
|
2021-01-06 01:31:23 +01:00
|
|
|
|
|
|
|
manifest.file.download = result;
|
|
|
|
|
2021-01-09 18:08:24 +01:00
|
|
|
const prettyProjectJson =
|
|
|
|
stringify(manifest.file, {
|
|
|
|
maxLength: 40,
|
|
|
|
indent: 4,
|
|
|
|
}) + "\n";
|
2021-01-06 01:31:23 +01:00
|
|
|
|
2021-01-09 18:08:24 +01:00
|
|
|
fs.writeJSONSync("package.json", packageJson, { spaces: 4 });
|
2021-01-09 18:40:52 +01:00
|
|
|
fs.writeJSONSync("package-lock.json", packageLockJson, { spaces: 4 });
|
2021-01-06 01:31:23 +01:00
|
|
|
fs.writeFileSync(path.join(manifest.root, manifest.name), prettyProjectJson, "utf8");
|
|
|
|
|
|
|
|
return cb();
|
|
|
|
} catch (err) {
|
|
|
|
cb(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-09 18:08:24 +01:00
|
|
|
const execBuild = gulp.parallel(buildTS, buildSASS, 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-01-09 18:08:24 +01:00
|
|
|
exports.updateManifest = updateManifest;
|