From e7fc318ea5d746ad61498c80fd6bb35e936df703 Mon Sep 17 00:00:00 2001
From: Johannes Loher <johannes.loher@fg4f.de>
Date: Wed, 17 Mar 2021 12:15:25 +0100
Subject: [PATCH 1/6] Use rollup to build typescript

---
 .eslintignore                  |   3 +
 .eslintrc.js                   |  27 ++-
 .gitlab-ci.yml                 |   2 +-
 .prettierignore                |   5 +
 gulpfile.js                    | 381 ++++++++++++---------------------
 package.json                   |  24 +--
 rollup.config.js               |  12 ++
 src/ds4.scss                   |  27 ---
 src/scss/ds4.scss              |  27 +++
 src/scss/global/_fonts.scss    |  10 +-
 src/scss/utils/_variables.scss |   2 +-
 src/system.json                |   2 +-
 tsconfig.eslint.json           |   4 +
 yarn.lock                      | 311 +++++++++++++++++++++++----
 14 files changed, 494 insertions(+), 343 deletions(-)
 create mode 100644 .eslintignore
 create mode 100644 .prettierignore
 create mode 100644 rollup.config.js
 delete mode 100644 src/ds4.scss
 create mode 100644 src/scss/ds4.scss
 create mode 100644 tsconfig.eslint.json

diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..e131453
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,3 @@
+/dist
+/.pnp.js
+/.yarn/
diff --git a/.eslintrc.js b/.eslintrc.js
index 3ddfac3..2e7be78 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -6,9 +6,30 @@ module.exports = {
         sourceType: "module",
     },
 
-    extends: ["plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"],
+    env: {
+        browser: true,
+    },
 
-    plugins: ["@typescript-eslint"],
+    extends: ["plugin:@typescript-eslint/recommended", "plugin:jest/recommended", "plugin:prettier/recommended"],
 
-    rules: {},
+    plugins: ["@typescript-eslint", "jest"],
+
+    rules: {
+        // Specify any specific ESLint rules.
+    },
+
+    overrides: [
+        {
+            files: ["./*.js"],
+            rules: {
+                "@typescript-eslint/no-var-requires": "off",
+            },
+        },
+        {
+            files: ["./test/**/*.js"],
+            env: {
+                "jest/globals": true,
+            },
+        },
+    ],
 };
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7a88822..1659658 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -58,7 +58,7 @@ build:
     cache:
         <<: *global_cache
     script: |
-        yarn updateManifest --update=${RELEASE_TYPE}
+        yarn bump-version --release=${RELEASE_TYPE}
         RELEASE_VERSION=$(jq -r '.version' < package.json)
         git add package.json src/system.json
         git --no-pager diff
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..c9ec7c7
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,5 @@
+/dist
+/package-lock.json
+/.pnp.js
+/.yarn/
+/.vscode/
diff --git a/gulpfile.js b/gulpfile.js
index 41fcdac..3279ee4 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -1,150 +1,58 @@
-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 { rollup } = require("rollup");
 const argv = require("yargs").argv;
-
+const chalk = require("chalk");
+const fs = require("fs-extra");
+const gulp = require("gulp");
+const path = require("path");
+const rollupConfig = require("./rollup.config");
+const semver = require("semver");
+const sass = require("gulp-sass");
 sass.compiler = require("sass");
 
-function getConfig() {
-    const configPath = path.resolve(process.cwd(), "foundryconfig.json");
-    let config;
+/********************/
+/*  CONFIGURATION   */
+/********************/
 
-    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()],
-    }),
-});
+const name = path.basename(path.resolve("."));
+const sourceDirectory = "./src";
+const distDirectory = "./dist";
+const stylesDirectory = path.join(sourceDirectory, "scss");
+const stylesExtension = ".scss";
+const sourceFileExtension = ".ts";
+const staticFiles = ["assets", "fonts", "lang", "packs", "templates", "system.json", "template.json"];
+const getDownloadURL = (version) =>
+    `https://git.f3l.de/dungeonslayers/ds4/-/jobs/artifacts/${version}/download?job=build`;
 
 /********************/
-/*		BUILD		*/
+/*      BUILD       */
 /********************/
 
 /**
- * Build TypeScript
+ * Build the distributable JavaScript code
  */
