diff --git a/package.json b/package.json index 125acfb..df2a4ac 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "suggest:format": "echo \"\nTo resolve this, run: $(tput bold)npm run format$(tput sgr0)\" && exit 1", "test:format": "prettier --check . || npm run suggest:format", "test:spelling": "cspell \"spec/**/*.md\" README.md LICENSE.md", - "test:structure": "find . -maxdepth 1 -type d -name 'GAP-*' -exec ./scripts/validate-structure.js {} \\;" + "test:structure": "./scripts/validate-structure.js ." }, "devDependencies": { "ajv": "^8.17.1", diff --git a/scripts/validate-structure.js b/scripts/validate-structure.js index e1a88b6..69694ba 100755 --- a/scripts/validate-structure.js +++ b/scripts/validate-structure.js @@ -1,15 +1,14 @@ #!/usr/bin/env node /** - * Validates the structure of a GAP directory. + * Validates the structure of GAP directories. * - * Usage: ./scripts/validate-structure.js + * Usage: ./scripts/validate-structure.js * - * Can be xarg'd over all GAP directories: - * find . -maxdepth 1 -type d -name 'GAP-*' | xargs -I{} node scripts/validate-structure.js {} + * Discovers and validates all GAP-* directories within the specified directory. */ -import { existsSync, readFileSync, statSync } from "node:fs"; +import { existsSync, readFileSync, statSync, globSync } from "node:fs"; import { basename, join, dirname } from "node:path"; import { fileURLToPath } from "node:url"; import { parseArgs } from "node:util"; @@ -27,7 +26,10 @@ const metadataSchema = JSON.parse(readFileSync(schemaPath, "utf8")); const ajv = new Ajv({ allErrors: true }); const validateMetadataSchema = ajv.compile(metadataSchema); +let errorSeen = 0; + function error(gapName, message) { + errorSeen += 1; console.error(`${gapName}: ${message}`); process.exit(1); } @@ -122,34 +124,45 @@ function validateMetadata(dirPath, gapName) { } } +function validateGapDirectory(dirPath) { + if (!existsSync(dirPath) || !statSync(dirPath).isDirectory()) { + throw new Error(`Not a directory: ${dirPath}`); + } + + // Validate directory naming + const gapName = validateDirectoryNaming(dirPath); + + // Validate README.md exists + validateReadmeExists(dirPath, gapName); + + // Validate metadata.yml + validateMetadata(dirPath, gapName); + + console.log(`✓ ${gapName} validated successfully`); +} + function main() { const { positionals } = parseArgs({ allowPositionals: true, strict: true }); if (positionals.length !== 1) { - console.error("Usage: ./scripts/validate-structure.js "); - process.exit(1); + throw new Error("Usage: ./scripts/validate-structure.js "); } - const dirPath = positionals[0]; - - if (!existsSync(dirPath)) { - console.error(`Directory does not exist: ${dirPath}`); - process.exit(1); - } + const searchDir = positionals[0]; - if (!statSync(dirPath).isDirectory()) { - console.error(`Not a directory: ${dirPath}`); - process.exit(1); + if (!existsSync(searchDir) || !statSync(searchDir).isDirectory()) { + throw new Error(`Not a directory: ${searchDir}`); } - // Validate directory naming - const gapName = validateDirectoryNaming(dirPath); + const gapDirs = globSync("GAP-*", { cwd: searchDir }); + console.log(`Found ${gapDirs.length} GAP directories`); - // Validate README.md exists - validateReadmeExists(dirPath, gapName); + for (const dir of gapDirs) { + validateGapDirectory(dir); + } - // Validate metadata.yml - validateMetadata(dirPath, gapName); + // return an exit code + return errorSeen > 0 ? 1 : 0; } -main(); +process.exit(main())