5etools-utils 0.14.39 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {BrewTester} from "../lib/BrewTester.js";
4
+
5
+ await BrewTester.pTestEditionSources();
@@ -0,0 +1,115 @@
1
+ import fs from "fs";
2
+ import Um from "../UtilMisc.js";
3
+ import {BrewTesterBase} from "./BrewTesterBase.js";
4
+ import * as Uf from "../UtilFs.js";
5
+ import {readJsonSync} from "../UtilFs.js";
6
+ import url from "url";
7
+ import pathlib from "path";
8
+ import {ObjectWalker} from "../ObjectWalker.js";
9
+
10
+ const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
11
+
12
+ export class BrewTesterEdition extends BrewTesterBase {
13
+ _LOG_TAG = "EDITION";
14
+
15
+ static _EDITION_CLASSIC = "classic";
16
+
17
+ // TODO(Future) this is non-exhaustive; we do not check e.g. `item.attachedSpells`
18
+ // Generalize an "entity -> used UIDs" system to use both here and in other tests
19
+ static _getSourcesUsed ({filePath, json}) {
20
+ return [
21
+ ...new Set([
22
+ ...this._getSourcesUsedMeta({json, prop: "dependencies"}),
23
+ ...this._getSourcesUsedMeta({json, prop: "includes"}),
24
+
25
+ ...Object.entries(json)
26
+ .flatMap(([prop, arr]) => {
27
+ if (!(arr instanceof Array)) return [];
28
+ return arr
29
+ .flatMap(ent => [
30
+ ...this._getSourcesUsedEntityDirect({ent}),
31
+ ...this._getSourcesUsedEntityText({filePath, ent}),
32
+ ]);
33
+ }),
34
+ ]),
35
+ ];
36
+ }
37
+
38
+ static _getSourcesUsedMeta ({json, prop}) {
39
+ if (!json._meta[prop]) return [];
40
+ return Object.values(json._meta[prop])
41
+ .flat();
42
+ }
43
+
44
+ static _getSourcesUsedEntityDirect ({ent}) {
45
+ return [
46
+ ent.source,
47
+ ent.inherits?.source,
48
+ ent._copy?.source,
49
+ ...(ent._copy?._templates?.map(it => it.source) || []),
50
+ ...(ent.otherSources?.map(it => it.source) || []),
51
+ ...(ent.referenceSources || []),
52
+ ]
53
+ .filter(Boolean);
54
+ }
55
+
56
+ static _RE_NAIVE_TAG = /{@[^ ]+ [^|]+\|(?<source>[^|}]+)/g;
57
+
58
+ static _getSourcesUsedEntityText ({filePath, ent}) {
59
+ const out = [];
60
+ ObjectWalker.walk({
61
+ obj: ent,
62
+ filePath,
63
+ primitiveHandlers: str => {
64
+ // TODO(Future) use more accurate source finding, e.g. that provided by `Renderer.utils.getTagMeta`
65
+ str.replace(this._RE_NAIVE_TAG, (...m) => {
66
+ const {source} = m.at(-1);
67
+ out.push(source);
68
+ return m[0];
69
+ });
70
+ },
71
+ });
72
+ return out;
73
+ }
74
+
75
+ /* -------------------------------------------- */
76
+
77
+ async _pRun () {
78
+ Um.info(this._LOG_TAG, `Checking sources used...`);
79
+
80
+ const schemaSources = readJsonSync(pathlib.join(__dirname, "..", "..", "schema", "site", "sources-5etools.json"));
81
+ const modernSources = Object.fromEntries(
82
+ schemaSources.$defs.sourcesModern.enum
83
+ .map(src => [src.toLowerCase(), src]),
84
+ );
85
+
86
+ const results = [];
87
+ Uf.runOnDirs((dir) => {
88
+ Um.info(this._LOG_TAG, `Checking dir "${dir}"...`);
89
+ const dirFiles = fs.readdirSync(dir, "utf8")
90
+ .filter(file => file.endsWith(".json"));
91
+
92
+ dirFiles.forEach(file => {
93
+ const filePath = `${dir}/${file}`;
94
+
95
+ const json = JSON.parse(fs.readFileSync(filePath, "utf-8"));
96
+
97
+ if (json._meta?.edition !== this.constructor._EDITION_CLASSIC) return;
98
+
99
+ const sourcesUsedModern = this.constructor._getSourcesUsed({filePath, json})
100
+ .map(src => modernSources[src.toLowerCase()])
101
+ .filter(Boolean);
102
+ if (!sourcesUsedModern.length) return;
103
+
104
+ results.push(`${dir}/${file} used ${sourcesUsedModern.length === 1 ? "a " : ""}modern source${sourcesUsedModern.length === 1 ? "" : "s"} but was marked as "edition": ${this.constructor._EDITION_CLASSIC}"! Source${sourcesUsedModern.length === 1 ? " was" : "s were"} ${sourcesUsedModern.map(src => `"${src}"`).join(", ")}`);
105
+ });
106
+ });
107
+
108
+ if (results.length) {
109
+ results.forEach(r => Um.error(this._LOG_TAG, r));
110
+ throw new Error(`${results.length} file${results.length === 1 ? ` used modern source(s) but was marked as "edition": ${this.constructor._EDITION_CLASSIC}"!` : `s used modern source(s) but were marked as "edition": ${this.constructor._EDITION_CLASSIC}"!`} See above for more info.`);
111
+ }
112
+
113
+ Um.info(this._LOG_TAG, `Complete.`);
114
+ }
115
+ }
package/lib/BrewTester.js CHANGED
@@ -2,10 +2,12 @@ import {BrewTesterJson} from "./BrewTester/BrewTesterJson.js";
2
2
  import {BrewTesterFileLocations} from "./BrewTester/BrewTesterFileLocations.js";