-function buildTS() {
-    return gulp.src("src/**/*.ts").pipe(tsConfig()).pipe(gulp.dest("dist"));
+async function buildCode() {
+    const build = await rollup({ input: rollupConfig.input, plugins: rollupConfig.plugins });
+    return build.write(rollupConfig.output);
 }
 
 /**
- * Build SASS
+ * Build style sheets
  */
-function buildSASS() {
-    return gulp.src("src/*.scss").pipe(sass().on("error", sass.logError)).pipe(gulp.dest("dist"));
+function buildStyles() {
+    return gulp
+        .src(path.join(stylesDirectory, `${name}${stylesExtension}`))
+        .pipe(sass().on("error", sass.logError))
+        .pipe(gulp.dest(path.join(distDirectory, "css")));
 }
 
 /**
  * Copy static files
  */
 async function copyFiles() {
-    const statics = ["lang", "fonts", "assets", "templates", "packs", "module.json", "system.json", "template.json"];
-    try {
-        for (const file of statics) {
-            if (fs.existsSync(path.join("src", file))) {
-                await fs.copy(path.join("src", file), path.join("dist", file));
-            }
+    for (const file of staticFiles) {
+        if (fs.existsSync(path.join(sourceDirectory, file))) {
+            await fs.copy(path.join(sourceDirectory, file), path.join(distDirectory, file));
         }
-        return Promise.resolve();
-    } catch (err) {
-        Promise.reject(err);
     }
 }
 
@@ -152,180 +60,161 @@ async function copyFiles() {
  * Watch for changes for each build step
  */
 function buildWatch() {
-    gulp.watch("src/**/*.ts", { ignoreInitial: false }, buildTS);
-    gulp.watch("src/**/*.scss", { ignoreInitial: false }, buildSASS);
     gulp.watch(
-        ["src/fonts", "src/lang", "src/templates", "src/*.json", "src/packs"],
+        path.join(sourceDirectory, "**", `*${sourceFileExtension}`).replace(/\\/g, "/"),
+        { ignoreInitial: false },
+        buildCode,
+    );
+    gulp.watch(
+        path.join(stylesDirectory, "**", `*${stylesExtension}`).replace(/\\/g, "/"),
+        { ignoreInitial: false },
+        buildStyles,
+    );
+    gulp.watch(
+        staticFiles.map((file) => path.join(sourceDirectory, file).replace(/\\/g, "/")),
         { ignoreInitial: false },
         copyFiles,
     );
 }
 
 /********************/
-/*		CLEAN		*/
+/*      CLEAN       */
 /********************/
 
 /**
- * Remove built files from `dist` folder
- * while ignoring source files
+ * Remove built files from `dist` folder while ignoring source files
  */
 async function clean() {
-    const name = path.basename(path.resolve("."));
-    const files = [];
+    const files = [...staticFiles, "module"];
 
-    // If the project uses TypeScript
-    if (fs.existsSync(path.join("src", "module", `${name}.ts`))) {
-        files.push(
-            "lang",
-            "templates",
-            "assets",
-            "module",
-            "packs",
-            `${name}.js`,
-            "module.json",
-            "system.json",
-            "template.json",
-        );
-    }
-
-    // If the project uses SASS
-    if (fs.existsSync(path.join("src", `${name}.scss`))) {
-        files.push("fonts", `${name}.css`);
+    if (fs.existsSync(path.join(stylesDirectory, `${name}${stylesExtension}`))) {
+        files.push("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);
+    for (const filePath of files) {
+        await fs.remove(path.join(distDirectory, filePath));
     }
 }
 
 /********************/
-/*		LINK		*/
+/*       LINK       */
 /********************/
 
+/**
+ * Get the data path of Foundry VTT based on what is configured in `foundryconfig.json`
+ */
+function getDataPath() {
+    const config = fs.readJSONSync("foundryconfig.json");
+
+    if (config?.dataPath) {
+        if (!fs.existsSync(path.resolve(config.dataPath))) {
+            throw new Error("User Data path invalid, no Data directory found");
+        }
+
+        return path.resolve(config.dataPath);
+    } else {
+        throw new Error("No User Data path defined in foundryconfig.json");
+    }
+}
+
 /**
  * Link build to User Data folder
  */
 async function linkUserData() {
-    const name = path.basename(path.resolve("."));
-    const config = fs.readJSONSync("foundryconfig.json");
+    let destinationDirectory;
+    if (fs.existsSync(path.resolve(".", sourceDirectory, "system.json"))) {
+        destinationDirectory = "systems";
+    } else {
+        throw new Error(`Could not find ${chalk.blueBright("system.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")}`);
-        }
+    const linkDirectory = path.resolve(getDataPath(), destinationDirectory, name);
 
-        let linkDir;
-        if (config.dataPath) {
-            if (!fs.existsSync(path.join(config.dataPath, "Data")))
-                throw Error("User Data path invalid, no Data directory found");
+    if (argv.clean || argv.c) {
+        console.log(chalk.yellow(`Removing build in ${chalk.blueBright(linkDirectory)}.`));
 
-            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);
+        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);
     }
 }
 
-/*********************/
-/*		PACKAGE		 */
-/*********************/
+/********************/
+/*    VERSIONING    */
+/********************/
 
 /**
- * Update version and URLs in the manifest JSON
+ * Get the contents of the manifest file as object.
  */
-function updateManifest(cb) {
+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) {
     const packageJson = fs.readJSONSync("package.json");
+    const packageLockJson = fs.existsSync("package-lock.json") ? fs.readJSONSync("package-lock.json") : undefined;
     const manifest = getManifest();
 
     if (!manifest) cb(Error(chalk.red("Manifest JSON not found")));
 
     try {
-        const version = argv.update || argv.u;
+        const release = argv.release || argv.r;
 
-        /* Update version */
+        const currentVersion = packageJson.version;
 
-        const versionMatch = /^(\d{1,}).(\d{1,}).(\d{1,})$/;
-        const currentVersion = manifest.file.version;
-        let targetVersion = "";
-
-        if (!version) {
-            cb(Error("Missing version number"));
+        if (!release) {
+            return cb(Error("Missing release type"));
         }
 
-        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 "";
-                }
-            });
-        }
+        const targetVersion = getTargetVersion(currentVersion, release);
 
-        if (targetVersion === "") {
-            return cb(Error(chalk.red("Error: Incorrect version arguments.")));
+        if (!targetVersion) {
+            return cb(new Error(chalk.red("Error: Incorrect version arguments")));
         }
 
         if (targetVersion === currentVersion) {
-            return cb(Error(chalk.red("Error: Target version is identical to current version.")));
+            return cb(new Error(chalk.red("Error: Target version is identical to current version")));
         }
+
         console.log(`Updating version number to '${targetVersion}'`);
 
         packageJson.version = targetVersion;
+        fs.writeJSONSync("package.json", packageJson, { spaces: 2 });
+
+        if (packageLockJson) {
+            packageLockJson.version = targetVersion;
+            fs.writeJSONSync("package-lock.json", packageLockJson, { spaces: 2 });
+        }
+
         manifest.file.version = targetVersion;
-
-        /* Update URL */
-        const result = `https://git.f3l.de/dungeonslayers/ds4/-/jobs/artifacts/${targetVersion}/download?job=build`;
-
-        manifest.file.download = result;
-
-        const prettyProjectJson =
-            stringify(manifest.file, {
-                maxLength: 40,
-                indent: 4,
-            }) + "\n";
-
-        fs.writeJSONSync("package.json", packageJson, { spaces: 4 });
-        fs.writeFileSync(path.join(manifest.root, manifest.name), prettyProjectJson, "utf8");
+        manifest.file.download = getDownloadURL(targetVersion);
+        fs.writeJSONSync(path.join(sourceDirectory, manifest.name), manifest.file, { spaces: 2 });
 
         return cb();
     } catch (err) {
@@ -333,10 +222,10 @@ function updateManifest(cb) {
     }
 }
 
-const execBuild = gulp.parallel(buildTS, buildSASS, copyFiles);
+const execBuild = gulp.parallel(buildCode, buildStyles, copyFiles);
 
 exports.build = gulp.series(clean, execBuild);
 exports.watch = buildWatch;
 exports.clean = clean;
 exports.link = linkUserData;
-exports.updateManifest = updateManifest;
+exports.bumpVersion = bumpVersion;
diff --git a/package.json b/package.json
index 440ce47..a5e2c6a 100644
--- a/package.json
+++ b/package.json
@@ -34,18 +34,20 @@
         "build": "gulp build",
         "build:watch": "gulp watch",
         "link-project": "gulp link",
-        "clean": "gulp clean && gulp link --clean",
-        "updateManifest": "gulp updateManifest",
-        "lint": "eslint 'src/**/*.ts' --cache",
-        "lint:fix": "eslint 'src/**/*.ts' --cache --fix",
+        "clean": "gulp clean",
+        "clean:link": "gulp link --clean",
+        "bump-version": "gulp bumpVersion",
+        "lint": "eslint --ext .ts,.js .",
+        "lint:fix": "eslint --ext .ts,.js --fix .",
         "test": "jest",
         "test:watch": "jest --watch",
         "test:ci": "jest --ci --reporters=default --reporters=jest-junit",
-        "format": "prettier --write 'src/**/*.(ts|json|scss)'",
+        "format": "prettier --write \"./**/*.(ts|js|json|scss)\"",
         "postinstall": "husky install"
     },
     "devDependencies": {
         "@league-of-foundry-developers/foundry-vtt-types": "^0.7.9-3",
+        "@rollup/plugin-node-resolve": "^11.2.0",
         "@types/fs-extra": "^9.0.8",
         "@types/jest": "^26.0.20",
         "@typescript-eslint/eslint-plugin": "^4.16.1",
@@ -53,27 +55,25 @@
         "chalk": "^4.1.0",
         "eslint": "^7.21.0",
         "eslint-config-prettier": "^8.1.0",
+        "eslint-plugin-jest": "^24.3.2",
         "eslint-plugin-prettier": "^3.3.1",
         "fs-extra": "^9.1.0",
         "gulp": "^4.0.2",
         "gulp-sass": "^4.1.0",
-        "gulp-typescript": "^6.0.0-alpha.1",
         "husky": "^5.1.3",
         "jest": "^26.6.3",
         "jest-junit": "^12.0.0",
-        "json-stringify-pretty-compact": "^3.0.0",
         "lint-staged": "^10.5.4",
         "prettier": "^2.2.1",
+        "rollup": "^2.41.4",
+        "rollup-plugin-typescript2": "^0.30.0",
         "sass": "^1.32.8",
+        "semver": "^7.3.4",
         "ts-jest": "^26.5.3",
+        "tslib": "^2.1.0",
         "typescript": "^4.2.3",
         "yargs": "^16.2.0"
     },
-    "husky": {
-        "hooks": {
-            "pre-commit": "lint-staged"
-        }
-    },
     "lint-staged": {
         "*.ts": "eslint --cache --fix",
         "*.(json|scss)": "prettier --write"
diff --git a/rollup.config.js b/rollup.config.js
new file mode 100644
index 0000000..d7b6c67
--- /dev/null
+++ b/rollup.config.js
@@ -0,0 +1,12 @@
+const typescript = require("rollup-plugin-typescript2");
+const { nodeResolve } = require("@rollup/plugin-node-resolve");
+
+module.exports = {
+    input: "src/module/ds4.ts",
+    output: {
+        dir: "dist/module",
+        format: "es",
+        sourcemap: true,
+    },
+    plugins: [nodeResolve(), typescript({})],
+};
diff --git a/src/ds4.scss b/src/ds4.scss
deleted file mode 100644
index 657ecdb..0000000
--- a/src/ds4.scss
+++ /dev/null
@@ -1,27 +0,0 @@
-@use 'sass:meta';
-
-/* Global styles */
-@include meta.load-css("scss/global/accessibility");
-@include meta.load-css("scss/global/flex");
-@include meta.load-css("scss/global/fonts");
-@include meta.load-css("scss/global/grid");
-@include meta.load-css("scss/global/window");
-@include meta.load-css("scss/components/actor_sheet");
-@include meta.load-css("scss/components/dice_total");
-
-/* Styles limited to ds4 sheets */
-.ds4 {
-    @include meta.load-css("scss/components/attributes_traits");
-    @include meta.load-css("scss/components/apps");
-    @include meta.load-css("scss/components/basic_property");
-    @include meta.load-css("scss/components/character_progression");
-    @include meta.load-css("scss/components/character_values");
-    @include meta.load-css("scss/components/combat_values");
-    @include meta.load-css("scss/components/description");
-    @include meta.load-css("scss/components/forms");
-    @include meta.load-css("scss/components/item_list");
-    @include meta.load-css("scss/components/tabs");
-    @include meta.load-css("scss/components/talent_rank_equation");
-    @include meta.load-css("scss/components/currency");
-    @include meta.load-css("scss/components/rollable_image");
-}
diff --git a/src/scss/ds4.scss b/src/scss/ds4.scss
new file mode 100644
index 0000000..1d06a5f
--- /dev/null
+++ b/src/scss/ds4.scss
@@ -0,0 +1,27 @@
+@use 'sass:meta';
+
+/* Global styles */
+@include meta.load-css("global/accessibility");
+@include meta.load-css("global/flex");
+@include meta.load-css("global/fonts");
+@include meta.load-css("global/grid");
+@include meta.load-css("global/window");
+@include meta.load-css("components/actor_sheet");
+@include meta.load-css("components/dice_total");
+
+/* Styles limited to ds4 sheets */
+.ds4 {
+    @include meta.load-css("components/attributes_traits");
+    @include meta.load-css("components/apps");
+    @include meta.load-css("components/basic_property");
+    @include meta.load-css("components/character_progression");
+    @include meta.load-css("components/character_values");
+    @include meta.load-css("components/combat_values");
+    @include meta.load-css("components/description");
+    @include meta.load-css("components/forms");
+    @include meta.load-css("components/item_list");
+    @include meta.load-css("components/tabs");
+    @include meta.load-css("components/talent_rank_equation");
+    @include meta.load-css("components/currency");
+    @include meta.load-css("components/rollable_image");
+}
diff --git a/src/scss/global/_fonts.scss b/src/scss/global/_fonts.scss
index eff1709..8f85a58 100644
--- a/src/scss/global/_fonts.scss
+++ b/src/scss/global/_fonts.scss
@@ -2,33 +2,33 @@
     font-family: "Lora";
     font-style: normal;
     font-weight: normal;
-    src: local("Lora"), url("fonts/Lora/Lora.woff") format("woff");
+    src: local("Lora"), url("/systems/ds4/fonts/Lora/Lora.woff") format("woff");
 }
 
 @font-face {
     font-family: "Lora";
     font-style: normal;
     font-weight: bold;
-    src: local("Lora"), url("fonts/Lora/Lora-Bold.woff") format("woff");
+    src: local("Lora"), url("/systems/ds4/fonts/Lora/Lora-Bold.woff") format("woff");
 }
 
 @font-face {
     font-family: "Lora";
     font-style: italic;
     font-weight: normal;
-    src: local("Lora"), url("fonts/Lora/Lora-Italic.woff") format("woff");
+    src: local("Lora"), url("/systems/ds4/fonts/Lora/Lora-Italic.woff") format("woff");
 }
 
 @font-face {
     font-family: "Lora";
     font-style: italic;
     font-weight: bold;
-    src: local("Lora"), url("fonts/Lora/Lora-BoldItalic.woff") format("woff");
+    src: local("Lora"), url("/systems/ds4/fonts/Lora/Lora-BoldItalic.woff") format("woff");
 }
 
 @font-face {
     font-family: "Wood Stamp";
     font-style: normal;
     font-weight: normal;
-    src: local("Wood Stamp"), url("fonts/Woodstamp/Woodstamp.woff") format("woff");
+    src: local("Wood Stamp"), url("/systems/ds4/fonts/Woodstamp/Woodstamp.woff") format("woff");
 }
diff --git a/src/scss/utils/_variables.scss b/src/scss/utils/_variables.scss
index f63ffea..0a8d4fc 100644
--- a/src/scss/utils/_variables.scss
+++ b/src/scss/utils/_variables.scss
@@ -9,6 +9,6 @@ $margin-lg: $padding-lg;
 
 $default-input-height: 26px;
 
-$official-icons-path: "assets/icons/official";
+$official-icons-path: "/systems/ds4/assets/icons/official";
 
 $border-groove: 2px groove colors.$c-border-groove;
diff --git a/src/system.json b/src/system.json
index 2965f31..9c8d688 100644
--- a/src/system.json
+++ b/src/system.json
@@ -26,7 +26,7 @@
         }
     ],
     "esmodules": ["module/ds4.js"],
-    "styles": ["ds4.css"],
+    "styles": ["css/ds4.css"],
     "scripts": [],
     "packs": [
         {
diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json
new file mode 100644
index 0000000..c394325
--- /dev/null
+++ b/tsconfig.eslint.json
@@ -0,0 +1,4 @@
+{
+    "extends": "./tsconfig.json",
+    "include": ["src", "spec", "*.js"]
+}
diff --git a/yarn.lock b/yarn.lock
index 2c6ae59..b96e2ee 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1070,6 +1070,47 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@rollup/plugin-node-resolve@npm:^11.2.0":
+  version: 11.2.0
+  resolution: "@rollup/plugin-node-resolve@npm:11.2.0"
+  dependencies:
+    "@rollup/pluginutils": ^3.1.0
+    "@types/resolve": 1.17.1
+    builtin-modules: ^3.1.0
+    deepmerge: ^4.2.2
+    is-module: ^1.0.0
+    resolve: ^1.19.0
+  peerDependencies:
+    rollup: ^1.20.0||^2.0.0
+  checksum: 173bb5822b8a6fd3a2c09303efd437711062885099dd1a4a6e91b449b99fcf5a4dc43e7d3836edeaca85ef7235547a193a3011314298ecbc529e8b123c371718
+  languageName: node
+  linkType: hard
+
+"@rollup/pluginutils@npm:^3.1.0":
+  version: 3.1.0
+  resolution: "@rollup/pluginutils@npm:3.1.0"
+  dependencies:
+    "@types/estree": 0.0.39
+    estree-walker: ^1.0.1
+    picomatch: ^2.2.2
+  peerDependencies:
+    rollup: ^1.20.0||^2.0.0
+  checksum: 45da6411e045d1b034242a8144f4a5e8c02ff1b68a2e0857807f5bb4b091c416f2015e075057f0f0dec200e7b35efe6ed4e301b43e365cedea09192f01a6839b
+  languageName: node
+  linkType: hard
+
+"@rollup/pluginutils@npm:^4.1.0":
+  version: 4.1.0
+  resolution: "@rollup/pluginutils@npm:4.1.0"
+  dependencies:
+    estree-walker: ^2.0.1
+    picomatch: ^2.2.2
+  peerDependencies:
+    rollup: ^1.20.0||^2.0.0
+  checksum: 566b8d2bcc0d52877f8c9f364026be40fa921c8d5860b5f2a5f476658dfebf462536632f079aa3f52fafe64d8aea6741c20bb198e67b33eaba8f9fe69b38ae3f
+  languageName: node
+  linkType: hard
+
 "@sinonjs/commons@npm:^1.7.0":
   version: 1.8.2
   resolution: "@sinonjs/commons@npm:1.8.2"
@@ -1129,6 +1170,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/estree@npm:0.0.39":
+  version: 0.0.39
+  resolution: "@types/estree@npm:0.0.39"
+  checksum: 43e5361de39969def145f32f4599391ab13055ec94841f1633a7cfe10f0e8a940ebf0e9a4b2770454a6bddd034b57e7e0d51a4d565cb2714ee2accf10a7718be
+  languageName: node
+  linkType: hard
+
 "@types/fs-extra@npm:^9.0.8":
   version: 9.0.8
   resolution: "@types/fs-extra@npm:9.0.8"
@@ -1233,6 +1281,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/resolve@npm:1.17.1":
+  version: 1.17.1
+  resolution: "@types/resolve@npm:1.17.1"
+  dependencies:
+    "@types/node": "*"
+  checksum: 8e72a73574f9489760662498c1ad512a8d4084a5db15f327e0d785cb277bb0a3146cd049241a8e3268bd0ed204ad3ee7b4a6b4622ef681e70547be9af258ca6a
+  languageName: node
+  linkType: hard
+
 "@types/sizzle@npm:*":
   version: 2.3.2
   resolution: "@types/sizzle@npm:2.3.2"
@@ -1308,6 +1365,22 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@typescript-eslint/experimental-utils@npm:^4.0.1":
+  version: 4.18.0
+  resolution: "@typescript-eslint/experimental-utils@npm:4.18.0"
+  dependencies:
+    "@types/json-schema": ^7.0.3
+    "@typescript-eslint/scope-manager": 4.18.0
+    "@typescript-eslint/types": 4.18.0
+    "@typescript-eslint/typescript-estree": 4.18.0
+    eslint-scope: ^5.0.0
+    eslint-utils: ^2.0.0
+  peerDependencies:
+    eslint: "*"
+  checksum: 1f1357b38aa6e1dc9088abec1c259372ff124be215644283df1725421c3faeeb90ca463c5e549247f10918d18031cd56b58b366d22a5c90e23f601826d1d7f3a
+  languageName: node
+  linkType: hard
+
 "@typescript-eslint/parser@npm:^4.16.1":
   version: 4.16.1
   resolution: "@typescript-eslint/parser@npm:4.16.1"
@@ -1335,6 +1408,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@typescript-eslint/scope-manager@npm:4.18.0":
+  version: 4.18.0
+  resolution: "@typescript-eslint/scope-manager@npm:4.18.0"
+  dependencies:
+    "@typescript-eslint/types": 4.18.0
+    "@typescript-eslint/visitor-keys": 4.18.0
+  checksum: c543d4bf73ad0193cca7303c376f15b099ee861be492a210cfc19909d2ec828b7dc898a59e17c89cc91e4cc2ea450731a83671d136cd995fb9b77f8a7db4d440
+  languageName: node
+  linkType: hard
+
 "@typescript-eslint/types@npm:4.16.1":
   version: 4.16.1
   resolution: "@typescript-eslint/types@npm:4.16.1"
@@ -1342,6 +1425,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@typescript-eslint/types@npm:4.18.0":
+  version: 4.18.0
+  resolution: "@typescript-eslint/types@npm:4.18.0"
+  checksum: 45d3df0c4993ceab017df2a4502bb2e3d9b21e6554997a539b88dfa5899c83bf6156a823d15eeb679e65dec15ab07ff371c6e5c09f98c166ed94f79a8223ffab
+  languageName: node
+  linkType: hard
+
 "@typescript-eslint/typescript-estree@npm:4.16.1":
   version: 4.16.1
   resolution: "@typescript-eslint/typescript-estree@npm:4.16.1"
@@ -1360,6 +1450,24 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@typescript-eslint/typescript-estree@npm:4.18.0":
+  version: 4.18.0
+  resolution: "@typescript-eslint/typescript-estree@npm:4.18.0"
+  dependencies:
+    "@typescript-eslint/types": 4.18.0
+    "@typescript-eslint/visitor-keys": 4.18.0
+    debug: ^4.1.1
+    globby: ^11.0.1
+    is-glob: ^4.0.1
+    semver: ^7.3.2
+    tsutils: ^3.17.1
+  peerDependenciesMeta:
+    typescript:
+      optional: true
+  checksum: b77e150d281d50aad89f915c05310b5f94fa2b1fc64eada20460d8a7f10c42d4c2a5ccffe185f128c965fc9bd209f77a0df8e1779af18b0a3a383241564ecc4b
+  languageName: node
+  linkType: hard
+
 "@typescript-eslint/visitor-keys@npm:4.16.1":
   version: 4.16.1
   resolution: "@typescript-eslint/visitor-keys@npm:4.16.1"
@@ -1370,6 +1478,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@typescript-eslint/visitor-keys@npm:4.18.0":
+  version: 4.18.0
+  resolution: "@typescript-eslint/visitor-keys@npm:4.18.0"
+  dependencies:
+    "@typescript-eslint/types": 4.18.0
+    eslint-visitor-keys: ^2.0.0
+  checksum: 654576d330531386773facffc715e213602721de8ca2f6268d71186a732975031954119fba414a4d502b4827b3941fae068ebb4368b4b7f94e937597b3f57d82
+  languageName: node
+  linkType: hard
+
 "abab@npm:^2.0.3":
   version: 2.0.5
   resolution: "abab@npm:2.0.5"
@@ -2063,6 +2181,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"builtin-modules@npm:^3.1.0":
+  version: 3.2.0
+  resolution: "builtin-modules@npm:3.2.0"
+  checksum: f0e7240f70ae472a0a0167bf76d2e828c73028fe60be8cd229939c38a27527ea68c92f700553dac1316fa124af3037bc7a765ca0e029a03d2e9201dfb372ea24
+  languageName: node
+  linkType: hard
+
 "cache-base@npm:^1.0.1":
   version: 1.0.1
   resolution: "cache-base@npm:1.0.1"
@@ -2463,6 +2588,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"commondir@npm:^1.0.1":
+  version: 1.0.1
+  resolution: "commondir@npm:1.0.1"
+  checksum: 98f18ad14f0ea38e0866db365bc8496f2a74250cf47ec96b94913e1b0574c99b4ff837a9f05dbc68d82505fd06b52dfba4f6bbe6fbda43094296cfaf33b475a0
+  languageName: node
+  linkType: hard
+
 "component-emitter@npm:^1.2.1":
   version: 1.3.0
   resolution: "component-emitter@npm:1.3.0"
@@ -2821,6 +2953,7 @@ __metadata:
   resolution: "dungeonslayers4@workspace:."
   dependencies:
     "@league-of-foundry-developers/foundry-vtt-types": ^0.7.9-3
+    "@rollup/plugin-node-resolve": ^11.2.0
     "@types/fs-extra": ^9.0.8
     "@types/jest": ^26.0.20
     "@typescript-eslint/eslint-plugin": ^4.16.1
@@ -2828,19 +2961,22 @@ __metadata:
     chalk: ^4.1.0
     eslint: ^7.21.0
     eslint-config-prettier: ^8.1.0
+    eslint-plugin-jest: ^24.3.2
     eslint-plugin-prettier: ^3.3.1
     fs-extra: ^9.1.0
     gulp: ^4.0.2
     gulp-sass: ^4.1.0
-    gulp-typescript: ^6.0.0-alpha.1
     husky: ^5.1.3
     jest: ^26.6.3
     jest-junit: ^12.0.0
-    json-stringify-pretty-compact: ^3.0.0
     lint-staged: ^10.5.4
     prettier: ^2.2.1
+    rollup: ^2.41.4
+    rollup-plugin-typescript2: ^0.30.0
     sass: ^1.32.8
+    semver: ^7.3.4
     ts-jest: ^26.5.3
+    tslib: ^2.1.0
     typescript: ^4.2.3
     yargs: ^16.2.0
   languageName: unknown
@@ -3049,6 +3185,21 @@ __metadata:
   languageName: node
   linkType: hard
 
+"eslint-plugin-jest@npm:^24.3.2":
+  version: 24.3.2
+  resolution: "eslint-plugin-jest@npm:24.3.2"
+  dependencies:
+    "@typescript-eslint/experimental-utils": ^4.0.1
+  peerDependencies:
+    "@typescript-eslint/eslint-plugin": ">= 4"
+    eslint: ">=5"
+  peerDependenciesMeta:
+    "@typescript-eslint/eslint-plugin":
+      optional: true
+  checksum: caf92f0bab6800bbf1fcfa8d75e1b7ad2bfb77914abdf1f0c33ac2b0d3b15c48cbec7b36a828931048f71dc181bbda9ede1d74b9a153f92029de0680644d1d14
+  languageName: node
+  linkType: hard
+
 "eslint-plugin-prettier@npm:^3.3.1":
   version: 3.3.1
   resolution: "eslint-plugin-prettier@npm:3.3.1"
@@ -3197,6 +3348,20 @@ __metadata:
   languageName: node
   linkType: hard
 
+"estree-walker@npm:^1.0.1":
+  version: 1.0.1
+  resolution: "estree-walker@npm:1.0.1"
+  checksum: 85e7cee763e9125a7d8a947b3a06a8b9282873936df220dd0d791d9b3315e45e40ab096b43ba71bdc99140c11a6d23fdcf686642dc119a7b2d6181004fdb24d2
+  languageName: node
+  linkType: hard
+
+"estree-walker@npm:^2.0.1":
+  version: 2.0.2
+  resolution: "estree-walker@npm:2.0.2"
+  checksum: 378cc9d3be56962c5219c55ad1fde732cb7d55a11cde5acbf5995f39ddd0e98c1095a43c0ef15a520d1d6910e816bd3daff5fc5d7d38baaf8b12d5a2970df57c
+  languageName: node
+  linkType: hard
+
 "esutils@npm:^2.0.2":
   version: 2.0.3
   resolution: "esutils@npm:2.0.3"
@@ -3478,6 +3643,17 @@ __metadata:
   languageName: node
   linkType: hard
 
+"find-cache-dir@npm:^3.3.1":
+  version: 3.3.1
+  resolution: "find-cache-dir@npm:3.3.1"
+  dependencies:
+    commondir: ^1.0.1
+    make-dir: ^3.0.2
+    pkg-dir: ^4.1.0
+  checksum: b1e23226ee89fba89646aa5f72d084c6d04bb64f6d523c9cb2d57a1b5280fcac39e92fd5be572e2fae8a83aa70bc5b797ce33a826b9a4b92373cc38e66d4aa64
+  languageName: node
+  linkType: hard
+
 "find-up@npm:^1.0.0":
   version: 1.1.2
   resolution: "find-up@npm:1.1.2"
@@ -3621,6 +3797,17 @@ __metadata:
   languageName: node
   linkType: hard
 
+"fs-extra@npm:8.1.0":
+  version: 8.1.0
+  resolution: "fs-extra@npm:8.1.0"
+  dependencies:
+    graceful-fs: ^4.2.0
+    jsonfile: ^4.0.0
+    universalify: ^0.1.0
+  checksum: 056a96d4f55ab8728b021e251175a4a6440d1edb5845e6c2e8e010019bde3e63de188a0eb99386c21c71804ca1a571cd6e08f507971f10a2bc4f4f7667720fa4
+  languageName: node
+  linkType: hard
+
 "fs-extra@npm:^9.1.0":
   version: 9.1.0
   resolution: "fs-extra@npm:9.1.0"
@@ -3669,7 +3856,7 @@ fsevents@^1.2.7:
   languageName: node
   linkType: hard
 
-fsevents@^2.1.2:
+"fsevents@^2.1.2, fsevents@~2.3.1":
   version: 2.3.2
   resolution: "fsevents@npm:2.3.2"
   dependencies:
@@ -3688,7 +3875,7 @@ fsevents@^2.1.2:
   languageName: node
   linkType: hard
 
-"fsevents@patch:fsevents@^2.1.2#builtin<compat/fsevents>":
+"fsevents@patch:fsevents@^2.1.2#builtin<compat/fsevents>, fsevents@patch:fsevents@~2.3.1#builtin<compat/fsevents>":
   version: 2.3.2
   resolution: "fsevents@patch:fsevents@npm%3A2.3.2#builtin<compat/fsevents>::version=2.3.2&hash=11e9ea"
   dependencies:
@@ -4033,22 +4220,6 @@ fsevents@^2.1.2:
   languageName: node
   linkType: hard
 
-"gulp-typescript@npm:^6.0.0-alpha.1":
-  version: 6.0.0-alpha.1
-  resolution: "gulp-typescript@npm:6.0.0-alpha.1"
-  dependencies:
-    ansi-colors: ^4.1.1
-    plugin-error: ^1.0.1
-    source-map: ^0.7.3
-    through2: ^3.0.1
-    vinyl: ^2.2.0
-    vinyl-fs: ^3.0.3
-  peerDependencies:
-    typescript: "~2.7.1 || >=2.8.0-dev || >=2.9.0-dev || ~3.0.0 || >=3.0.0-dev || >=3.1.0-dev || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.7.0-dev "
-  checksum: 39ee6423d25da5cffab8942af65973629e48af23c6fb1aa91f19a4142d8b42f50c052784c99982a4bb45c7f58aba731dad87225b599414bbb2510e9cf875de03
-  languageName: node
-  linkType: hard
-
 "gulp@npm:^4.0.2":
   version: 4.0.2
   resolution: "gulp@npm:4.0.2"
@@ -4341,7 +4512,7 @@ fsevents@^2.1.2:
   languageName: node
   linkType: hard
 
-"inherits@npm:2, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.0, inherits@npm:~2.0.3":
+"inherits@npm:2, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:~2.0.0, inherits@npm:~2.0.3":
   version: 2.0.4
   resolution: "inherits@npm:2.0.4"
   checksum: 98426da247ddfc3dcd7d7daedd90c3ca32d5b08deca08949726f12d49232aef94772a07b36cf4ff833e105ae2ef931777f6de4a6dd8245a216b9299ad4a50bea
@@ -4574,6 +4745,13 @@ fsevents@^2.1.2:
   languageName: node
   linkType: hard
 
+"is-module@npm:^1.0.0":
+  version: 1.0.0
+  resolution: "is-module@npm:1.0.0"
+  checksum: 2cbd41e2760874130b76aee84cc53120c4feef0d0f196fa665326857b444c8549909cc840f3f3a59652a7e8df46146a77f6c0f3f70a578704e03670975843e74
+  languageName: node
+  linkType: hard
+
 "is-negated-glob@npm:^1.0.0":
   version: 1.0.0
   resolution: "is-negated-glob@npm:1.0.0"
@@ -5373,13 +5551,6 @@ fsevents@^2.1.2:
   languageName: node
   linkType: hard
 
-"json-stringify-pretty-compact@npm:^3.0.0":
-  version: 3.0.0
-  resolution: "json-stringify-pretty-compact@npm:3.0.0"
-  checksum: 743d0485399d51e052835f8b6ccfb150a1c37ccd41d0be7c6bbfa49778fe0d1a50f123d44d2fbf759f560c2ae0e9341da8de056b583a7959c4c391ca89f31840
-  languageName: node
-  linkType: hard
-
 "json-stringify-safe@npm:~5.0.1":
   version: 5.0.1
   resolution: "json-stringify-safe@npm:5.0.1"
@@ -5398,6 +5569,18 @@ fsevents@^2.1.2:
   languageName: node
   linkType: hard
 
+"jsonfile@npm:^4.0.0":
+  version: 4.0.0
+  resolution: "jsonfile@npm:4.0.0"
+  dependencies:
+    graceful-fs: ^4.1.6
+  dependenciesMeta:
+    graceful-fs:
+      optional: true
+  checksum: a40b7b64da41c84b0dc7ad753737ba240bb0dc50a94be20ec0b73459707dede69a6f89eb44b4d29e6994ed93ddf8c9b6e57f6b1f09dd707567959880ad6cee7f
+  languageName: node
+  linkType: hard
+
 "jsonfile@npm:^6.0.1":
   version: 6.1.0
   resolution: "jsonfile@npm:6.1.0"
@@ -5696,7 +5879,7 @@ fsevents@^2.1.2:
   languageName: node
   linkType: hard
 
-"make-dir@npm:^3.0.0":
+"make-dir@npm:^3.0.0, make-dir@npm:^3.0.2":
   version: 3.1.0
   resolution: "make-dir@npm:3.1.0"
   dependencies:
@@ -6621,7 +6804,7 @@ fsevents@^2.1.2:
   languageName: node
   linkType: hard
 
-"picomatch@npm:^2.0.4, picomatch@npm:^2.0.5, picomatch@npm:^2.2.1":
+"picomatch@npm:^2.0.4, picomatch@npm:^2.0.5, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2":
   version: 2.2.2
   resolution: "picomatch@npm:2.2.2"
   checksum: 20fa75e0a58b39d83425b3db68744d5f6f361fd4fd66ec7745d884036d502abba0d553a637703af79939b844164b13e60eea339ccb043d7fbd74c3da2592b864
@@ -6711,7 +6894,7 @@ fsevents@^2.1.2:
   languageName: node
   linkType: hard
 
-"pkg-dir@npm:^4.2.0":
+"pkg-dir@npm:^4.1.0, pkg-dir@npm:^4.2.0":
   version: 4.2.0
   resolution: "pkg-dir@npm:4.2.0"
   dependencies:
@@ -6954,7 +7137,7 @@ fsevents@^2.1.2:
   languageName: node
   linkType: hard
 
-"readable-stream@npm:2 || 3, readable-stream@npm:^2.0.0, readable-stream@npm:^2.0.1, readable-stream@npm:^2.0.2, readable-stream@npm:^2.0.5, readable-stream@npm:^2.0.6, readable-stream@npm:^2.1.5, readable-stream@npm:^2.2.2, readable-stream@npm:^2.3.3, readable-stream@npm:^2.3.5, readable-stream@npm:^2.3.6, readable-stream@npm:~2.3.6":
+"readable-stream@npm:^2.0.0, readable-stream@npm:^2.0.1, readable-stream@npm:^2.0.2, readable-stream@npm:^2.0.5, readable-stream@npm:^2.0.6, readable-stream@npm:^2.1.5, readable-stream@npm:^2.2.2, readable-stream@npm:^2.3.3, readable-stream@npm:^2.3.5, readable-stream@npm:^2.3.6, readable-stream@npm:~2.3.6":
   version: 2.3.7
   resolution: "readable-stream@npm:2.3.7"
   dependencies:
@@ -7214,7 +7397,7 @@ fsevents@^2.1.2:
   languageName: node
   linkType: hard
 
-"resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.18.1, resolve@^1.4.0":
+"resolve@1.20.0, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.18.1, resolve@^1.19.0, resolve@^1.4.0":
   version: 1.20.0
   resolution: "resolve@npm:1.20.0"
   dependencies:
@@ -7224,7 +7407,7 @@ fsevents@^2.1.2:
   languageName: node
   linkType: hard
 
-"resolve@patch:resolve@^1.1.6#builtin<compat/resolve>, resolve@patch:resolve@^1.1.7#builtin<compat/resolve>, resolve@patch:resolve@^1.10.0#builtin<compat/resolve>, resolve@patch:resolve@^1.18.1#builtin<compat/resolve>, resolve@patch:resolve@^1.4.0#builtin<compat/resolve>":
+"resolve@patch:resolve@1.20.0#builtin<compat/resolve>, resolve@patch:resolve@^1.1.6#builtin<compat/resolve>, resolve@patch:resolve@^1.1.7#builtin<compat/resolve>, resolve@patch:resolve@^1.10.0#builtin<compat/resolve>, resolve@patch:resolve@^1.18.1#builtin<compat/resolve>, resolve@patch:resolve@^1.19.0#builtin<compat/resolve>, resolve@patch:resolve@^1.4.0#builtin<compat/resolve>":
   version: 1.20.0
   resolution: "resolve@patch:resolve@npm%3A1.20.0#builtin<compat/resolve>::version=1.20.0&hash=3388aa"
   dependencies:
@@ -7290,6 +7473,36 @@ fsevents@^2.1.2:
   languageName: node
   linkType: hard
 
+"rollup-plugin-typescript2@npm:^0.30.0":
+  version: 0.30.0
+  resolution: "rollup-plugin-typescript2@npm:0.30.0"
+  dependencies:
+    "@rollup/pluginutils": ^4.1.0
+    find-cache-dir: ^3.3.1
+    fs-extra: 8.1.0
+    resolve: 1.20.0
+    tslib: 2.1.0
+  peerDependencies:
+    rollup: ">=1.26.3"
+    typescript: ">=2.4.0"
+  checksum: 3bf7a4d398f53461d6486ddb92f3649e646a6d1f89340090bb242764e9ba09e97d48659ffa9135e3c8b898d9ed3bcca9269e0d6beaef4e44659ae06791f79bea
+  languageName: node
+  linkType: hard
+
+"rollup@npm:^2.41.4":
+  version: 2.41.4
+  resolution: "rollup@npm:2.41.4"
+  dependencies:
+    fsevents: ~2.3.1
+  dependenciesMeta:
+    fsevents:
+      optional: true
+  bin:
+    rollup: dist/bin/rollup
+  checksum: 993457491ed6d89d247839a4466e76dd95a5d4ba85a2419aaa02b431612eda62d79ec2c7700ab841bf0ebde8efc729f321e81ccf64b8387260d6916e24a90575
+  languageName: node
+  linkType: hard
+
 "rsvp@npm:^4.8.4":
   version: 4.8.5
   resolution: "rsvp@npm:4.8.5"
@@ -7435,7 +7648,7 @@ fsevents@^2.1.2:
   languageName: node
   linkType: hard
 
-"semver@npm:7.x, semver@npm:^7.2.1, semver@npm:^7.3.2":
+"semver@npm:7.x, semver@npm:^7.2.1, semver@npm:^7.3.2, semver@npm:^7.3.4":
   version: 7.3.4
   resolution: "semver@npm:7.3.4"
   dependencies:
@@ -8103,16 +8316,6 @@ fsevents@^2.1.2:
   languageName: node
   linkType: hard
 
-"through2@npm:^3.0.1":
-  version: 3.0.2
-  resolution: "through2@npm:3.0.2"
-  dependencies:
-    inherits: ^2.0.4
-    readable-stream: 2 || 3
-  checksum: 26c76a8989c8870e422c262506b55020ab42ae9c0888b8096dd140f8d6ac09ada59f71cddd630ccc5b3aa0bba373c223a27b969e830ee6040f12db952c15a8cd
-  languageName: node
-  linkType: hard
-
 "through@npm:^2.3.8":
   version: 2.3.8
   resolution: "through@npm:2.3.8"
@@ -8276,6 +8479,13 @@ fsevents@^2.1.2:
   languageName: node
   linkType: hard
 
+"tslib@npm:2.1.0, tslib@npm:^2.1.0":
+  version: 2.1.0
+  resolution: "tslib@npm:2.1.0"
+  checksum: d8f5bdd067611651c6b846c2388f4dc8ba1f5af124e66105f5263d1ad56da17f4b8c6566887ca2f205c5a9758451871ceca87d5d06087af2dca1699c5e33db69
+  languageName: node
+  linkType: hard
+
 "tslib@npm:^1.8.1, tslib@npm:^1.9.0":
   version: 1.14.1
   resolution: "tslib@npm:1.14.1"
@@ -8489,6 +8699,13 @@ typescript@^4.2.3:
   languageName: node
   linkType: hard
 
+"universalify@npm:^0.1.0":
+  version: 0.1.2
+  resolution: "universalify@npm:0.1.2"
+  checksum: 420fc6547357782c700d53e9a92506a8e95345b13e97684c8f9ab75237912ec2ebb6af8ac10d4f7406b7b6bd21c58f6c5c0811414fb0b4091b78b4743fa6806e
+  languageName: node
+  linkType: hard
+
 "universalify@npm:^2.0.0":
   version: 2.0.0
   resolution: "universalify@npm:2.0.0"
@@ -8626,7 +8843,7 @@ typescript@^4.2.3:
   languageName: node
   linkType: hard
 
-"vinyl-fs@npm:^3.0.0, vinyl-fs@npm:^3.0.3":
+"vinyl-fs@npm:^3.0.0":
   version: 3.0.3
   resolution: "vinyl-fs@npm:3.0.3"
   dependencies:
@@ -8675,7 +8892,7 @@ typescript@^4.2.3:
   languageName: node
   linkType: hard
 
-"vinyl@npm:^2.0.0, vinyl@npm:^2.2.0":
+"vinyl@npm:^2.0.0":
   version: 2.2.1
   resolution: "vinyl@npm:2.2.1"
   dependencies:

From 5d0ccf8e3e6c68953830f1d9cb0a7094414e93e2 Mon Sep 17 00:00:00 2001
From: Johannes Loher <johannes.loher@fg4f.de>
Date: Wed, 17 Mar 2021 12:18:03 +0100
Subject: [PATCH 2/6] Fix formatting in bump-version

---
 gulpfile.js | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/gulpfile.js b/gulpfile.js
index 3279ee4..4348cab 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -205,16 +205,11 @@ function bumpVersion(cb) {
         console.log(`Updating version number to '${targetVersion}'`);
 
         packageJson.version = targetVersion;
-        fs.writeJSONSync("package.json", packageJson, { spaces: 2 });
-
-        if (packageLockJson) {
-            packageLockJson.version = targetVersion;
-            fs.writeJSONSync("package-lock.json", packageLockJson, { spaces: 2 });
-        }
+        fs.writeJSONSync("package.json", packageJson, { spaces: 4 });
 
         manifest.file.version = targetVersion;
         manifest.file.download = getDownloadURL(targetVersion);
-        fs.writeJSONSync(path.join(sourceDirectory, manifest.name), manifest.file, { spaces: 2 });
+        fs.writeJSONSync(path.join(sourceDirectory, manifest.name), manifest.file, { spaces: 4 });
 
         return cb();
     } catch (err) {

From 39b3affed917d5286117d62230828b292b838f5d Mon Sep 17 00:00:00 2001
From: Johannes Loher <johannes.loher@fg4f.de>
Date: Wed, 17 Mar 2021 12:30:44 +0100
Subject: [PATCH 3/6] Properly generate sourceMap and add launch config for
 chrome debugging

---
 .vscode/launch.json | 16 ++++++++++++++++
 tsconfig.json       |  3 ++-
 2 files changed, 18 insertions(+), 1 deletion(-)
 create mode 100644 .vscode/launch.json

diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..9371697
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,16 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "type": "pwa-chrome",
+            "request": "launch",
+            "runtimeExecutable": "/usr/bin/chromium",
+            "name": "Launch Chrome against localhost",
+            "url": "http://localhost:30000/game",
+            "webRoot": "${workspaceFolder}/dist"
+        }
+    ]
+}
diff --git a/tsconfig.json b/tsconfig.json
index d21acca..55672c0 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -6,7 +6,8 @@
         "esModuleInterop": true,
         "moduleResolution": "node",
         "forceConsistentCasingInFileNames": true,
-        "strict": true
+        "strict": true,
+        "sourceMap": true
     },
     "include": ["src"]
 }

From 56dfcfdb6c064a65fc06518dd4004de8222b070c Mon Sep 17 00:00:00 2001
From: Johannes Loher <johannes.loher@fg4f.de>
Date: Wed, 17 Mar 2021 12:32:53 +0100
Subject: [PATCH 4/6] update dependencies

---
 package.json |   6 +--
 yarn.lock    | 125 +++++++++++++++++----------------------------------
 2 files changed, 43 insertions(+), 88 deletions(-)

diff --git a/package.json b/package.json
index a5e2c6a..a67a015 100644
--- a/package.json
+++ b/package.json
@@ -50,10 +50,10 @@
         "@rollup/plugin-node-resolve": "^11.2.0",
         "@types/fs-extra": "^9.0.8",
         "@types/jest": "^26.0.20",
-        "@typescript-eslint/eslint-plugin": "^4.16.1",
-        "@typescript-eslint/parser": "^4.16.1",
+        "@typescript-eslint/eslint-plugin": "^4.18.0",
+        "@typescript-eslint/parser": "^4.18.0",
         "chalk": "^4.1.0",
-        "eslint": "^7.21.0",
+        "eslint": "^7.22.0",
         "eslint-config-prettier": "^8.1.0",
         "eslint-plugin-jest": "^24.3.2",
         "eslint-plugin-prettier": "^3.3.1",
diff --git a/yarn.lock b/yarn.lock
index b96e2ee..21e5aac 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1327,12 +1327,12 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@typescript-eslint/eslint-plugin@npm:^4.16.1":
-  version: 4.16.1
-  resolution: "@typescript-eslint/eslint-plugin@npm:4.16.1"
+"@typescript-eslint/eslint-plugin@npm:^4.18.0":
+  version: 4.18.0
+  resolution: "@typescript-eslint/eslint-plugin@npm:4.18.0"
   dependencies:
-    "@typescript-eslint/experimental-utils": 4.16.1
-    "@typescript-eslint/scope-manager": 4.16.1
+    "@typescript-eslint/experimental-utils": 4.18.0
+    "@typescript-eslint/scope-manager": 4.18.0
     debug: ^4.1.1
     functional-red-black-tree: ^1.0.1
     lodash: ^4.17.15
@@ -1345,27 +1345,11 @@ __metadata:
   peerDependenciesMeta:
     typescript:
       optional: true
-  checksum: 873347906fdfe9a70dc80b80f1cbcc6dff00fae5a367ec186e52c6ce616941aa757cd5bc8dbba706f86633df4af396e6c33d68b890983444417a3e76a94c9ad4
+  checksum: f137baf23f42345986a3570016ef0bacfff9f1e973f87962e09b826dde26b2f3d4c383a2b22839d2cd46baeb54753ac52c8837d41aa6caaf2ce122efdefea689
   languageName: node
   linkType: hard
 
-"@typescript-eslint/experimental-utils@npm:4.16.1":
-  version: 4.16.1
-  resolution: "@typescript-eslint/experimental-utils@npm:4.16.1"
-  dependencies:
-    "@types/json-schema": ^7.0.3
-    "@typescript-eslint/scope-manager": 4.16.1
-    "@typescript-eslint/types": 4.16.1
-    "@typescript-eslint/typescript-estree": 4.16.1
-    eslint-scope: ^5.0.0
-    eslint-utils: ^2.0.0
-  peerDependencies:
-    eslint: "*"
-  checksum: 526ca13632841963ed29fcd3688ff300d5ee3ecd442b8e1e540bee7fe09e4595cd43da7aa6c3c5f27c8876f55c823b4fd34e9639ceaf1f8af2a5db4561c57e82
-  languageName: node
-  linkType: hard
-
-"@typescript-eslint/experimental-utils@npm:^4.0.1":
+"@typescript-eslint/experimental-utils@npm:4.18.0, @typescript-eslint/experimental-utils@npm:^4.0.1":
   version: 4.18.0
   resolution: "@typescript-eslint/experimental-utils@npm:4.18.0"
   dependencies:
@@ -1381,30 +1365,20 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@typescript-eslint/parser@npm:^4.16.1":
-  version: 4.16.1
-  resolution: "@typescript-eslint/parser@npm:4.16.1"
+"@typescript-eslint/parser@npm:^4.18.0":
+  version: 4.18.0
+  resolution: "@typescript-eslint/parser@npm:4.18.0"
   dependencies:
-    "@typescript-eslint/scope-manager": 4.16.1
-    "@typescript-eslint/types": 4.16.1
-    "@typescript-eslint/typescript-estree": 4.16.1
+    "@typescript-eslint/scope-manager": 4.18.0
+    "@typescript-eslint/types": 4.18.0
+    "@typescript-eslint/typescript-estree": 4.18.0
     debug: ^4.1.1
   peerDependencies:
     eslint: ^5.0.0 || ^6.0.0 || ^7.0.0
   peerDependenciesMeta:
     typescript:
       optional: true
-  checksum: 9ce7c8b2ec9679c6428b44fe06f6a56f145b54b72549691d97e3d6a4ffd0fc116ca61bdef695e77c3217fc30f2988434078e09009ab2dc5ec028e6f3cecb9a16
-  languageName: node
-  linkType: hard
-
-"@typescript-eslint/scope-manager@npm:4.16.1":
-  version: 4.16.1
-  resolution: "@typescript-eslint/scope-manager@npm:4.16.1"
-  dependencies:
-    "@typescript-eslint/types": 4.16.1
-    "@typescript-eslint/visitor-keys": 4.16.1
-  checksum: 2872ae6b3c1afe6d0de2168cf4c14864ac6183de8db081f8efc236a4a6f6448d59f80abc529ab3b50b48b8a9a5b21c4bacbad8936a384ca3c2f1bb4b950fd4de
+  checksum: d2f907dc2888078fa6aaca329e39209cc0ceff0dfe43657835b9fbd73678d848077572fdf451dd0cae4ea199b8bfa0f3791037bd9174049668914c7a8ac55157
   languageName: node
   linkType: hard
 
@@ -1418,13 +1392,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@typescript-eslint/types@npm:4.16.1":
-  version: 4.16.1
-  resolution: "@typescript-eslint/types@npm:4.16.1"
-  checksum: 5df220b8dff372540921d8ef478f4107e6eb51824e7346c942dafc2d181cd937983fa80f44c2e94abf28b57a303e72205915d2bca13ac37c028a98710fd37baa
-  languageName: node
-  linkType: hard
-
 "@typescript-eslint/types@npm:4.18.0":
   version: 4.18.0
   resolution: "@typescript-eslint/types@npm:4.18.0"
@@ -1432,24 +1399,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@typescript-eslint/typescript-estree@npm:4.16.1":
-  version: 4.16.1
-  resolution: "@typescript-eslint/typescript-estree@npm:4.16.1"
-  dependencies:
-    "@typescript-eslint/types": 4.16.1
-    "@typescript-eslint/visitor-keys": 4.16.1
-    debug: ^4.1.1
-    globby: ^11.0.1
-    is-glob: ^4.0.1
-    semver: ^7.3.2
-    tsutils: ^3.17.1
-  peerDependenciesMeta:
-    typescript:
-      optional: true
-  checksum: d09de17eb15f08a44574d62a3eadcacd6d331372bd7525cfb7d08d9caeb8d09c2f5a195927ea48a71996337baab47bf9c7d50549c160b901be6a6bc1df9c3f39
-  languageName: node
-  linkType: hard
-
 "@typescript-eslint/typescript-estree@npm:4.18.0":
   version: 4.18.0
   resolution: "@typescript-eslint/typescript-estree@npm:4.18.0"
@@ -1468,16 +1417,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@typescript-eslint/visitor-keys@npm:4.16.1":
-  version: 4.16.1
-  resolution: "@typescript-eslint/visitor-keys@npm:4.16.1"
-  dependencies:
-    "@typescript-eslint/types": 4.16.1
-    eslint-visitor-keys: ^2.0.0
-  checksum: 7b3f87165fc3533e80c8e5848306dca7ffbe7a6c04c40895cb5cdbfdf55bca606933efae20c16d91576e0ab926f8f539257b1fb13231aac3b0c8ad9d741042c9
-  languageName: node
-  linkType: hard
-
 "@typescript-eslint/visitor-keys@npm:4.18.0":
   version: 4.18.0
   resolution: "@typescript-eslint/visitor-keys@npm:4.18.0"
@@ -2956,10 +2895,10 @@ __metadata:
     "@rollup/plugin-node-resolve": ^11.2.0
     "@types/fs-extra": ^9.0.8
     "@types/jest": ^26.0.20
-    "@typescript-eslint/eslint-plugin": ^4.16.1
-    "@typescript-eslint/parser": ^4.16.1
+    "@typescript-eslint/eslint-plugin": ^4.18.0
+    "@typescript-eslint/parser": ^4.18.0
     chalk: ^4.1.0
-    eslint: ^7.21.0
+    eslint: ^7.22.0
     eslint-config-prettier: ^8.1.0
     eslint-plugin-jest: ^24.3.2
     eslint-plugin-prettier: ^3.3.1
@@ -3248,9 +3187,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"eslint@npm:^7.21.0":
-  version: 7.21.0
-  resolution: "eslint@npm:7.21.0"
+"eslint@npm:^7.22.0":
+  version: 7.22.0
+  resolution: "eslint@npm:7.22.0"
   dependencies:
     "@babel/code-frame": 7.12.11
     "@eslint/eslintrc": ^0.4.0
@@ -3269,7 +3208,7 @@ __metadata:
     file-entry-cache: ^6.0.1
     functional-red-black-tree: ^1.0.1
     glob-parent: ^5.0.0
-    globals: ^12.1.0
+    globals: ^13.6.0
     ignore: ^4.0.6
     import-fresh: ^3.0.0
     imurmurhash: ^0.1.4
@@ -3277,7 +3216,7 @@ __metadata:
     js-yaml: ^3.13.1
     json-stable-stringify-without-jsonify: ^1.0.1
     levn: ^0.4.1
-    lodash: ^4.17.20
+    lodash: ^4.17.21
     minimatch: ^3.0.4
     natural-compare: ^1.4.0
     optionator: ^0.9.1
@@ -3291,7 +3230,7 @@ __metadata:
     v8-compile-cache: ^2.0.3
   bin:
     eslint: bin/eslint.js
-  checksum: aa8fd50cddc4ab259e2d0ff8f43f0601060543c12e335d76ee074bf25ad02a885bea9d48a367de736d3bdb871de7eb62e6d67930c0173cc46280ddd0f236e740
+  checksum: 9be0a215b6b1e2941318b3e0c11ada8ba9a4adacf5960ab916d07f1d619828af40cba00e8ed7d151b8c715ba8ea81f4c2a56e46a2558d9795788b4f410a95ec4
   languageName: node
   linkType: hard
 
@@ -4128,6 +4067,15 @@ fsevents@^1.2.7:
   languageName: node
   linkType: hard
 
+"globals@npm:^13.6.0":
+  version: 13.6.0
+  resolution: "globals@npm:13.6.0"
+  dependencies:
+    type-fest: ^0.20.2
+  checksum: 0322d9c1b210be233060aa79592bc65c45572237be8dbedabf830dbd70120ac21f8721309a396782463e60c4cc0b92a6476a348b4b13e481f35e361195328b8e
+  languageName: node
+  linkType: hard
+
 "globby@npm:^11.0.1":
   version: 11.0.2
   resolution: "globby@npm:11.0.2"
@@ -5822,7 +5770,7 @@ fsevents@^1.2.7:
   languageName: node
   linkType: hard
 
-"lodash@npm:4.x, lodash@npm:^4.0.0, lodash@npm:^4.17.11, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:~4.17.10":
+"lodash@npm:4.x, lodash@npm:^4.0.0, lodash@npm:^4.17.11, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:~4.17.10":
   version: 4.17.21
   resolution: "lodash@npm:4.17.21"
   checksum: 4983720b9abca930a4a46f18db163d7dad8dd00dbed6db0cc7b499b33b717cce69f80928b27bbb1ff2cbd3b19d251ee90669a8b5ea466072ca81c2ebe91e7468
@@ -8552,6 +8500,13 @@ fsevents@^1.2.7:
   languageName: node
   linkType: hard
 
+"type-fest@npm:^0.20.2":
+  version: 0.20.2
+  resolution: "type-fest@npm:0.20.2"
+  checksum: 1f887bc6150e632fb772fd28e33c22a4ab036c6f484fa9ac2e2115f6cae9d62bba7ca0368e3332b539d85bd2c8391c7bff22ad410abcbc9ab3774d61e250b210
+  languageName: node
+  linkType: hard
+
 "type-fest@npm:^0.6.0":
   version: 0.6.0
   resolution: "type-fest@npm:0.6.0"

From 9332baab825cd7447655e1d4eff1390ee9227608 Mon Sep 17 00:00:00 2001
From: Johannes Loher <johannes.loher@fg4f.de>
Date: Wed, 17 Mar 2021 17:32:29 +0100
Subject: [PATCH 5/6] Small fix in tsconfig.spec.json

---
 spec/tsconfig.spec.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/spec/tsconfig.spec.json b/spec/tsconfig.spec.json
index eb736d7..e8d5b37 100644
--- a/spec/tsconfig.spec.json
+++ b/spec/tsconfig.spec.json
@@ -3,5 +3,5 @@
     "compilerOptions": {
         "types": ["@league-of-foundry-developers/foundry-vtt-types", "jest"]
     },
-    "include": ["src", "./"]
+    "include": ["../src", "./"]
 }

