refactor: piece系設定解決をresolveConfigValueへ統一

This commit is contained in:
nrslib 2026-02-19 10:57:07 +09:00
parent cbde7ac654
commit 6b425d64fc
9 changed files with 79 additions and 51 deletions

View File

@ -20,15 +20,22 @@ vi.mock('../infra/config/global/globalConfig.js', () => ({
loadGlobalConfig: vi.fn().mockReturnValue({}), loadGlobalConfig: vi.fn().mockReturnValue({}),
})); }));
vi.mock('../infra/config/loadConfig.js', () => ({ vi.mock('../infra/config/resolveConfigValue.js', () => ({
loadConfig: vi.fn(() => ({ resolveConfigValue: vi.fn((_cwd: string, key: string) => {
global: { if (key === 'language') return languageState.value;
language: languageState.value, if (key === 'enableBuiltinPieces') return true;
disabledBuiltins: [], if (key === 'disabledBuiltins') return [];
enableBuiltinPieces: true, return undefined;
}, }),
project: {}, resolveConfigValues: vi.fn((_cwd: string, keys: readonly string[]) => {
})), const result: Record<string, unknown> = {};
for (const key of keys) {
if (key === 'language') result[key] = languageState.value;
if (key === 'enableBuiltinPieces') result[key] = true;
if (key === 'disabledBuiltins') result[key] = [];
}
return result;
}),
})); }));
// --- Imports (after mocks) --- // --- Imports (after mocks) ---

View File

@ -57,14 +57,21 @@ vi.mock('../infra/config/project/projectConfig.js', () => ({
loadProjectConfig: vi.fn().mockReturnValue({}), loadProjectConfig: vi.fn().mockReturnValue({}),
})); }));
vi.mock('../infra/config/loadConfig.js', () => ({ vi.mock('../infra/config/resolveConfigValue.js', () => ({
loadConfig: vi.fn().mockReturnValue({ resolveConfigValue: vi.fn((_cwd: string, key: string) => {
global: { if (key === 'language') return 'en';
language: 'en', if (key === 'enableBuiltinPieces') return true;
enableBuiltinPieces: true, if (key === 'disabledBuiltins') return [];
disabledBuiltins: [], return undefined;
}, }),
project: {}, resolveConfigValues: vi.fn((_cwd: string, keys: readonly string[]) => {
const result: Record<string, unknown> = {};
for (const key of keys) {
if (key === 'language') result[key] = 'en';
if (key === 'enableBuiltinPieces') result[key] = true;
if (key === 'disabledBuiltins') result[key] = [];
}
return result;
}), }),
})); }));

View File

@ -17,15 +17,22 @@ vi.mock('../infra/config/global/globalConfig.js', async (importOriginal) => {
}; };
}); });
vi.mock('../infra/config/loadConfig.js', () => ({ vi.mock('../infra/config/resolveConfigValue.js', () => ({
loadConfig: () => ({ resolveConfigValue: (_cwd: string, key: string) => {
global: { if (key === 'language') return 'en';
language: 'en', if (key === 'enableBuiltinPieces') return false;
enableBuiltinPieces: false, if (key === 'disabledBuiltins') return [];
disabledBuiltins: [], return undefined;
}, },
project: {}, resolveConfigValues: (_cwd: string, keys: readonly string[]) => {
}), const result: Record<string, unknown> = {};
for (const key of keys) {
if (key === 'language') result[key] = 'en';
if (key === 'enableBuiltinPieces') result[key] = false;
if (key === 'disabledBuiltins') result[key] = [];
}
return result;
},
})); }));
const { listPieces } = await import('../infra/config/loaders/pieceLoader.js'); const { listPieces } = await import('../infra/config/loaders/pieceLoader.js');

View File

