Module:Chem box: Difference between revisions

From Space Station 14 Wiki
Aliser (talk | contribs)
changed data source
Aliser (talk | contribs)
m uppercased [K]elvin
 
(17 intermediate revisions by 2 users not shown)
Line 1: Line 1:
local p = {} --p stands for package
local p = {} --p stands for package
local getArgs = require('Module:Arguments').getArgs
local getArgs = require("Module:Arguments").getArgs
local yesNo = require('Module:Yesno')
local yesNo = require("Module:Yesno")
local reagent_card = require('Module:Chemistry').reagent_card


local chem_data = mw.loadJsonData("Module:Chem box/chem data.json")
local chem_data = mw.loadJsonData("Module:Chem box/chem data.json")


local current_frame = mw.getCurrentFrame()
local current_frame = mw.getCurrentFrame()
local beaker_el = current_frame:expandTemplate {
    title = 'Beaker'
}


-- ====================
-- ====================


local function numeric_table_length(t)
local function numeric_table_length(t)
    local count = 0
local count = 0
    for _ in ipairs(t) do count = count + 1 end
for _ in ipairs(t) do
    return count
count = count + 1
end
return count
end
end


local function table_length(t)
local function table_length(t)
    local count = 0
local count = 0
    for _ in pairs(t) do count = count + 1 end
for _ in pairs(t) do
    return count
count = count + 1
end
return count
end
end


local function table_has_value(tab, val)
local function table_has_value(tab, val)
    for _, value in ipairs(tab) do
for _, value in ipairs(tab) do
        if value == val then
if value == val then
            return true
return true
        end
end
    end
end


    return false
return false
end
end


local function assert_value_not_nil(value, error_message)
local function assert_value_not_nil(value, error_message)
    if value == nil then
if value == nil then
        if error_message == nil then
if error_message == nil then
            error("value is nil")
error("value is nil")
        else
else
            error(error_message)
error(error_message)
        end
end
    end
end
end
end


Line 49: Line 49:
-- Source: https://stackoverflow.com/a/2421746
-- Source: https://stackoverflow.com/a/2421746
local function capitalize(str)
local function capitalize(str)
    return (str:gsub("^%l", string.upper))
return (str:gsub("^%l", string.upper))
end
end


local function passthrough_assert_true(value, valueToReturnIfTrue, errorMessageOnFalse)
local function passthrough_assert_true(value, valueToReturnIfTrue, errorMessageOnFalse)
    if value then
if value then
        return valueToReturnIfTrue
return valueToReturnIfTrue
    else
else
        error(errorMessageOnFalse)
error(errorMessageOnFalse)
    end
end
end
end


local function find_first_numeric_table_item_matching_condition(table, condition)
local function find_first_numeric_table_item_matching_condition(table, condition)
    for i, item in ipairs(table) do
for i, item in ipairs(table) do
        if condition(item, i, table) then
if condition(item, i, table) then
            return item
return item
        end
end
    end
end
end
end


-- table concat function because ofcourse fucking table.concat doesn't work
-- table concat function because ofcourse fucking table.concat doesn't work
local function concat_numberic_table(tbl, sep)
local function concat_numberic_table(tbl, sep)
    local temp_table = {}
local temp_table = {}
    for i = 1, numeric_table_length(tbl) do
for i = 1, numeric_table_length(tbl) do
        table.insert(temp_table, tbl[i])
table.insert(temp_table, tbl[i])
end
 
return table.concat(temp_table, sep)
end
 
local function ternary_strict(valueToCheck, valueIfTrue, valueIfFalse)
if valueToCheck == true then
return valueIfTrue
else
return valueIfFalse
end
end
 
local function table_map(tbl, mapFn)
    local res = {}
    for k, v in pairs(tbl) do
        table.insert(res, mapFn(v, k, tbl))
    end
    return res
end
 
