--- Build strict file-reference rules for shell scripts
-- @module formats.sh.references

local sh_references = {}

-- Pattern breakdown: sourcing commands begin a line or follow a shell command separator before their literal argument
local source_start_prefix = "^%s*source%f[^%w_]%s+"
local source_after_separator_prefix = "[;&|]%s*source%f[^%w_]%s+"
local dot_start_prefix = "^%s*%.%s+"
local dot_after_separator_prefix = "[;&|]%s*%.%s+"

--- Return whether one shell source target is a literal path
-- @param reference table parsed file reference
-- @return boolean accepted
local function is_literal_path(reference)
	local path = reference.path

	return not path:find("$", 1, true)
		and not path:find("`", 1, true)
		and not path:find("*", 1, true)
		and not path:find("?", 1, true)
		and not path:find("[", 1, true)
end

--- Return literal paths passed to shell sourcing commands
-- @return table rules
function sh_references.new()
	local rules = {}

	-- Each command position accepts normal shell quote styles or one plain path token
	for _, prefix in ipairs({
		source_start_prefix,
		source_after_separator_prefix,
		dot_start_prefix,
		dot_after_separator_prefix,
	}) do
		rules[#rules + 1] = {
			prefix = prefix, open = "\"", close = "\"", validate = is_literal_path,
		}
		rules[#rules + 1] = {
			prefix = prefix, open = "'", close = "'", validate = is_literal_path,
		}
		rules[#rules + 1] = {
			prefix = prefix, validate = is_literal_path,
		}
	end

	return rules
end

return sh_references
