typescript-runtime-schemas
Version:
A TypeScript schema generation tool that extracts Zod schemas from TypeScript source files with runtime validation support. Generate validation schemas directly from your existing TypeScript types with support for computed types and constraint-based valid
178 lines • 6.53 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileDiscovery = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const fast_glob_1 = __importDefault(require("fast-glob"));
const utils_1 = require("./utils");
class FileDiscovery {
/**
* Discover files based on input and options
*/
static async discoverFiles(input, options = {}) {
const inputType = await this.detectInputType(input);
switch (inputType) {
case "file":
return this.discoverSingleFile(input);
case "directory":
return this.discoverFromDirectory(input, options);
default:
return []; // Not a file/directory input
}
}
/**
* Detect whether input is source code, file path, or directory path
*/
static async detectInputType(input) {
// If it looks like source code, treat it as such
if ((0, utils_1.isSourceCode)(input)) {
return "source";
}
try {
const stats = await fs.promises.stat(input);
if (stats.isFile()) {
return "file";
}
else if (stats.isDirectory()) {
return "directory";
}
}
catch (error) {
// File/directory doesn't exist, assume it's source code
return "source";
}
return "source";
}
/**
* Discover a single file
*/
static async discoverSingleFile(filePath) {
try {
const absolutePath = path.resolve(filePath);
const stats = await fs.promises.stat(absolutePath);
if (!stats.isFile()) {
throw new Error(`Path is not a file: ${filePath}`);
}
// Check if it's a TypeScript file
if (!this.isTypeScriptFile(absolutePath)) {
throw new Error(`File is not a TypeScript file: ${filePath}`);
}
return [
{
path: absolutePath,
relativePath: path.relative(process.cwd(), absolutePath),
},
];
}
catch (error) {
throw new Error(`Failed to discover file ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Discover files from a directory using glob patterns
*/
static async discoverFromDirectory(dirPath, options) {
try {
const absoluteDirPath = path.resolve(dirPath);
const stats = await fs.promises.stat(absoluteDirPath);
if (!stats.isDirectory()) {
throw new Error(`Path is not a directory: ${dirPath}`);
}
// Prepare glob patterns
const globPatterns = this.prepareGlobPatterns(options.glob);
const excludePatterns = this.prepareExcludePatterns(options.exclude);
// Configure fast-glob options
const globOptions = {
cwd: absoluteDirPath,
ignore: excludePatterns,
onlyFiles: true,
absolute: true,
followSymbolicLinks: options.followSymlinks ?? false,
caseSensitiveMatch: options.caseSensitive ?? true,
deep: options.recursive !== false ? Infinity : 1,
};
// Find matching files
const matchedFiles = await (0, fast_glob_1.default)(globPatterns, globOptions);
// Convert to DiscoveredFile objects
return matchedFiles.map((filePath) => ({
path: filePath,
relativePath: path.relative(process.cwd(), filePath),
}));
}
catch (error) {
throw new Error(`Failed to discover files in directory ${dirPath}: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Prepare glob patterns, using defaults if none provided
*/
static prepareGlobPatterns(glob) {
if (!glob) {
return this.DEFAULT_GLOB_PATTERNS;
}
return Array.isArray(glob) ? glob : [glob];
}
/**
* Prepare exclude patterns, merging with defaults
*/
static prepareExcludePatterns(exclude) {
const userExcludes = exclude
? Array.isArray(exclude)
? exclude
: [exclude]
: [];
return [...this.DEFAULT_EXCLUDE_PATTERNS, ...userExcludes];
}
/**
* Check if a file is a TypeScript file
*/
static isTypeScriptFile(filePath) {
const ext = path.extname(filePath).toLowerCase();
return ext === ".ts" || ext === ".tsx";
}
}
exports.FileDiscovery = FileDiscovery;
FileDiscovery.DEFAULT_GLOB_PATTERNS = ["**/*.ts", "**/*.tsx"];
FileDiscovery.DEFAULT_EXCLUDE_PATTERNS = [
"**/node_modules/**",
"**/dist/**",
"**/build/**",
"**/.git/**",
];
//# sourceMappingURL=file-discovery.js.map