local function num_table_reduce(tbl, reduceFn, initial_value)
    local out = initial_value
 
    for i, v in ipairs(tbl) do
        out = reduceFn(out, v, i, tbl)
    end
 
    return out
end
 
local function table_filter(tbl, filterFn)
    local out = {}
 
    for k, v in pairs(tbl) do
        if filterFn(v, k, tbl) then out[k] = v end
    end
 
    return out
end
 
 
-- Sorts a table into a new table.
-- An alternative to cases such as when table.sort is not working,
-- like when trying to sort JSON tables (thanks fuckass lua).
local function table_to_sorted(tbl, sortfn)
    local keys = {}
 
    for key, _ in pairs(tbl) do
        table.insert(keys, key)
    end
 
    table.sort(keys, function(keyA, keyB) return sortfn(tbl[keyA], tbl[keyB]) end)
 
    local t2 = {}
 
    for _, key in ipairs(keys) do
        table.insert(t2, tbl[key])
     end
     end


     return table.concat(temp_table, sep)
     return t2
end
end


Line 85: Line 143:
-- Set `no_error` to `true` to return `nil` instead.
-- Set `no_error` to `true` to return `nil` instead.
function p.lookup_reagent(query, no_error)
function p.lookup_reagent(query, no_error)
    local query_lower = string.lower(query)
local query_lower = string.lower(query)
 
for _, reagent in ipairs(chem_data) do
assert_value_not_nil(reagent.id)
assert_value_not_nil(reagent.name)
 
if reagent.id == query then
return reagent
end
if string.lower(reagent.name) == query_lower then
return reagent
end
end
 
return passthrough_assert_true(no_error, nil, "failed to lookup reagent: no match was found")
end
 
local function get_sort_reagent_az_final_comparator(map_of_reagent_name_or_id_to_order, a, b)
return function (a, b)
return map_of_reagent_name_or_id_to_order[string.lower(a.name or a.id)]
< map_of_reagent_name_or_id_to_order[string.lower(b.name or b.id)]
end
end
 
-- Sorts an array of reagents in place by name (or ID if no name), a to z.
-- @param reagents Reagents to sort.
-- @param to_sorted Whether to create a new sorted table instead of sorting in place.
local function sort_reagents_az(reagents, to_sorted)
local reagents_names_or_ids = table_map(reagents, function (reagent)
return string.lower(reagent.name or reagent.id)
end)
table.sort(reagents_names_or_ids)


    for _, reagent in ipairs(chem_data) do
local map_of_reagent_name_or_id_to_order = num_table_reduce(reagents_names_or_ids, function (accum, value, i)
        assert_value_not_nil(reagent.id)
accum[value] = i
        assert_value_not_nil(reagent.name)


        if reagent.id == query then return reagent end
return accum
        if string.lower(reagent.name) == query_lower then return reagent end
end, {})
    end


    return passthrough_assert_true(
if to_sorted then
        no_error,
return table_to_sorted(reagents, get_sort_reagent_az_final_comparator(map_of_reagent_name_or_id_to_order))
        nil,
else
        "failed to lookup reagent: no match was found"
table.sort(reagents, get_sort_reagent_az_final_comparator(map_of_reagent_name_or_id_to_order))
    )
end
end
end


Line 105: Line 192:


function p.generate_chem_box(frame)
function p.generate_chem_box(frame)
    local args = getArgs(frame)
local args = getArgs(frame)
 
local query = args[1]
assert_value_not_nil(query, "failed to generate chem box: query was not provided")
 
-- ===================


    local query = args[1]
local reagent = p.lookup_reagent(query)
    assert_value_not_nil(query, "failed to generate chem box: query was not provided")
assert_value_not_nil(reagent.color)
assert_value_not_nil(reagent.name)
assert_value_not_nil(reagent.recipes)
assert_value_not_nil(reagent.effectStrings)
assert_value_not_nil(reagent.description)
assert_value_not_nil(reagent.physicalDescription)
assert_value_not_nil(reagent.textColorTheme)


    -- ===================
