summaryrefslogtreecommitdiff
path: root/src/luarocks/type
diff options
context:
space:
mode:
authorMike Vink <mike@pionative.com>2025-02-03 21:29:42 +0100
committerMike Vink <mike@pionative.com>2025-02-03 21:29:42 +0100
commit5155816b7b925dec5d5feb1568b1d7ceb00938b9 (patch)
treedeca28ea15e79f6f804c3d90d2ba757881638af5 /src/luarocks/type
fetch tarballHEADmaster
Diffstat (limited to 'src/luarocks/type')
-rw-r--r--src/luarocks/type/manifest.lua80
-rw-r--r--src/luarocks/type/rockspec.lua199
2 files changed, 279 insertions, 0 deletions
diff --git a/src/luarocks/type/manifest.lua b/src/luarocks/type/manifest.lua
new file mode 100644
index 0000000..043366e
--- /dev/null
+++ b/src/luarocks/type/manifest.lua
@@ -0,0 +1,80 @@
+local type_manifest = {}
+
+local type_check = require("luarocks.type_check")
+
+local manifest_formats = type_check.declare_schemas({
+ ["3.0"] = {
+ repository = {
+ _mandatory = true,
+ -- packages
+ _any = {
+ -- versions
+ _any = {
+ -- items
+ _any = {
+ arch = { _type = "string", _mandatory = true },
+ modules = { _any = { _type = "string" } },
+ commands = { _any = { _type = "string" } },
+ dependencies = { _any = { _type = "string" } },
+ -- TODO: to be extended with more metadata.
+ }
+ }
+ }
+ },
+ modules = {
+ _mandatory = true,
+ -- modules
+ _any = {
+ -- providers
+ _any = { _type = "string" }
+ }
+ },
+ commands = {
+ _mandatory = true,
+ -- modules
+ _any = {
+ -- commands
+ _any = { _type = "string" }
+ }
+ },
+ dependencies = {
+ -- each module
+ _any = {
+ -- each version
+ _any = {
+ -- each dependency
+ _any = {
+ name = { _type = "string" },
+ namespace = { _type = "string" },
+ constraints = {
+ _any = {
+ no_upgrade = { _type = "boolean" },
+ op = { _type = "string" },
+ version = {
+ string = { _type = "string" },
+ _any = { _type = "number" },
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+})
+
+--- Type check a manifest table.
+-- Verify the correctness of elements from a
+-- manifest table, reporting on unknown fields and type
+-- mismatches.
+-- @return boolean or (nil, string): true if type checking
+-- succeeded, or nil and an error message if it failed.
+function type_manifest.check(manifest, globals)
+ assert(type(manifest) == "table")
+ local format = manifest_formats["3.0"]
+ local ok, err = type_check.check_undeclared_globals(globals, format)
+ if not ok then return nil, err end
+ return type_check.type_check_table("3.0", manifest, format, "")
+end
+
+return type_manifest
diff --git a/src/luarocks/type/rockspec.lua b/src/luarocks/type/rockspec.lua
new file mode 100644
index 0000000..0b4b5dc
--- /dev/null
+++ b/src/luarocks/type/rockspec.lua
@@ -0,0 +1,199 @@
+local type_rockspec = {}
+
+local type_check = require("luarocks.type_check")
+
+type_rockspec.rockspec_format = "3.0"
+
+-- Syntax for type-checking tables:
+--
+-- A type-checking table describes typing data for a value.
+-- Any key starting with an underscore has a special meaning:
+-- _type (string) is the Lua type of the value. Default is "table".
+-- _mandatory (boolean) indicates if the value is a mandatory key in its container table. Default is false.
+-- For "string" types only:
+-- _pattern (string) is the string-matching pattern, valid for string types only. Default is ".*".
+-- For "table" types only:
+-- _any (table) is the type-checking table for unspecified keys, recursively checked.
+-- _more (boolean) indicates that the table accepts unspecified keys and does not type-check them.
+-- Any other string keys that don't start with an underscore represent known keys and are type-checking tables, recursively checked.
+
+local rockspec_formats, versions = type_check.declare_schemas({
+ ["1.0"] = {
+ rockspec_format = { _type = "string" },
+ package = { _type = "string", _mandatory = true },
+ version = { _type = "string", _pattern = "[%w.]+-[%d]+", _mandatory = true },
+ description = {
+ summary = { _type = "string" },
+ detailed = { _type = "string" },
+ homepage = { _type = "string" },
+ license = { _type = "string" },
+ maintainer = { _type = "string" },
+ },
+ dependencies = {
+ platforms = type_check.MAGIC_PLATFORMS,
+ _any = {
+ _type = "string",
+ _name = "a valid dependency string",
+ _pattern = "%s*([a-zA-Z0-9][a-zA-Z0-9%.%-%_]*)%s*([^/]*)",
+ },
+ },
+ supported_platforms = {
+ _any = { _type = "string" },
+ },
+ external_dependencies = {
+ platforms = type_check.MAGIC_PLATFORMS,
+ _any = {
+ program = { _type = "string" },
+ header = { _type = "string" },
+ library = { _type = "string" },
+ }
+ },
+ source = {
+ _mandatory = true,
+ platforms = type_check.MAGIC_PLATFORMS,
+ url = { _type = "string", _mandatory = true },
+ md5 = { _type = "string" },
+ file = { _type = "string" },
+ dir = { _type = "string" },
+ tag = { _type = "string" },
+ branch = { _type = "string" },
+ module = { _type = "string" },
+ cvs_tag = { _type = "string" },
+ cvs_module = { _type = "string" },
+ },
+ build = {
+ platforms = type_check.MAGIC_PLATFORMS,
+ type = { _type = "string" },
+ install = {
+ lua = {
+ _more = true
+ },
+ lib = {
+ _more = true
+ },
+ conf = {
+ _more = true
+ },
+ bin = {
+ _more = true
+ }
+ },
+ copy_directories = {
+ _any = { _type = "string" },
+ },
+ _more = true,
+ _mandatory = true
+ },
+ hooks = {
+ platforms = type_check.MAGIC_PLATFORMS,
+ post_install = { _type = "string" },
+ },
+ },
+
+ ["1.1"] = {
+ deploy = {
+ wrap_bin_scripts = { _type = "boolean" },
+ }
+ },
+
+ ["3.0"] = {
+ description = {
+ labels = {
+ _any = { _type = "string" }
+ },
+ issues_url = { _type = "string" },
+ },
+ dependencies = {
+ _any = {
+ _pattern = "%s*([a-zA-Z0-9%.%-%_]*/?[a-zA-Z0-9][a-zA-Z0-9%.%-%_]*)%s*([^/]*)",
+ },
+ },
+ build_dependencies = {
+ platforms = type_check.MAGIC_PLATFORMS,
+ _any = {
+ _type = "string",
+ _name = "a valid dependency string",
+ _pattern = "%s*([a-zA-Z0-9%.%-%_]*/?[a-zA-Z0-9][a-zA-Z0-9%.%-%_]*)%s*([^/]*)",
+ },
+ },
+ test_dependencies = {
+ platforms = type_check.MAGIC_PLATFORMS,
+ _any = {
+ _type = "string",
+ _name = "a valid dependency string",
+ _pattern = "%s*([a-zA-Z0-9%.%-%_]*/?[a-zA-Z0-9][a-zA-Z0-9%.%-%_]*)%s*([^/]*)",
+ },
+ },
+ build = {
+ _mandatory = false,
+ },
+ test = {
+ platforms = type_check.MAGIC_PLATFORMS,
+ type = { _type = "string" },
+ _more = true,
+ },
+ }
+})
+
+type_rockspec.order = {"rockspec_format", "package", "version",
+ { "source", { "url", "tag", "branch", "md5" } },
+ { "description", {"summary", "detailed", "homepage", "license" } },
+ "supported_platforms", "dependencies", "build_dependencies", "external_dependencies",
+ { "build", {"type", "modules", "copy_directories", "platforms"} },
+ "test_dependencies", { "test", {"type"} },
+ "hooks"}
+
+local function check_rockspec_using_version(rockspec, globals, version)
+ local schema = rockspec_formats[version]
+ if not schema then
+ return nil, "unknown rockspec format " .. version
+ end
+ local ok, err = type_check.check_undeclared_globals(globals, schema)
+ if ok then
+ ok, err = type_check.type_check_table(version, rockspec, schema, "")
+ end
+ if ok then
+ return true
+ else
+ return nil, err
+ end
+end
+
+--- Type check a rockspec table.
+-- Verify the correctness of elements from a
+-- rockspec table, reporting on unknown fields and type
+-- mismatches.
+-- @return boolean or (nil, string): true if type checking
+-- succeeded, or nil and an error message if it failed.
+function type_rockspec.check(rockspec, globals)
+ assert(type(rockspec) == "table")
+
+ local version = rockspec.rockspec_format or "1.0"
+ local ok, err = check_rockspec_using_version(rockspec, globals, version)
+ if ok then
+ return true
+ end
+
+ -- Rockspec parsing failed.
+ -- Let's see if it would pass using a later version.
+
+ local found = false
+ for _, v in ipairs(versions) do
+ if not found then
+ if v == version then
+ found = true
+ end
+ else
+ local v_ok, v_err = check_rockspec_using_version(rockspec, globals, v)
+ if v_ok then
+ return nil, err .. " (using rockspec format " .. version .. " -- " ..
+ [[adding 'rockspec_format = "]] .. v .. [["' to the rockspec ]] ..
+ [[will fix this)]]
+ end
+ end
+ end
+
+ return nil, err .. " (using rockspec format " .. version .. ")"
+end
+
+return type_rockspec