3
3
  import {BrewTesterFileNames} from "./BrewTester/BrewTesterFileNames.js";
4
4
  import {BrewTesterFileProps} from "./BrewTester/BrewTesterFileProps.js";
5
+ import {BrewTesterEdition} from "./BrewTester/BrewTesterEdition.js";
5
6
 
6
7
  export class BrewTester {
7
8
  static async pTestJson ({mode, filepath, dir}) { return (new BrewTesterJson({mode, filepath, dir})).pRun(); }
8
9
  static pTestFileLocations () { return (new BrewTesterFileLocations()).pRun(); }
9
10
  static pTestFileNames () { return (new BrewTesterFileNames()).pRun(); }
10
11
  static pTestFileProps () { return (new BrewTesterFileProps()).pRun(); }
12
+ static pTestEditionSources () { return (new BrewTesterEdition()).pRun(); }
11
13
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "5etools-utils",
3
- "version": "0.14.39",
3
+ "version": "0.15.0",
4
4
  "description": "Shared utilities for the 5etools ecosystem.",
5
5
  "type": "module",
6
6
  "main": "lib/Api.js",
@@ -16,7 +16,8 @@
16
16
  "test-json-ua": "bin/test-json-ua.js",
17
17
  "test-file-names": "bin/test-file-names.js",
18
18
  "test-file-locations": "bin/test-file-locations.js",
19
- "test-file-props": "bin/test-file-props.js"
19
+ "test-file-props": "bin/test-file-props.js",
20
+ "test-edition-sources": "bin/test-edition-sources.js"
20
21
  },
