Module:Franchise

local p = {} local h = {}

local Error = require("Module:Error") local utilsString = require("Module:UtilsString") local utilsTable = require("Module:UtilsTable")

local Constants = mw.loadData("Module:Constants/Data") local cache = mw.loadData("Module:Franchise/Cache")

-- Many templates need "Series" as if it were a game. Since it does not fit into the data model of Data:Franchise, it is manually defined here. local series = { article = "The Legend of Zelda (Series)", shortName = "The Legend of Zelda Series", logo = "File:Zelda Logo TP.png", link = "The Legend of Zelda series", display = "The Legend of Zelda series", canonicity = "canon", code = "Series", }

-- Template:Game Link function p.Link(frame) local args = frame:getParent.args local game, nowarn = args[1], args.nowarn if game == nil or game == "" then return Error.printError("No game provided", "Category:"..Constants.catInvalidArgs, nowarn) end game = utilsString.trim(game) local link = p.link(game) if not link then return Error.printError(string.format("Invalid game ", game), "Category:"..Constants.catInvalidArgs, nowarn) end local correctGameCode = p.code(game) if game ~= correctGameCode then link = link..Error.warn(string.format(" should be written as  .", game, correctGameCode), "Category:"..Constants.catInvalidArgs) end return link end

-- Template:Franchise/Store * function p.AddToPreview(frame) -- Performance optimization local utilsArg = require("Module:UtilsArg") local utilsVar = require("Module:UtilsVar") local utilsMarkup = require("Module:UtilsMarkup") local doc = mw.loadData("Module:Franchise/Documentation/Data") local orderCounter = utilsVar.counter("canonOrder") local entryType = frame.args[1] local args, err = utilsArg.parse(frame:getParent.args, doc.Templates["Franchise/Store " .. entryType]) if err then return utilsMarkup.categories(err.categories) end args = utilsTable.merge({}, args, {		entryType = entryType,		link = p.deriveLink(entryType, args),		display = p.deriveDisplay(entryType, args),	}) if entryType == "Game" or entryType == "Book" or entryType == "TV" then args.canonOrder = orderCounter.value else args.canonOrder = "—" end if type == "Book" then args.phraseLink = p.derivePhraseLink(args) end utilsVar.add("rows", args) end function p.StoreOrder(frame) -- Performance optimization local utilsVar = require("Module:UtilsVar") local orderCounter = utilsVar.counter("canonOrder") return orderCounter.increment end function p.StoreLink(frame) return p.deriveLink(frame.args[1], frame:getParent.args) end function p.StoreDisplay(frame) return p.deriveDisplay(frame.args[1], frame:getParent.args) end function p.StorePhraseLink(frame) return p.derivePhraseLink(frame:getParent.args) end function p.deriveDisplay(entryType, args) if args.display ~= nil and args.display ~= "" then return args.display elseif entryType == "Book" then return h.deriveBookFields(args).display else return ("%s"):format(args.shortName) end end function p.deriveLink(entryType, args) if args.display ~= nil and args.display ~= "" then return args.link elseif entryType == "Book" then return h.deriveBookFields(args).link else return ("%s"):format(args.article, args.shortName) end end function p.derivePhraseLink(args) return h.deriveBookFields(args).phraseLink end

function p.Preview(frame) -- Performance optimization local utilsMarkup = require("Module:UtilsMarkup") local utilsLayout = require("Module:UtilsLayout") local utilsVar = require("Module:UtilsVar") local previewColumns = { common = {"canonOrder", "code", "link", "display", "logo", "releaseDate", "canonicity"}, Game = {"type", "graphics", "family", "remakeOf", "supersededBy"}, Book = {"type", "phraseLink", "authors", "basedOn"}, TV = {"type"}, Compilation = {"titles"}, Group = {"games"}, }	previewColumns.Game = utilsTable.concat(previewColumns.common, previewColumns.Game) previewColumns.Book = utilsTable.concat(previewColumns.common, previewColumns.Book) previewColumns.TV = utilsTable.concat(previewColumns.common, previewColumns.TV) previewColumns.Compilation = utilsTable.concat(previewColumns.common, previewColumns.Compilation) previewColumns.Group = utilsTable.concat(previewColumns.common, previewColumns.Group) local rows = utilsVar.get("rows") for _, row in ipairs(rows) do		row.logo = utilsMarkup.link(row.logo) end local rowGroups = utilsTable.groupBy(rows, "entryType") local titles = utilsLayout.table({		sortable = true,		headers = previewColumns.common,		rows = utilsTable.map(rows, utilsTable._toArray(previewColumns.common, ""))	}) local games = utilsLayout.table({		sortable = true,		headers = previewColumns.Game,		rows = utilsTable.map(rowGroups.Game, utilsTable._toArray(previewColumns.Game, ""))	}) local books = utilsLayout.table({		sortable = true,		headers = previewColumns.Book,		rows = utilsTable.map(rowGroups.Book, utilsTable._toArray(previewColumns.Book, ""))	}) local tv = utilsLayout.table({		sortable = true,		headers = previewColumns.TV,		rows = utilsTable.map(rowGroups.TV, utilsTable._toArray(previewColumns.TV, ""))	}) local compilations = utilsLayout.table({		sortable = true,		headers = previewColumns.Compilation,		rows = utilsTable.map(rowGroups.Compilation or {}, utilsTable._toArray(previewColumns.Compilation, ""))	}) local groups = utilsLayout.table({		sortable = true,		headers = previewColumns.Group,		rows = utilsTable.map(rowGroups.Group or {}, utilsTable._toArray(previewColumns.Group, ""))	}) local preview = utilsLayout.tabs({		{			label = "All Titles",			content = titles,		},		{			label = "Games",			content = games,		},		{			label = "Books",			content = books,		},		{			label = "TV Shows",			content = tv,		},		{			label = "Compilations",			content = compilations		},		{			label = "Groups",			content = groups,		}	}, { columns = 15 }) return preview end

