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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | 5x 5x 7x 7x 1x 6x 6x 6x 6x 6x 4x 12x 12x 12x 12x 19x 19x 6x 6x 5x 1x 1x 13x 13x 13x 11x 1x 11x 17x 17x 17x 17x 6x 11x 11x 3x | import { resolve, extname, basename } from "node:path";
import { existsSync, statSync, readdirSync } from "node:fs";
/**
* Input expansion for C-Next CLI
*
* Expands file paths and directories into a list of .cnx files to compile.
* Handles recursive directory scanning and file validation.
*/
class InputExpansion {
/**
* Expand inputs (files or directories) to list of .cnx files
*
* @param inputs - Array of file paths or directories
* @returns Array of .cnx file paths
*/
static expandInputs(inputs: string[]): string[] {
const files: string[] = [];
for (const input of inputs) {
const resolvedPath = resolve(input);
if (!existsSync(resolvedPath)) {
throw new Error(`Input not found: ${input}`);
}
const stats = statSync(resolvedPath);
Iif (stats.isDirectory()) {
// Recursively find .cnx files
const cnextFiles = this.findCNextFiles(resolvedPath);
files.push(...cnextFiles);
E} else if (stats.isFile()) {
// Validate and add file
this.validateFileExtension(resolvedPath);
files.push(resolvedPath);
}
}
// Remove duplicates
return Array.from(new Set(files));
}
/**
* Recursively find .cnx files in directory
*
* @param dir - Directory to scan
* @returns Array of .cnx file paths
*/
static findCNextFiles(dir: string): string[] {
const files: string[] = [];
try {
const entries = readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = resolve(dir, entry.name);
// Skip hidden directories and common build/dependency directories
if (entry.isDirectory()) {
const dirName = entry.name;
if (
dirName.startsWith(".") ||
dirName === "node_modules" ||
dirName === "build" ||
dirName === ".pio" ||
dirName === "dist"
) {
continue;
}
// Recursively scan subdirectory
const subFiles = this.findCNextFiles(fullPath);
files.push(...subFiles);
E} else if (entry.isFile()) {
const ext = extname(entry.name);
if (ext === ".cnx" || ext === ".cnext") {
files.push(fullPath);
}
}
}
} catch (error) {
throw new Error(`Failed to scan directory ${dir}: ${error}`, {
cause: error,
});
}
return files;
}
/**
* Validate file extension
*
* Accepts: .cnx, .cnext
* Rejects: .c, .cpp, .cc, .cxx, .c++ (implementation files)
*
* @param path - File path to validate
* @throws Error if extension is invalid
*/
static validateFileExtension(path: string): void {
const ext = extname(path);
const fileName = basename(path);
// Reject implementation files
const rejectedExtensions = [".c", ".cpp", ".cc", ".cxx", ".c++"];
if (rejectedExtensions.includes(ext)) {
throw new Error(
`Cannot process implementation file '${fileName}'. ` +
`C-Next only compiles .cnx files. ` +
`If you need to include this file, create a header (.h) instead.`,
);
}
// Accept C-Next source files
const acceptedExtensions = [".cnx", ".cnext"];
if (!acceptedExtensions.includes(ext)) {
throw new Error(
`Invalid file extension '${ext}' for file '${fileName}'. ` +
`C-Next only accepts .cnx or .cnext files.`,
);
}
}
}
export default InputExpansion;
|