|
1 | | -/* oxlint-disable socket/sort-source-methods -- CLI handler with helper functions interleaved with module-level config constants; reordering would split state from its consumers. */ |
2 | 1 | /** |
3 | 2 | * @file `socket-lib check primordials` handler. Loads a JSON config from disk |
4 | 3 | * (default `primordials-coverage.config.json` at the repo root, override with |
@@ -63,92 +62,20 @@ interface ParsedArgs { |
63 | 62 | readonly help: boolean |
64 | 63 | } |
65 | 64 |
|
66 | | -export function parseArgs(argv: readonly string[]): ParsedArgs { |
67 | | - const { values } = parseLibArgs({ |
68 | | - args: argv, |
69 | | - strict: false, |
70 | | - options: { |
71 | | - config: { type: 'string', short: 'c' }, |
72 | | - explain: { type: 'boolean' }, |
73 | | - help: { type: 'boolean', short: 'h' }, |
74 | | - json: { type: 'boolean' }, |
75 | | - silent: { type: 'boolean' }, |
76 | | - }, |
77 | | - }) |
78 | | - // `config` is left undefined when neither `--config` nor `-c` was |
79 | | - // passed, so the resolver below can fall back to the search list. |
80 | | - // An explicit value short-circuits the search. |
81 | | - const explicitConfig = values['config'] |
82 | | - return { |
83 | | - config: typeof explicitConfig === 'string' ? explicitConfig : undefined, |
84 | | - json: Boolean(values['json']), |
85 | | - explain: Boolean(values['explain']), |
86 | | - silent: Boolean(values['silent']), |
87 | | - help: Boolean(values['help']), |
88 | | - } |
89 | | -} |
90 | | - |
91 | | -/** |
92 | | - * Pick the config file. Returns the explicit `--config` argument when given |
93 | | - * (even if it doesn't exist — the caller will surface the error with the path |
94 | | - * they typed). Otherwise probes the fallback list in order and returns the |
95 | | - * first hit. Returns the head of the list when none exist, so the caller's |
96 | | - * "config file not found" error message names the canonical default. |
97 | | - */ |
98 | | -export function resolveConfigPath(explicit: string | undefined): string { |
99 | | - if (explicit !== undefined) { |
100 | | - return explicit |
101 | | - } |
102 | | - for (let i = 0, { length } = FALLBACK_CONFIG_PATHS; i < length; i += 1) { |
103 | | - const candidate = FALLBACK_CONFIG_PATHS[i]! |
104 | | - if (existsSync(path.resolve(candidate))) { |
105 | | - return candidate |
106 | | - } |
107 | | - } |
108 | | - return FALLBACK_CONFIG_PATHS[0]! |
109 | | -} |
110 | | - |
111 | | -export function printHelp(): void { |
112 | | - logger.log('socket-lib check primordials — primordials drift check') |
113 | | - logger.log('') |
114 | | - logger.log('Usage:') |
115 | | - logger.log(' socket-lib check primordials [opts]') |
116 | | - logger.log(' socket-lib check prim [opts] # short alias') |
117 | | - logger.log('') |
118 | | - logger.log('Options:') |
119 | | - logger.log( |
120 | | - ` --config, -c <path> Config file. Default: ${DEFAULT_CONFIG_PATH}`, |
121 | | - ) |
122 | | - logger.log(` (falls back to .config/socket-lib.json)`) |
123 | | - logger.log(' --explain Print one detailed line per finding.') |
124 | | - logger.log(' --json Machine-readable JSON output.') |
125 | | - logger.log(' --silent Silent on success.') |
126 | | - logger.log(' --help, -h Print this help.') |
127 | | - logger.log('') |
128 | | - logger.log('Config (.socket-lib.json — primordials section):') |
129 | | - logger.log(' {') |
130 | | - logger.log(' "primordials": {') |
131 | | - logger.log( |
132 | | - ' "scanDirs": ["src", "additions/source-patched/lib"]', |
133 | | - ) |
134 | | - logger.log(' }') |
135 | | - logger.log(' }') |
136 | | - logger.log('') |
137 | | - logger.log('Only `scanDirs` is required. `aliasMap` and `nodeInternalOnly`') |
138 | | - logger.log('default to the fleet-canonical sets and only need entries when') |
139 | | - logger.log('your repo extends or overrides them.') |
140 | | - logger.log('') |
141 | | - logger.log('A bare object (no `primordials` section) is also accepted for') |
142 | | - logger.log('repos that only run this one check.') |
143 | | -} |
144 | | - |
145 | 65 | interface RawConfig { |
146 | 66 | scanDirs?: unknown | undefined |
147 | 67 | aliasMap?: unknown | undefined |
148 | 68 | nodeInternalOnly?: unknown | undefined |
149 | 69 | socketLibPrimordialsPath?: unknown | undefined |
150 | 70 | } |
151 | 71 |
|
| 72 | +interface SerializedFinding { |
| 73 | + kind: PrimordialsFinding['kind'] |
| 74 | + name: string |
| 75 | + files: readonly string[] |
| 76 | + hint: string |
| 77 | +} |
| 78 | + |
152 | 79 | export function loadConfig(configPath: string): PrimordialsCheckConfig { |
153 | 80 | if (!existsSync(configPath)) { |
154 | 81 | throw new ErrorCtor(`config file not found: ${configPath}`) |
@@ -229,30 +156,65 @@ export function loadConfig(configPath: string): PrimordialsCheckConfig { |
229 | 156 | } |
230 | 157 | } |
231 | 158 |
|
232 | | -interface SerializedFinding { |
233 | | - kind: PrimordialsFinding['kind'] |
234 | | - name: string |
235 | | - files: readonly string[] |
236 | | - hint: string |
237 | | -} |
238 | | - |
239 | | -export function serialize(result: PrimordialsCheckResult): { |
240 | | - ok: boolean |
241 | | - used: number |
242 | | - findings: SerializedFinding[] |
243 | | -} { |
| 159 | +export function parseArgs(argv: readonly string[]): ParsedArgs { |
| 160 | + const { values } = parseLibArgs({ |
| 161 | + args: argv, |
| 162 | + strict: false, |
| 163 | + options: { |
| 164 | + config: { type: 'string', short: 'c' }, |
| 165 | + explain: { type: 'boolean' }, |
| 166 | + help: { type: 'boolean', short: 'h' }, |
| 167 | + json: { type: 'boolean' }, |
| 168 | + silent: { type: 'boolean' }, |
| 169 | + }, |
| 170 | + }) |
| 171 | + // `config` is left undefined when neither `--config` nor `-c` was |
| 172 | + // passed, so the resolver below can fall back to the search list. |
| 173 | + // An explicit value short-circuits the search. |
| 174 | + const explicitConfig = values['config'] |
244 | 175 | return { |
245 | | - ok: result.findings.length === 0, |
246 | | - used: result.used.size, |
247 | | - findings: result.findings.map(f => ({ |
248 | | - kind: f.kind, |
249 | | - name: f.name, |
250 | | - files: f.files, |
251 | | - hint: f.hint, |
252 | | - })), |
| 176 | + config: typeof explicitConfig === 'string' ? explicitConfig : undefined, |
| 177 | + json: Boolean(values['json']), |
| 178 | + explain: Boolean(values['explain']), |
| 179 | + silent: Boolean(values['silent']), |
| 180 | + help: Boolean(values['help']), |
253 | 181 | } |
254 | 182 | } |
255 | 183 |
|
| 184 | +export function printHelp(): void { |
| 185 | + logger.log('socket-lib check primordials — primordials drift check') |
| 186 | + logger.log('') |
| 187 | + logger.log('Usage:') |
| 188 | + logger.log(' socket-lib check primordials [opts]') |
| 189 | + logger.log(' socket-lib check prim [opts] # short alias') |
| 190 | + logger.log('') |
| 191 | + logger.log('Options:') |
| 192 | + logger.log( |
| 193 | + ` --config, -c <path> Config file. Default: ${DEFAULT_CONFIG_PATH}`, |
| 194 | + ) |
| 195 | + logger.log(` (falls back to .config/socket-lib.json)`) |
| 196 | + logger.log(' --explain Print one detailed line per finding.') |
| 197 | + logger.log(' --json Machine-readable JSON output.') |
| 198 | + logger.log(' --silent Silent on success.') |
| 199 | + logger.log(' --help, -h Print this help.') |
| 200 | + logger.log('') |
| 201 | + logger.log('Config (.socket-lib.json — primordials section):') |
| 202 | + logger.log(' {') |
| 203 | + logger.log(' "primordials": {') |
| 204 | + logger.log( |
| 205 | + ' "scanDirs": ["src", "additions/source-patched/lib"]', |
| 206 | + ) |
| 207 | + logger.log(' }') |
| 208 | + logger.log(' }') |
| 209 | + logger.log('') |
| 210 | + logger.log('Only `scanDirs` is required. `aliasMap` and `nodeInternalOnly`') |
| 211 | + logger.log('default to the fleet-canonical sets and only need entries when') |
| 212 | + logger.log('your repo extends or overrides them.') |
| 213 | + logger.log('') |
| 214 | + logger.log('A bare object (no `primordials` section) is also accepted for') |
| 215 | + logger.log('repos that only run this one check.') |
| 216 | +} |
| 217 | + |
256 | 218 | export function renderHuman( |
257 | 219 | result: PrimordialsCheckResult, |
258 | 220 | args: ParsedArgs, |
@@ -283,6 +245,26 @@ export function renderHuman( |
283 | 245 | } |
284 | 246 | } |
285 | 247 |
|
| 248 | +/** |
| 249 | + * Pick the config file. Returns the explicit `--config` argument when given |
| 250 | + * (even if it doesn't exist — the caller will surface the error with the path |
| 251 | + * they typed). Otherwise probes the fallback list in order and returns the |
| 252 | + * first hit. Returns the head of the list when none exist, so the caller's |
| 253 | + * "config file not found" error message names the canonical default. |
| 254 | + */ |
| 255 | +export function resolveConfigPath(explicit: string | undefined): string { |
| 256 | + if (explicit !== undefined) { |
| 257 | + return explicit |
| 258 | + } |
| 259 | + for (let i = 0, { length } = FALLBACK_CONFIG_PATHS; i < length; i += 1) { |
| 260 | + const candidate = FALLBACK_CONFIG_PATHS[i]! |
| 261 | + if (existsSync(path.resolve(candidate))) { |
| 262 | + return candidate |
| 263 | + } |
| 264 | + } |
| 265 | + return FALLBACK_CONFIG_PATHS[0]! |
| 266 | +} |
| 267 | + |
286 | 268 | export async function runCheckPrimordials( |
287 | 269 | argv: readonly string[], |
288 | 270 | ): Promise<number> { |
@@ -312,3 +294,20 @@ export async function runCheckPrimordials( |
312 | 294 | } |
313 | 295 | return result.findings.length === 0 ? 0 : 1 |
314 | 296 | } |
| 297 | + |
| 298 | +export function serialize(result: PrimordialsCheckResult): { |
| 299 | + ok: boolean |
| 300 | + used: number |
| 301 | + findings: SerializedFinding[] |
| 302 | +} { |
| 303 | + return { |
| 304 | + ok: result.findings.length === 0, |
| 305 | + used: result.used.size, |
| 306 | + findings: result.findings.map(f => ({ |
| 307 | + kind: f.kind, |
| 308 | + name: f.name, |
| 309 | + files: f.files, |
| 310 | + hint: f.hint, |
| 311 | + })), |
| 312 | + } |
| 313 | +} |
0 commit comments