From 3d5499c225c64af564bb95b7f0584493f25d0c64 Mon Sep 17 00:00:00 2001 From: Mark Larah Date: Mon, 16 Feb 2026 09:51:51 -0600 Subject: [PATCH 1/2] Add -maxdepth 1 guard to prevent searching nested directories The find command now uses -maxdepth 1 to restrict the search to the top-level directory only, preventing unintended matches in subdirectories like node_modules. Co-Authored-By: Claude Sonnet 4.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 894711f..125acfb 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 . -type d -name 'GAP-*' -exec ./scripts/validate-structure.js {} \\;" + "test:structure": "find . -maxdepth 1 -type d -name 'GAP-*' -exec ./scripts/validate-structure.js {} \\;" }, "devDependencies": { "ajv": "^8.17.1", From 3513f3f143144b574bf95da46a667d59f6db26c8 Mon Sep 17 00:00:00 2001 From: Mark Larah Date: Mon, 16 Feb 2026 09:52:50 -0600 Subject: [PATCH 2/2] Make validation script self-contained with GAP directory discovery The script now handles directory discovery internally using Node.js's built-in readdirSync, eliminating the need for find in the npm script. When invoked without arguments, it automatically discovers and validates all GAP-* directories in the repository root. A single directory can still be passed for targeted validation. This keeps all logic self-contained in the script and simplifies the npm task. Co-Authored-By: Claude Sonnet 4.5 --- package.json | 2 +- scripts/validate-structure.js | 55 ++++++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 125acfb..87056b9 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..ee2ecd3 100755 --- a/scripts/validate-structure.js +++ b/scripts/validate-structure.js @@ -1,15 +1,15 @@ #!/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 [gap-directory] * - * Can be xarg'd over all GAP directories: - * find . -maxdepth 1 -type d -name 'GAP-*' | xargs -I{} node scripts/validate-structure.js {} + * If no directory is provided, automatically discovers and validates all GAP-* directories + * in the repository root. */ -import { existsSync, readFileSync, statSync } from "node:fs"; +import { existsSync, readFileSync, statSync, readdirSync } from "node:fs"; import { basename, join, dirname } from "node:path"; import { fileURLToPath } from "node:url"; import { parseArgs } from "node:util"; @@ -122,16 +122,16 @@ function validateMetadata(dirPath, gapName) { } } -function main() { - const { positionals } = parseArgs({ allowPositionals: true, strict: true }); - - if (positionals.length !== 1) { - console.error("Usage: ./scripts/validate-structure.js "); - process.exit(1); - } +function discoverGapDirectories() { + const rootDir = join(__dirname, ".."); + const entries = readdirSync(rootDir, { withFileTypes: true }); - const dirPath = positionals[0]; + return entries + .filter((entry) => entry.isDirectory() && /^GAP-/.test(entry.name)) + .map((entry) => join(rootDir, entry.name)); +} +function validateGapDirectory(dirPath) { if (!existsSync(dirPath)) { console.error(`Directory does not exist: ${dirPath}`); process.exit(1); @@ -150,6 +150,35 @@ function main() { // Validate metadata.yml validateMetadata(dirPath, gapName); + + console.log(`✓ ${gapName} validated successfully`); +} + +function main() { + const { positionals } = parseArgs({ allowPositionals: true, strict: true }); + + if (positionals.length === 0) { + // No arguments provided - discover and validate all GAP directories + const gapDirs = discoverGapDirectories(); + + if (gapDirs.length === 0) { + console.error("No GAP directories found"); + process.exit(1); + } + + console.log(`Found ${gapDirs.length} GAP director${gapDirs.length === 1 ? "y" : "ies"}`); + + for (const dir of gapDirs) { + validateGapDirectory(dir); + } + } else if (positionals.length === 1) { + // Single directory provided - validate it + const dirPath = positionals[0]; + validateGapDirectory(dirPath); + } else { + console.error("Usage: ./scripts/validate-structure.js [gap-directory]"); + process.exit(1); + } } main();