local recipes_container_el = mw.html.create("div")
if numeric_table_length(reagent.recipes) == 0 then
local no_recipes_text_el = mw.html.create("span"):css("color", "gray"):node("No recipes")


    local reagent = p.lookup_reagent(query)
recipes_container_el:node(no_recipes_text_el)
    assert_value_not_nil(reagent.color)
else
    assert_value_not_nil(reagent.name)
for _, recipe in ipairs(reagent.recipes) do
    assert_value_not_nil(reagent.recipes)
assert_value_not_nil(recipe.id)
    assert_value_not_nil(reagent.effects)
assert_value_not_nil(recipe.reactants)
    assert_value_not_nil(reagent.desc)
assert_value_not_nil(recipe.products)
    assert_value_not_nil(reagent.physicalDesc)


    local recipes_container_el = mw.html.create("div")
local recipe_box_template_args = {}
    if numeric_table_length(reagent.recipes) == 0 then
recipe_box_template_args.name = recipe.id
        local no_recipes_text_el = mw.html.create("span")
            :css("color", "gray")
            :node("No recipes")


        recipes_container_el:node(no_recipes_text_el)
-- a list of catalist reactants.
    else
-- contains "id" and "amount"
        for _, recipe in ipairs(reagent.recipes) do
local catalyst_reactants = {}
            assert_value_not_nil(recipe.id)
            assert_value_not_nil(recipe.reactants)
            assert_value_not_nil(recipe.products)


            local recipe_box_template_args = {}
for reactant_i, reactant in ipairs(recipe.reactants) do
            recipe_box_template_args.name = recipe.id
local reactant_name = capitalize(reactant.name)
local reactant_amount = reactant.count
local reactant_is_catalyst = reactant.isCatalyst or false


            -- a list of catalist reactants.
local label = reactant_name
            -- contains "id" and "amount"
local link = reactant.id
            local catalyst_reactants = {}


            for reactant_i, reactant in ipairs(recipe.reactants) do
if reactant_is_catalyst then
                local reactant_id = reactant[1]
table.insert(catalyst_reactants, {
                local reactant_amount = reactant[2]
name = reactant_name,
                local reactant_is_catalyst = reactant[3] or false
id = reactant_id,
amount = reactant_amount,
})
end


                local label = reactant_id
local component_el = current_frame:expandTemplate({
title = "Recipe Component",
args = {
item = label,
amount = reactant_amount,
itemlink = link
-- TODO
-- image = ""
},
})


                if reactant_is_catalyst then
recipe_box_template_args["component-" .. reactant_i] = component_el
                    table.insert(catalyst_reactants, {
end
                        id = reactant_id,
                        amount = reactant_amount
                    })
                end


                local component_el = current_frame:expandTemplate {
local temperature_args = {}
                    title = 'Recipe Component',
if recipe.minTemp ~= nil or recipe.maxTemp ~= nil then
                    args = {
local temperature_string = ""
                        item = label,
if recipe.minTemp ~= nil then
                        amount = reactant_amount
temperature_string = tostring(recipe.minTemp) .. "K "
                        -- TODO
end
                        -- image = ""
temperature_string = temperature_string .. "<"
                    }
if recipe.maxTemp ~= nil then
                }
temperature_string = temperature_string .. " " .. tostring(recipe.maxTemp) .. "K"
end
temperature_args = {temperature = temperature_string}
end
local required_mixer = "Beaker"
if recipe.requiredMixerCategories ~= nil then
required_mixer = recipe.requiredMixerCategories[1]
end
recipe_box_template_args.transformer = current_frame:expandTemplate({
title = required_mixer,
args = temperature_args
})


                recipe_box_template_args['component-' .. reactant_i] = component_el
for product_i, product in ipairs(recipe.products) do
            end
