Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | 1x 13x 1x 13x 13x 13x 13x | import { readFileSync } from 'node:fs';
import { resolve, dirname, join } from 'node:path';
import { DEFAULT_CACHE_FILENAME } from './cache.js';
import { homedir } from 'node:os';
export interface PluginEntry {
/** npm package name or local path relative to contractkit.config.json */
plugin: string;
/**
* Plugin-specific options passed as ctx.options.
*
* One reserved key: `keys?: Record<string, string>`. Entries are merged across all plugin
* entries into a workspace-wide fallback map for `{{var}}` substitution in `.ck` files.
* A file's `options { keys }` block still wins over this fallback when both define a name.
*/
options?: Record<string, unknown>;
}
/** Record-keyed plugin config: each key is the plugin package name, value is options. */
export type PluginsConfig = Record<string, Record<string, unknown>>;
export interface DslConfig {
rootDir?: string;
cache?: boolean | string;
/** Glob patterns for .ck files to compile, relative to rootDir. */
patterns?: string[];
/** Run prettier on generated TypeScript files after compilation. Default: false. */
prettier?: boolean;
/** Plugins to load: each key is the plugin package name, value is its options. */
plugins?: PluginsConfig;
}
export interface ResolvedCacheConfig {
enabled: boolean;
filename: string;
}
const CONFIG_FILENAME = 'contractkit.config.json';
/**
* Load config from an explicit path, or search upward from `startDir`
* for contractkit.config.json.
*/
export function loadConfig(configPath?: string, startDir: string = process.cwd()): { config: DslConfig; configDir: string } {
if (configPath) {
const resolved = resolve(configPath);
try {
const text = readFileSync(resolved, 'utf-8');
return { config: JSON.parse(text) as DslConfig, configDir: dirname(resolved) };
} catch (err) {
throw new Error(`Failed to load config from ${resolved}: ${(err as Error).message}`, { cause: err });
}
}
let dir = resolve(startDir);
while (true) {
const candidate = join(dir, CONFIG_FILENAME);
try {
const text = readFileSync(candidate, 'utf-8');
return { config: JSON.parse(text) as DslConfig, configDir: dir };
} catch {
// File not found or invalid -- walk up
}
const parent = dirname(dir);
if (parent === dir) break;
dir = parent;
}
return { config: {}, configDir: resolve(startDir) };
}
export interface ResolvedConfig {
patterns: string[];
rootDir: string;
cache: ResolvedCacheConfig;
watch: boolean;
force: boolean;
prettier: boolean;
plugins: PluginEntry[];
configDir: string;
}
function normalizePlugins(plugins: PluginsConfig | undefined): PluginEntry[] {
if (!plugins) return [];
return Object.entries(plugins).map(([name, options]) => ({ plugin: name, options }));
}
/** Merge config file values with CLI flags. */
export function mergeConfig(config: DslConfig, cliArgs: { watch: boolean; force: boolean }, configDir: string = process.cwd()): ResolvedConfig {
const cache: ResolvedCacheConfig =
typeof config.cache === 'string'
? { enabled: true, filename: config.cache }
: { enabled: config.cache === true, filename: DEFAULT_CACHE_FILENAME };
let rootDir = config.rootDir ?? '.';
Iif (rootDir.startsWith('~')) {
rootDir = homedir() + rootDir.slice(1);
}
return {
patterns: config.patterns ?? [],
rootDir: resolve(rootDir),
cache,
watch: cliArgs.watch,
force: cliArgs.force,
prettier: config.prettier ?? false,
plugins: normalizePlugins(config.plugins),
configDir,
};
}
|