mirror of
https://github.com/Kornstalx/5etools-mirror-2.github.io.git
synced 2025-10-28 20:45:35 -05:00
v1.207.0
This commit is contained in:
90
test/test-adventure-book-map-grids-parents.js
Normal file
90
test/test-adventure-book-map-grids-parents.js
Normal file
@@ -0,0 +1,90 @@
|
||||
import "../js/parser.js";
|
||||
import "../js/utils.js";
|
||||
import * as ut from "../node/util.js";
|
||||
|
||||
const getClosestEntryId = stack => {
|
||||
const ent = [...stack].reverse().find(ent => ent.id);
|
||||
if (!ent) return null;
|
||||
return ent.id;
|
||||
};
|
||||
|
||||
const getMapLogName = ({obj, stack}) => {
|
||||
const closestEntryId = getClosestEntryId(stack);
|
||||
const ptsId = [
|
||||
obj.id ? `id "${obj.id}"` : "",
|
||||
obj.mapParent?.id ? `parent id "${obj.mapParent.id}"` : "",
|
||||
closestEntryId ? `closest entry id "${closestEntryId}"` : "",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("; ");
|
||||
|
||||
return `${obj.title ? `"${obj.title}"` : "[Untitled]"}${ptsId ? ` (${ptsId})` : ""}`;
|
||||
};
|
||||
|
||||
const getJoinedWarnings = ({filename, warnings}) => {
|
||||
return `in "${filename}"\n${warnings.map(it => `\t${it}`).join("\n")}`;
|
||||
};
|
||||
|
||||
let ixLogGroup = 0;
|
||||
const logGroup = ({name, lines}) => {
|
||||
if (!lines.length) return;
|
||||
if (ixLogGroup++) console.log(`\n${"-".repeat(20)}`);
|
||||
|
||||
console.log(`\n=== ${name} ===\n`);
|
||||
lines.forEach(wrn => console.warn(wrn));
|
||||
};
|
||||
|
||||
async function main () {
|
||||
console.log(`##### Validating adventure/book map grids #####`);
|
||||
|
||||
const warningsNoParent = [];
|
||||
const warningsNoGrid = [];
|
||||
|
||||
const walker = MiscUtil.getWalker({isNoModification: true, keyBlocklist: MiscUtil.GENERIC_WALKER_ENTRIES_KEY_BLOCKLIST});
|
||||
const IMAGE_TYPES_MAP = new Set(["map", "mapPlayer"]);
|
||||
|
||||
[
|
||||
{filename: "adventures.json", prop: "adventure", dir: "adventure"},
|
||||
{filename: "books.json", prop: "book", dir: "book"},
|
||||
]
|
||||
.flatMap(({filename, prop, dir}) => ut.readJson(`./data/${filename}`)[prop]
|
||||
.map(({id}) => ({filename: `./data/${dir}/${dir}-${id.toLowerCase()}.json`})))
|
||||
.forEach(({filename}) => {
|
||||
const json = ut.readJson(filename);
|
||||
|
||||
const warningsNoParentFile = [];
|
||||
const warningsNoGridFile = [];
|
||||
|
||||
const stack = [];
|
||||
walker.walk(
|
||||
json,
|
||||
{
|
||||
object: (obj) => {
|
||||
if (obj.type !== "image" || !IMAGE_TYPES_MAP.has(obj.imageType)) return;
|
||||
|
||||
if (obj.imageType === "mapPlayer" && !obj.mapParent?.id) {
|
||||
warningsNoParentFile.push(getMapLogName({obj, stack}));
|
||||
}
|
||||
|
||||
if (obj.grid !== undefined) return;
|
||||
|
||||
warningsNoGridFile.push(getMapLogName({obj, stack}));
|
||||
},
|
||||
},
|
||||
null,
|
||||
stack,
|
||||
);
|
||||
|
||||
if (warningsNoParentFile.length) warningsNoParent.push(`Found "mapPlayer"${warningsNoParentFile.length === 1 ? "" : "s"} with no "mapParent" ${getJoinedWarnings({filename, warnings: warningsNoParentFile})}`);
|
||||
if (warningsNoGridFile.length) warningsNoGrid.push(`Found map${warningsNoGridFile.length === 1 ? "" : "s"} with no "grid" ${getJoinedWarnings({filename, warnings: warningsNoGridFile})}`);
|
||||
});
|
||||
|
||||
logGroup({name: "Map Parents", lines: warningsNoParent});
|
||||
logGroup({name: "Map Grids", lines: warningsNoGrid});
|
||||
|
||||
if (warningsNoParent.length || warningsNoGrid.length) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export default main();
|
||||
@@ -1,65 +0,0 @@
|
||||
import "../js/parser.js";
|
||||
import "../js/utils.js";
|
||||
import * as ut from "../node/util.js";
|
||||
|
||||
const getClosestEntryId = stack => {
|
||||
const ent = [...stack].reverse().find(ent => ent.id);
|
||||
if (!ent) return null;
|
||||
return ent.id;
|
||||
};
|
||||
|
||||
async function main () {
|
||||
console.log(`##### Validating adventure/book map grids #####`);
|
||||
|
||||
const errors = [];
|
||||
const walker = MiscUtil.getWalker({isNoModification: true, keyBlocklist: MiscUtil.GENERIC_WALKER_ENTRIES_KEY_BLOCKLIST});
|
||||
const IMAGE_TYPES_MAP = new Set(["map", "mapPlayer"]);
|
||||
|
||||
[
|
||||
{filename: "adventures.json", prop: "adventure", dir: "adventure"},
|
||||
{filename: "books.json", prop: "book", dir: "book"},
|
||||
]
|
||||
.flatMap(({filename, prop, dir}) => ut.readJson(`./data/${filename}`)[prop]
|
||||
.map(({id}) => ({filename: `./data/${dir}/${dir}-${id.toLowerCase()}.json`})))
|
||||
.forEach(({filename}) => {
|
||||
const json = ut.readJson(filename);
|
||||
|
||||
const errorsFile = [];
|
||||
const stack = [];
|
||||
walker.walk(
|
||||
json,
|
||||
{
|
||||
object: (obj) => {
|
||||
if (obj.type !== "image" || !IMAGE_TYPES_MAP.has(obj.imageType)) return;
|
||||
|
||||
if (obj.grid !== undefined) return;
|
||||
|
||||
const closestEntryId = getClosestEntryId(stack);
|
||||
const ptsId = [
|
||||
obj.id ? `id "${obj.id}"` : "",
|
||||
obj.mapParent?.id ? `parent id "${obj.mapParent.id}"` : "",
|
||||
closestEntryId ? `closest entry id "${closestEntryId}"` : "",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("; ");
|
||||
|
||||
errorsFile.push(`${obj.title ? `"${obj.title}"` : "[Untitled]"}${ptsId ? ` (${ptsId})` : ""}`);
|
||||
},
|
||||
},
|
||||
null,
|
||||
stack,
|
||||
);
|
||||
if (!errorsFile.length) return;
|
||||
|
||||
errors.push(`Found maps with no "grid" in "${filename}"\n${errorsFile.map(it => `\t${it}`).join("\n")}`);
|
||||
});
|
||||
|
||||
if (errors.length) {
|
||||
errors.forEach(err => console.error(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export default main();
|
||||
@@ -15,7 +15,7 @@ async function main () {
|
||||
if (!(await (await import("./test-multisource.js")).default)) handleFail();
|
||||
if (!(await (await import("./test-language-fonts.js")).default)) handleFail();
|
||||
if (!(await (await import("./test-adventure-book-contents.js")).default)) handleFail();
|
||||
await (await import("./test-adventure-book-map-grids.js")).default; // don't fail on missing map grids
|
||||
await (await import("./test-adventure-book-map-grids-parents.js")).default; // don't fail on missing map grids
|
||||
if (!(await (await import("./test-foundry.js")).default)) handleFail();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
import * as fs from "fs";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import "../js/parser.js";
|
||||
import "../js/utils.js";
|
||||
import * as ut from "../node/util.js";
|
||||
import {listFiles} from "../node/util.js";
|
||||
|
||||
class _TestTokenImages {
|
||||
static _IS_CLEAN_MM_EXTRAS = false;
|
||||
static _IS_CLEAN_EXTRAS = false;
|
||||
static _IS_MOVE_EXTRAS = false;
|
||||
static _SOURCES_CLEAN_EXTRAS = [
|
||||
Parser.SRC_MM,
|
||||
Parser.SRC_MPMM,
|
||||
Parser.SRC_BAM,
|
||||
Parser.SRC_VRGR,
|
||||
];
|
||||
|
||||
static _PATH_BASE = `./img/bestiary/tokens`;
|
||||
static _EXT = "webp";
|
||||
@@ -20,11 +28,11 @@ class _TestTokenImages {
|
||||
static _existing = new Set();
|
||||
static _expectedFromHashToken = {};
|
||||
|
||||
static _mmTokens = null;
|
||||
static _existingSourceTokens = null;
|
||||
|
||||
static _isMmToken (filename) {
|
||||
if (!this._mmTokens) this._mmTokens = fs.readdirSync(`${this._PATH_BASE}/${Parser.SRC_MM}`).mergeMap(it => ({[it]: true}));
|
||||
return !!this._mmTokens[filename.split("/").last()];
|
||||
static _isExistingSourceToken ({filename, src}) {
|
||||
(this._existingSourceTokens ||= {})[src] ||= fs.readdirSync(`${this._PATH_BASE}/${src}`).mergeMap(it => ({[it]: true}));
|
||||
return !!this._existingSourceTokens[src][filename.split("/").last()];
|
||||
}
|
||||
|
||||
static _readBestiaryJson () {
|
||||
@@ -79,12 +87,25 @@ class _TestTokenImages {
|
||||
});
|
||||
this._existing.forEach((img) => {
|
||||
delete this._expectedFromHashToken[img];
|
||||
|
||||
if (!this._expected.has(img)) {
|
||||
if (this._IS_CLEAN_MM_EXTRAS && this._isMmToken(img)) {
|
||||
fs.unlinkSync(img);
|
||||
results.push(`[ !DELETE] ${img}`);
|
||||
return;
|
||||
if (this._IS_CLEAN_EXTRAS) {
|
||||
const srcExisting = this._SOURCES_CLEAN_EXTRAS
|
||||
.find(src => this._isExistingSourceToken({filename: img, src}));
|
||||
if (srcExisting) {
|
||||
fs.unlinkSync(img);
|
||||
results.push(`[ !DELETE] ${img} (found in "${srcExisting}")`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this._IS_MOVE_EXTRAS) {
|
||||
const dir = path.join(path.dirname(img), "extras");
|
||||
fs.mkdirSync(dir, {recursive: true});
|
||||
fs.copyFileSync(img, path.join(dir, path.basename(img)));
|
||||
fs.unlinkSync(img);
|
||||
}
|
||||
|
||||
results.push(`[ EXTRA] ${img}`);
|
||||
isError = true;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ async function main () {
|
||||
return relativeFilePath;
|
||||
},
|
||||
});
|
||||
await jsonTester.pInit();
|
||||
|
||||
const fileList = Uf.listJsonFiles("data")
|
||||
.filter(filePath => {
|
||||
|
||||
@@ -968,6 +968,11 @@ class DuplicateEntityCheck extends DataTesterBase {
|
||||
.forEach(([prop, arr]) => {
|
||||
const positions = {};
|
||||
arr.forEach((ent, i) => {
|
||||
if (ent == null) return;
|
||||
if (typeof ent !== "object" || ent instanceof Array) return;
|
||||
|
||||
ent.__prop = prop;
|
||||
|
||||
isSkipBaseCheck || this._doAddPosition({prop, ent, ixArray: i, positions});
|
||||
|
||||
if (!ent._versions) return;
|
||||
|
||||
@@ -12,6 +12,7 @@ export const BLOCKLIST_SOURCES_PAGES = new Set([
|
||||
Parser.SRC_LK,
|
||||
Parser.SRC_AATM,
|
||||
Parser.SRC_HFStCM,
|
||||
Parser.SRC_VNotEE,
|
||||
|
||||
// N.b.: other MCV source creatures mysteriously have page numbers on Beyond
|
||||
Parser.SRC_MCV4EC,
|
||||
|
||||
Reference in New Issue
Block a user