local component_el = current_frame:expandTemplate({
title = "Recipe Component",
args = {
item = capitalize(product.name),
amount = product.count,
-- TODO
-- image = ""
},
})


            recipe_box_template_args.transformer = beaker_el
recipe_box_template_args["result-" .. product_i] = component_el
end


            for product_i, product in ipairs(recipe.products) do
-- add catalysts as products, if any
                local component_el = current_frame:expandTemplate {
for catalyst_product_i, catalyst_product_entry in ipairs(catalyst_reactants) do
                    title = 'Recipe Component',
local product_name = catalyst_product_entry.name
                    args = {
local product_amount = catalyst_product_entry.amount
                        item = product[1],
                        amount = product[2]
                        -- TODO
                        -- image = ""
                    }
                }


                recipe_box_template_args['result-' .. product_i] = component_el
local label = current_frame:expandTemplate({
            end
title = "Tooltip",
args = {
'<sup class="quickbox-catalyst-note">+</sup>',
'<span class="quickbox-catalyst-note-tooltip">This product is a catalyst reactant, remaining after the reaction.</span>',
},
}) .. product_name


            -- add catalysts as products, if any
local component_el = current_frame:expandTemplate({
            for catalyst_product_i, catalyst_product_entry in ipairs(catalyst_reactants) do
title = "Recipe Component",
                local product_id = catalyst_product_entry.id
args = {
                local product_amount = catalyst_product_entry.amount
item = label,
amount = product_amount,
-- TODO
-- image = ""
},
})


                local label = current_frame:expandTemplate {
local index = numeric_table_length(recipe.products) + catalyst_product_i
                    title = 'Tooltip',
recipe_box_template_args["result-" .. index] = component_el
                    args = {
end
                        '<sup class="quickbox-catalyst-note">+</sup>',
                        '<span class="quickbox-catalyst-note-tooltip">This product is a catalyst reactant, remaining after the reaction.</span>'
                    }
                } .. product_id
               
                local component_el = current_frame:expandTemplate {
                    title = 'Recipe Component',
                    args = {
                        item = label,
                        amount = product_amount
                        -- TODO
                        -- image = ""
                    }
                }


                local index = numeric_table_length(recipe.products) + catalyst_product_i
local recipes_el = current_frame:expandTemplate({
                recipe_box_template_args['result-' .. index] = component_el
title = "Recipe Box",
            end
args = recipe_box_template_args,
})


            local recipes_el = current_frame:expandTemplate {
recipes_container_el:node(recipes_el)
                title = 'Recipe Box',
end
                args = recipe_box_template_args
end
            }


            recipes_container_el:node(recipes_el)
local effects = current_frame:preprocess(concat_numberic_table(reagent.effectStrings, ""))
        end
    end


    local effects = concat_numberic_table(reagent.effects, "")
return reagent_card {
id = reagent.id,
color = reagent.color,
name = capitalize(reagent.name),
recipes = tostring(recipes_container_el:allDone()),
metabolisms = effects,
desc = reagent.description,
physicalDesc = reagent.physicalDescription,


    return current_frame:expandTemplate {
}
        title = 'Manual Chem Box',
        args = {
            color = reagent.color,
            -- textcolor = "",
            name = capitalize(reagent.name),
            recipes = tostring(recipes_container_el:allDone()),
            metabolisms = effects,
            desc = reagent.desc,
            physicalDesc = reagent.physicalDesc,
        }
    }
end
end


function p.generate_chem_boxes_for_all_reagents()
function p.generate_chem_boxes_for_all_reagents()
    local container_el = mw.html.create("div")
local container_el = mw.html.create("div"):addClass("reagents-list")
        :addClass("reagents-list")
 
-- sort to a new obj cuz chem data is a json loaded table and is not enumerable by table.sort
local reagents_sorted = sort_reagents_az(chem_data, true)
 
for _, reagent in ipairs(reagents_sorted) do
assert_value_not_nil(reagent.id)
 
container_el:node(p.generate_chem_box({
reagent.id,
}))
end
 
