feat(yomitan): add read-only external profile support for shared dictionaries (#18)

This commit is contained in:
2026-03-12 01:17:34 -07:00
committed by GitHub
parent 68833c76c4
commit 1b56360a24
67 changed files with 1230 additions and 135 deletions
+49 -5
View File
@@ -65,7 +65,7 @@ test('ensureDefaultConfigBootstrap creates config dir and default jsonc only whe
});
});
test('ensureDefaultConfigBootstrap does not seed default config into an existing config directory', () => {
test('ensureDefaultConfigBootstrap seeds default config into an existing config directory when missing', () => {
withTempDir((root) => {
const configDir = path.join(root, 'SubMiner');
fs.mkdirSync(configDir, { recursive: true });
@@ -74,10 +74,13 @@ test('ensureDefaultConfigBootstrap does not seed default config into an existing
ensureDefaultConfigBootstrap({
configDir,
configFilePaths: getDefaultConfigFilePaths(configDir),
generateTemplate: () => 'should-not-write',
generateTemplate: () => '{\n "logging": {}\n}\n',
});
assert.equal(fs.existsSync(path.join(configDir, 'config.jsonc')), false);
assert.equal(
fs.readFileSync(path.join(configDir, 'config.jsonc'), 'utf8'),
'{\n "logging": {}\n}\n',
);
assert.equal(fs.readFileSync(path.join(configDir, 'existing-user-file.txt'), 'utf8'), 'keep\n');
});
});
@@ -91,6 +94,7 @@ test('readSetupState ignores invalid files and round-trips valid state', () => {
const state = createDefaultSetupState();
state.status = 'completed';
state.completionSource = 'user';
state.yomitanSetupMode = 'internal';
state.lastSeenYomitanDictionaryCount = 2;
writeSetupState(statePath, state);
@@ -98,7 +102,7 @@ test('readSetupState ignores invalid files and round-trips valid state', () => {
});
});
test('readSetupState migrates v1 state to v2 windows shortcut defaults', () => {
test('readSetupState migrates v1 state to v3 windows shortcut defaults', () => {
withTempDir((root) => {
const statePath = getSetupStatePath(root);
fs.writeFileSync(
@@ -115,10 +119,11 @@ test('readSetupState migrates v1 state to v2 windows shortcut defaults', () => {
);
assert.deepEqual(readSetupState(statePath), {
version: 2,
version: 3,
status: 'incomplete',
completedAt: null,
completionSource: null,
yomitanSetupMode: null,
lastSeenYomitanDictionaryCount: 0,
pluginInstallStatus: 'unknown',
pluginInstallPathSummary: null,
@@ -131,6 +136,45 @@ test('readSetupState migrates v1 state to v2 windows shortcut defaults', () => {
});
});
test('readSetupState migrates completed v2 state to internal yomitan setup mode', () => {
withTempDir((root) => {
const statePath = getSetupStatePath(root);
fs.writeFileSync(
statePath,
JSON.stringify({
version: 2,
status: 'completed',
completedAt: '2026-03-12T00:00:00.000Z',
completionSource: 'user',
lastSeenYomitanDictionaryCount: 1,
pluginInstallStatus: 'unknown',
pluginInstallPathSummary: null,
windowsMpvShortcutPreferences: {
startMenuEnabled: true,
desktopEnabled: true,
},
windowsMpvShortcutLastStatus: 'unknown',
}),
);
assert.deepEqual(readSetupState(statePath), {
version: 3,
status: 'completed',
completedAt: '2026-03-12T00:00:00.000Z',
completionSource: 'user',
yomitanSetupMode: 'internal',
lastSeenYomitanDictionaryCount: 1,
pluginInstallStatus: 'unknown',
pluginInstallPathSummary: null,
windowsMpvShortcutPreferences: {
startMenuEnabled: true,
desktopEnabled: true,
},
windowsMpvShortcutLastStatus: 'unknown',
});
});
});
test('resolveDefaultMpvInstallPaths resolves linux, macOS, and Windows defaults', () => {
const linuxHomeDir = path.join(path.sep, 'tmp', 'home');
const xdgConfigHome = path.join(path.sep, 'tmp', 'xdg');