@ -26,15 +26,22 @@ vi.mock('../infra/config/global/globalConfig.js', async (importOriginal) => {
}; };
}); });
vi.mock('../infra/config/loadConfig.js', () => ({ vi.mock('../infra/config/resolveConfigValue.js', () => ({
loadConfig: () => ({ resolveConfigValue: (_cwd: string, key: string) => {
global: { if (key === 'language') return languageState.value;
language: languageState.value, if (key === 'enableBuiltinPieces') return true;
enableBuiltinPieces: true, if (key === 'disabledBuiltins') return [];
disabledBuiltins: [], return undefined;
}, },
project: {}, resolveConfigValues: (_cwd: string, keys: readonly string[]) => {
}), const result: Record<string, unknown> = {};
for (const key of keys) {
if (key === 'language') result[key] = languageState.value;
if (key === 'enableBuiltinPieces') result[key] = true;
if (key === 'disabledBuiltins') result[key] = [];
}
return result;
},
})); }));
vi.mock('../infra/resources/index.js', async (importOriginal) => { vi.mock('../infra/resources/index.js', async (importOriginal) => {

View File

@ -7,7 +7,7 @@
import { existsSync, mkdirSync, writeFileSync } from 'node:fs'; import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
import { dirname, join } from 'node:path'; import { dirname, join } from 'node:path';
import { getGlobalConfigDir } from '../paths.js'; import { getGlobalConfigDir } from '../paths.js';
import { loadConfig } from '../loadConfig.js'; import { resolveConfigValue } from '../resolveConfigValue.js';
const INITIAL_USER_CATEGORIES_CONTENT = 'piece_categories: {}\n'; const INITIAL_USER_CATEGORIES_CONTENT = 'piece_categories: {}\n';
@ -17,9 +17,9 @@ function getDefaultPieceCategoriesPath(): string {
/** Get the path to the user's piece categories file. */ /** Get the path to the user's piece categories file. */
export function getPieceCategoriesPath(cwd: string): string { export function getPieceCategoriesPath(cwd: string): string {
const config = loadConfig(cwd); const pieceCategoriesFile = resolveConfigValue(cwd, 'pieceCategoriesFile');
if (config.pieceCategoriesFile) { if (pieceCategoriesFile) {
return config.pieceCategoriesFile; return pieceCategoriesFile;
} }
return getDefaultPieceCategoriesPath(); return getDefaultPieceCategoriesPath();
} }

View File

@ -16,11 +16,11 @@ import {
getBuiltinPiecesDir, getBuiltinPiecesDir,
isPathSafe, isPathSafe,
} from '../paths.js'; } from '../paths.js';
import { loadConfig } from '../loadConfig.js'; import { resolveConfigValue } from '../resolveConfigValue.js';
/** Get all allowed base directories for persona prompt files */ /** Get all allowed base directories for persona prompt files */
function getAllowedPromptBases(cwd: string): string[] { function getAllowedPromptBases(cwd: string): string[] {
const lang = loadConfig(cwd).language; const lang = resolveConfigValue(cwd, 'language');
return [ return [
getGlobalPersonasDir(), getGlobalPersonasDir(),
getGlobalPiecesDir(), getGlobalPiecesDir(),

View File

@ -13,7 +13,7 @@ import { z } from 'zod/v4';
import { getPieceCategoriesPath } from '../global/pieceCategories.js'; import { getPieceCategoriesPath } from '../global/pieceCategories.js';
import { getLanguageResourcesDir } from '../../resources/index.js'; import { getLanguageResourcesDir } from '../../resources/index.js';
import { listBuiltinPieceNames } from './pieceResolver.js'; import { listBuiltinPieceNames } from './pieceResolver.js';
import { loadConfig } from '../loadConfig.js'; import { resolveConfigValues } from '../resolveConfigValue.js';
import type { PieceWithSource } from './pieceResolver.js'; import type { PieceWithSource } from './pieceResolver.js';
const CategoryConfigSchema = z.object({ const CategoryConfigSchema = z.object({
@ -233,7 +233,7 @@ function resolveOthersCategoryName(defaultConfig: ParsedCategoryConfig, userConf
* Returns null if file doesn't exist or has no piece_categories. * Returns null if file doesn't exist or has no piece_categories.
*/ */
export function loadDefaultCategories(cwd: string): CategoryConfig | null { export function loadDefaultCategories(cwd: string): CategoryConfig | null {
const lang = loadConfig(cwd).language; const { language: lang } = resolveConfigValues(cwd, ['language']);
const filePath = join(getLanguageResourcesDir(lang), 'piece-categories.yaml'); const filePath = join(getLanguageResourcesDir(lang), 'piece-categories.yaml');
const parsed = loadCategoryConfigFromPath(filePath, filePath); const parsed = loadCategoryConfigFromPath(filePath, filePath);
@ -256,7 +256,7 @@ export function loadDefaultCategories(cwd: string): CategoryConfig | null {
/** Get the path to the builtin default categories file. */ /** Get the path to the builtin default categories file. */
export function getDefaultCategoriesPath(cwd: string): string { export function getDefaultCategoriesPath(cwd: string): string {
const lang = loadConfig(cwd).language; const { language: lang } = resolveConfigValues(cwd, ['language']);
return join(getLanguageResourcesDir(lang), 'piece-categories.yaml'); return join(getLanguageResourcesDir(lang), 'piece-categories.yaml');
} }
@ -378,7 +378,7 @@ export function buildCategorizedPieces(
config: CategoryConfig, config: CategoryConfig,
cwd: string, cwd: string,
): CategorizedPieces { ): CategorizedPieces {
const globalConfig = loadConfig(cwd); const globalConfig = resolveConfigValues(cwd, ['enableBuiltinPieces', 'disabledBuiltins']);
const ignoreMissing = new Set<string>(); const ignoreMissing = new Set<string>();
if (globalConfig.enableBuiltinPieces === false) { if (globalConfig.enableBuiltinPieces === false) {
for (const name of listBuiltinPieceNames(cwd, { includeDisabled: true })) { for (const name of listBuiltinPieceNames(cwd, { includeDisabled: true })) {

View File

@ -11,7 +11,7 @@ import { parse as parseYaml } from 'yaml';
import type { z } from 'zod'; import type { z } from 'zod';
import { PieceConfigRawSchema, PieceMovementRawSchema } from '../../../core/models/index.js'; import { PieceConfigRawSchema, PieceMovementRawSchema } from '../../../core/models/index.js';
import type { PieceConfig, PieceMovement, PieceRule, OutputContractEntry, OutputContractItem, LoopMonitorConfig, LoopMonitorJudge, ArpeggioMovementConfig, ArpeggioMergeMovementConfig, TeamLeaderConfig } from '../../../core/models/index.js'; import type { PieceConfig, PieceMovement, PieceRule, OutputContractEntry, OutputContractItem, LoopMonitorConfig, LoopMonitorJudge, ArpeggioMovementConfig, ArpeggioMergeMovementConfig, TeamLeaderConfig } from '../../../core/models/index.js';
import { loadConfig } from '../loadConfig.js'; import { resolveConfigValue } from '../resolveConfigValue.js';
import { import {
type PieceSections, type PieceSections,
type FacetResolutionContext, type FacetResolutionContext,
@ -439,7 +439,7 @@ export function loadPieceFromFile(filePath: string, projectDir: string): PieceCo
const pieceDir = dirname(filePath); const pieceDir = dirname(filePath);
const context: FacetResolutionContext = { const context: FacetResolutionContext = {
lang: loadConfig(projectDir).language, lang: resolveConfigValue(projectDir, 'language'),
projectDir, projectDir,
}; };

View File

@ -10,7 +10,7 @@ import { join, resolve, isAbsolute } from 'node:path';
import { homedir } from 'node:os'; import { homedir } from 'node:os';
import type { PieceConfig, PieceMovement, InteractiveMode } from '../../../core/models/index.js'; import type { PieceConfig, PieceMovement, InteractiveMode } from '../../../core/models/index.js';
import { getGlobalPiecesDir, getBuiltinPiecesDir, getProjectConfigDir } from '../paths.js'; import { getGlobalPiecesDir, getBuiltinPiecesDir, getProjectConfigDir } from '../paths.js';
import { loadConfig } from '../loadConfig.js'; import { resolveConfigValues } from '../resolveConfigValue.js';
import { createLogger, getErrorMessage } from '../../../shared/utils/index.js'; import { createLogger, getErrorMessage } from '../../../shared/utils/index.js';
import { loadPieceFromFile } from './pieceParser.js'; import { loadPieceFromFile } from './pieceParser.js';
@ -24,7 +24,7 @@ export interface PieceWithSource {
} }
export function listBuiltinPieceNames(cwd: string, options?: { includeDisabled?: boolean }): string[] { export function listBuiltinPieceNames(cwd: string, options?: { includeDisabled?: boolean }): string[] {
const config = loadConfig(cwd); const config = resolveConfigValues(cwd, ['language', 'disabledBuiltins']);
const lang = config.language; const lang = config.language;
const dir = getBuiltinPiecesDir(lang); const dir = getBuiltinPiecesDir(lang);
const disabled = options?.includeDisabled ? undefined : (config.disabledBuiltins ?? []); const disabled = options?.includeDisabled ? undefined : (config.disabledBuiltins ?? []);
@ -37,7 +37,7 @@ export function listBuiltinPieceNames(cwd: string, options?: { includeDisabled?:
/** Get builtin piece by name */ /** Get builtin piece by name */
export function getBuiltinPiece(name: string, projectCwd: string): PieceConfig | null { export function getBuiltinPiece(name: string, projectCwd: string): PieceConfig | null {
const config = loadConfig(projectCwd); const config = resolveConfigValues(projectCwd, ['enableBuiltinPieces', 'language', 'disabledBuiltins']);
if (config.enableBuiltinPieces === false) return null; if (config.enableBuiltinPieces === false) return null;
const lang = config.language; const lang = config.language;
const disabled = config.disabledBuiltins ?? []; const disabled = config.disabledBuiltins ?? [];
@ -373,7 +373,7 @@ function* iteratePieceDir(
/** Get the 3-layer directory list (builtin → user → project-local) */ /** Get the 3-layer directory list (builtin → user → project-local) */
function getPieceDirs(cwd: string): { dir: string; source: PieceSource; disabled?: string[] }[] { function getPieceDirs(cwd: string): { dir: string; source: PieceSource; disabled?: string[] }[] {
const config = loadConfig(cwd); const config = resolveConfigValues(cwd, ['enableBuiltinPieces', 'language', 'disabledBuiltins']);
const disabled = config.disabledBuiltins ?? []; const disabled = config.disabledBuiltins ?? [];
const lang = config.language; const lang = config.language;
const dirs: { dir: string; source: PieceSource; disabled?: string[] }[] = []; const dirs: { dir: string; source: PieceSource; disabled?: string[] }[] = [];