21
22
  "scripts": {
22
23
  "build:dangerous:sources": "node node/fetch-5etools-sources.js",
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "foundry-items.json",
4
- "version": "1.2.2",
4
+ "version": "1.2.3",
5
5
  "type": "object",
6
6
  "properties": {
7
7
  "magicvariant": {
8
8
  "$ref": "util-foundry.json#/$defs/foundrySideDataGenericArray"
9
9
  },
10
+ "baseitem": {
11
+ "$ref": "util-foundry.json#/$defs/foundrySideDataGenericArray"
12
+ },
10
13
  "item": {
11
14
  "type": "array",
12
15
  "minItems": 1,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "version": "1.11.5",
3
+ "version": "1.11.6",
4
4
  "type": "object",
5
5
  "description": "Homebrew for 5etools. Should include arrays titled similarly to the main site data, e.g. `spell` or `class`",
6
6
  "$defs": {
@@ -627,6 +627,9 @@
627
627
  "foundryMagicvariant": {
628
628
  "$ref": "foundry-items.json#/properties/magicvariant"
629
629
  },
630
+ "foundryBaseitem": {
631
+ "$ref": "foundry-items.json#/properties/baseitem"
632
+ },
630
633
  "itemGroup": {
631
634
  "$ref": "items.json#/properties/itemGroup"
632
635
  },
@@ -114,6 +114,7 @@
114
114
  "XPHB",
115
115
  "XDMG",
116
116
  "XMM",
117
+ "XSAC",
117
118
  "DrDe",
118
119
  "DrDe-DaS",
119
120
  "DrDe-BD",
@@ -188,6 +189,208 @@
188
189
  "MisMV1",
189
190
  "AATM"
190
191
  ]
192
+ },
193
+ "sourcesLegacy": {
194
+ "type": "string",
195
+ "enum": [
196
+ "PHB",
197
+ "DMG",
198
+ "MM",
199
+ "EEPC",
200
+ "VGM",
201
+ "MTF",
202
+ "Screen"
203
+ ]
204
+ },
205
+ "sourcesClassic": {
206
+ "type": "string",
207
+ "enum": [
208
+ "PHB",
209
+ "DMG",
210
+ "MM",
211
+ "CoS",
212
+ "EEPC",
213
+ "EET",
214
+ "HotDQ",
215
+ "LMoP",
216
+ "OotA",
217
+ "PotA",
218
+ "RoT",
219
+ "RoTOS",
220
+ "SCAG",
221
+ "SKT",
222
+ "ToA",
223
+ "TLK",
224
+ "ToD",
225
+ "TTP",
226
+ "TftYP",
227
+ "TftYP-AtG",
228
+ "TftYP-DiT",
229
+ "TftYP-TFoF",
230
+ "TftYP-THSoT",
231
+ "TftYP-TSC",
232
+ "TftYP-ToH",
233
+ "TftYP-WPM",
234
+ "VGM",
235
+ "XGE",
236
+ "OGA",
237
+ "MTF",
238
+ "WDH",
239
+ "WDMM",
240
+ "GGR",
241
+ "KKW",
242
+ "LLK",
243
+ "AZfyT",
244
+ "GoS",
245
+ "AI",
246
+ "OoW",
247
+ "ESK",
248
+ "DIP",
249
+ "HftT",
250
+ "DC",
251
+ "SLW",
252
+ "SDW",
253
+ "BGDIA",
254
+ "LR",
255
+ "AL",
256
+ "SAC",
257
+ "ERLW",
258
+ "EFR",
259
+ "RMBRE",
260
+ "RMR",
261
+ "MFF",
262
+ "AWM",
263
+ "IMR",
264
+ "SADS",
265
+ "EGW",
266
+ "ToR",
267
+ "DD",
268
+ "FS",
269
+ "US",
270
+ "MOT",
271
+ "IDRotF",
272
+ "TCE",
273
+ "VRGR",
274
+ "HoL",
275
+ "RtG",
276
+ "AitFR",
277
+ "AitFR-ISF",
278
+ "AitFR-THP",
279
+ "AitFR-AVT",
280
+ "AitFR-DN",
281
+ "AitFR-FCD",
282
+ "WBtW",
283
+ "DoD",
284
+ "MaBJoV",
285
+ "FTD",
286
+ "SCC",
287
+ "SCC-CK",
288
+ "SCC-HfMT",
289
+ "SCC-TMM",
290
+ "SCC-ARiR",
291
+ "MPMM",
292
+ "CRCotN",
293
+ "JttRC",
294
+ "SAiS",
295
+ "AAG",
296
+ "BAM",
297
+ "LoX",
298
+ "DoSI",
299
+ "DSotDQ",
300
+ "KftGV",
301
+ "BGG",
302
+ "PaBTSO",
303
+ "PAitM",
304
+ "SatO",
305
+ "ToFW",
306
+ "MPP",
307
+ "BMT",
308
+ "DMTCRG",
309
+ "QftIS",
310
+ "VEoR",
311
+ "TD",
312
+ "Screen",
313
+ "ScreenWildernessKit",
314
+ "ScreenDungeonKit",
315
+ "ScreenSpelljammer",
316
+ "HF",
317
+ "HFFotM",
318
+ "HFStCM",
319
+ "PaF",
320
+ "CM",
321
+ "NRH",
322
+ "NRH-TCMC",
323
+ "NRH-AVitW",
324
+ "NRH-ASS",
325
+ "NRH-CoI",
326
+ "NRH-TLT",
327
+ "NRH-AWoL",
328
+ "NRH-AT",
329
+ "MGELFT",
330
+ "VD",
331
+ "SjA",
332
+ "HAT-TG",
333
+ "HAT-LMI",
334
+ "GotSF",
335
+ "LK",
336
+ "CoA",
337
+ "PiP",
338
+ "DitLCoT",
339
+ "VNotEE",
340
+ "LRDT",
341
+ "ALCurseOfStrahd",
342
+ "ALElementalEvil",
343
+ "ALRageOfDemons",
344
+ "PSA",
345
+ "PSI",
346
+ "PSK",
347
+ "PSZ",
348
+ "PSX",
349
+ "PSD",
350
+ "XMtS",
351
+ "UATheMysticClass",
352
+ "MCV1SC",
353
+ "MCV2DC",
354
+ "MCV3MC",
355
+ "MCV4EC",
356
+ "MisMV1",
357
+ "AATM"
358
+ ]
359
+ },
360
+ "sourcesModern": {
361
+ "type": "string",
362
+ "enum": [
363
+ "XPHB",
364
+ "XDMG",
365
+ "XMM",
366
+ "XSAC",
367
+ "DrDe",
368
+ "DrDe-DaS",
369
+ "DrDe-BD",
370
+ "DrDe-TWoO",
371
+ "DrDe-FWtVC",
372
+ "DrDe-TDoN",
373
+ "DrDe-TFV",
374
+ "DrDe-BtS",
375
+ "DrDe-SD",
376
+ "DrDe-ACfaS",
377
+ "DrDe-DotSC",
378
+ "HotB",
379
+ "WttHC",
380
+ "FRAiF",
381
+ "FRHoF",
382
+ "ABH",
383
+ "NF",
384
+ "LFL",
385
+ "EFA",
386
+ "FFotR",
387
+ "XScreen",
388
+ "HFDoMM",
389
+ "UtHftLH",
390
+ "ScoEE",
391
+ "HBTD",
392
+ "BQGT"
393
+ ]
191
394
  }
192
395
  },
193
396
  "markdownDescription": "A dump of 5etools sources. See node/fetch-5etools-sources.js."
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "foundry-items.json",
4
- "version": "1.2.2",
4
+ "version": "1.2.3",
5
5
  "type": "object",
6
6
  "properties": {
7
7
  "magicvariant": {
8
8
  "$ref": "util-foundry.json#/$defs/foundrySideDataGenericArray"
9
9
  },
10
+ "baseitem": {
11
+ "$ref": "util-foundry.json#/$defs/foundrySideDataGenericArray"
12
+ },
10
13
  "item": {
11
14
  "type": "array",
12
15
  "minItems": 1,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "version": "1.11.5",
3
+ "version": "1.11.6",
4
4
  "type": "object",
5
5
  "description": "Homebrew for 5etools. Should include arrays titled similarly to the main site data, e.g. `spell` or `class`",
6
6
  "$defs": {
@@ -625,6 +625,9 @@
625
625
  "foundryMagicvariant": {
626
626
  "$ref": "foundry-items.json#/properties/magicvariant"
627
627
  },
628
+ "foundryBaseitem": {
629
+ "$ref": "foundry-items.json#/properties/baseitem"
630
+ },
628
631
  "itemGroup": {
629
632
  "$ref": "items.json#/properties/itemGroup"
630
633
  },
@@ -114,6 +114,7 @@
114
114
  "XPHB",
115
115
  "XDMG",
116
116
  "XMM",
117
+ "XSAC",
117
118
  "DrDe",
118
119
  "DrDe-DaS",
119
120
  "DrDe-BD",
@@ -188,6 +189,208 @@
188
189
  "MisMV1",
189
190
  "AATM"
190
191
  ]
192
+ },
193
+ "sourcesLegacy": {
194
+ "type": "string",
195
+ "enum": [
196
+ "PHB",
197
+ "DMG",
198
+ "MM",
199
+ "EEPC",
200
+ "VGM",
201
+ "MTF",
202
+ "Screen"
203
+ ]
204
+ },
205
+ "sourcesClassic": {
206
+ "type": "string",
207
+ "enum": [
208
+ "PHB",
209
+ "DMG",
210
+ "MM",
211
+ "CoS",
212
+ "EEPC",
213
+ "EET",
214
+ "HotDQ",
215
+ "LMoP",
216
+ "OotA",
217
+ "PotA",
218
+ "RoT",
219
+ "RoTOS",
220
+ "SCAG",
221
+ "SKT",
222
+ "ToA",
223
+ "TLK",
224
+ "ToD",
225
+ "TTP",
226
+ "TftYP",
227
+ "TftYP-AtG",
228
+ "TftYP-DiT",
229
+ "TftYP-TFoF",
230
+ "TftYP-THSoT",
231
+ "TftYP-TSC",
232
+ "TftYP-ToH",
233
+ "TftYP-WPM",
234
+ "VGM",
235
+ "XGE",
236
+ "OGA",
237
+ "MTF",
238
+ "WDH",
239
+ "WDMM",
240
+ "GGR",
241
+ "KKW",
242
+ "LLK",
243
+ "AZfyT",
244
+ "GoS",
245
+ "AI",
246
+ "OoW",
247
+ "ESK",
248
+ "DIP",
249
+ "HftT",
250
+ "DC",
251
+ "SLW",
252
+ "SDW",
253
+ "BGDIA",
254
+ "LR",
255
+ "AL",
256
+ "SAC",
257
+ "ERLW",
258
+ "EFR",
259
+ "RMBRE",
260
+ "RMR",
261
+ "MFF",
262
+ "AWM",
263
+ "IMR",
264
+ "SADS",
265
+ "EGW",
266
+ "ToR",
267
+ "DD",
268
+ "FS",
269
+ "US",
270
+ "MOT",
271
+ "IDRotF",
272
+ "TCE",
273
+ "VRGR",
274
+ "HoL",
275
+ "RtG",
276
+ "AitFR",
277
+ "AitFR-ISF",
278
+ "AitFR-THP",
279
+ "AitFR-AVT",
280
+ "AitFR-DN",
281
+ "AitFR-FCD",
282
+ "WBtW",
283
+ "DoD",
284
+ "MaBJoV",
285
+ "FTD",
286
+ "SCC",
287
+ "SCC-CK",
288
+ "SCC-HfMT",
289
+ "SCC-TMM",
290
+ "SCC-ARiR",
291
+ "MPMM",
292
+ "CRCotN",
293
+ "JttRC",
294
+ "SAiS",
295
+ "AAG",
296
+ "BAM",
297
+ "LoX",
298
+ "DoSI",
299
+ "DSotDQ",
300
+ "KftGV",
301
+ "BGG",
302
+ "PaBTSO",
303
+ "PAitM",
304
+ "SatO",
305
+ "ToFW",
306
+ "MPP",
307
+ "BMT",
308
+ "DMTCRG",
309
+ "QftIS",
310
+ "VEoR",
311
+ "TD",
312
+ "Screen",
313
+ "ScreenWildernessKit",
314
+ "ScreenDungeonKit",
315
+ "ScreenSpelljammer",
316
+ "HF",
317
+ "HFFotM",
318
+ "HFStCM",
319
+ "PaF",
320
+ "CM",
321
+ "NRH",
322
+ "NRH-TCMC",
323
+ "NRH-AVitW",
324
+ "NRH-ASS",
325
+ "NRH-CoI",
326
+ "NRH-TLT",
327
+ "NRH-AWoL",
328
+ "NRH-AT",
329
+ "MGELFT",
330
+ "VD",
331
+ "SjA",
332
+ "HAT-TG",
333
+ "HAT-LMI",
334
+ "GotSF",
335
+ "LK",
336
+ "CoA",
337
+ "PiP",
338
+ "DitLCoT",
339
+ "VNotEE",
340
+ "LRDT",
341
+ "ALCurseOfStrahd",
342
+ "ALElementalEvil",
343
+ "ALRageOfDemons",
344
+ "PSA",
345
+ "PSI",
346
+ "PSK",
347
+ "PSZ",
348
+ "PSX",
349
+ "PSD",
350
+ "XMtS",
351
+ "UATheMysticClass",
352
+ "MCV1SC",
353
+ "MCV2DC",
354
+ "MCV3MC",
355
+ "MCV4EC",
356
+ "MisMV1",
357
+ "AATM"
358
+ ]
359
+ },
360
+ "sourcesModern": {
361
+ "type": "string",
362
+ "enum": [
363
+ "XPHB",
364
+ "XDMG",
365
+ "XMM",
366
+ "XSAC",
367
+ "DrDe",
368
+ "DrDe-DaS",
369
+ "DrDe-BD",
370
+ "DrDe-TWoO",
371
+ "DrDe-FWtVC",
372
+ "DrDe-TDoN",
373
+ "DrDe-TFV",
374
+ "DrDe-BtS",
375
+ "DrDe-SD",
376
+ "DrDe-ACfaS",
377
+ "DrDe-DotSC",
378
+ "HotB",
379
+ "WttHC",
380
+ "FRAiF",
381
+ "FRHoF",
382
+ "ABH",
383
+ "NF",
384
+ "LFL",
385
+ "EFA",
386
+ "FFotR",
387
+ "XScreen",
388
+ "HFDoMM",
389
+ "UtHftLH",
390
+ "ScoEE",
391
+ "HBTD",
392
+ "BQGT"
393
+ ]
191
394
  }
192
395
  },
193
396
  "markdownDescription": "A dump of 5etools sources. See node/fetch-5etools-sources.js."
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "foundry-items.json",
4
- "version": "1.2.2",
4
+ "version": "1.2.3",
5
5
  "type": "object",
6
6
  "properties": {
7
7
  "magicvariant": {
8
8
  "$ref": "util-foundry.json#/$defs/foundrySideDataGenericArray"
9
9
  },
10
+ "baseitem": {
11
+ "$ref": "util-foundry.json#/$defs/foundrySideDataGenericArray"
12
+ },
10
13
  "item": {
11
14
  "type": "array",
12
15
  "minItems": 1,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "version": "1.11.5",
3
+ "version": "1.11.6",
4
4
  "type": "object",
5
5
  "description": "Homebrew for 5etools. Should include arrays titled similarly to the main site data, e.g. `spell` or `class`",
6
6
  "$defs": {
@@ -627,6 +627,9 @@
627
627
  "foundryMagicvariant": {
628
628
  "$ref": "foundry-items.json#/properties/magicvariant"
629
629
  },
630
+ "foundryBaseitem": {
631
+ "$ref": "foundry-items.json#/properties/baseitem"
632
+ },
630
633
  "itemGroup": {
631
634
  "$ref": "items.json#/properties/itemGroup"
632
635
  },