local TemplateData = { serial = "2017-11-06",                        suite  = "TemplateData" } local plaintext = require("মডিউল:সরল পাঠ্য") --[=[ improve template:TemplateData ]=] local Config = {     -- multiple #invoke option names mapped into unique internal fields     cat            = "strange",     classNoNumTOC  = "suppressTOCnum", --  classParams    = "classTable",     cssParams      = "stylesTable",     cssParWrap     = "stylesTabWrap",     debug          = false,     docpageCreate  = "suffix",     docpageDetect  = "subpage",     msgDescMiss    = "solo", --  classTable     = false,    -- class for params table     loudly         = false,    -- show exported element, etc.     solo           = false,    -- complaint on missing description     strange        = false,    -- title of maintenance category     stylesTable    = false,    -- styles for params table     stylesTabWrap  = false,    -- styles for params table wrapper     subpage        = false,    -- pattern to identify subpage     suffix         = false,     -- subpage creation scheme     suppressTOCnum = false    -- class for TOC number suppression } local Data = {     div     = false,    -- <div class="mw-templatedata-doc-wrap">     got     = false,    -- table, initial templatedata object     heirs   = false,    -- table, params that are inherited     less    = false,    -- main description missing     lasting = false,    -- old syntax encountered     lazy    = false,    -- doc mode; do not generate effective ", j, true )         if k then            r = mw.text.trim( s:sub( j + 1,  k - 1 ) )         end     end     return r end -- find()  local function flat( adjust )     -- Remove formatting from text string     -- Parameter:     --     arglist  -- string, to be stripped, or nil     -- Returns string, or nil     local r     if adjust then         r = adjust:gsub( "\n", " " )         if r:find( "<noexport>", 1, true ) then             r = r:gsub( "(.*)", "" )         end         r = plaintext._main(r)         if r:find( "&", 1, true ) then             r = mw.text.decode( r )         end     end     return r end -- flat()  local function flush()     -- JSON encode narrowed input; obey unnamed (numerical) parameters     -- Returns <templatedata> JSON string     local r     if Data.tag then         r = mw.text.jsonEncode( Data.tag ):gsub( "%}$", "," )     else         r = "{"     end     r = r .. "\n\"params\":{"     if Data.order then         local sep = ""         local s         for i = 1, #Data.order do             s   = Data.order[ i ]             r   = string.format( "%s%s\n%s:%s",                                  r,                                  sep,                                  mw.text.jsonEncode( s ),                                  mw.text.jsonEncode( Data.params[ s ] ) )             sep = ",\n"         end -- for i = 1, #Data.order     end     r = r .. "\n}\n}"     return r end -- flush()  local function focus( access )     -- Check components; focus multilingual description, build trees     -- Parameter:     --     access  -- string, name of parameter, nil for root     local f = function ( a, at )                     local r                     if at then                         r = string.format( "params.%s", at )                     else                         r = "root"                     end                     if a then                         r = string.format( "%s.%s", r, a )                     end                     return r                 end     local parent     if access then         parent = Data.got.params[ access ]     else         parent = Data.got     end     if type( parent ) == "table" then         local elem, got, permit, s, scope, slot, tag, target         if access then             permit = Permit.params             if type( access ) == "number" then                 slot = tostring( access )             else                 slot = access             end         else             permit = Permit.root         end         for k, v in pairs( parent ) do             scope = permit[ k ]             if scope then                 s = type( v )                 if s == "string" then                     v = mw.text.trim( v )                 end                 if scope:find( s, 1, true ) then                     if scope:find( "I18N", 1, true ) then                         if s == "string" then                             elem = handleNoexportWhitespace( v )                         else                             local translated                             v, translated = faraway( v )                             if v then                                 if translated  and                                    k == "description" then                                     elem = { [ 1 ] = handleNoexportWhitespace( v ),                                              [ 2 ] = translated }                                 else                                     elem = handleNoexportWhitespace( v )                                 end                             else                                 elem = false                             end                         end                         if v then                             if scope:find( "nowiki", 1, true ) then                                 elem = mw.text.nowiki( v )                             else                                 v = flat( v )                             end                         end                     else                         if k == "params"  and  not access then                             v    = nil                             elem = nil                         elseif k == "format"  and  not access then                             v    = mw.text.decode( v )                             elem = v                         elseif k == "inherits" then                             elem = v                             if not Data.heirs then                                 Data.heirs = { }                             end                             Data.heirs[ slot ] = v                             v                  = nil                         elseif s == "string" then                             v    = mw.text.nowiki( v )                             elem = v                         else                             elem = v                         end                     end                     if type( elem ) ~= "nil" then                         if not target then                              if access then                                  if not Data.tree.params then                                      Data.tree.params = { }                                  end                                  Data.tree.params[ slot ] = { }                                  target = Data.tree.params[ slot ]                              else                                  Data.tree = { }                                  target    = Data.tree                              end                         end                         target[ k ] = elem                         elem        = false                     end                     if type( v ) ~= "nil" then                         if not tag then                             if access then                                 if not Data.params then                                     Data.params = { }                                 end                                 Data.params[ slot ] = { }                                 tag = Data.params[ slot ]                             else                                 Data.tag = { }                                 tag      = Data.tag                             end                         end                         tag[ k ] = v                     end                 else                     s = string.format( "Type %s bad for %s",                                        scope,  f( k, slot ) )                     Fault( s )                 end             else                 Fault( "Unknown component " .. f( k, slot ) )             end         end -- for k, v     else         Fault( f() .. " needs to be of object type" )     end end -- focus()  local function format()     -- Build presented documentation     -- Returns <div>     local r = mw.html.create( "div" )     local s = feasible( Data.tree, true )     if s then         r:node( s )     end     if Data.leading then         local toc = mw.html.create( "div" )         if Config.suppressTOCnum then             toc:addClass( Config.suppressTOCnum )         end         toc:css( "margin-top", "0.5em" )            :wikitext( "__TOC__" )         r:newline()          :node( toc )          :newline()     end     s = features()     if s then         if Data.leading then             r:node( mw.html.create( "h2" )                            :wikitext( getLocalizedText( "doc-params" ) ) )              :newline()         end         r:node( s )     end     if Data.tree and Data.tree.format then         local e, style         s = Data.tree.format:lower( Data.tree.format )         if s == "inline"  or  s == "block" then             style = "i"         else             style = "code"         end         r:node( mw.html.create( "p" )                        :wikitext( "Format: " )                        :node( mw.html.create( style )                                      :wikitext( s ) ) )     end     return r end -- format()  local function free()     -- Remove JSON comment lines     Data.source:gsub( "([{,\"'])(%s*\n%s*//.*\n%s*)([},\"'])",                       "%1%3" ) end -- free()  local function full()     -- Build HTML table for display from JSON data, and append an invisible     -- <templatedata> block.     Data.div = mw.html.create( "div" )                       :addClass( "mw-templatedata-doc-wrap" )     focus()     if Data.tag then         if type( Data.got.params ) == "table" then             for k, v in pairs( Data.got.params ) do                 focus( k )             end -- for k, v             if Data.heirs then                 fathers()             end         end     end     Data.div:node( format() )     if not Data.lazy then         Data.slim = flush()         if TemplateData.frame then             local div   = mw.html.create( "div" )             local tdata = { [ 1 ] = "templatedata",                             [ 2 ] = Data.slim }             Data.strip = TemplateData.frame:callParserFunction( "#tag",                                                                 tdata )             div:wikitext( Data.strip )             if Config.loudly then             	-- Display raw templatedata table all the time.                 Data.div:node( mw.html.create( "hr" ) )                 Data.div:node( div )             else             	-- Creates an expand link to check raw templatedata table.             	local wrapper = mw.html.create( "div" )                 wrapper:addClass( "mw-collapsible" )                 wrapper:addClass( "mw-collapsed" )                 wrapper:css( "font-size", "85%" )                 div:addClass( "mw-collapsible-content" )                 wrapper:wikitext( "Test of raw TemplateData output: " )                 wrapper:node( div )                 Data.div:node( wrapper )             end         end     end end -- full()  local function furnish( adapt, arglist )     -- Called by f, this function is the first to do any real work when the     -- module is invoked.     -- Parameter:     --     adapt    -- table, #invoke parameters     --     arglist  -- table, template parameters     -- Returns string --local spy=""     local source     for k, v in pairs( Config ) do         if adapt[ k ]  and  adapt[ k ] ~= "" then             Config[ v ] = adapt[ k ]         end     end -- for k, v     Config.loudly = faculty( arglist.debug or adapt.debug ) --if mw.site.server:find( "//de.wikipedia.beta.wmflabs.org", 1, true ) then --    Config.loudly  = true --end     Data.lazy     = faculty( arglist.lazy )  and  not Config.loudly     Data.leading  = faculty( arglist.TOC )     if arglist.JSON then         source = arglist.JSON     elseif arglist[ 1 ] then         local s     = mw.text.trim( arglist[ 1 ] )         local start = s:sub( 1, 1 )         if start == "<" then             Data.strip = s         elseif start == "{" then             source = s         elseif mw.ustring.sub( s, 1, 8 ) ==                mw.ustring.char( 127, 39, 34, 96, 85, 78, 73, 81 ) then -- <DEL> ' " ` U N I Q             Data.strip = s         end     end     if not source then         Data.title = mw.title.getCurrentTitle()         source = find()         if not source  and            Config.subpage  and  Config.suffix  and            not Data.title.text:match( Config.subpage ) then             local s = string.format( Config.suffix,                                      Data.title.prefixedText )             Data.title = mw.title.new( s )             if Data.title.exists then                 source = find()             end         end --if source  and --           ( source:find( "|", 1, true ) or --             source:find( "}}", 1, true ) ) then --                      --  <ref --spy=string.format( "category:%s", Config.strange ) --end     end     if not Data.lazy  and  Config.subpage then         if not Data.title then             Data.title = mw.title.getCurrentTitle()         end         Data.lazy = Data.title.text:match( Config.subpage )     end     TemplateData.getPlainJSON( source )     return finalize() --return spy .. finalize() end -- furnish()  TemplateData.failsafe = function ( assert ) 	-- Checks the age of this implementation against some minimum ("assert").     local r     if not assert  or  assert <= TemplateData.serial then         r = TemplateData.serial     else         r = false     end     return r end -- TemplateData.failsafe()  TemplateData.getPlainJSON = function ( adapt )     -- Reduce enhanced JSON data to plain text localized JSON     -- Parameter:     --     adapt  -- string, with enhanced JSON     -- Returns string, or not     if type( adapt ) == "string" then         Data.source = adapt         free()         Data.got = mw.text.jsonDecode( Data.source )         if Data.got then             full()             if Data.lasting then                 Fault( "deprecated type syntax" )             end             if Data.less then                 Fault( Config.solo )             end         elseif not Data.strip then             Fault( "fatal JSON error" )         end     end     return Data.slim end -- TemplateData.getPlainJSON()  TemplateData.test = function ( adapt, arglist )     TemplateData.frame = mw.getCurrentFrame()     return furnish( adapt, arglist ) end -- TemplateData.test()  -- Export local p = { }  p.f = function ( frame )     -- The entry point for templates invoking the module.     -- Just wraps furnish in an exception handler.     local lucky, result     TemplateData.frame = frame     lucky, result = pcall( furnish, frame.args, frame:getParent().args )     if not lucky then         Fault( "INTERNAL: " .. result )         result = failures()     end     return result end -- p.f()  p.failsafe = function ( frame )     -- Versioning interface     local s = type( frame )     local since     if s == "table" then         since = frame.args[ 1 ]     elseif s == "string" then         since = frame     end     if since then         since = mw.text.trim( since )         if since == "" then             since = false         end     end     return TemplateData.failsafe( since )  or  "" end -- p.failsafe()  p.TemplateData = function ()     -- Module interface     return TemplateData end  return p