Module:Cite

From Undertale Yellow Wiki
Jump to navigation Jump to search

Generates citations across the wiki to ensure standard formatting. The module accepts several different types of citations and processes each differently, based on the f table's functions. When the module is called without a type, it acts as a citation needed template.

Documentation

Package items

cite.main(frame) (function)
Template entrypoint for Template:Cite.
Parameter: frame Scribunto frame object (table)
Returns: Citation text (string)
f.twitter(args) (function)
Handles Twitter citations. Twitter citations receive arguments in this order:
  • Twitter snowflake
  • Tweet author's handle
  • Citation from the tweet
  • (Optional) Timestamp of the tweet's archival
  • (Optional) Whether the original tweet link is dead
Parameter: args Citation type arguments (table)
Returns: Citation text (string)
f.game(args) (function)
Handles citations of text in the game. Game citations receive arguments in this order:
  • Quotation
  • Quote author and the situation in which they made the quote
Parameter: args Citation type arguments (table)
Returns: Citation text (string)
f.youtube(args) (function)
Handles citations of YouTube videos. YouTube citations receive arguments in this order:
  • YouTube video ID
  • Video title
  • (Optional) Time at which the video plays
Parameter: args Citation type arguments (table)
Returns: Citation text (string)
f.tumblr(args) (function)
Handles Tumblr citations. Tumblr citations receive arguments in this order:
  • Tumblr name of the author
  • Tumblr post ID
  • Citation from the post
  • Date in YYYY-MM-DD format (or any other standard format)
Parameter: args Citation type arguments (table)
Returns: Citation text (string)
f.code(args) (function)
Handles citations of the game's code. Code citations receive arguments in this order:
  • GML script name
  • (Optional) Starting line number
  • (Optional) Ending line number
Parameter: args Citation type arguments (table)
Returns: Citation text (string)
See also: https://github.com/KockaAdmiralac/deltarune-viewer
f.news(args) (function)
Handles citations from news sources. News citations receive arguments in this order:
  • Excerpt from the news
  • News post title
  • News site name
  • News post URL
  • News post date
  • (Optional) First name of the author
  • (Optional) Last name of the author