From c768712e439f2ace19cf68bbadced615eb7b93ea Mon Sep 17 00:00:00 2001
From: Johannes Loher <johannes.loher@fg4f.de>
Date: Wed, 17 Mar 2021 17:35:26 +0100
Subject: [PATCH 6/6] Somemore small fixes

---
 .eslintrc.js | 6 ------
 gulpfile.js  | 1 -
 2 files changed, 7 deletions(-)

diff --git a/.eslintrc.js b/.eslintrc.js
index 2e7be78..616d3ef 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -25,11 +25,5 @@ module.exports = {
                 "@typescript-eslint/no-var-requires": "off",
             },
         },
-        {
-            files: ["./test/**/*.js"],
-            env: {
-                "jest/globals": true,
-            },
-        },
     ],
 };
diff --git a/gulpfile.js b/gulpfile.js
index 4348cab..f35486d 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -178,7 +178,6 @@ function getTargetVersion(currentVersion, release) {
  */
 function bumpVersion(cb) {
     const packageJson = fs.readJSONSync("package.json");
-    const packageLockJson = fs.existsSync("package-lock.json") ? fs.readJSONSync("package-lock.json") : undefined;
     const manifest = getManifest();
 
     if (!manifest) cb(Error(chalk.red("Manifest JSON not found")));