@readium/navigator-html-injectables 2.3.1-alpha.2 → 2.4.0-beta.1
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.
- package/dist/index.js +852 -701
- package/dist/index.umd.cjs +24 -13
- package/package.json +8 -8
- package/src/Loader.ts +3 -3
- package/src/comms/comms.ts +5 -5
- package/src/comms/index.ts +3 -3
- package/src/helpers/css.ts +2 -4
- package/src/helpers/document.ts +13 -10
- package/src/helpers/locator.ts +2 -2
- package/src/index.ts +4 -4
- package/src/modules/Decorator.ts +18 -18
- package/src/modules/Module.ts +4 -4
- package/src/modules/ModuleLibrary.ts +15 -11
- package/src/modules/Peripherals.ts +70 -61
- package/src/modules/index.ts +4 -4
- package/src/modules/setup/FixedSetup.ts +6 -6
- package/src/modules/setup/ReflowableSetup.ts +6 -6
- package/src/modules/setup/Setup.ts +5 -5
- package/src/modules/setup/WebPubSetup.ts +5 -5
- package/src/modules/snapper/CJKVerticalSnapper.ts +322 -0
- package/src/modules/snapper/ColumnSnapper.ts +161 -99
- package/src/modules/snapper/ScrollSnapper.ts +18 -18
- package/src/modules/snapper/Snapper.ts +5 -5
- package/src/modules/snapper/WebPubSnapper.ts +15 -15
- package/src/protection/BulkCopyProtector.ts +15 -15
- package/src/protection/KeyCombinationManager.ts +8 -8
- package/src/protection/PatternAnalyzer.ts +18 -18
- package/src/protection/PrintProtector.ts +12 -12
- package/src/protection/SelectionAnalyzer.ts +1 -1
- package/src/protection/config.ts +4 -4
- package/src/protection/index.ts +6 -6
- package/src/vendor/hypothesis/anchoring/html.ts +1 -1
- package/src/vendor/hypothesis/anchoring/types.ts +1 -1
- package/types/src/Loader.d.ts +2 -2
- package/types/src/comms/comms.d.ts +2 -2
- package/types/src/comms/index.d.ts +3 -3
- package/types/src/helpers/css.d.ts +1 -2
- package/types/src/helpers/document.d.ts +1 -1
- package/types/src/index.d.ts +4 -4
- package/types/src/modules/Decorator.d.ts +4 -4
- package/types/src/modules/Module.d.ts +3 -3
- package/types/src/modules/ModuleLibrary.d.ts +2 -2
- package/types/src/modules/Peripherals.d.ts +10 -9
- package/types/src/modules/index.d.ts +4 -4
- package/types/src/modules/setup/FixedSetup.d.ts +4 -4
- package/types/src/modules/setup/ReflowableSetup.d.ts +3 -3
- package/types/src/modules/setup/Setup.d.ts +4 -4
- package/types/src/modules/setup/WebPubSetup.d.ts +3 -3
- package/types/src/modules/snapper/CJKVerticalSnapper.d.ts +57 -0
- package/types/src/modules/snapper/ColumnSnapper.d.ts +16 -5
- package/types/src/modules/snapper/ScrollSnapper.d.ts +5 -5
- package/types/src/modules/snapper/Snapper.d.ts +4 -4
- package/types/src/modules/snapper/WebPubSnapper.d.ts +5 -5
- package/types/src/protection/BulkCopyProtector.d.ts +1 -1
- package/types/src/protection/KeyCombinationManager.d.ts +3 -3
- package/types/src/protection/PrintProtector.d.ts +4 -4
- package/types/src/protection/config.d.ts +3 -3
- package/types/src/protection/index.d.ts +6 -6
- package/types/src/vendor/hypothesis/anchoring/html.d.ts +1 -1
- package/types/src/vendor/hypothesis/anchoring/types.d.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@readium/navigator-html-injectables",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0-beta.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "An embeddable solution for connecting frames of HTML publications with a Readium Navigator",
|
|
6
6
|
"author": "readium",
|
|
@@ -26,6 +26,10 @@
|
|
|
26
26
|
"reader",
|
|
27
27
|
"viewer"
|
|
28
28
|
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"clean": "rimraf types dist",
|
|
31
|
+
"build": "pnpm clean && tsc && vite build"
|
|
32
|
+
},
|
|
29
33
|
"main": "./dist/index.umd.cjs",
|
|
30
34
|
"module": "./dist/index.js",
|
|
31
35
|
"types": "./types/src/index.d.ts",
|
|
@@ -45,15 +49,11 @@
|
|
|
45
49
|
"node": ">=18"
|
|
46
50
|
},
|
|
47
51
|
"devDependencies": {
|
|
52
|
+
"@readium/shared": "workspace:*",
|
|
48
53
|
"css-selector-generator": "^3.8.0",
|
|
49
54
|
"rimraf": "^6.1.2",
|
|
50
55
|
"tslib": "^2.8.1",
|
|
51
56
|
"typescript": "^5.9.3",
|
|
52
|
-
"vite": "^7.3.1"
|
|
53
|
-
"@readium/shared": "2.2.0-alpha.1"
|
|
54
|
-
},
|
|
55
|
-
"scripts": {
|
|
56
|
-
"clean": "rimraf types dist",
|
|
57
|
-
"build": "pnpm clean && tsc && vite build"
|
|
57
|
+
"vite": "^7.3.1"
|
|
58
58
|
}
|
|
59
|
-
}
|
|
59
|
+
}
|
package/src/Loader.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Comms } from "./comms/comms";
|
|
2
|
-
import { ReadiumWindow } from "./helpers/dom";
|
|
3
|
-
import { Module, ModuleDerived, ModuleLibrary, ModuleName } from "./modules";
|
|
1
|
+
import { Comms } from "./comms/comms.ts";
|
|
2
|
+
import { ReadiumWindow } from "./helpers/dom.ts";
|
|
3
|
+
import { Module, ModuleDerived, ModuleLibrary, ModuleName } from "./modules/index.ts";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* The Module loader. Handles initialization of the HTML injectables
|
package/src/comms/comms.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ReadiumWindow } from "../helpers/dom";
|
|
2
|
-
import { CommsEventKey, CommsCommandKey } from "./keys";
|
|
3
|
-
import { mid } from "./mid";
|
|
1
|
+
import { ReadiumWindow } from "../helpers/dom.ts";
|
|
2
|
+
import { CommsEventKey, CommsCommandKey } from "./keys.ts";
|
|
3
|
+
import { mid } from "./mid.ts";
|
|
4
4
|
|
|
5
5
|
export const COMMS_VERSION = 1;
|
|
6
6
|
|
|
@@ -21,7 +21,7 @@ export type CommsAck = (ok: boolean) => void;
|
|
|
21
21
|
export type CommsCallback = (data: unknown, ack: CommsAck) => void; // TODO: maybe more than void?
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* Comms is basically a wrapper around window.postMessage that
|
|
24
|
+
* Comms is basically a wrapper around window.postMessage that
|
|
25
25
|
* adds structure to the messages and lets modules register callbacks.
|
|
26
26
|
*/
|
|
27
27
|
export class Comms {
|
|
@@ -165,4 +165,4 @@ export class Comms {
|
|
|
165
165
|
this.destination.postMessage(msg, this.origin, transfer);
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
|
-
}
|
|
168
|
+
}
|
package/src/comms/index.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from './comms';
|
|
2
|
-
export * from './keys';
|
|
3
|
-
export * from './mid';
|
|
1
|
+
export * from './comms.ts';
|
|
2
|
+
export * from './keys.ts';
|
|
3
|
+
export * from './mid.ts';
|
package/src/helpers/css.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { ReadiumWindow } from "./dom";
|
|
2
|
-
|
|
3
|
-
export const isTypedOMSupported = () => typeof window.CSSTransformValue !== 'undefined';
|
|
1
|
+
import { ReadiumWindow } from "./dom.ts";
|
|
4
2
|
|
|
5
3
|
export function getProperties(wnd: ReadiumWindow) {
|
|
6
4
|
const cssProperties: { [key: string]: string } = {};
|
|
@@ -52,4 +50,4 @@ export function setProperty(wnd: ReadiumWindow, key: string, value: string) {
|
|
|
52
50
|
// Easy way to remove a CSS property
|
|
53
51
|
export function removeProperty(wnd: ReadiumWindow, key: string) {
|
|
54
52
|
wnd.document.documentElement.style.removeProperty(key);
|
|
55
|
-
}
|
|
53
|
+
}
|
package/src/helpers/document.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { ReadiumWindow } from "./dom";
|
|
1
|
+
import { ReadiumWindow } from "./dom.ts";
|
|
2
2
|
|
|
3
3
|
export function isRTL(wnd: ReadiumWindow): boolean {
|
|
4
|
-
|
|
4
|
+
// Check body first (author-declared direction), then fall back to the
|
|
5
|
+
// root element where we inject dir="rtl" for RTL publications.
|
|
6
|
+
const dir = wnd.document.body.dir || wnd.document.documentElement.dir;
|
|
7
|
+
return dir.toLowerCase() === "rtl";
|
|
5
8
|
}
|
|
6
9
|
|
|
7
10
|
export function getColumnCountPerScreen(wnd: ReadiumWindow): number {
|
|
@@ -12,7 +15,7 @@ export function getColumnCountPerScreen(wnd: ReadiumWindow): number {
|
|
|
12
15
|
);
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
/**
|
|
18
|
+
/**
|
|
16
19
|
* Returns the "content height" of an element, which is its clientHeight
|
|
17
20
|
* minus any vertical padding.
|
|
18
21
|
*
|
|
@@ -26,9 +29,9 @@ export function getContentHeight(el: Element): number {
|
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
/**
|
|
29
|
-
* We have to make sure that the total number of columns is a multiple
|
|
30
|
-
* of the number of columns per screen.
|
|
31
|
-
* Otherwise it causes snapping and page turning issues.
|
|
32
|
+
* We have to make sure that the total number of columns is a multiple
|
|
33
|
+
* of the number of columns per screen.
|
|
34
|
+
* Otherwise it causes snapping and page turning issues.
|
|
32
35
|
* To fix this, we insert and remove blank virtual columns at the end of the resource.
|
|
33
36
|
*/
|
|
34
37
|
export function appendVirtualColumnIfNeeded(wnd: ReadiumWindow): boolean {
|
|
@@ -56,7 +59,7 @@ export function appendVirtualColumnIfNeeded(wnd: ReadiumWindow): boolean {
|
|
|
56
59
|
const lonelyColCount = totalColCount % colCountPerScreen;
|
|
57
60
|
|
|
58
61
|
const needed = colCountPerScreen === 1 || lonelyColCount === 0
|
|
59
|
-
? 0
|
|
62
|
+
? 0
|
|
60
63
|
: colCountPerScreen - lonelyColCount;
|
|
61
64
|
|
|
62
65
|
if (needed > 0) {
|
|
@@ -84,14 +87,14 @@ export function appendVirtualColumnIfNeeded(wnd: ReadiumWindow): boolean {
|
|
|
84
87
|
* This forces a recalculation in WebKit browsers.
|
|
85
88
|
* It is needed in scroll mode to ensure that the content is scrollable.
|
|
86
89
|
* Webkit seems to find itself in some kind of limbo if we do not do that.
|
|
87
|
-
* It has everything correct but the scroll listener is non-functional,
|
|
90
|
+
* It has everything correct but the scroll listener is non-functional,
|
|
88
91
|
* unless you force a recalc or reflow.
|
|
89
92
|
* It is not needed in paginated mode.
|
|
90
93
|
*/
|
|
91
94
|
export function forceWebkitRecalc(wnd: ReadiumWindow) {
|
|
92
|
-
// Borrowed from APB themselves…
|
|
95
|
+
// Borrowed from APB themselves…
|
|
93
96
|
const styleElement = wnd.document.createElement("style");
|
|
94
97
|
styleElement.appendChild(wnd.document.createTextNode("*{}"));
|
|
95
98
|
wnd.document.body.appendChild(styleElement);
|
|
96
99
|
wnd.document.body.removeChild(styleElement);
|
|
97
|
-
}
|
|
100
|
+
}
|
package/src/helpers/locator.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Locator } from "@readium/shared";
|
|
2
|
-
import { TextQuoteAnchor } from "../vendor/hypothesis/anchoring/types";
|
|
2
|
+
import { TextQuoteAnchor } from "../vendor/hypothesis/anchoring/types.ts";
|
|
3
3
|
|
|
4
4
|
function isReplacedLikeElement(element: Element): boolean {
|
|
5
5
|
const tagName = element.tagName.toUpperCase();
|
|
@@ -66,4 +66,4 @@ export function rangeFromLocator(doc: Document, locator: Locator) {
|
|
|
66
66
|
console.error(e);
|
|
67
67
|
}
|
|
68
68
|
return null;
|
|
69
|
-
}
|
|
69
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export * from './comms';
|
|
2
|
-
export * from './modules';
|
|
3
|
-
export * from './Loader';
|
|
4
|
-
export * from './protection';
|
|
1
|
+
export * from './comms/index.ts';
|
|
2
|
+
export * from './modules/index.ts';
|
|
3
|
+
export * from './Loader.ts';
|
|
4
|
+
export * from './protection/index.ts';
|
package/src/modules/Decorator.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Locator } from "@readium/shared";
|
|
2
|
-
import { Comms } from "../comms/comms";
|
|
3
|
-
import { Module } from "./Module";
|
|
4
|
-
import { rangeFromLocator } from "../helpers/locator";
|
|
5
|
-
import { ModuleName } from "./ModuleLibrary";
|
|
6
|
-
import { Rect, getClientRectsNoOverlap } from "../helpers/rect";
|
|
7
|
-
import { getProperty } from "../helpers/css";
|
|
8
|
-
import { ReadiumWindow } from "../helpers/dom";
|
|
9
|
-
import { isDarkColor, getContrastingTextColor } from "../helpers/color";
|
|
2
|
+
import { Comms } from "../comms/comms.ts";
|
|
3
|
+
import { Module } from "./Module.ts";
|
|
4
|
+
import { rangeFromLocator } from "../helpers/locator.ts";
|
|
5
|
+
import { ModuleName } from "./ModuleLibrary.ts";
|
|
6
|
+
import { Rect, getClientRectsNoOverlap } from "../helpers/rect.ts";
|
|
7
|
+
import { getProperty } from "../helpers/css.ts";
|
|
8
|
+
import { ReadiumWindow } from "../helpers/dom.ts";
|
|
9
|
+
import { isDarkColor, getContrastingTextColor } from "../helpers/color.ts";
|
|
10
10
|
|
|
11
11
|
const DEFAULT_HIGHLIGHT_COLOR = "#FFFF00"; // Yellow in HEX
|
|
12
12
|
|
|
@@ -184,7 +184,7 @@ class DecorationGroup {
|
|
|
184
184
|
const [stylesheet, highlighter]: [HTMLStyleElement, any] = this.requireContainer(true) as [HTMLStyleElement, unknown];
|
|
185
185
|
highlighter.add(item.range);
|
|
186
186
|
|
|
187
|
-
const backgroundColor = getProperty(this.wnd, "--USER__backgroundColor") ||
|
|
187
|
+
const backgroundColor = getProperty(this.wnd, "--USER__backgroundColor") ||
|
|
188
188
|
this.wnd.getComputedStyle(this.wnd.document.documentElement).getPropertyValue("background-color");
|
|
189
189
|
const tint = item.decoration?.style?.tint ?? DEFAULT_HIGHLIGHT_COLOR;
|
|
190
190
|
|
|
@@ -198,7 +198,7 @@ class DecorationGroup {
|
|
|
198
198
|
|
|
199
199
|
/**
|
|
200
200
|
* Layouts a single DecorationItem.
|
|
201
|
-
* @param item
|
|
201
|
+
* @param item
|
|
202
202
|
*/
|
|
203
203
|
private layout(item: DecorationItem) {
|
|
204
204
|
if (this.experimentalHighlights && !this.notTextFlag?.has(item.id)) {
|
|
@@ -264,7 +264,7 @@ class DecorationGroup {
|
|
|
264
264
|
|
|
265
265
|
template.innerHTML = `
|
|
266
266
|
<div
|
|
267
|
-
data-readium="true"
|
|
267
|
+
data-readium="true"
|
|
268
268
|
class="readium-highlight"
|
|
269
269
|
style="${[
|
|
270
270
|
`background-color: ${item.decoration?.style?.tint ?? DEFAULT_HIGHLIGHT_COLOR} !important`,
|
|
@@ -416,7 +416,7 @@ export class Decorator extends Module {
|
|
|
416
416
|
|
|
417
417
|
private extractCustomProperty(style: string | null, propertyName: string): string | null {
|
|
418
418
|
if (!style) return null;
|
|
419
|
-
|
|
419
|
+
|
|
420
420
|
const match = style.match(new RegExp(`${propertyName}:\\s*([^;]+)`));
|
|
421
421
|
return match ? match[1].trim() : null;
|
|
422
422
|
}
|
|
@@ -478,24 +478,24 @@ export class Decorator extends Module {
|
|
|
478
478
|
const element = mutation.target as Element;
|
|
479
479
|
const oldStyle = mutation.oldValue;
|
|
480
480
|
const newStyle = element.getAttribute("style");
|
|
481
|
-
|
|
481
|
+
|
|
482
482
|
// Check if the relevant CSS custom properties actually changed
|
|
483
483
|
const oldAppearance = this.extractCustomProperty(oldStyle, "--USER__appearance");
|
|
484
484
|
const newAppearance = this.extractCustomProperty(newStyle, "--USER__appearance");
|
|
485
485
|
const oldBgColor = this.extractCustomProperty(oldStyle, "--USER__backgroundColor");
|
|
486
486
|
const newBgColor = this.extractCustomProperty(newStyle, "--USER__backgroundColor");
|
|
487
|
-
|
|
488
|
-
return oldAppearance !== newAppearance ||
|
|
487
|
+
|
|
488
|
+
return oldAppearance !== newAppearance ||
|
|
489
489
|
oldBgColor !== newBgColor;
|
|
490
490
|
}
|
|
491
491
|
return false;
|
|
492
492
|
});
|
|
493
|
-
|
|
493
|
+
|
|
494
494
|
if (shouldUpdate) {
|
|
495
495
|
this.updateHighlightStyles();
|
|
496
496
|
}
|
|
497
497
|
});
|
|
498
|
-
|
|
498
|
+
|
|
499
499
|
this.backgroundObserver.observe(wnd.document.documentElement, {
|
|
500
500
|
attributes: true,
|
|
501
501
|
attributeFilter: ["style"],
|
|
@@ -519,4 +519,4 @@ export class Decorator extends Module {
|
|
|
519
519
|
comms.log("Decorator Unmounted");
|
|
520
520
|
return true;
|
|
521
521
|
}
|
|
522
|
-
}
|
|
522
|
+
}
|
package/src/modules/Module.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Comms } from "../comms";
|
|
2
|
-
import { ReadiumWindow } from "../helpers/dom";
|
|
3
|
-
import { ModuleName } from "./ModuleLibrary";
|
|
1
|
+
import { Comms } from "../comms/index.ts";
|
|
2
|
+
import { ReadiumWindow } from "../helpers/dom.ts";
|
|
3
|
+
import { ModuleName } from "./ModuleLibrary.ts";
|
|
4
4
|
|
|
5
5
|
export abstract class Module {
|
|
6
6
|
static readonly moduleName: ModuleName; // snake_case name of the module, must be unique.
|
|
@@ -20,4 +20,4 @@ export abstract class Module {
|
|
|
20
20
|
abstract unmount(wnd: ReadiumWindow, comms: Comms): boolean;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export type ModuleDerived = {new (): Module} & typeof Module;
|
|
23
|
+
export type ModuleDerived = {new (): Module} & typeof Module;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { ModuleDerived } from "./Module";
|
|
2
|
-
import { ColumnSnapper } from "./snapper/ColumnSnapper";
|
|
3
|
-
import { ScrollSnapper } from "./snapper/ScrollSnapper";
|
|
4
|
-
import { WebPubSnapper } from "./snapper/WebPubSnapper";
|
|
5
|
-
import { Peripherals } from "./Peripherals";
|
|
6
|
-
import { ReflowableSetup } from "./setup/ReflowableSetup";
|
|
7
|
-
import { FixedSetup } from "./setup/FixedSetup";
|
|
8
|
-
import { Decorator } from "./Decorator";
|
|
9
|
-
import { WebPubSetup } from "./setup/WebPubSetup";
|
|
10
|
-
import { PrintProtector } from "../protection/PrintProtector";
|
|
1
|
+
import { ModuleDerived } from "./Module.ts";
|
|
2
|
+
import { ColumnSnapper } from "./snapper/ColumnSnapper.ts";
|
|
3
|
+
import { ScrollSnapper } from "./snapper/ScrollSnapper.ts";
|
|
4
|
+
import { WebPubSnapper } from "./snapper/WebPubSnapper.ts";
|
|
5
|
+
import { Peripherals } from "./Peripherals.ts";
|
|
6
|
+
import { ReflowableSetup } from "./setup/ReflowableSetup.ts";
|
|
7
|
+
import { FixedSetup } from "./setup/FixedSetup.ts";
|
|
8
|
+
import { Decorator } from "./Decorator.ts";
|
|
9
|
+
import { WebPubSetup } from "./setup/WebPubSetup.ts";
|
|
10
|
+
import { PrintProtector } from "../protection/PrintProtector.ts";
|
|
11
|
+
import { CJKVerticalSnapper } from "./snapper/CJKVerticalSnapper.ts";
|
|
11
12
|
|
|
12
13
|
// All the module names. TODO: Come up with a better way of collecting these in a way TS will recognize
|
|
13
14
|
export type ModuleName =
|
|
@@ -15,6 +16,7 @@ export type ModuleName =
|
|
|
15
16
|
"snapper" |
|
|
16
17
|
"column_snapper" |
|
|
17
18
|
"scroll_snapper" |
|
|
19
|
+
"cjk_vertical_snapper" |
|
|
18
20
|
"webpub_snapper" |
|
|
19
21
|
"fixed_setup" |
|
|
20
22
|
"decorator" |
|
|
@@ -38,6 +40,7 @@ export const ReflowableModules: ModuleName[] = [
|
|
|
38
40
|
"peripherals",
|
|
39
41
|
"column_snapper",
|
|
40
42
|
"scroll_snapper",
|
|
43
|
+
"cjk_vertical_snapper",
|
|
41
44
|
"print_protection"
|
|
42
45
|
];
|
|
43
46
|
|
|
@@ -60,5 +63,6 @@ export const ModuleLibrary = new Map<string, ModuleDerived>([
|
|
|
60
63
|
Decorator,
|
|
61
64
|
ColumnSnapper,
|
|
62
65
|
ScrollSnapper,
|
|
66
|
+
CJKVerticalSnapper,
|
|
63
67
|
PrintProtector
|
|
64
|
-
].map(m => [m.moduleName, m])); // Turn module list into K/V list for quick access by name
|
|
68
|
+
].map(m => [m.moduleName, m])); // Turn module list into K/V list for quick access by name
|