mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-22 12:11:27 -07:00
feat(stats): add v1 immersion stats dashboard (#19)
This commit is contained in:
@@ -20,21 +20,21 @@ function makeContext(ankiConnect: unknown): {
|
||||
return { context, warnings };
|
||||
}
|
||||
|
||||
test('modern invalid nPlusOne.highlightEnabled warns modern key and does not fallback to legacy', () => {
|
||||
test('modern invalid knownWords.highlightEnabled warns modern key and does not fallback to legacy', () => {
|
||||
const { context, warnings } = makeContext({
|
||||
behavior: { nPlusOneHighlightEnabled: true },
|
||||
nPlusOne: { highlightEnabled: 'yes' },
|
||||
nPlusOne: { highlightEnabled: true },
|
||||
knownWords: { highlightEnabled: 'yes' },
|
||||
});
|
||||
|
||||
applyAnkiConnectResolution(context);
|
||||
|
||||
assert.equal(
|
||||
context.resolved.ankiConnect.nPlusOne.highlightEnabled,
|
||||
DEFAULT_CONFIG.ankiConnect.nPlusOne.highlightEnabled,
|
||||
context.resolved.ankiConnect.knownWords.highlightEnabled,
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.highlightEnabled,
|
||||
);
|
||||
assert.ok(warnings.some((warning) => warning.path === 'ankiConnect.nPlusOne.highlightEnabled'));
|
||||
assert.ok(warnings.some((warning) => warning.path === 'ankiConnect.knownWords.highlightEnabled'));
|
||||
assert.equal(
|
||||
warnings.some((warning) => warning.path === 'ankiConnect.behavior.nPlusOneHighlightEnabled'),
|
||||
warnings.some((warning) => warning.path === 'ankiConnect.nPlusOne.highlightEnabled'),
|
||||
false,
|
||||
);
|
||||
});
|
||||
@@ -53,18 +53,48 @@ test('normalizes ankiConnect tags by trimming and deduping', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('warns and falls back for invalid nPlusOne.decks entries', () => {
|
||||
test('accepts knownWords.decks object format with field arrays', () => {
|
||||
const { context, warnings } = makeContext({
|
||||
nPlusOne: { decks: ['Core Deck', 123] },
|
||||
knownWords: { decks: { 'Core Deck': ['Word', 'Reading'], Mining: ['Expression'] } },
|
||||
});
|
||||
|
||||
applyAnkiConnectResolution(context);
|
||||
|
||||
assert.deepEqual(
|
||||
context.resolved.ankiConnect.nPlusOne.decks,
|
||||
DEFAULT_CONFIG.ankiConnect.nPlusOne.decks,
|
||||
assert.deepEqual(context.resolved.ankiConnect.knownWords.decks, {
|
||||
'Core Deck': ['Word', 'Reading'],
|
||||
Mining: ['Expression'],
|
||||
});
|
||||
assert.equal(
|
||||
warnings.some((warning) => warning.path === 'ankiConnect.knownWords.decks'),
|
||||
false,
|
||||
);
|
||||
assert.ok(warnings.some((warning) => warning.path === 'ankiConnect.nPlusOne.decks'));
|
||||
});
|
||||
|
||||
test('accepts knownWords.addMinedWordsImmediately boolean override', () => {
|
||||
const { context, warnings } = makeContext({
|
||||
knownWords: { addMinedWordsImmediately: false },
|
||||
});
|
||||
|
||||
applyAnkiConnectResolution(context);
|
||||
|
||||
assert.equal(context.resolved.ankiConnect.knownWords.addMinedWordsImmediately, false);
|
||||
assert.equal(
|
||||
warnings.some((warning) => warning.path === 'ankiConnect.knownWords.addMinedWordsImmediately'),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test('converts legacy knownWords.decks array to object with default fields', () => {
|
||||
const { context, warnings } = makeContext({
|
||||
knownWords: { decks: ['Core Deck'] },
|
||||
});
|
||||
|
||||
applyAnkiConnectResolution(context);
|
||||
|
||||
assert.deepEqual(context.resolved.ankiConnect.knownWords.decks, {
|
||||
'Core Deck': ['Expression', 'Word', 'Reading', 'Word Reading'],
|
||||
});
|
||||
assert.ok(warnings.some((warning) => warning.path === 'ankiConnect.knownWords.decks'));
|
||||
});
|
||||
|
||||
test('accepts valid proxy settings', () => {
|
||||
@@ -89,6 +119,52 @@ test('accepts valid proxy settings', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('accepts configured ankiConnect.fields.word override', () => {
|
||||
const { context, warnings } = makeContext({
|
||||
fields: {
|
||||
word: 'TargetWord',
|
||||
},
|
||||
});
|
||||
|
||||
applyAnkiConnectResolution(context);
|
||||
|
||||
assert.equal(context.resolved.ankiConnect.fields.word, 'TargetWord');
|
||||
assert.equal(
|
||||
warnings.some((warning) => warning.path === 'ankiConnect.fields.word'),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test('accepts ankiConnect.media.syncAnimatedImageToWordAudio override', () => {
|
||||
const { context, warnings } = makeContext({
|
||||
media: {
|
||||
syncAnimatedImageToWordAudio: false,
|
||||
},
|
||||
});
|
||||
|
||||
applyAnkiConnectResolution(context);
|
||||
|
||||
assert.equal(context.resolved.ankiConnect.media.syncAnimatedImageToWordAudio, false);
|
||||
assert.equal(
|
||||
warnings.some((warning) => warning.path === 'ankiConnect.media.syncAnimatedImageToWordAudio'),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test('maps legacy ankiConnect.wordField to modern ankiConnect.fields.word', () => {
|
||||
const { context, warnings } = makeContext({
|
||||
wordField: 'TargetWordLegacy',
|
||||
});
|
||||
|
||||
applyAnkiConnectResolution(context);
|
||||
|
||||
assert.equal(context.resolved.ankiConnect.fields.word, 'TargetWordLegacy');
|
||||
assert.equal(
|
||||
warnings.some((warning) => warning.path === 'ankiConnect.wordField'),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test('warns and falls back for invalid proxy settings', () => {
|
||||
const { context, warnings } = makeContext({
|
||||
proxy: {
|
||||
|
||||
@@ -14,6 +14,7 @@ export function applyAnkiConnectResolution(context: ResolveContext): void {
|
||||
const metadata = isObject(ac.metadata) ? (ac.metadata as Record<string, unknown>) : {};
|
||||
const proxy = isObject(ac.proxy) ? (ac.proxy as Record<string, unknown>) : {};
|
||||
const legacyKeys = new Set([
|
||||
'wordField',
|
||||
'audioField',
|
||||
'imageField',
|
||||
'sentenceField',
|
||||
@@ -30,6 +31,7 @@ export function applyAnkiConnectResolution(context: ResolveContext): void {
|
||||
'animatedMaxWidth',
|
||||
'animatedMaxHeight',
|
||||
'animatedCrf',
|
||||
'syncAnimatedImageToWordAudio',
|
||||
'audioPadding',
|
||||
'fallbackDuration',
|
||||
'maxMediaDuration',
|
||||
@@ -42,12 +44,13 @@ export function applyAnkiConnectResolution(context: ResolveContext): void {
|
||||
]);
|
||||
|
||||
const {
|
||||
knownWords: _knownWordsConfigFromAnkiConnect,
|
||||
nPlusOne: _nPlusOneConfigFromAnkiConnect,
|
||||
ai: _ankiAiConfig,
|
||||
...ankiConnectWithoutNPlusOne
|
||||
...ankiConnectWithoutKnownWordsOrNPlusOne
|
||||
} = ac as Record<string, unknown>;
|
||||
const ankiConnectWithoutLegacy = Object.fromEntries(
|
||||
Object.entries(ankiConnectWithoutNPlusOne).filter(([key]) => !legacyKeys.has(key)),
|
||||
Object.entries(ankiConnectWithoutKnownWordsOrNPlusOne).filter(([key]) => !legacyKeys.has(key)),
|
||||
);
|
||||
|
||||
context.resolved.ankiConnect = {
|
||||
@@ -67,6 +70,9 @@ export function applyAnkiConnectResolution(context: ResolveContext): void {
|
||||
? (ac.media as (typeof context.resolved)['ankiConnect']['media'])
|
||||
: {}),
|
||||
},
|
||||
knownWords: {
|
||||
...context.resolved.ankiConnect.knownWords,
|
||||
},
|
||||
behavior: {
|
||||
...context.resolved.ankiConnect.behavior,
|
||||
...(isObject(ac.behavior)
|
||||
@@ -355,6 +361,17 @@ export function applyAnkiConnectResolution(context: ResolveContext): void {
|
||||
'Expected string.',
|
||||
);
|
||||
}
|
||||
if (!hasOwn(fields, 'word')) {
|
||||
mapLegacy(
|
||||
'wordField',
|
||||
asString,
|
||||
(value) => {
|
||||
context.resolved.ankiConnect.fields.word = value;
|
||||
},
|
||||
context.resolved.ankiConnect.fields.word,
|
||||
'Expected string.',
|
||||
);
|
||||
}
|
||||
if (!hasOwn(fields, 'image')) {
|
||||
mapLegacy(
|
||||
'imageField',
|
||||
@@ -520,6 +537,17 @@ export function applyAnkiConnectResolution(context: ResolveContext): void {
|
||||
'Expected integer between 0 and 63.',
|
||||
);
|
||||
}
|
||||
if (!hasOwn(media, 'syncAnimatedImageToWordAudio')) {
|
||||
mapLegacy(
|
||||
'syncAnimatedImageToWordAudio',
|
||||
asBoolean,
|
||||
(value) => {
|
||||
context.resolved.ankiConnect.media.syncAnimatedImageToWordAudio = value;
|
||||
},
|
||||
context.resolved.ankiConnect.media.syncAnimatedImageToWordAudio,
|
||||
'Expected boolean.',
|
||||
);
|
||||
}
|
||||
if (!hasOwn(media, 'audioPadding')) {
|
||||
mapLegacy(
|
||||
'audioPadding',
|
||||
@@ -620,81 +648,145 @@ export function applyAnkiConnectResolution(context: ResolveContext): void {
|
||||
);
|
||||
}
|
||||
|
||||
const knownWordsConfig = isObject(ac.knownWords)
|
||||
? (ac.knownWords as Record<string, unknown>)
|
||||
: {};
|
||||
const nPlusOneConfig = isObject(ac.nPlusOne) ? (ac.nPlusOne as Record<string, unknown>) : {};
|
||||
|
||||
const nPlusOneHighlightEnabled = asBoolean(nPlusOneConfig.highlightEnabled);
|
||||
if (nPlusOneHighlightEnabled !== undefined) {
|
||||
context.resolved.ankiConnect.nPlusOne.highlightEnabled = nPlusOneHighlightEnabled;
|
||||
const knownWordsHighlightEnabled = asBoolean(knownWordsConfig.highlightEnabled);
|
||||
const legacyNPlusOneHighlightEnabled = asBoolean(nPlusOneConfig.highlightEnabled);
|
||||
if (knownWordsHighlightEnabled !== undefined) {
|
||||
context.resolved.ankiConnect.knownWords.highlightEnabled = knownWordsHighlightEnabled;
|
||||
} else if (knownWordsConfig.highlightEnabled !== undefined) {
|
||||
context.warn(
|
||||
'ankiConnect.knownWords.highlightEnabled',
|
||||
knownWordsConfig.highlightEnabled,
|
||||
context.resolved.ankiConnect.knownWords.highlightEnabled,
|
||||
'Expected boolean.',
|
||||
);
|
||||
context.resolved.ankiConnect.knownWords.highlightEnabled =
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.highlightEnabled;
|
||||
} else if (legacyNPlusOneHighlightEnabled !== undefined) {
|
||||
context.resolved.ankiConnect.knownWords.highlightEnabled = legacyNPlusOneHighlightEnabled;
|
||||
context.warn(
|
||||
'ankiConnect.nPlusOne.highlightEnabled',
|
||||
nPlusOneConfig.highlightEnabled,
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.highlightEnabled,
|
||||
'Legacy key is deprecated; use ankiConnect.knownWords.highlightEnabled',
|
||||
);
|
||||
} else if (nPlusOneConfig.highlightEnabled !== undefined) {
|
||||
context.warn(
|
||||
'ankiConnect.nPlusOne.highlightEnabled',
|
||||
nPlusOneConfig.highlightEnabled,
|
||||
context.resolved.ankiConnect.nPlusOne.highlightEnabled,
|
||||
context.resolved.ankiConnect.knownWords.highlightEnabled,
|
||||
'Expected boolean.',
|
||||
);
|
||||
context.resolved.ankiConnect.nPlusOne.highlightEnabled =
|
||||
DEFAULT_CONFIG.ankiConnect.nPlusOne.highlightEnabled;
|
||||
context.resolved.ankiConnect.knownWords.highlightEnabled =
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.highlightEnabled;
|
||||
} else {
|
||||
const legacyNPlusOneHighlightEnabled = asBoolean(behavior.nPlusOneHighlightEnabled);
|
||||
if (legacyNPlusOneHighlightEnabled !== undefined) {
|
||||
context.resolved.ankiConnect.nPlusOne.highlightEnabled = legacyNPlusOneHighlightEnabled;
|
||||
const legacyBehaviorNPlusOneHighlightEnabled = asBoolean(behavior.nPlusOneHighlightEnabled);
|
||||
if (legacyBehaviorNPlusOneHighlightEnabled !== undefined) {
|
||||
context.resolved.ankiConnect.knownWords.highlightEnabled =
|
||||
legacyBehaviorNPlusOneHighlightEnabled;
|
||||
context.warn(
|
||||
'ankiConnect.behavior.nPlusOneHighlightEnabled',
|
||||
behavior.nPlusOneHighlightEnabled,
|
||||
DEFAULT_CONFIG.ankiConnect.nPlusOne.highlightEnabled,
|
||||
'Legacy key is deprecated; use ankiConnect.nPlusOne.highlightEnabled',
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.highlightEnabled,
|
||||
'Legacy key is deprecated; use ankiConnect.knownWords.highlightEnabled',
|
||||
);
|
||||
} else {
|
||||
context.resolved.ankiConnect.nPlusOne.highlightEnabled =
|
||||
DEFAULT_CONFIG.ankiConnect.nPlusOne.highlightEnabled;
|
||||
context.resolved.ankiConnect.knownWords.highlightEnabled =
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.highlightEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
const nPlusOneRefreshMinutes = asNumber(nPlusOneConfig.refreshMinutes);
|
||||
const hasValidNPlusOneRefreshMinutes =
|
||||
nPlusOneRefreshMinutes !== undefined &&
|
||||
Number.isInteger(nPlusOneRefreshMinutes) &&
|
||||
nPlusOneRefreshMinutes > 0;
|
||||
if (nPlusOneRefreshMinutes !== undefined) {
|
||||
if (hasValidNPlusOneRefreshMinutes) {
|
||||
context.resolved.ankiConnect.nPlusOne.refreshMinutes = nPlusOneRefreshMinutes;
|
||||
const knownWordsRefreshMinutes = asNumber(knownWordsConfig.refreshMinutes);
|
||||
const legacyNPlusOneRefreshMinutes = asNumber(nPlusOneConfig.refreshMinutes);
|
||||
const hasValidKnownWordsRefreshMinutes =
|
||||
knownWordsRefreshMinutes !== undefined &&
|
||||
Number.isInteger(knownWordsRefreshMinutes) &&
|
||||
knownWordsRefreshMinutes > 0;
|
||||
const hasValidLegacyNPlusOneRefreshMinutes =
|
||||
legacyNPlusOneRefreshMinutes !== undefined &&
|
||||
Number.isInteger(legacyNPlusOneRefreshMinutes) &&
|
||||
legacyNPlusOneRefreshMinutes > 0;
|
||||
if (knownWordsRefreshMinutes !== undefined) {
|
||||
if (hasValidKnownWordsRefreshMinutes) {
|
||||
context.resolved.ankiConnect.knownWords.refreshMinutes = knownWordsRefreshMinutes;
|
||||
} else {
|
||||
context.warn(
|
||||
'ankiConnect.knownWords.refreshMinutes',
|
||||
knownWordsConfig.refreshMinutes,
|
||||
context.resolved.ankiConnect.knownWords.refreshMinutes,
|
||||
'Expected a positive integer.',
|
||||
);
|
||||
context.resolved.ankiConnect.knownWords.refreshMinutes =
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.refreshMinutes;
|
||||
}
|
||||
} else if (legacyNPlusOneRefreshMinutes !== undefined) {
|
||||
if (hasValidLegacyNPlusOneRefreshMinutes) {
|
||||
context.resolved.ankiConnect.knownWords.refreshMinutes = legacyNPlusOneRefreshMinutes;
|
||||
context.warn(
|
||||
'ankiConnect.nPlusOne.refreshMinutes',
|
||||
nPlusOneConfig.refreshMinutes,
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.refreshMinutes,
|
||||
'Legacy key is deprecated; use ankiConnect.knownWords.refreshMinutes',
|
||||
);
|
||||
} else {
|
||||
context.warn(
|
||||
'ankiConnect.nPlusOne.refreshMinutes',
|
||||
nPlusOneConfig.refreshMinutes,
|
||||
context.resolved.ankiConnect.nPlusOne.refreshMinutes,
|
||||
context.resolved.ankiConnect.knownWords.refreshMinutes,
|
||||
'Expected a positive integer.',
|
||||
);
|
||||
context.resolved.ankiConnect.nPlusOne.refreshMinutes =
|
||||
DEFAULT_CONFIG.ankiConnect.nPlusOne.refreshMinutes;
|
||||
context.resolved.ankiConnect.knownWords.refreshMinutes =
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.refreshMinutes;
|
||||
}
|
||||
} else if (asNumber(behavior.nPlusOneRefreshMinutes) !== undefined) {
|
||||
const legacyNPlusOneRefreshMinutes = asNumber(behavior.nPlusOneRefreshMinutes);
|
||||
const legacyBehaviorNPlusOneRefreshMinutes = asNumber(behavior.nPlusOneRefreshMinutes);
|
||||
const hasValidLegacyRefreshMinutes =
|
||||
legacyNPlusOneRefreshMinutes !== undefined &&
|
||||
Number.isInteger(legacyNPlusOneRefreshMinutes) &&
|
||||
legacyNPlusOneRefreshMinutes > 0;
|
||||
legacyBehaviorNPlusOneRefreshMinutes !== undefined &&
|
||||
Number.isInteger(legacyBehaviorNPlusOneRefreshMinutes) &&
|
||||
legacyBehaviorNPlusOneRefreshMinutes > 0;
|
||||
if (hasValidLegacyRefreshMinutes) {
|
||||
context.resolved.ankiConnect.nPlusOne.refreshMinutes = legacyNPlusOneRefreshMinutes;
|
||||
context.resolved.ankiConnect.knownWords.refreshMinutes = legacyBehaviorNPlusOneRefreshMinutes;
|
||||
context.warn(
|
||||
'ankiConnect.behavior.nPlusOneRefreshMinutes',
|
||||
behavior.nPlusOneRefreshMinutes,
|
||||
DEFAULT_CONFIG.ankiConnect.nPlusOne.refreshMinutes,
|
||||
'Legacy key is deprecated; use ankiConnect.nPlusOne.refreshMinutes',
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.refreshMinutes,
|
||||
'Legacy key is deprecated; use ankiConnect.knownWords.refreshMinutes',
|
||||
);
|
||||
} else {
|
||||
context.warn(
|
||||
'ankiConnect.behavior.nPlusOneRefreshMinutes',
|
||||
behavior.nPlusOneRefreshMinutes,
|
||||
context.resolved.ankiConnect.nPlusOne.refreshMinutes,
|
||||
context.resolved.ankiConnect.knownWords.refreshMinutes,
|
||||
'Expected a positive integer.',
|
||||
);
|
||||
context.resolved.ankiConnect.nPlusOne.refreshMinutes =
|
||||
DEFAULT_CONFIG.ankiConnect.nPlusOne.refreshMinutes;
|
||||
context.resolved.ankiConnect.knownWords.refreshMinutes =
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.refreshMinutes;
|
||||
}
|
||||
} else {
|
||||
context.resolved.ankiConnect.nPlusOne.refreshMinutes =
|
||||
DEFAULT_CONFIG.ankiConnect.nPlusOne.refreshMinutes;
|
||||
context.resolved.ankiConnect.knownWords.refreshMinutes =
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.refreshMinutes;
|
||||
}
|
||||
|
||||
const knownWordsAddMinedWordsImmediately = asBoolean(knownWordsConfig.addMinedWordsImmediately);
|
||||
if (knownWordsAddMinedWordsImmediately !== undefined) {
|
||||
context.resolved.ankiConnect.knownWords.addMinedWordsImmediately =
|
||||
knownWordsAddMinedWordsImmediately;
|
||||
} else if (knownWordsConfig.addMinedWordsImmediately !== undefined) {
|
||||
context.warn(
|
||||
'ankiConnect.knownWords.addMinedWordsImmediately',
|
||||
knownWordsConfig.addMinedWordsImmediately,
|
||||
context.resolved.ankiConnect.knownWords.addMinedWordsImmediately,
|
||||
'Expected boolean.',
|
||||
);
|
||||
context.resolved.ankiConnect.knownWords.addMinedWordsImmediately =
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.addMinedWordsImmediately;
|
||||
} else {
|
||||
context.resolved.ankiConnect.knownWords.addMinedWordsImmediately =
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.addMinedWordsImmediately;
|
||||
}
|
||||
|
||||
const nPlusOneMinSentenceWords = asNumber(nPlusOneConfig.minSentenceWords);
|
||||
@@ -720,72 +812,138 @@ export function applyAnkiConnectResolution(context: ResolveContext): void {
|
||||
DEFAULT_CONFIG.ankiConnect.nPlusOne.minSentenceWords;
|
||||
}
|
||||
|
||||
const nPlusOneMatchMode = asString(nPlusOneConfig.matchMode);
|
||||
const legacyNPlusOneMatchMode = asString(behavior.nPlusOneMatchMode);
|
||||
const hasValidNPlusOneMatchMode =
|
||||
nPlusOneMatchMode === 'headword' || nPlusOneMatchMode === 'surface';
|
||||
const hasValidLegacyMatchMode =
|
||||
const knownWordsMatchMode = asString(knownWordsConfig.matchMode);
|
||||
const legacyNPlusOneMatchMode = asString(nPlusOneConfig.matchMode);
|
||||
const legacyBehaviorNPlusOneMatchMode = asString(behavior.nPlusOneMatchMode);
|
||||
const hasValidKnownWordsMatchMode =
|
||||
knownWordsMatchMode === 'headword' || knownWordsMatchMode === 'surface';
|
||||
const hasValidLegacyNPlusOneMatchMode =
|
||||
legacyNPlusOneMatchMode === 'headword' || legacyNPlusOneMatchMode === 'surface';
|
||||
if (hasValidNPlusOneMatchMode) {
|
||||
context.resolved.ankiConnect.nPlusOne.matchMode = nPlusOneMatchMode;
|
||||
} else if (nPlusOneMatchMode !== undefined) {
|
||||
const hasValidLegacyMatchMode =
|
||||
legacyBehaviorNPlusOneMatchMode === 'headword' || legacyBehaviorNPlusOneMatchMode === 'surface';
|
||||
if (hasValidKnownWordsMatchMode) {
|
||||
context.resolved.ankiConnect.knownWords.matchMode = knownWordsMatchMode;
|
||||
} else if (knownWordsMatchMode !== undefined) {
|
||||
context.warn(
|
||||
'ankiConnect.nPlusOne.matchMode',
|
||||
nPlusOneConfig.matchMode,
|
||||
DEFAULT_CONFIG.ankiConnect.nPlusOne.matchMode,
|
||||
'ankiConnect.knownWords.matchMode',
|
||||
knownWordsConfig.matchMode,
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.matchMode,
|
||||
"Expected 'headword' or 'surface'.",
|
||||
);
|
||||
context.resolved.ankiConnect.nPlusOne.matchMode = DEFAULT_CONFIG.ankiConnect.nPlusOne.matchMode;
|
||||
context.resolved.ankiConnect.knownWords.matchMode =
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.matchMode;
|
||||
} else if (legacyNPlusOneMatchMode !== undefined) {
|
||||
if (hasValidLegacyNPlusOneMatchMode) {
|
||||
context.resolved.ankiConnect.knownWords.matchMode = legacyNPlusOneMatchMode;
|
||||
context.warn(
|
||||
'ankiConnect.nPlusOne.matchMode',
|
||||
nPlusOneConfig.matchMode,
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.matchMode,
|
||||
'Legacy key is deprecated; use ankiConnect.knownWords.matchMode',
|
||||
);
|
||||
} else {
|
||||
context.warn(
|
||||
'ankiConnect.nPlusOne.matchMode',
|
||||
nPlusOneConfig.matchMode,
|
||||
context.resolved.ankiConnect.knownWords.matchMode,
|
||||
"Expected 'headword' or 'surface'.",
|
||||
);
|
||||
context.resolved.ankiConnect.knownWords.matchMode =
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.matchMode;
|
||||
}
|
||||
} else if (legacyBehaviorNPlusOneMatchMode !== undefined) {
|
||||
if (hasValidLegacyMatchMode) {
|
||||
context.resolved.ankiConnect.nPlusOne.matchMode = legacyNPlusOneMatchMode;
|
||||
context.resolved.ankiConnect.knownWords.matchMode = legacyBehaviorNPlusOneMatchMode;
|
||||
context.warn(
|
||||
'ankiConnect.behavior.nPlusOneMatchMode',
|
||||
behavior.nPlusOneMatchMode,
|
||||
DEFAULT_CONFIG.ankiConnect.nPlusOne.matchMode,
|
||||
'Legacy key is deprecated; use ankiConnect.nPlusOne.matchMode',
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.matchMode,
|
||||
'Legacy key is deprecated; use ankiConnect.knownWords.matchMode',
|
||||
);
|
||||
} else {
|
||||
context.warn(
|
||||
'ankiConnect.behavior.nPlusOneMatchMode',
|
||||
behavior.nPlusOneMatchMode,
|
||||
context.resolved.ankiConnect.nPlusOne.matchMode,
|
||||
context.resolved.ankiConnect.knownWords.matchMode,
|
||||
"Expected 'headword' or 'surface'.",
|
||||
);
|
||||
context.resolved.ankiConnect.nPlusOne.matchMode =
|
||||
DEFAULT_CONFIG.ankiConnect.nPlusOne.matchMode;
|
||||
context.resolved.ankiConnect.knownWords.matchMode =
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.matchMode;
|
||||
}
|
||||
} else {
|
||||
context.resolved.ankiConnect.nPlusOne.matchMode = DEFAULT_CONFIG.ankiConnect.nPlusOne.matchMode;
|
||||
context.resolved.ankiConnect.knownWords.matchMode =
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.matchMode;
|
||||
}
|
||||
|
||||
const nPlusOneDecks = nPlusOneConfig.decks;
|
||||
if (Array.isArray(nPlusOneDecks)) {
|
||||
const normalizedDecks = nPlusOneDecks
|
||||
const DEFAULT_FIELDS = [
|
||||
DEFAULT_CONFIG.ankiConnect.fields.word,
|
||||
'Word',
|
||||
'Reading',
|
||||
'Word Reading',
|
||||
];
|
||||
const knownWordsDecks = knownWordsConfig.decks;
|
||||
const legacyNPlusOneDecks = nPlusOneConfig.decks;
|
||||
if (isObject(knownWordsDecks)) {
|
||||
const resolved: Record<string, string[]> = {};
|
||||
for (const [deck, fields] of Object.entries(knownWordsDecks as Record<string, unknown>)) {
|
||||
const deckName = deck.trim();
|
||||
if (!deckName) continue;
|
||||
if (Array.isArray(fields) && fields.every((f) => typeof f === 'string')) {
|
||||
resolved[deckName] = (fields as string[]).map((f) => f.trim()).filter((f) => f.length > 0);
|
||||
} else {
|
||||
context.warn(
|
||||
`ankiConnect.knownWords.decks["${deckName}"]`,
|
||||
fields,
|
||||
DEFAULT_FIELDS,
|
||||
'Expected an array of field name strings.',
|
||||
);
|
||||
resolved[deckName] = DEFAULT_FIELDS;
|
||||
}
|
||||
}
|
||||
context.resolved.ankiConnect.knownWords.decks = resolved;
|
||||
} else if (Array.isArray(knownWordsDecks)) {
|
||||
const normalized = knownWordsDecks
|
||||
.filter((entry): entry is string => typeof entry === 'string')
|
||||
.map((entry) => entry.trim())
|
||||
.filter((entry) => entry.length > 0);
|
||||
|
||||
if (normalizedDecks.length === nPlusOneDecks.length) {
|
||||
context.resolved.ankiConnect.nPlusOne.decks = [...new Set(normalizedDecks)];
|
||||
} else if (nPlusOneDecks.length > 0) {
|
||||
const resolved: Record<string, string[]> = {};
|
||||
for (const deck of new Set(normalized)) {
|
||||
resolved[deck] = DEFAULT_FIELDS;
|
||||
}
|
||||
context.resolved.ankiConnect.knownWords.decks = resolved;
|
||||
if (normalized.length > 0) {
|
||||
context.warn(
|
||||
'ankiConnect.knownWords.decks',
|
||||
knownWordsDecks,
|
||||
resolved,
|
||||
'Legacy array format is deprecated; use object format: { "Deck Name": ["Field1", "Field2"] }',
|
||||
);
|
||||
}
|
||||
} else if (knownWordsDecks !== undefined) {
|
||||
context.warn(
|
||||
'ankiConnect.knownWords.decks',
|
||||
knownWordsDecks,
|
||||
context.resolved.ankiConnect.knownWords.decks,
|
||||
'Expected an object mapping deck names to field arrays.',
|
||||
);
|
||||
} else if (Array.isArray(legacyNPlusOneDecks)) {
|
||||
const normalized = legacyNPlusOneDecks
|
||||
.filter((entry): entry is string => typeof entry === 'string')
|
||||
.map((entry) => entry.trim())
|
||||
.filter((entry) => entry.length > 0);
|
||||
const resolved: Record<string, string[]> = {};
|
||||
for (const deck of new Set(normalized)) {
|
||||
resolved[deck] = DEFAULT_FIELDS;
|
||||
}
|
||||
context.resolved.ankiConnect.knownWords.decks = resolved;
|
||||
if (normalized.length > 0) {
|
||||
context.warn(
|
||||
'ankiConnect.nPlusOne.decks',
|
||||
nPlusOneDecks,
|
||||
context.resolved.ankiConnect.nPlusOne.decks,
|
||||
'Expected an array of strings.',
|
||||
legacyNPlusOneDecks,
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.decks,
|
||||
'Legacy key is deprecated; use ankiConnect.knownWords.decks with object format',
|
||||
);
|
||||
} else {
|
||||
context.resolved.ankiConnect.nPlusOne.decks = [];
|
||||
}
|
||||
} else if (nPlusOneDecks !== undefined) {
|
||||
context.warn(
|
||||
'ankiConnect.nPlusOne.decks',
|
||||
nPlusOneDecks,
|
||||
context.resolved.ankiConnect.nPlusOne.decks,
|
||||
'Expected an array of strings.',
|
||||
);
|
||||
context.resolved.ankiConnect.nPlusOne.decks = [];
|
||||
}
|
||||
|
||||
const nPlusOneHighlightColor = asColor(nPlusOneConfig.nPlusOne);
|
||||
@@ -801,17 +959,34 @@ export function applyAnkiConnectResolution(context: ResolveContext): void {
|
||||
context.resolved.ankiConnect.nPlusOne.nPlusOne = DEFAULT_CONFIG.ankiConnect.nPlusOne.nPlusOne;
|
||||
}
|
||||
|
||||
const nPlusOneKnownWordColor = asColor(nPlusOneConfig.knownWord);
|
||||
if (nPlusOneKnownWordColor !== undefined) {
|
||||
context.resolved.ankiConnect.nPlusOne.knownWord = nPlusOneKnownWordColor;
|
||||
const knownWordsColor = asColor(knownWordsConfig.color);
|
||||
const legacyNPlusOneKnownWordColor = asColor(nPlusOneConfig.knownWord);
|
||||
if (knownWordsColor !== undefined) {
|
||||
context.resolved.ankiConnect.knownWords.color = knownWordsColor;
|
||||
} else if (knownWordsConfig.color !== undefined) {
|
||||
context.warn(
|
||||
'ankiConnect.knownWords.color',
|
||||
knownWordsConfig.color,
|
||||
context.resolved.ankiConnect.knownWords.color,
|
||||
'Expected a hex color value.',
|
||||
);
|
||||
context.resolved.ankiConnect.knownWords.color = DEFAULT_CONFIG.ankiConnect.knownWords.color;
|
||||
} else if (legacyNPlusOneKnownWordColor !== undefined) {
|
||||
context.resolved.ankiConnect.knownWords.color = legacyNPlusOneKnownWordColor;
|
||||
context.warn(
|
||||
'ankiConnect.nPlusOne.knownWord',
|
||||
nPlusOneConfig.knownWord,
|
||||
DEFAULT_CONFIG.ankiConnect.knownWords.color,
|
||||
'Legacy key is deprecated; use ankiConnect.knownWords.color',
|
||||
);
|
||||
} else if (nPlusOneConfig.knownWord !== undefined) {
|
||||
context.warn(
|
||||
'ankiConnect.nPlusOne.knownWord',
|
||||
nPlusOneConfig.knownWord,
|
||||
context.resolved.ankiConnect.nPlusOne.knownWord,
|
||||
context.resolved.ankiConnect.knownWords.color,
|
||||
'Expected a hex color value.',
|
||||
);
|
||||
context.resolved.ankiConnect.nPlusOne.knownWord = DEFAULT_CONFIG.ankiConnect.nPlusOne.knownWord;
|
||||
context.resolved.ankiConnect.knownWords.color = DEFAULT_CONFIG.ankiConnect.knownWords.color;
|
||||
}
|
||||
|
||||
if (
|
||||
|
||||
@@ -1,9 +1,68 @@
|
||||
import { ResolveContext } from './context';
|
||||
import { ImmersionTrackingRetentionMode, ImmersionTrackingRetentionPreset } from '../../types';
|
||||
import { asBoolean, asNumber, asString, isObject } from './shared';
|
||||
|
||||
const DEFAULT_RETENTION_MODE: ImmersionTrackingRetentionMode = 'preset';
|
||||
const DEFAULT_RETENTION_PRESET: ImmersionTrackingRetentionPreset = 'balanced';
|
||||
|
||||
const BASE_RETENTION = {
|
||||
eventsDays: 0,
|
||||
telemetryDays: 0,
|
||||
sessionsDays: 0,
|
||||
dailyRollupsDays: 0,
|
||||
monthlyRollupsDays: 0,
|
||||
vacuumIntervalDays: 0,
|
||||
};
|
||||
|
||||
const RETENTION_PRESETS: Record<ImmersionTrackingRetentionPreset, typeof BASE_RETENTION> = {
|
||||
minimal: {
|
||||
eventsDays: 3,
|
||||
telemetryDays: 14,
|
||||
sessionsDays: 14,
|
||||
dailyRollupsDays: 30,
|
||||
monthlyRollupsDays: 365,
|
||||
vacuumIntervalDays: 7,
|
||||
},
|
||||
balanced: BASE_RETENTION,
|
||||
'deep-history': {
|
||||
eventsDays: 14,
|
||||
telemetryDays: 60,
|
||||
sessionsDays: 60,
|
||||
dailyRollupsDays: 730,
|
||||
monthlyRollupsDays: 5 * 365,
|
||||
vacuumIntervalDays: 7,
|
||||
},
|
||||
};
|
||||
|
||||
const DEFAULT_LIFETIME_SUMMARIES = {
|
||||
global: true,
|
||||
anime: true,
|
||||
media: true,
|
||||
};
|
||||
|
||||
function asRetentionMode(value: unknown): value is ImmersionTrackingRetentionMode {
|
||||
return value === 'preset' || value === 'advanced';
|
||||
}
|
||||
|
||||
function asRetentionPreset(value: unknown): value is ImmersionTrackingRetentionPreset {
|
||||
return value === 'minimal' || value === 'balanced' || value === 'deep-history';
|
||||
}
|
||||
|
||||
export function applyImmersionTrackingConfig(context: ResolveContext): void {
|
||||
const { src, resolved, warn } = context;
|
||||
|
||||
if (!isObject(src.immersionTracking)) {
|
||||
resolved.immersionTracking.retentionMode = DEFAULT_RETENTION_MODE;
|
||||
resolved.immersionTracking.retentionPreset = DEFAULT_RETENTION_PRESET;
|
||||
resolved.immersionTracking.retention = {
|
||||
...BASE_RETENTION,
|
||||
};
|
||||
resolved.immersionTracking.lifetimeSummaries = {
|
||||
...DEFAULT_LIFETIME_SUMMARIES,
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
if (isObject(src.immersionTracking)) {
|
||||
const enabled = asBoolean(src.immersionTracking.enabled);
|
||||
if (enabled !== undefined) {
|
||||
@@ -93,81 +152,186 @@ export function applyImmersionTrackingConfig(context: ResolveContext): void {
|
||||
);
|
||||
}
|
||||
|
||||
const retentionMode = asString(src.immersionTracking.retentionMode);
|
||||
if (asRetentionMode(retentionMode)) {
|
||||
resolved.immersionTracking.retentionMode = retentionMode;
|
||||
} else if (src.immersionTracking.retentionMode !== undefined) {
|
||||
warn(
|
||||
'immersionTracking.retentionMode',
|
||||
src.immersionTracking.retentionMode,
|
||||
DEFAULT_RETENTION_MODE,
|
||||
'Expected "preset" or "advanced".',
|
||||
);
|
||||
resolved.immersionTracking.retentionMode = DEFAULT_RETENTION_MODE;
|
||||
} else {
|
||||
resolved.immersionTracking.retentionMode = DEFAULT_RETENTION_MODE;
|
||||
}
|
||||
|
||||
const retentionPreset = asString(src.immersionTracking.retentionPreset);
|
||||
if (asRetentionPreset(retentionPreset)) {
|
||||
resolved.immersionTracking.retentionPreset = retentionPreset;
|
||||
} else if (src.immersionTracking.retentionPreset !== undefined) {
|
||||
warn(
|
||||
'immersionTracking.retentionPreset',
|
||||
src.immersionTracking.retentionPreset,
|
||||
DEFAULT_RETENTION_PRESET,
|
||||
'Expected "minimal", "balanced", or "deep-history".',
|
||||
);
|
||||
resolved.immersionTracking.retentionPreset = DEFAULT_RETENTION_PRESET;
|
||||
} else {
|
||||
resolved.immersionTracking.retentionPreset =
|
||||
resolved.immersionTracking.retentionPreset ?? DEFAULT_RETENTION_PRESET;
|
||||
}
|
||||
|
||||
const resolvedPreset =
|
||||
resolved.immersionTracking.retentionPreset === 'minimal' ||
|
||||
resolved.immersionTracking.retentionPreset === 'balanced' ||
|
||||
resolved.immersionTracking.retentionPreset === 'deep-history'
|
||||
? resolved.immersionTracking.retentionPreset
|
||||
: DEFAULT_RETENTION_PRESET;
|
||||
|
||||
const baseRetention =
|
||||
resolved.immersionTracking.retentionMode === 'preset'
|
||||
? RETENTION_PRESETS[resolvedPreset]
|
||||
: BASE_RETENTION;
|
||||
|
||||
const retention = {
|
||||
eventsDays: baseRetention.eventsDays,
|
||||
telemetryDays: baseRetention.telemetryDays,
|
||||
sessionsDays: baseRetention.sessionsDays,
|
||||
dailyRollupsDays: baseRetention.dailyRollupsDays,
|
||||
monthlyRollupsDays: baseRetention.monthlyRollupsDays,
|
||||
vacuumIntervalDays: baseRetention.vacuumIntervalDays,
|
||||
};
|
||||
|
||||
if (isObject(src.immersionTracking.retention)) {
|
||||
const eventsDays = asNumber(src.immersionTracking.retention.eventsDays);
|
||||
if (eventsDays !== undefined && eventsDays >= 1 && eventsDays <= 3650) {
|
||||
resolved.immersionTracking.retention.eventsDays = Math.floor(eventsDays);
|
||||
if (eventsDays !== undefined && eventsDays >= 0 && eventsDays <= 3650) {
|
||||
retention.eventsDays = Math.floor(eventsDays);
|
||||
} else if (src.immersionTracking.retention.eventsDays !== undefined) {
|
||||
warn(
|
||||
'immersionTracking.retention.eventsDays',
|
||||
src.immersionTracking.retention.eventsDays,
|
||||
resolved.immersionTracking.retention.eventsDays,
|
||||
'Expected integer between 1 and 3650.',
|
||||
retention.eventsDays,
|
||||
'Expected integer between 0 and 3650.',
|
||||
);
|
||||
}
|
||||
|
||||
const telemetryDays = asNumber(src.immersionTracking.retention.telemetryDays);
|
||||
if (telemetryDays !== undefined && telemetryDays >= 1 && telemetryDays <= 3650) {
|
||||
resolved.immersionTracking.retention.telemetryDays = Math.floor(telemetryDays);
|
||||
if (telemetryDays !== undefined && telemetryDays >= 0 && telemetryDays <= 3650) {
|
||||
retention.telemetryDays = Math.floor(telemetryDays);
|
||||
} else if (src.immersionTracking.retention.telemetryDays !== undefined) {
|
||||
warn(
|
||||
'immersionTracking.retention.telemetryDays',
|
||||
src.immersionTracking.retention.telemetryDays,
|
||||
resolved.immersionTracking.retention.telemetryDays,
|
||||
'Expected integer between 1 and 3650.',
|
||||
retention.telemetryDays,
|
||||
'Expected integer between 0 and 3650.',
|
||||
);
|
||||
}
|
||||
|
||||
const sessionsDays = asNumber(src.immersionTracking.retention.sessionsDays);
|
||||
if (sessionsDays !== undefined && sessionsDays >= 0 && sessionsDays <= 3650) {
|
||||
retention.sessionsDays = Math.floor(sessionsDays);
|
||||
} else if (src.immersionTracking.retention.sessionsDays !== undefined) {
|
||||
warn(
|
||||
'immersionTracking.retention.sessionsDays',
|
||||
src.immersionTracking.retention.sessionsDays,
|
||||
retention.sessionsDays,
|
||||
'Expected integer between 0 and 3650.',
|
||||
);
|
||||
}
|
||||
|
||||
const dailyRollupsDays = asNumber(src.immersionTracking.retention.dailyRollupsDays);
|
||||
if (dailyRollupsDays !== undefined && dailyRollupsDays >= 1 && dailyRollupsDays <= 36500) {
|
||||
resolved.immersionTracking.retention.dailyRollupsDays = Math.floor(dailyRollupsDays);
|
||||
if (dailyRollupsDays !== undefined && dailyRollupsDays >= 0 && dailyRollupsDays <= 36500) {
|
||||
retention.dailyRollupsDays = Math.floor(dailyRollupsDays);
|
||||
} else if (src.immersionTracking.retention.dailyRollupsDays !== undefined) {
|
||||
warn(
|
||||
'immersionTracking.retention.dailyRollupsDays',
|
||||
src.immersionTracking.retention.dailyRollupsDays,
|
||||
resolved.immersionTracking.retention.dailyRollupsDays,
|
||||
'Expected integer between 1 and 36500.',
|
||||
retention.dailyRollupsDays,
|
||||
'Expected integer between 0 and 36500.',
|
||||
);
|
||||
}
|
||||
|
||||
const monthlyRollupsDays = asNumber(src.immersionTracking.retention.monthlyRollupsDays);
|
||||
if (
|
||||
monthlyRollupsDays !== undefined &&
|
||||
monthlyRollupsDays >= 1 &&
|
||||
monthlyRollupsDays >= 0 &&
|
||||
monthlyRollupsDays <= 36500
|
||||
) {
|
||||
resolved.immersionTracking.retention.monthlyRollupsDays = Math.floor(monthlyRollupsDays);
|
||||
retention.monthlyRollupsDays = Math.floor(monthlyRollupsDays);
|
||||
} else if (src.immersionTracking.retention.monthlyRollupsDays !== undefined) {
|
||||
warn(
|
||||
'immersionTracking.retention.monthlyRollupsDays',
|
||||
src.immersionTracking.retention.monthlyRollupsDays,
|
||||
resolved.immersionTracking.retention.monthlyRollupsDays,
|
||||
'Expected integer between 1 and 36500.',
|
||||
retention.monthlyRollupsDays,
|
||||
'Expected integer between 0 and 36500.',
|
||||
);
|
||||
}
|
||||
|
||||
const vacuumIntervalDays = asNumber(src.immersionTracking.retention.vacuumIntervalDays);
|
||||
if (
|
||||
vacuumIntervalDays !== undefined &&
|
||||
vacuumIntervalDays >= 1 &&
|
||||
vacuumIntervalDays >= 0 &&
|
||||
vacuumIntervalDays <= 3650
|
||||
) {
|
||||
resolved.immersionTracking.retention.vacuumIntervalDays = Math.floor(vacuumIntervalDays);
|
||||
retention.vacuumIntervalDays = Math.floor(vacuumIntervalDays);
|
||||
} else if (src.immersionTracking.retention.vacuumIntervalDays !== undefined) {
|
||||
warn(
|
||||
'immersionTracking.retention.vacuumIntervalDays',
|
||||
src.immersionTracking.retention.vacuumIntervalDays,
|
||||
resolved.immersionTracking.retention.vacuumIntervalDays,
|
||||
'Expected integer between 1 and 3650.',
|
||||
retention.vacuumIntervalDays,
|
||||
'Expected integer between 0 and 3650.',
|
||||
);
|
||||
}
|
||||
} else if (src.immersionTracking.retention !== undefined) {
|
||||
warn(
|
||||
'immersionTracking.retention',
|
||||
src.immersionTracking.retention,
|
||||
resolved.immersionTracking.retention,
|
||||
baseRetention,
|
||||
'Expected object.',
|
||||
);
|
||||
}
|
||||
|
||||
resolved.immersionTracking.retention = {
|
||||
eventsDays: retention.eventsDays,
|
||||
telemetryDays: retention.telemetryDays,
|
||||
sessionsDays: retention.sessionsDays,
|
||||
dailyRollupsDays: retention.dailyRollupsDays,
|
||||
monthlyRollupsDays: retention.monthlyRollupsDays,
|
||||
vacuumIntervalDays: retention.vacuumIntervalDays,
|
||||
};
|
||||
|
||||
const lifetimeSummaries = {
|
||||
global: DEFAULT_LIFETIME_SUMMARIES.global,
|
||||
anime: DEFAULT_LIFETIME_SUMMARIES.anime,
|
||||
media: DEFAULT_LIFETIME_SUMMARIES.media,
|
||||
};
|
||||
|
||||
if (isObject(src.immersionTracking.lifetimeSummaries)) {
|
||||
const global = asBoolean(src.immersionTracking.lifetimeSummaries.global);
|
||||
if (global !== undefined) {
|
||||
lifetimeSummaries.global = global;
|
||||
}
|
||||
|
||||
const anime = asBoolean(src.immersionTracking.lifetimeSummaries.anime);
|
||||
if (anime !== undefined) {
|
||||
lifetimeSummaries.anime = anime;
|
||||
}
|
||||
|
||||
const media = asBoolean(src.immersionTracking.lifetimeSummaries.media);
|
||||
if (media !== undefined) {
|
||||
lifetimeSummaries.media = media;
|
||||
}
|
||||
} else if (src.immersionTracking.lifetimeSummaries !== undefined) {
|
||||
warn(
|
||||
'immersionTracking.lifetimeSummaries',
|
||||
src.immersionTracking.lifetimeSummaries,
|
||||
DEFAULT_LIFETIME_SUMMARIES,
|
||||
'Expected object.',
|
||||
);
|
||||
}
|
||||
|
||||
resolved.immersionTracking.lifetimeSummaries = lifetimeSummaries;
|
||||
}
|
||||
}
|
||||
|
||||
53
src/config/resolve/stats.ts
Normal file
53
src/config/resolve/stats.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { ResolveContext } from './context';
|
||||
import { asBoolean, asNumber, asString, isObject } from './shared';
|
||||
|
||||
export function applyStatsConfig(context: ResolveContext): void {
|
||||
const { src, resolved, warn } = context;
|
||||
|
||||
if (!isObject(src.stats)) return;
|
||||
|
||||
const toggleKey = asString(src.stats.toggleKey);
|
||||
if (toggleKey !== undefined) {
|
||||
resolved.stats.toggleKey = toggleKey;
|
||||
} else if (src.stats.toggleKey !== undefined) {
|
||||
warn('stats.toggleKey', src.stats.toggleKey, resolved.stats.toggleKey, 'Expected string.');
|
||||
}
|
||||
|
||||
const markWatchedKey = asString(src.stats.markWatchedKey);
|
||||
if (markWatchedKey !== undefined) {
|
||||
resolved.stats.markWatchedKey = markWatchedKey;
|
||||
} else if (src.stats.markWatchedKey !== undefined) {
|
||||
warn('stats.markWatchedKey', src.stats.markWatchedKey, resolved.stats.markWatchedKey, 'Expected string.');
|
||||
}
|
||||
|
||||
const serverPort = asNumber(src.stats.serverPort);
|
||||
if (serverPort !== undefined) {
|
||||
resolved.stats.serverPort = serverPort;
|
||||
} else if (src.stats.serverPort !== undefined) {
|
||||
warn('stats.serverPort', src.stats.serverPort, resolved.stats.serverPort, 'Expected number.');
|
||||
}
|
||||
|
||||
const autoStartServer = asBoolean(src.stats.autoStartServer);
|
||||
if (autoStartServer !== undefined) {
|
||||
resolved.stats.autoStartServer = autoStartServer;
|
||||
} else if (src.stats.autoStartServer !== undefined) {
|
||||
warn(
|
||||
'stats.autoStartServer',
|
||||
src.stats.autoStartServer,
|
||||
resolved.stats.autoStartServer,
|
||||
'Expected boolean.',
|
||||
);
|
||||
}
|
||||
|
||||
const autoOpenBrowser = asBoolean(src.stats.autoOpenBrowser);
|
||||
if (autoOpenBrowser !== undefined) {
|
||||
resolved.stats.autoOpenBrowser = autoOpenBrowser;
|
||||
} else if (src.stats.autoOpenBrowser !== undefined) {
|
||||
warn(
|
||||
'stats.autoOpenBrowser',
|
||||
src.stats.autoOpenBrowser,
|
||||
resolved.stats.autoOpenBrowser,
|
||||
'Expected boolean.',
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user