Module:Soyjak categorizer2

From Soyjak Wiki, the free ensoyclopedia
Jump to navigationJump to search
If you are looking for config/records in use to adjust something, click here
If you are looking for this module's maintenance categories, click here

This module assigns categories to pages using {{Infobox soyjak}}. It distinguishes variants from subvariants, and categorizes them by origin year, parent variant (for subvariants), site of origin, and their SoyBooru post count. It relies on Module:Infobox categorizer for reading fields, alias matching, resolving overrides and issuing category links.

If the module produces a redlink category, or in other words, a category not yet created, it will state this in the preview with recommendation on what to do and put the page into a maintenance category.

It is only intended to be used for {{Infobox soyjak}}. Do not invoke this module in any other infobox, template, etc.

Rules

Parameter Handling
type The module expects to read whether the infobox describes a variant or subvariant from this field. A recognized subvariant alias takes precedence over a variant alias. Blank or unrecognized types default to variant, unrecognized nonblank types receive a silent maintenance category.
origin The module expects to read the origin year and site from this field. The first distinct four-digit year is used, more than one is considered ambiguous and is put in a silent maintenance category. Each matched site can issue a category.
based_on The module expects to read the subject parent variant from this field. Only mainspace wikilink targets will be read.[a] Recognized parent aliases are converted to "canonical" variant names.[b] Accepts up to three distinct parents, more than three is considered excessive and results in a silent maintenance category.
booru_posts The module expects to read Module:CatMark-provided post counts. Post count categories only apply to variants. If the expected count marker from CatMark is absent, a silent maintenance category is issued.

All other infobox fields do not affect this module's categories.

Type

Type aliases are defined in the subject config.

Type matching uses cleaned text and defaults to compact substring matching. If necessary, individual alias records can specify another matching mode in config.

The module chooses one classification for variant and subvariant. Type detection is important for this module to issue categories correctly. Subvariant has precedence over variant.

Type is also read to see if a match for "Trend" is found, in which case it will issue a preview warning recommending the infobox be switched to {{Infobox trend}} and put the page in a maintenance category.

Origin year

A detected year produces a category such as Category:2020 variants or Category:2020 subvariants. If no year is found, the module places the page in an undated-year category.

Years are read in their order of appearance in wikitext, not sorted chronologically. For example, 2020 or 2019 will result in 2020 being picked. The page is put in a maintenance category for multiple possible origin years. Ranges, such as 2020 - 2022, are not expanded or interpreted as a period and result in the same maintenance behavior.

References and all other "hidden" material removed by the toolkit's text cleaner cannot supply years.

Site of origin

Site records are loaded from Module:Infobox categorizer/sites. Matching uses cleaned origin text and any domains configured in those records. The default alias matching mode is compact substring matching, customization can be done at config.

The module will accept internal links and external links during reading.

Each matched site produces a category using the resolved classification, such as 4chan variants or SoyBooru subvariants.

Subject configs can use siteBuckets to map canonical site names to broader labels. Unmapped names pass through unchanged. This controls whether individual sites are grouped into categories such as Other-site variants. Simply put, it's a bucket you can use to put multiple sites into one group.

Parent variants

If you find the module producing redlink cats when expecting something else, it is very likely the parent name linked in based_on may be an alias currently unknown to the module. If so, add it to the relevant variant's alias group in the shared config to fix this. Otherwise, check the linked title and whether the category truly needs creating. You can also leave it as is, the page will be tracked in a maintenance category for staff to review.

Parent records are loaded from Module:Infobox categorizer/variants. If a recognized alias is found, it is converted to its canonical variant before categorization.

For example

|type = Soyjak subvariant

|based_on = [[Wholesome Soyjak]]

Since you used an alias, and this alias is recorded, this will produce Category:Gapejak subvariants.

