( pluginRoot: string, raw: unknown, diagnostics: PluginDiagnostic[], )
| 315 | } |
| 316 | |
| 317 | async function readCommands( |
| 318 | pluginRoot: string, |
| 319 | raw: unknown, |
| 320 | diagnostics: PluginDiagnostic[], |
| 321 | ): Promise<readonly PluginCommandEntry[] | undefined> { |
| 322 | if (raw === undefined) return undefined; |
| 323 | const entries: string[] = []; |
| 324 | if (typeof raw === 'string') { |
| 325 | entries.push(raw); |
| 326 | } else if (Array.isArray(raw) && raw.every((entry) => typeof entry === 'string')) { |
| 327 | entries.push(...raw); |
| 328 | } else { |
| 329 | diagnostics.push({ severity: 'warn', message: '"commands" must be a string or string[]' }); |
| 330 | return undefined; |
| 331 | } |
| 332 | |
| 333 | const files: PluginCommandEntry[] = []; |
| 334 | for (const entry of entries) { |
| 335 | const resolved = await resolvePluginPathField({ |
| 336 | pluginRoot, |
| 337 | field: 'commands', |
| 338 | value: entry, |
| 339 | diagnostics, |
| 340 | }); |
| 341 | if (resolved === undefined) continue; |
| 342 | if (await isDir(resolved)) { |
| 343 | files.push(...(await listMarkdownFilesRecursive(resolved))); |
| 344 | } else if ((await isFile(resolved)) && resolved.endsWith('.md')) { |
| 345 | files.push({ path: resolved, name: commandNameFromFile(resolved, path.dirname(resolved)) }); |
| 346 | } else { |
| 347 | diagnostics.push({ |
| 348 | severity: 'warn', |
| 349 | message: `"commands" entry must be a directory or .md file (${entry})`, |
| 350 | }); |
| 351 | } |
| 352 | } |
| 353 | return files.length === 0 ? undefined : files.toSorted((a, b) => a.name.localeCompare(b.name)); |
| 354 | } |
| 355 | |
| 356 | async function listMarkdownFilesRecursive(root: string): Promise<readonly PluginCommandEntry[]> { |
| 357 | const out: PluginCommandEntry[] = []; |
no test coverage detected