Parameter: args Citation type arguments (table)
Returns: Citation text (string)
f.twitch(args) (function)
Handles citations from Twitch clips. Twitch clip citations receive arguments in this order:
  • Clip URL segment (the part after https://clips.twitch.tv/)
  • Clip title
  • Twitch username of the streamer
  • Stream date (not clipping date)
Parameter: args Citation type arguments (table)
Returns: Citation text (string)


--- Generates citations across the wiki to ensure standard formatting.
--  The module accepts several different types of citations and processes each
--  differently, based on the <code>f</code> table's functions. When the module
--  is called without a type, it acts as a citation needed template.
--  @module             cite
--  @alias              p
--  @require            Dev:Date
--  @require            Dev:User error
--  @require            Dev:Yesno
--  @require            Module:Tags
--  @author             [[User:KockaAdmiralac|KockaAdmiralac]]
--  <nowiki>
local p = {}

-- Module dependencies
local Date = require('Dev:Date')
local userError = require('Dev:User error')
local yesno = require('Dev:Yesno')
local tags = require('Module:Tags')
local data = mw.loadData('Module:Cite/data')
local title = mw.title.getCurrentTitle()

--  Private logic.

--- Wrapper for <code>userError</code> that places the page under the Pages with
--  user errors category.
--  @function           err
--  @param              {string} text Text to display as an error
--  @return             {string} Wikitext with the error and category
--  @local
local function err(text)
    return userError(text, 'Pages with user errors')
end

--- Checks whether a given date string is a valid date.
--  @function           valid_date
--  @param              {string} d Date string to check
--  @return             {bool} Whether the string is a valid date
--  @local
function valid_date(d)
    return pcall(function()
        Date(d)
    end)
end

--- Table of possible citation types and the way they are processed.
--  Each type has a function associated with it that gets passed the arguments
--  after the type, does validation of these arguments and returns the whole
--  citation text.
--  @table              cite_functions
--  @alias              f
local f = {}

--- Handles Twitter citations.
--  Twitter citations receive arguments in this order:
--  * Twitter snowflake
--  * Tweet author's handle
--  * Citation from the tweet
--  * (Optional) Timestamp of the tweet's archival
--  * (Optional) Whether the original tweet link is dead
--  @function           f.twitter
--  @param              {table} args Citation type arguments
--  @return             {string} Citation text
function f.twitter(args)
    -- Check validity of arguments
    if not args[1] or not tonumber(args[1]) then
        return err('Tweet snowflake invalid or not specified')
    end
    if not args[2] or not args[3] then
        return err('Tweet author or citation not specified')
    end
    -- Twitter snowflake date extraction
    -- Credits: https://github.com/client9/snowflake2time
    local snowflake = tonumber(args[1])
    local epoch = math.floor(snowflake / 4194304 + 1288834974657)
    local date1 = Date(math.floor(epoch / 1000))
    -- Format citation
    local deadurl = yesno(args[5], false)
    local archived = yesno(args[4], true)
    local str = {
        '\'\'',
        args[3],
        '\'\' - ['
    }
    if deadurl and archived then
        table.insert(str, 'https://web.archive.org/web/')
        table.insert(str, args[4])
        table.insert(str, '/')
    end
    table.insert(str, 'https://twitter.com/')
    table.insert(str, args[2])
    table.insert(str, '/status/')
    table.insert(str, args[1])
    if data.twitter[args[2]] then
        table.insert(str, ' ')
        table.insert(str, data.twitter[args[2]])
        table.insert(str, ' (@')
        table.insert(str, args[2])
        table.insert(str, ')')
    else
        table.insert(str, ' @')
        table.insert(str, args[2])
    end
    table.insert(str, ' on Twitter,] ')
    table.insert(str, date1:fmt('%B %d, %Y.'))
    if deadurl then
        if archived then
            table.insert(str, ' Archived on ')
            table.insert(str, Date(args[4]):fmt('%B %d, %Y.'))
        else
            table.insert(str, ' \'\'\'[deleted]\'\'\'')
        end
    end
    return table.concat(str)
end

--- Handles citations of text in the game.
--  Game citations receive arguments in this order:
--  * Quotation
--  * Quote author and the situation in which they made the quote
--  @function           f.game
--  @param              {table} args Citation type arguments
--  @return             {string} Citation text
function f.game(args)
    if not args[1] then
        return err('Quote not specified')
    end
    if not args[2] then
        return err('Quote author not specified')
    end
    return table.concat({
        '\'\'',
        tags.replace(args[1]),
        '\'\' - ',
        args[2]
    })
end

--- Handles citations of YouTube videos.
--  YouTube citations receive arguments in this order:
--  * YouTube video ID
--  * Video title
--  * (Optional) Time at which the video plays
--  @function           f.youtube
--  @param              {table} args Citation type arguments
--  @return             {string} Citation text
function f.youtube(args)
    if not args[1] or not args[2] then
        return err('Video ID or title not specified')
    end
    local str = {
        '\'\'',
        args[2],
        '\'\' - [https://youtu.be/',
        args[1]
    }
    if args[3] then
        table.insert(str, '?t=')
        table.insert(str, args[3])
    end
    table.insert(str, ' YouTube]')
    return table.concat(str)
end

--- Handles Tumblr citations.
--  Tumblr citations receive arguments in this order:
--  * Tumblr name of the author
--  * Tumblr post ID
--  * Citation from the post
--  * Date in YYYY-MM-DD format (or any other standard format)
--  @function           f.tumblr
--  @param              {table} args Citation type arguments
--  @return             {string} Citation text
function f.tumblr(args)
    if not args[1] or not args[3] then
        return err('Author or quote not specified')
    end
    if not args[2] or not tonumber(args[2]) then
        return err('Post ID invalid or not specified')
    end
    if not args[4] or not valid_date(args[4]) then
        return err('Date invalid or not specified')
    end
    return table.concat({
        '\'\'',
        tags.replace(args[3]),
        '\'\' - [http://',
        args[1],
        '.tumblr.com/post/',
        args[2],
        ' ',
        args[1],
        ' on Tumblr,] ',
        Date(args[4]):fmt('%B %d, %Y.')
    })
end

--- Handles citations of the game's code.
--  Code citations receive arguments in this order:
--  * GML script name
--  * (Optional) Starting line number
--  * (Optional) Ending line number
--  @function           f.code
--  @param              {table} args Citation type arguments
--  @return             {string} Citation text
--  @see                https://github.com/KockaAdmiralac/deltarune-viewer
function f.code(args)
    local str = {}
    if not args[1] then
        return err('Script name not specified')
    end
    if (args[2] and not tonumber(args[2])) or (args[3] and not tonumber(args[3])) then
        return err('Line number is not a number')
    end
    if data.script_repo ~= nil then
        str = {
            '[',
            data.script_repo,
            '/',
            args[1],
            '.html',
        }
        if args[2] then
            table.insert(str, '#L')
            table.insert(str, args[2])
        end
        table.insert(str, ' ')
        table.insert(str, args[1])
        table.insert(str, ' script]')
    else
        str = {
            args[1],
            ' script'
        }
    end
    if args[2] then
        table.insert(str, ', line')
        if args[3] then
            table.insert(str, 's ')
            table.insert(str, args[2])
            table.insert(str, '–')
            table.insert(str, args[3])
        else
            table.insert(str, ' ')
            table.insert(str, args[2])
        end
    end
    return table.concat(str)
end

--- Handles citations from news sources.
--  News citations receive arguments in this order:
--  * Excerpt from the news
--  * News post title
--  * News site name
--  * News post URL
--  * News post date
--  * (Optional) First name of the author
--  * (Optional) Last name of the author
--  @function           f.news
--  @param              {table} args Citation type arguments
--  @return             {string} Citation text
function f.news(args)
    if not args[1] then
        return err('Relevant news post excerpt not specified')
    end
    if not args[2] then
        return err('News post title not specified')
    end
    if not args[3] then
        return err('News site name not specified')
    end
    if not args[4] then
        return err('News post URL not specified')
    end
    if not args[5] or not valid_date(args[5]) then
        return err('News post date invalid or not specified')
    end
    local author = {}
    if args[6] then
        if args[7] then
            table.insert(author, args[7])
            table.insert(author, ', ')
        end
        table.insert(author, args[6])
        table.insert(author, ', ')
    end
    return table.concat({
        '\'\'',
        tags.replace(args[1]),
        '\'\' - [',
        args[4],
        ' ',
        args[2],
        '] (',
        table.concat(author),
        Date(args[5]):fmt('%B %d, %Y.'),
        ') \'\'',
        args[3],
        '\'\'.'
    })
end

--- Handles citations from Twitch clips.
--  Twitch clip citations receive arguments in this order:
--  * Clip URL segment (the part after https://clips.twitch.tv/)
--  * Clip title
--  * Twitch username of the streamer
--  * Stream date (not clipping date)
--  @function f.twitch
--  @param {table} args Citation type arguments
--  @return {string} Citation text
function f.twitch(args)
    if not args[1] then
        return err('Clip URL segment not specified')
    end
    if not args[2] then
        return err('Clip title not specified')
    end
    if not args[3] then
        return err('Streamer username not specified')
    end
    if not args[4] or not valid_date(args[4]) then
        return err('Stream date invalid or not specified')
    end
    return table.concat({
        '"\'\'[https://clips.twitch.tv/',
        args[1],
        ' "',
        args[2],
        ',]\'\'" a clip from [https://twitch.tv/',
        mw.ustring.lower(args[3]),
        ' @',
        args[3],
        '\'s] Twitch stream on ',
        Date(args[4]):fmt('%B %d, %Y.')
    })
end

-- Package items.

--- Template entrypoint for [[Template:Cite]].
--  @function           p.main
--  @param              {table} frame Scribunto frame object
--  @return             {string} Citation text
function p.main(frame)
    local args = frame:getParent().args
    local t = args[1]
    if t then
        if f[t] then
            local nargs = {}
            for i, v in ipairs(args) do
                if i > 1 then
                    nargs[i - 1] = v
                end
            end
            return f[t](nargs);
        else
            return err('Invalid citation type specified')
        end
    else
        -- {{cite}} was used
        local str = '<sup>&#91;[[w:c:ut:Project:Manual of Style#Citation needed|<span title="This statement needs proper citation.">citation needed</span>]]&#93;</sup>'
        if title.namespace == 0 or title.namespace == 14 then
            return str .. '[[Category:Articles lacking sources]]'
        else
            return str
        end
    end
end

return p