return container_el:allDone()
end


    for _, reagent in ipairs(chem_data) do
function p.generate_chem_boxes_for_group(frame)
        assert_value_not_nil(reagent.id)
local args = getArgs(frame)
local query = args[1]
assert_value_not_nil(query)
-- ========
local query_lc = string.lower(query)
local container_el = mw.html.create("div"):addClass("reagents-list")


        container_el:node(
local reagents = table_filter(chem_data, function (reagent)
            p.generate_chem_box {
return reagent.group
                reagent.id
and string.lower(reagent.group) == query_lc
            }
end)
        )
-- sort to a new obj cuz chem data is a json loaded table and is not enumerable by table.sort,
    end
-- even when filtered smh
reagents = sort_reagents_az(reagents, true)
 
for _, reagent in ipairs(reagents) do
container_el:node(p.generate_chem_box({
reagent.id,
}))
end


    return container_el:allDone()
return container_el:allDone()
end
end


return p
return p

Latest revision as of 22:14, 10 June 2025

Module documentation
View or edit this documentation (about module documentation)
Uses JSON data
This module uses JSON data pages:

Implements {{chem box}}.


local p = {} --p stands for package
local getArgs = require("Module:Arguments").getArgs
local yesNo = require("Module:Yesno")
local reagent_card = require('Module:Chemistry').reagent_card

local chem_data = mw.loadJsonData("Module:Chem box/chem data.json")

local current_frame = mw.getCurrentFrame()

-- ====================

local function numeric_table_length(t)
	local count = 0
	for _ in ipairs(t) do
		count = count + 1
	end
	return count
end

local function table_length(t)
	local count = 0
	for _ in pairs(t) do
		count = count + 1
	end
	return count
end

local function table_has_value(tab, val)
	for _, value in ipairs(tab) do
		if value == val then
			return true
		end
	end

	return false
end

local function assert_value_not_nil(value, error_message)
	if value == nil then
		if error_message == nil then
			error("value is nil")
		else
			error(error_message)
		end
	end
end

-- Makes the first letter uppercase.
-- Source: https://stackoverflow.com/a/2421746
local function capitalize(str)
	return (str:gsub("^%l", string.upper))
end

local function passthrough_assert_true(value, valueToReturnIfTrue, errorMessageOnFalse)
	if value then
		return valueToReturnIfTrue
	else
		error(errorMessageOnFalse)
	end
end

local function find_first_numeric_table_item_matching_condition(table, condition)
	for i, item in ipairs(table) do
		if condition(item, i, table) then
			return item
		end
	end
end

-- table concat function because ofcourse fucking table.concat doesn't work
local function concat_numberic_table(tbl, sep)
	local temp_table = {}
	for i = 1, numeric_table_length(tbl) do
		table.insert(temp_table, tbl[i])
	end

	return table.concat(temp_table, sep)
end

local function ternary_strict(valueToCheck, valueIfTrue, valueIfFalse)
	if valueToCheck == true then
		return valueIfTrue
	else
		return valueIfFalse
	end
end

local function table_map(tbl, mapFn)
    local res = {}
    for k, v in pairs(tbl) do
        table.insert(res, mapFn(v, k, tbl))
    end
    return res
end

local function num_table_reduce(tbl, reduceFn, initial_value)
    local out = initial_value

    for i, v in ipairs(tbl) do
        out = reduceFn(out, v, i, tbl)
    end

    return out
end

local function table_filter(tbl, filterFn)
    local out = {}

    for k, v in pairs(tbl) do
        if filterFn(v, k, tbl) then out[k] = v end
    end

    return out
end


-- Sorts a table into a new table.
-- An alternative to cases such as when table.sort is not working,
-- like when trying to sort JSON tables (thanks fuckass lua).
local function table_to_sorted(tbl, sortfn)
    local keys = {}

    for key, _ in pairs(tbl) do
        table.insert(keys, key)
    end

    table.sort(keys, function(keyA, keyB) return sortfn(tbl[keyA], tbl[keyB]) end)

    local t2 = {}

    for _, key in ipairs(keys) do
        table.insert(t2, tbl[key])
    end

    return t2
