mirror of
https://github.com/Kornstalx/5etools-mirror-2.github.io.git
synced 2025-10-28 20:45:35 -05:00
v1.201.0
This commit is contained in:
67
test/jest/SplitByTags.test.js
Normal file
67
test/jest/SplitByTags.test.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import "../../js/parser.js";
|
||||
import "../../js/utils.js";
|
||||
import "../../js/render.js";
|
||||
|
||||
describe("Splitting by tags", () => {
|
||||
it("Should handle a single tag", () => {
|
||||
expect(Renderer.splitByTags("aa {@b bb} cc"))
|
||||
.toStrictEqual([
|
||||
"aa ",
|
||||
"{@b bb}",
|
||||
" cc",
|
||||
]);
|
||||
|
||||
expect(Renderer.splitByTags("aa{@b bb}"))
|
||||
.toStrictEqual([
|
||||
"aa",
|
||||
"{@b bb}",
|
||||
]);
|
||||
|
||||
expect(Renderer.splitByTags("{@b bb}"))
|
||||
.toStrictEqual([
|
||||
"{@b bb}",
|
||||
]);
|
||||
|
||||
expect(Renderer.splitByTags("{@h}"))
|
||||
.toStrictEqual([
|
||||
"{@h}",
|
||||
]);
|
||||
});
|
||||
|
||||
it("Should handle multiple tags", () => {
|
||||
expect(Renderer.splitByTags("{@b {@i aaa} bb} {@b cc}"))
|
||||
.toStrictEqual([
|
||||
"{@b {@i aaa} bb}",
|
||||
" ",
|
||||
"{@b cc}",
|
||||
]);
|
||||
});
|
||||
|
||||
it("Should handle property injectors", () => {
|
||||
expect(Renderer.splitByTags("{=amount1/v} {=amount2}"))
|
||||
.toStrictEqual([
|
||||
"{=amount1/v}",
|
||||
" ",
|
||||
"{=amount2}",
|
||||
]);
|
||||
|
||||
expect(Renderer.splitByTags("{=amount1/v} {@unit {=amount1}|egg|eggs}"))
|
||||
.toStrictEqual([
|
||||
"{=amount1/v}",
|
||||
" ",
|
||||
"{@unit {=amount1}|egg|eggs}",
|
||||
]);
|
||||
});
|
||||
|
||||
it("Should handle non-tags", () => {
|
||||
expect(Renderer.splitByTags("{@@a {@@b"))
|
||||
.toStrictEqual([
|
||||
"{@@a {@@b",
|
||||
]);
|
||||
|
||||
expect(Renderer.splitByTags("{@}"))
|
||||
.toStrictEqual([
|
||||
"{@}",
|
||||
]);
|
||||
});
|
||||
});
|
||||
31
test/jest/StripTags.test.js
Normal file
31
test/jest/StripTags.test.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import "../../js/parser.js";
|
||||
import "../../js/utils.js";
|
||||
import "../../js/render.js";
|
||||
|
||||
describe("Stripping tags", () => {
|
||||
it("Should handle a single tag", () => {
|
||||
expect(Renderer.stripTags("aa {@b bb} cc")).toBe("aa bb cc");
|
||||
expect(Renderer.stripTags("aa{@b bb}")).toBe("aabb");
|
||||
expect(Renderer.stripTags("{@b bb}")).toBe("bb");
|
||||
expect(Renderer.stripTags("{@h}")).toBe("Hit: ");
|
||||
});
|
||||
|
||||
it("Should handle multiple tags", () => {
|
||||
expect(Renderer.stripTags("{@b {@i aaa} bb} {@b cc}")).toBe("aaa bb cc");
|
||||
});
|
||||
|
||||
it("Should ignore property injectors", () => {
|
||||
expect(Renderer.stripTags("{=amount1/v} {=amount2}")).toBe("{=amount1/v} {=amount2}");
|
||||
expect(Renderer.stripTags("{=amount1/v} {@unit {=amount1}|egg|eggs}")).toBe("{=amount1/v} egg");
|
||||
});
|
||||
|
||||
it("Should ignore tags in allowlist", () => {
|
||||
expect(Renderer.stripTags("{@b {@i aaa} bb} {@b cc}", {allowlistTags: new Set(["@i"])})).toBe("{@i aaa} bb cc");
|
||||
expect(Renderer.stripTags("{@b {@i aaa} bb} {@b cc}", {allowlistTags: new Set([])})).toBe("aaa bb cc");
|
||||
});
|
||||
|
||||
it("Should only remove tags in blocklist", () => {
|
||||
expect(Renderer.stripTags("{@b {@i aaa} bb} {@b cc}", {blocklistTags: new Set(["@b"])})).toBe("{@i aaa} bb cc");
|
||||
expect(Renderer.stripTags("{@b {@i aaa} bb} {@b cc}", {blocklistTags: new Set([])})).toBe("{@b {@i aaa} bb} {@b cc}");
|
||||
});
|
||||
});
|
||||
@@ -7,12 +7,15 @@ const _BLOCKLIST_SOURCES = new Set([
|
||||
Parser.SRC_SCREEN_WILDERNESS_KIT,
|
||||
Parser.SRC_SCREEN_DUNGEON_KIT,
|
||||
Parser.SRC_SCREEN_SPELLJAMMER,
|
||||
|
||||
Parser.SRC_AL,
|
||||
Parser.SRC_SAC,
|
||||
]);
|
||||
|
||||
async function main () {
|
||||
console.log(`##### Validating adventure/book credits #####`);
|
||||
|
||||
[
|
||||
const cnt = [
|
||||
{filename: "adventures.json", prop: "adventure"},
|
||||
{filename: "books.json", prop: "book"},
|
||||
]
|
||||
@@ -24,10 +27,14 @@ async function main () {
|
||||
if (_BLOCKLIST_SOURCES.has(meta.source)) return false;
|
||||
return meta.contents && !meta.contents.some(it => it.name === "Credits");
|
||||
});
|
||||
if (!noCredits.length) return;
|
||||
if (!noCredits.length) return 0;
|
||||
|
||||
console.error(`\nMissing "Credits" chapters in "${filename}":\n${noCredits.map(meta => `\t${meta.source}`).join("\n")}`);
|
||||
});
|
||||
console.error(`\nMissing "Credits" chapters in "${filename}":\n${noCredits.map(meta => `\t${meta.id}`).join("\n")}`);
|
||||
return noCredits.length;
|
||||
})
|
||||
.sum();
|
||||
|
||||
if (!cnt) console.log("Credits are as expected.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -34,90 +34,113 @@ const BLOCKLIST_KEYS = new Set([
|
||||
"dragonMundaneItems",
|
||||
]);
|
||||
|
||||
const SUB_KEYS = {};
|
||||
const BLOCKLIST_ENTITIES = {
|
||||
"monster": {
|
||||
[Parser.SRC_DoSI]: new Set([
|
||||
"Merrow Extortionist",
|
||||
]),
|
||||
},
|
||||
"feat": {
|
||||
// Feats not in original PDF
|
||||
[Parser.SRC_GHLoE]: new Set(["*"]),
|
||||
},
|
||||
"spell": {
|
||||
// Feats not in original PDF
|
||||
[Parser.SRC_GHLoE]: new Set(["*"]),
|
||||
},
|
||||
};
|
||||
|
||||
function run ({isModificationMode = false} = {}) {
|
||||
const isBlocklistedEntity = ({prop, ent}) => {
|
||||
const source = SourceUtil.getEntitySource(ent);
|
||||
|
||||
if (BLOCKLIST_SOURCES_PAGES.has(source)) return true;
|
||||
|
||||
const set = MiscUtil.get(BLOCKLIST_ENTITIES, prop, source);
|
||||
if (!set) return false;
|
||||
|
||||
if (set.has("*")) return true;
|
||||
if (set.has(ent.name)) return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const isMissingPage = ({ent}) => {
|
||||
if (ent.inherits ? ent.inherits.page : ent.page) return false;
|
||||
if (ent._copy?._preserve?.page) return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
const doSaveMods = ({mods, json, file}) => {
|
||||
if (!mods) return;
|
||||
|
||||
let answer = "";
|
||||
while (!["y", "n", "quit"].includes(answer)) {
|
||||
answer = rl.question(`Save file with ${mods} modification${mods === 1 ? "" : "s"}? [y/n/quit]`);
|
||||
if (answer === "y") {
|
||||
console.log(`Saving ${file}...`);
|
||||
fs.writeFileSync(file, CleanUtil.getCleanJson(json), "utf-8");
|
||||
} else if (answer === "quit") {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const main = ({isModificationMode = false} = {}) => {
|
||||
console.log(`##### Checking for Missing Page Numbers #####`);
|
||||
|
||||
const FILE_MAP = {};
|
||||
const files = ut.listFiles({dir: `./data`, blocklistFilePrefixes: BLOCKLIST_FILE_PREFIXES});
|
||||
files
|
||||
ut.listFiles({dir: `./data`, blocklistFilePrefixes: BLOCKLIST_FILE_PREFIXES})
|
||||
.forEach(file => {
|
||||
let mods = 0;
|
||||
|
||||
const json = ut.readJson(file);
|
||||
Object.keys(json)
|
||||
.filter(k => !BLOCKLIST_KEYS.has(k))
|
||||
.forEach(k => {
|
||||
const data = json[k];
|
||||
if (data instanceof Array) {
|
||||
const noPage = data
|
||||
.filter(it => !BLOCKLIST_SOURCES_PAGES.has(SourceUtil.getEntitySource(it)))
|
||||
.filter(it => !(it.inherits ? it.inherits.page : it.page))
|
||||
.filter(it => !it._copy?._preserve?.page);
|
||||
.forEach(prop => {
|
||||
const data = json[prop];
|
||||
if (!(data instanceof Array)) return;
|
||||
|
||||
const subKeys = SUB_KEYS[k];
|
||||
if (subKeys) {
|
||||
subKeys.forEach(sk => {
|
||||
data
|
||||
.filter(it => it[sk] && it[sk] instanceof Array)
|
||||
.forEach(it => {
|
||||
const subArr = it[sk];
|
||||
subArr
|
||||
.forEach(subIt => subIt.source = subIt.source || it.source);
|
||||
noPage.push(...subArr
|
||||
// Skip un-named entries, as these are usually found on the page of their parent
|
||||
.filter(subIt => subIt.name)
|
||||
.filter(subIt => !BLOCKLIST_SOURCES_PAGES.has(subIt.source))
|
||||
.filter(subIt => !subIt.page));
|
||||
});
|
||||
});
|
||||
}
|
||||
const entsNoPage = data
|
||||
.filter(ent => !isBlocklistedEntity({prop, ent}) && isMissingPage({ent}));
|
||||
|
||||
if (noPage.length && isModificationMode) {
|
||||
console.log(`${file}:`);
|
||||
console.log(`\t${noPage.length} missing page number${noPage.length === 1 ? "" : "s"}`);
|
||||
}
|
||||
|
||||
noPage
|
||||
.forEach(it => {
|
||||
const ident = `${k.padEnd(20, " ")} ${SourceUtil.getEntitySource(it).padEnd(32, " ")} ${it.name}`;
|
||||
if (isModificationMode) {
|
||||
console.log(` ${ident}`);
|
||||
const page = rl.questionInt(" - Page = ");
|
||||
if (page) {
|
||||
it.page = page;
|
||||
mods++;
|
||||
}
|
||||
} else {
|
||||
const list = (FILE_MAP[file] = FILE_MAP[file] || []);
|
||||
list.push(ident);
|
||||
}
|
||||
});
|
||||
if (entsNoPage.length && isModificationMode) {
|
||||
console.log(`${file}:`);
|
||||
console.log(`\t${entsNoPage.length} missing page number${entsNoPage.length === 1 ? "" : "s"}`);
|
||||
}
|
||||
|
||||
entsNoPage
|
||||
.forEach(it => {
|
||||
const ident = `${prop.padEnd(20, " ")} ${SourceUtil.getEntitySource(it).padEnd(32, " ")} ${it.name}`;
|
||||
|
||||
if (!isModificationMode) {
|
||||
const list = (FILE_MAP[file] = FILE_MAP[file] || []);
|
||||
list.push(ident);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(` ${ident}`);
|
||||
const page = rl.questionInt(" - Page = ");
|
||||
if (page) {
|
||||
it.page = page;
|
||||
mods++;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (mods > 0) {
|
||||
let answer = "";
|
||||
while (!["y", "n", "quit"].includes(answer)) {
|
||||
answer = rl.question(`Save file with ${mods} modification${mods === 1 ? "" : "s"}? [y/n/quit]`);
|
||||
if (answer === "y") {
|
||||
console.log(`Saving ${file}...`);
|
||||
fs.writeFileSync(file, CleanUtil.getCleanJson(json), "utf-8");
|
||||
} else if (answer === "quit") {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
doSaveMods({mods, json, file});
|
||||
});
|
||||
|
||||
const filesWithMissingPages = Object.keys(FILE_MAP);
|
||||
if (filesWithMissingPages.length) {
|
||||
console.warn(`##### Files with Missing Page Numbers #####`);
|
||||
filesWithMissingPages.forEach(f => {
|
||||
console.warn(`${f}:`);
|
||||
FILE_MAP[f].forEach(it => console.warn(`\t${it}`));
|
||||
});
|
||||
} else console.log(`Page numbers are as expected.`);
|
||||
}
|
||||
if (!filesWithMissingPages.length) {
|
||||
console.log(`Page numbers are as expected.`);
|
||||
return;
|
||||
}
|
||||
|
||||
run();
|
||||
console.warn(`##### Files with Missing Page Numbers #####`);
|
||||
filesWithMissingPages.forEach(f => {
|
||||
console.warn(`${f}:`);
|
||||
FILE_MAP[f].forEach(it => console.warn(`\t${it}`));
|
||||
});
|
||||
};
|
||||
|
||||
main();
|
||||
|
||||
@@ -523,6 +523,8 @@ class ScaleDiceCheck extends DataTesterBase {
|
||||
}
|
||||
|
||||
class StripTagTest extends DataTesterBase {
|
||||
static _seenErrors = new Set();
|
||||
|
||||
static registerParsedPrimitiveHandlers (parsedJsonChecker) {
|
||||
parsedJsonChecker.addPrimitiveHandler("string", this._checkString.bind(this));
|
||||
}
|
||||
@@ -540,7 +542,6 @@ class StripTagTest extends DataTesterBase {
|
||||
}
|
||||
}
|
||||
}
|
||||
StripTagTest._seenErrors = new Set();
|
||||
|
||||
class TableDiceTest extends DataTesterBase {
|
||||
static registerParsedPrimitiveHandlers (parsedJsonChecker) {
|
||||
|
||||
Reference in New Issue
Block a user