Files
metabuilder/packages/package_validator/seed/scripts/structure_validator.lua
JohnDoe6345789 459182b655 feat: Add comprehensive validation for package structure, metadata, and components
- Implemented component schema validation in `component_schema.lua`.
- Created metadata schema validation in `metadata_schema.lua`.
- Developed structure validation logic in `structure_validator.lua`.
- Introduced Lua file validation functions in `lua_validator.lua`.
- Added integration tests for validation logic in `validate.test.lua`.
- Created unit tests for component, metadata, and structure validation.
- Added SVG icon for package representation.
- Established a main validation orchestrator in `validate.lua` to coordinate the validation process.
2025-12-30 02:19:28 +00:00

216 lines
6.1 KiB
Lua

-- Package folder structure validation
local M = {}
-- Expected package structure
M.REQUIRED_STRUCTURE = {
["seed/metadata.json"] = true,
["seed/components.json"] = true
}
M.OPTIONAL_STRUCTURE = {
["seed/scripts/"] = "directory",
["seed/scripts/init.lua"] = "file",
["seed/scripts/tests/"] = "directory",
["static_content/"] = "directory",
["static_content/icon.svg"] = "file",
["README.md"] = "file",
["examples/"] = "directory"
}
-- Validate basic folder structure
function M.validate_structure(package_path)
local errors = {}
local warnings = {}
-- Check required files
for path, _ in pairs(M.REQUIRED_STRUCTURE) do
local full_path = package_path .. "/" .. path
local file = io.open(full_path, "r")
if not file then
table.insert(errors, "Required file missing: " .. path)
else
file:close()
end
end
-- Check optional but recommended files
for path, type in pairs(M.OPTIONAL_STRUCTURE) do
local full_path = package_path .. "/" .. path
if type == "file" then
local file = io.open(full_path, "r")
if not file then
table.insert(warnings, "Recommended file missing: " .. path)
else
file:close()
end
elseif type == "directory" then
-- Note: Directory checking would be done with OS-specific commands
-- This is a placeholder for the pattern
end
end
return errors, warnings
end
-- Validate scripts directory structure
function M.validate_scripts_structure(package_path, metadata)
local errors = {}
local warnings = {}
local scripts_path = package_path .. "/scripts"
-- Check if scripts directory exists when exports.scripts is defined
if metadata.exports and metadata.exports.scripts and #metadata.exports.scripts > 0 then
local dir_exists = false
local test_file = io.open(scripts_path .. "/init.lua", "r")
if test_file then
test_file:close()
dir_exists = true
end
if not dir_exists then
table.insert(errors, "scripts/ directory required when exports.scripts is defined")
end
-- Check for init.lua
local init_file = io.open(scripts_path .. "/init.lua", "r")
if not init_file then
table.insert(warnings, "scripts/init.lua is recommended as entry point")
else
init_file:close()
end
-- Check for tests directory
local test_init = io.open(scripts_path .. "/tests/metadata.test.lua", "r")
if not test_init then
table.insert(warnings, "scripts/tests/ directory recommended for test files")
else
test_init:close()
end
end
return errors, warnings
end
-- Validate static content structure
function M.validate_static_content(package_path, metadata)
local errors = {}
local warnings = {}
if metadata.icon then
local icon_path = package_path .. "/" .. metadata.icon
local icon_file = io.open(icon_path, "r")
if not icon_file then
table.insert(errors, "Icon file not found: " .. metadata.icon)
else
icon_file:close()
end
else
table.insert(warnings, "No icon defined in metadata")
end
return errors, warnings
end
-- Check for orphaned files (files not referenced in metadata)
function M.check_orphaned_files(package_path, metadata)
local warnings = {}
-- This would scan the package directory and check if files are referenced
-- Placeholder for the pattern
return warnings
end
-- Validate naming conventions
function M.validate_naming_conventions(package_path, metadata)
local errors = {}
local warnings = {}
-- Package directory should match packageId
local dir_name = package_path:match("([^/]+)$")
if dir_name ~= metadata.packageId then
table.insert(errors, "Package directory name '" .. dir_name .. "' does not match packageId '" .. metadata.packageId .. "'")
end
-- Check script file naming
if metadata.exports and metadata.exports.scripts then
for _, script_name in ipairs(metadata.exports.scripts) do
-- Script names should be lowercase with underscores
if not string.match(script_name, "^[a-z_]+$") then
table.insert(warnings, "Script name '" .. script_name .. "' should use lowercase and underscores only")
end
end
end
-- Check component naming
if metadata.exports and metadata.exports.components then
for _, component_name in ipairs(metadata.exports.components) do
-- Component names can be PascalCase or snake_case
local is_valid = string.match(component_name, "^[A-Z][a-zA-Z]+$") or
string.match(component_name, "^[a-z_]+$")
if not is_valid then
table.insert(warnings, "Component name '" .. component_name .. "' should use PascalCase or snake_case")
end
end
end
return errors, warnings
end
-- Validate complete package structure
function M.validate_package_structure(package_path, metadata)
local results = {
valid = true,
errors = {},
warnings = {}
}
-- Basic structure
local struct_errors, struct_warnings = M.validate_structure(package_path)
for _, err in ipairs(struct_errors) do
table.insert(results.errors, err)
results.valid = false
end
for _, warn in ipairs(struct_warnings) do
table.insert(results.warnings, warn)
end
-- Scripts structure
local script_errors, script_warnings = M.validate_scripts_structure(package_path, metadata)
for _, err in ipairs(script_errors) do
table.insert(results.errors, err)
results.valid = false
end
for _, warn in ipairs(script_warnings) do
table.insert(results.warnings, warn)
end
-- Static content
local static_errors, static_warnings = M.validate_static_content(package_path, metadata)
for _, err in ipairs(static_errors) do
table.insert(results.errors, err)
results.valid = false
end
for _, warn in ipairs(static_warnings) do
table.insert(results.warnings, warn)
end
-- Naming conventions
local naming_errors, naming_warnings = M.validate_naming_conventions(package_path, metadata)
for _, err in ipairs(naming_errors) do
table.insert(results.errors, err)
results.valid = false
end
for _, warn in ipairs(naming_warnings) do
table.insert(results.warnings, warn)
end
return results
end
return M