end

-- ====================

-- Lookups reagent by ID or name.
--
-- Raises an error if no reagent was found.
-- Set `no_error` to `true` to return `nil` instead.
function p.lookup_reagent(query, no_error)
	local query_lower = string.lower(query)

	for _, reagent in ipairs(chem_data) do
		assert_value_not_nil(reagent.id)
		assert_value_not_nil(reagent.name)

		if reagent.id == query then
			return reagent
		end
		if string.lower(reagent.name) == query_lower then
			return reagent
		end
	end

	return passthrough_assert_true(no_error, nil, "failed to lookup reagent: no match was found")
end

local function get_sort_reagent_az_final_comparator(map_of_reagent_name_or_id_to_order, a, b)
	return function (a, b)
		return map_of_reagent_name_or_id_to_order[string.lower(a.name or a.id)]
			< map_of_reagent_name_or_id_to_order[string.lower(b.name or b.id)]
	end 
end

-- Sorts an array of reagents in place by name (or ID if no name), a to z.
-- @param reagents Reagents to sort.
-- @param to_sorted Whether to create a new sorted table instead of sorting in place.
local function sort_reagents_az(reagents, to_sorted)
	local reagents_names_or_ids = table_map(reagents, function (reagent)
		return string.lower(reagent.name or reagent.id)
	end)
	table.sort(reagents_names_or_ids)

	local map_of_reagent_name_or_id_to_order = num_table_reduce(reagents_names_or_ids, function (accum, value, i)
		accum[value] = i

		return accum
	end, {})

	if to_sorted then
		return table_to_sorted(reagents, get_sort_reagent_az_final_comparator(map_of_reagent_name_or_id_to_order))
	else
		table.sort(reagents, get_sort_reagent_az_final_comparator(map_of_reagent_name_or_id_to_order))
	end
end

-- ====================