function p.UploadField(frame) -- Performance optimization local utilsMarkup = require("Module:UtilsMarkup") local utilsVar = require("Module:UtilsVar") local rows = utilsVar.get("rows") local groups = utilsTable.groupBy(rows, "entryType") local mainGames, otherGames = utilsTable.partition(groups["Game"], {		canonicity = "canon"	}) local remakes = utilsTable.groupBy(mainGames, "remakeOf") local books = groups["Book"] local tvShows = groups["TV"] local sortedMainGames = {} for _, mainGame in ipairs(utilsTable.reverse(mainGames)) do		if not mainGame.remakeOf then table.insert(sortedMainGames, mainGame) for _, remake in ipairs(remakes[mainGame.code] or {}) do				table.insert(sortedMainGames, remake) end end end local result = "" result = result .. "**|None\n" result = result .. "**Series|The Legend of Zelda Series\n" result = h.append(result, "Main Series", sortedMainGames) result = h.append(result, "Other Games", otherGames) result = h.append(result, "Books, Comics, and Manga", books) result = h.append(result, "TV Shows", tvShows) return utilsMarkup.pre(result) end function h.append(result, title, entries) result = result .. "\n*"..title.."\n" for _, entry in ipairs(entries) do result = result .. string.format("**%s|%s\n", entry.code, entry.shortName) end return result end

function h.deriveBookFields(args) local ListPages = require("Module:List Pages") local utilsString = require("Module:UtilsString")

local subtitle, display, link, phraseLink local parens = string.find(args.shortName, "%s%([^)]+%)")	if parens then		subtitle = string.sub(args.shortName, 1, parens - 1)		local descriptor = string.sub(args.shortName, parens)		display = ("%s%s"):format(subtitle, descriptor)		link = ("%s"):format(args.article, display)		local authors = ListPages.main(utilsString.split(args.authors))		phraseLink = ("%s %s by %s"):format(args.article, subtitle, args.type, authors)	else		display = ("%s"):format(args.shortName)		link = ("%s"):format(args.article, args.shortName)		phraseLink = link	end	return {		display = display,		link = link,		phraseLink = phraseLink,	} end

-- QUERIES: ALL

function p.enum(options) if not options then return cache.enum end enum = utilsTable.clone(cache.enum) -- clone the read-only cache item so that we can modify it	if options.includeSeries then table.insert(enum, 1, "Series") end if options.includeCompilations then local codes = utilsTable.map(cache.compilations, "code") enum = utilsTable.concat(codes, enum) end if options.includeGroups then -- insert "groups" so as to not disrupt the release order. This matters for Template:Media (e.g. the Figher page, which uses SSB4) for _, group in ipairs(cache.groups) do			local i = 1 repeat i = i + 1 until i == #enum or p.isCanon(enum[i]) == p.isCanon(group.code) and p.releaseDate(enum[i]) >= p.releaseDate(group.code) table.insert(enum, i, group.code) end end enum.reference = "Data:Franchise" return enum end

function p.article(code) return h.get(code, "article") end

function p.canonicity(code) return h.get(code, "canonicity") end

function p.code(code) return h.get(code, "code") end

function p.display(code) return h.get(code, "display") end

function p.isCanon(code) return p.canonicity(code) == "canon" end

function p.link(code) return h.get(code, "link") end

function p.logo(code) return h.get(code, "logo") end

function p.releaseDate(code) return h.get(code, "releaseDate") end

function p.ShortName(frame) -- Performance optimization local utilsArg = require("Module:UtilsArg") local utilsMarkup = require("Module:UtilsMarkup")

local args, err = utilsArg.parse(frame.args, {		params = {			[1] = {				name = "code",				enum = p.enum({ includeSeries = true, includeCompilations = true, includeGroups = true, }),			}		}	})	if err then return utilsMarkup.categories(err.categories) end return p.shortName(args.code) end function p.shortName(code) return h.get(code, "shortName") end

function p.type(code) return h.get(code, "type") end

-- QUERIES: GAMES

function p.enumGames(includeSeries) if includeSeries then local enum = utilsTable.concat({"Series"}, cache.enumGames) enum.reference = "Data:Franchise" return enum end return cache.enumGames end

function p.baseGame(code) local baseGame = h.get(code, "remakeOf") local hasBaseGame = baseGame ~= nil and baseGame ~= "" return hasBaseGame and baseGame or code end

function p.family(code) return h.get(code, "family") end

function p.graphics(code) return h.get(code, "graphics") end

function p.hasRemakes(code) return utilsTable.hasKey(cache.remakes, string.lower(code)) end

function p.isRemake(code) return p.type(code) == "remake" end

function p.remakes(code) return utilsTable.clone(cache.remakes[string.lower(code)]) or {} end

-- QUERIES: BOOKS

function p.phraseLink(code) return h.get(code, "phraseLink") end

function h.get(code, prop) code = string.lower(code) if code == "series" then return series[prop] end local title = cache.titlesByCode[code] return title and title[prop] end

return p