Display labels and section fragments do not change the linked target. If, for example, Gapejak had a "Wholesome soyjak" section as [[Gapejak#Wholesome Soyjak]] or [[Gapejak#History|Wholesome soyjak]] instead of its own page, the outcome will still be the same.

Plain text does not supply a parent. Unrecognized but valid mainspace link targets still pass through as parent names. The module does not follow redirects, but the name of the redirect can still be recognized as an alias.

When more than three distinct canonical parents are detected, the first three are categorized, and the multiple-parents maintenance category is added. Parent categories and parent-detection maintenance apply only to subvariants unless disabled.

Configuration and shared data

Page Purpose
Module:Soyjak categorizer2/config Exclusive config for this module. Type aliases, category patterns, post-count bands, maintenance categories, infobox misuse detection[c], site grouping, and allowed namespaces.
Module:Infobox categorizer/sites Global site records, holds "canonical" site labels, aliases, and optional domains used to identify websites of origin.
Module:Infobox categorizer/variants You are probably looking for this if you came to this doc for help.
Global variant records, holds "canonical" variant names and aliases used to identify parent variants. Easily editable.

Rows shaded blue contain "global" data also used by other subject modules.

Notes

  1. ↑ Even if you write "Bernd", the module will not recognize it as a parent until it is properly linked!
  2. ↑ For example, Gapejak is also known as "Guinness World Record Soyjak". This is impossible for the module to know beforehand, so a config supplies this information to correct the category link it is going to produce.
  3. ↑ If the infobox detects "Trend" in type, it will put up a warning, recommending use of {{Infobox trend}} and issue a maintenance category.



local p = {}
local core = require('Module:Infobox categorizer')
local config = mw.loadData('Module:Soyjak categorizer2/config')

local where = 'Module:Soyjak categorizer2/config'
local dims = core.need(config, 'dimensions', where)
local maintenance = core.need(config, 'maintenance', where)
local invalidOverrideCat = core.need(maintenance, 'invalidOverride', where .. '.maintenance')
local usingOverrideCat = core.need(maintenance, 'usingOverride', where .. '.maintenance')

local D = {}
for _, key in ipairs({
	'type',
	'year',
	'site',
	'parent',
	'posts',
}) do
	D[key] = core.need(dims, key, where .. '.dimensions')
end

local types = core.compileAliasSet({ core.need(config, 'types', where) }, { match = 'substring' })
local sites = core.compileAliasSet({ mw.loadData('Module:Infobox categorizer/sites') }, { match = 'substring' })
local variants = core.compileAliasSet({ mw.loadData('Module:Infobox categorizer/variants') })
local siteBucket = core.fromMap(config.siteBuckets or {}) -- unused now, for future folding split sites back into Other-site categories
local misuseCfg = core.need(config, 'misuse', where)
local misuse =
	core.compileAliasSet({ { { category = 'trend', aliases = core.need(misuseCfg, 'aliases', where .. '.misuse') } } })
core.need(misuseCfg, 'warning', where .. '.misuse')
core.need(misuseCfg, 'maintenance', where .. '.misuse')

local function aliasOverride(compiled)
	return function(value)
		return core.parseAliasSetOverride(value, compiled)
	end
end

local function typeOverride(value)
	return core.parseExactOverride(value, { 'variant', 'subvariant' })
end

local function variantCanon(value)
	local found, valid = core.parseAliasSetOverride(value, variants)
	return valid and found[1] or value
end

local function maint(dim, key)
	return dim.maintenance and dim.maintenance[key]
end

function p._categories(args)
	local out = core.newList()
	local function has(field)
		return core.trim(args[field]) ~= ''
	end

	local function emit(pattern, state)
		for _, value in ipairs(state.values) do
			out:add(core.fill(pattern, value))
		end
	end

	local typeMatches = core.matchAliasSets(args.type, types)
	local misused = #core.matchAliasSets(args.type, misuse) > 0
	if misused then
		mw.addWarning(misuseCfg.warning)
		out:add(misuseCfg.maintenance)
	end

	local detectedType = 'variant'
	for _, value in ipairs(typeMatches) do
		if value == 'subvariant' then detectedType = 'subvariant' end
	end

	local kind = core.resolve {
		candidates = { detectedType },
		override = args.category_type,
		parse = typeOverride,
		max = 1,
	}
	local classification = kind.values[1]
	if kind.source ~= 'override' and has('type') and #typeMatches == 0 and not misused then
		out:add(maint(D.type, 'unrecognized'))
	end

	local year = core.resolve {
		candidates = core.findYears(args.origin),
		override = args.category_year,
		parse = core.parseYearOverride,
		suppress = args.noyearcat, -- backward compatability
		max = 1,
	}
	if year.source ~= 'suppressed' then
		if year.values[1] then
			out:add(core.fill(D.year.name[classification], year.values[1]))
		else
			out:add(D.year.undated[classification])
		end
		if year.overflow then out:add(maint(D.year, 'overflow')) end
	end

	local site = core.resolve {
		candidates = core.matchAliasSets(args.origin, sites),
		override = args.category_site,
		parse = aliasOverride(sites),
		canon = siteBucket,
	}
	emit(D.site.name[classification], site)
	if site.source == 'detected' and site.undetected then out:add(maint(D.site, 'unrecognized')) end

	local parent = core.resolve {
		candidates = core.findLinkTargets(args.parent),
		override = args.category_parent,
		parse = core.parseLinkTargetOverride,
		canon = variantCanon,
		applicable = classification == 'subvariant',
		suppress = args.noparentcat,
		max = 3,
	}
	if parent.source == 'detected' or parent.source == 'override' then
		emit(D.parent.name, parent)
		if #parent.values == 0 then out:add(maint(D.parent, 'undetected')) end
		if parent.overflow then out:add(maint(D.parent, 'overflow')) end
	end

	if classification == 'variant' then
		local counts = core.readDataAttr(args.booru_posts, 'boorusearch-count')
		if #counts == 0 then
			out:add(maint(D.posts, 'missing'))
		else
			out:add(core.pickBand(core.parseNumber(counts[1]), D.posts.bands))
		end
	end

	if core.anyCustomized(kind, year, site, parent) then out:add(usingOverrideCat) end

	if core.anyInvalid(kind, year, site, parent) then out:add(invalidOverrideCat) end
	return out
end

p.main = core.makeMain(p._categories, config.namespaces)

return p