function p.generate_chem_box(frame)
	local args = getArgs(frame)

	local query = args[1]
	assert_value_not_nil(query, "failed to generate chem box: query was not provided")

	-- ===================

	local reagent = p.lookup_reagent(query)
	assert_value_not_nil(reagent.color)
	assert_value_not_nil(reagent.name)
	assert_value_not_nil(reagent.recipes)
	assert_value_not_nil(reagent.effectStrings)
	assert_value_not_nil(reagent.description)
	assert_value_not_nil(reagent.physicalDescription)
	assert_value_not_nil(reagent.textColorTheme)

	local recipes_container_el = mw.html.create("div")
	if numeric_table_length(reagent.recipes) == 0 then
		local no_recipes_text_el = mw.html.create("span"):css("color", "gray"):node("No recipes")

		recipes_container_el:node(no_recipes_text_el)
	else
		for _, recipe in ipairs(reagent.recipes) do
			assert_value_not_nil(recipe.id)
			assert_value_not_nil(recipe.reactants)
			assert_value_not_nil(recipe.products)

			local recipe_box_template_args = {}
			recipe_box_template_args.name = recipe.id

			-- a list of catalist reactants.
			-- contains "id" and "amount"
			local catalyst_reactants = {}

			for reactant_i, reactant in ipairs(recipe.reactants) do
				local reactant_name = capitalize(reactant.name)
				local reactant_amount = reactant.count
				local reactant_is_catalyst = reactant.isCatalyst or false

				local label = reactant_name
				local link = reactant.id

				if reactant_is_catalyst then
					table.insert(catalyst_reactants, {
						name = reactant_name,
						id = reactant_id,
						amount = reactant_amount,
					})
				end

				local component_el = current_frame:expandTemplate({
					title = "Recipe Component",
					args = {
						item = label,
						amount = reactant_amount,
						itemlink = link
						-- TODO
						-- image = ""
					},
				})

				recipe_box_template_args["component-" .. reactant_i] = component_el
			end

			local temperature_args = {}
			if recipe.minTemp ~= nil or recipe.maxTemp ~= nil then
				local temperature_string = ""
				if recipe.minTemp ~= nil then
					temperature_string = tostring(recipe.minTemp) .. "K "
				end
				temperature_string = temperature_string .. "<"
				if recipe.maxTemp ~= nil then
					temperature_string = temperature_string .. " " .. tostring(recipe.maxTemp) .. "K"
				end
				temperature_args = {temperature = temperature_string}
			end
			local required_mixer = "Beaker"
			if recipe.requiredMixerCategories ~= nil then
				required_mixer = recipe.requiredMixerCategories[1]
			end
			recipe_box_template_args.transformer = current_frame:expandTemplate({
				title = required_mixer,
				args = temperature_args
			})

			for product_i, product in ipairs(recipe.products) do
				local component_el = current_frame:expandTemplate({
					title = "Recipe Component",
					args = {
						item = capitalize(product.name),
						amount = product.count,
						-- TODO
						-- image = ""
					},
				})

				recipe_box_template_args["result-" .. product_i] = component_el
			end

			-- add catalysts as products, if any
			for catalyst_product_i, catalyst_product_entry in ipairs(catalyst_reactants) do
				local product_name = catalyst_product_entry.name
				local product_amount = catalyst_product_entry.amount

				local label = current_frame:expandTemplate({
					title = "Tooltip",
					args = {
						'<sup class="quickbox-catalyst-note">+</sup>',
						'<span class="quickbox-catalyst-note-tooltip">This product is a catalyst reactant, remaining after the reaction.</span>',
					},
				}) .. product_name

				local component_el = current_frame:expandTemplate({
					title = "Recipe Component",
					args = {
						item = label,
						amount = product_amount,
						-- TODO
						-- image = ""
					},
				})

				local index = numeric_table_length(recipe.products) + catalyst_product_i
				recipe_box_template_args["result-" .. index] = component_el
			end

			local recipes_el = current_frame:expandTemplate({
				title = "Recipe Box",
				args = recipe_box_template_args,
			})

			recipes_container_el:node(recipes_el)
		end
	end

	local effects = current_frame:preprocess(concat_numberic_table(reagent.effectStrings, ""))

	return reagent_card {
		id = reagent.id,
		color = reagent.color,
		name = capitalize(reagent.name),
		recipes = tostring(recipes_container_el:allDone()),
		metabolisms = effects,
		desc = reagent.description,
		physicalDesc = reagent.physicalDescription,

	}
end

function p.generate_chem_boxes_for_all_reagents()
	local container_el = mw.html.create("div"):addClass("reagents-list")

	-- sort to a new obj cuz chem data is a json loaded table and is not enumerable by table.sort
	local reagents_sorted = sort_reagents_az(chem_data, true)

	for _, reagent in ipairs(reagents_sorted) do
		assert_value_not_nil(reagent.id)

		container_el:node(p.generate_chem_box({
			reagent.id,
		}))
	end

	return container_el:allDone()
end

function p.generate_chem_boxes_for_group(frame)
	local args = getArgs(frame)
	local query = args[1]
	assert_value_not_nil(query)
	
	-- ========
	
	local query_lc = string.lower(query)
	local container_el = mw.html.create("div"):addClass("reagents-list")

	local reagents = table_filter(chem_data, function (reagent)
		return reagent.group 
			and string.lower(reagent.group) == query_lc
	end)
	-- sort to a new obj cuz chem data is a json loaded table and is not enumerable by table.sort,
	-- even when filtered smh
	reagents = sort_reagents_az(reagents, true)

	for _, reagent in ipairs(reagents) do
		container_el:node(p.generate_chem_box({
			reagent.id,
		}))
	end

	return container_el:allDone()
end

return p