<commit_before>--[[
Package Metadata Commands
================

These commands work with packages metadata.

pkg.query(fs, path) -> meta, path           - Query an on-disk path for package info.
pkg.queryDb(db, path) -> meta, kind         - Query an in-db hash for package info.
pky.normalize(meta) -> author, tag, version - Extract and normalize pkg info
]]

local isFile = require('git').modes.isFile
local semver = require('semver')
local pathJoin = require('luvi').path.join
local listToMap = require('git').listToMap

local function evalModule(data, name)
  local fn = assert(loadstring(data, name))
  local exports = {}
  local module = { exports = exports }
  setfenv(fn, {
    exports = exports,
  })
  local success, ret = pcall(fn)

  local meta = success and type(ret) == "table" and ret or module.exports
  if not meta then return nil, "Missing exports in " .. name end
  if not meta.name then return nil, "Missing name in package description in " .. name end
  if not meta.version then return nil, "Missing version in package description in " .. name end
  return meta
end

local validKeys = {
  name = "string",
  version = "string",
  private = "boolean", -- Don't allow publishing.
  obsolete = "boolean", -- Hide from search results.
  description = "string",
  keywords = "table", -- list of strings
  tags = "table", -- list of strings
  homepage = "string",
  license = "string",
  licenses = "table", -- table of strings
  author = "table", -- person {name=name, email=email, url=url}
  contributors = "table", -- list of people
  dependencies = "table", -- list of strings
  luvi = "table", -- {flavor=flavor,version=version}
}

function exports.query(fs, path)
  local packagePath = path
  local stat, data, err
  stat, err = fs.stat(path)
  if stat then
    if stat.type == "directory" then
      packagePath = path .. "/"
      data, err = fs.readFile(pathJoin(path, "package.lua"))
      if err and not err:match("^ENOENT:") then error(err) end
      if not data then
        data, err = fs.readFile(pathJoin(path, "init.lua"))
        if err and not err:match("^ENOENT:") then error(err) end
      end
    else
      data, err = fs.readFile(packagePath)
    end
  elseif err:match("^ENOENT:") then
    packagePath = packagePath .. ".lua"
    data, err = fs.readFile(packagePath)
  end
  if not data then
    return data, err or "Can't find package at " .. path
  end
  local meta = evalModule(data, packagePath)
  local clean = {}
  for key, value in pairs(meta) do
    if type(value) == validKeys[key] then
      clean[key] = value
    end
  end
  return clean, packagePath
end
<commit_msg>Improve error reporting with package metadata is missing<commit_after>--[[
Package Metadata Commands
================

These commands work with packages metadata.

pkg.query(fs, path) -> meta, path           - Query an on-disk path for package info.
pkg.queryDb(db, path) -> meta, kind         - Query an in-db hash for package info.
pky.normalize(meta) -> author, tag, version - Extract and normalize pkg info
]]

local isFile = require('git').modes.isFile
local semver = require('semver')
local pathJoin = require('luvi').path.join
local listToMap = require('git').listToMap

local function evalModule(data, name)
  local fn = assert(loadstring(data, name))
  local exports = {}
  local module = { exports = exports }
  setfenv(fn, {
    exports = exports,
  })
  local success, ret = pcall(fn)

  local meta = success and type(ret) == "table" and ret or module.exports
  if not meta then return nil, "Missing exports in " .. name end
  if not meta.name then return nil, "Missing name in package description in " .. name end
  if not meta.version then return nil, "Missing version in package description in " .. name end
  return meta
end

local validKeys = {
  name = "string",
  version = "string",
  private = "boolean", -- Don't allow publishing.
  obsolete = "boolean", -- Hide from search results.
  description = "string",
  keywords = "table", -- list of strings
  tags = "table", -- list of strings
  homepage = "string",
  license = "string",
  licenses = "table", -- table of strings
  author = "table", -- person {name=name, email=email, url=url}
  contributors = "table", -- list of people
  dependencies = "table", -- list of strings
  luvi = "table", -- {flavor=flavor,version=version}
}

function exports.query(fs, path)
  local packagePath = path
  local stat, data, err
  stat, err = fs.stat(path)
  if stat then
    if stat.type == "directory" then
      packagePath = path .. "/"
      data, err = fs.readFile(pathJoin(path, "package.lua"))
      if err and not err:match("^ENOENT:") then error(err) end
      if not data then
        data, err = fs.readFile(pathJoin(path, "init.lua"))
        if err and not err:match("^ENOENT:") then error(err) end
      end
    else
      data, err = fs.readFile(packagePath)
    end
  elseif err:match("^ENOENT:") then
    packagePath = packagePath .. ".lua"
    data, err = fs.readFile(packagePath)
  end
  if not data then
    return data, err or "Can't find package at " .. path
  end
  local meta = evalModule(data, packagePath)
  local clean = {}
  if not meta then return nil, "No meta found" end
  for key, value in pairs(meta) do
    if type(value) == validKeys[key] then
      clean[key] = value
    end
  end
  return clean, packagePath
end

{'fraction_non_alphanumeric': 0.12626641651031895, 'fraction_numerical': 0.0, 'mean_word_length': 3.1976377952755906, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5469469', 'n_tokens_mistral': 1623, 'n_tokens_neox': 1603, 'n_words': 591}