הבדלים בין גרסאות בדף "יחידה:ParamValidator"

קפיצה לניווט קפיצה לחיפוש
נוספו 1,854 בתים ,  01:41, 22 בדצמבר 2021
ביטול גרסה 19053 של מוטל'ה (שיחה)
מ (גרסה אחת יובאה)
 
(ביטול גרסה 19053 של מוטל'ה (שיחה))
תגית: ביטול
 
(3 גרסאות ביניים של 3 משתמשים אינן מוצגות)
שורה 4: שורה 4:


the source of this module is in //he.wikipedia.org/wiki/Module:ParamValidator
the source of this module is in //he.wikipedia.org/wiki/Module:ParamValidator
main purpose: use "templatedata" to verify the parameters passed to a template
Terminology: "numeric parameter" means order-based parameter. e.g. if the template is transcluded like so {{x  | k |  | a = m | b = }}
"a" and "b" are "named" parameters, and there are 2 "numeric", or order based parameters, 1 and 2.
we say that the value of a is "m", the value of 1 is "k", and "b" and 2 are "empty".


This module exports two functions: calculateViolations( frame, subpages ), and validateParams( frame ).  
This module exports two functions: calculateViolations( frame, subpages ), and validateParams( frame ).  
שורה 35: שורה 41:
it expects a parameter named "options", which contains the definition of the output. typically, it's used by placing something like so:
it expects a parameter named "options", which contains the definition of the output. typically, it's used by placing something like so:


<includeonly>{{#invoke:ParamValidatoe | validateParams | options = {{PV default options}} }}</includeonly>
<includeonly>{{#invoke:ParamValidator | validateParams | options = {{PV default options}} }}</includeonly>


at the top of the template (be mindful not to add extra spaces and newlines to the template).
at the top of the template (be mindful not to add extra spaces and newlines to the template).
to bypass some mediawiki limitation, it is also possible to pass the options as "module", like so (use one of the two, but not both):
<includeonly>{{#invoke:ParamValidator | validateParams | module_options = Module:PV default options}} }}</includeonly>
the first form expects a template named "Template:PV default options" which contains the options, and the 2nd form expects a module,
suitable for mw.loadData(), which returns a map of namespace => options (i.e. { [0] = <options>, [2] => <options> } .... )


the options parameter should be a JSON-encoded string, defining the output, and some special behaviors.  
the options parameter should be a JSON-encoded string, defining the output, and some special behaviors.  
שורה 91: שורה 102:
typically, this JSON structure will be placed in a separate template, and retrieved for the module-use as shown above.
typically, this JSON structure will be placed in a separate template, and retrieved for the module-use as shown above.
<includeonly>{{#invoke:ParamValidatoe | validateParams | options = {{PV default options}} | options1 = {"key":"value"} }}</includeonly>
<includeonly>{{#invoke:ParamValidator | validateParams | options = {{PV default options}} | options1 = {"key":"value"} }}</includeonly>
"key" can override any of the options fields described above.
"key" can override any of the options fields described above.


שורה 111: שורה 122:
if type( module_options ) ~= 'table' then return {} end
if type( module_options ) ~= 'table' then return {} end
local title = mw.title.getCurrentTitle()
local title = mw.title.getCurrentTitle()
return module_options[ title.namespace ] or module_options[ title.nsText ] or {}  
local local_ptions = module_options[ title.namespace ] or module_options[ title.nsText ] or {}  
for k, v in pairs( local_ptions ) do options[k] = v end
end
end
שורה 147: שורה 159:
local capture =  templateContent and mw.ustring.match( templateContent, '<templatedata%s*>(.*)</templatedata%s*>' ) -- templatedata as text
local capture =  templateContent and mw.ustring.match( templateContent, '<templatedata%s*>(.*)</templatedata%s*>' ) -- templatedata as text
-- capture = capture and mw.ustring.gsub( capture, '"(%d+)"', tonumber ) -- convert "1": {} to 1: {}. frame.args uses numerical indexes for order-based params.
-- capture = capture and mw.ustring.gsub( capture, '"(%d+)"', tonumber ) -- convert "1": {} to 1: {}. frame.args uses numerical indexes for order-based params.
if capture then return pcall( mw.text.jsonDecode, capture ) end
local trailingComma = capture and mw.ustring.find( capture, ',%s*[%]%}]' ) -- look for ,] or ,} : jsonDecode allows it, but it's verbotten in json
if capture and not trailingComma then return pcall( mw.text.jsonDecode, capture ) end
return false
return false
end
end
שורה 168: שורה 181:
-- if second parameter is nil, only tempalte page will be searched for templatedata.
-- if second parameter is nil, only tempalte page will be searched for templatedata.
function calculateViolations( frame, subpages )
function calculateViolations( frame, subpages )
-- used for parameter type validy test. keyed by TD 'type' string. values are function(val) returning bool.
-- used for parameter type validy test. keyed by TD 'type' string. values are function(val) returning bool.
local type_validators = {  
local type_validators = {  
שורה 183: שורה 195:
local templatedata = readTemplateData( td_source )
local templatedata = readTemplateData( td_source )
local td_params = templatedata and templatedata.params
local td_params = templatedata and templatedata.params
local all_aliases = {}
local all_aliases, all_series = {}, {}
if not td_params then return { ['no-templatedata'] = { [''] = '' } } end
if not td_params then return { ['no-templatedata'] = { [''] = '' } } end
שורה 193: שורה 205:
for _, p in pairs( td_params ) do for _, alias in ipairs( p.aliases or {} ) do  
for _, p in pairs( td_params ) do for _, alias in ipairs( p.aliases or {} ) do  
all_aliases[alias] = p
all_aliases[alias] = p
if tonumber(alias) then all_aliases[tonumber(alias)] = p end
end end
end end
 
-- handle undeclared and deprecated
-- handle undeclared and deprecated
local already_seen = {}
local already_seen = {}
local series = frame.args['series']
for p_name, value in pairs( t_args ) do
for p_name, value in pairs( t_args ) do
local tp_param, noval, numeric, table_name = td_params[p_name] or all_aliases[p_name], util.empty( value ), tonumber( p_name )
local tp_param, noval, numeric, table_name = td_params[p_name] or all_aliases[p_name], util.empty( value ), tonumber( p_name )
local hasval = not noval
if not tp_param and series then -- 2nd chance. check to see if series
for s_name, p in pairs(td_params) do
if mw.ustring.match( p_name, '^' .. s_name .. '%d+' .. '$') then
-- mw.log('found p_name '.. p_name .. '  s_name:' .. s_name, ' p is:', p) debugging series support
tp_param = p
end -- don't bother breaking. td always correct.
end
end
if not tp_param then -- not in TD: this is called undeclared
if not tp_param then -- not in TD: this is called undeclared
שורה 205: שורה 229:
noval and numeric and 'empty-undeclared-numeric' or
noval and numeric and 'empty-undeclared-numeric' or
noval and not numeric and 'empty-undeclared' or
noval and not numeric and 'empty-undeclared' or
not noval and numeric and 'undeclared-numeric' or
hasval and numeric and 'undeclared-numeric' or
'undeclared' -- tzvototi nishar.
'undeclared' -- tzvototi nishar.
else -- in td: test for depracation and mistype. if deprecated, no further tests
else -- in td: test for deprecation and mistype. if deprecated, no further tests
table_name = tp_param.deprecated and not noval and 'deprecated'  
table_name = tp_param.deprecated and hasval and 'deprecated'  
or tp_param.deprecated and noval and 'empty-deprecated'  
or tp_param.deprecated and noval and 'empty-deprecated'  
or not compatible( tp_param.type, value ) and 'incompatible'  
or not compatible( tp_param.type, value ) and 'incompatible'  
or already_seen[tp_param] and 'duplicate'
or not series and already_seen[tp_param] and hasval and 'duplicate'
already_seen[tp_param] = true
already_seen[tp_param] = hasval
end
end
-- report it.
-- report it.
שורה 235: שורה 259:
return res
return res
end
-- wraps report in hidden frame
function wrapReport(report, template_name, options)
if util.empty( report ) then return '' end
local naked = mw.title.new( template_name )['text']
mw.log(report)
report = ( options['wrapper-prefix'] or "<div class = 'paramvalidator-wrapper'><span class='paramvalidator-error'>" )
.. report
.. ( options['wrapper-suffix'] or "</span></div>" )
report = mw.ustring.gsub( report, 'tname_naked', naked )
report = mw.ustring.gsub( report, 'templatename', template_name )
return report
end
end


שורה 240: שורה 279:
function validateParams( frame )
function validateParams( frame )
local options, report, template_name = util.extract_options( frame ), '', frame:getParent():getTitle()
local options, report, template_name = util.extract_options( frame ), '', frame:getParent():getTitle()
local wrap_report = function()
if util.empty( report ) then return '' end
local naked = mw.title.new( template_name )['text']
report = ( options['wrapper-prefix'] or "<div class = 'paramvalidator-wrapper'>" )
.. report
.. ( options['wrapper-suffix'] or "</div>" )
report = mw.ustring.gsub( report, 'tname_naked', naked )
report = mw.ustring.gsub( report, 'templatename', template_name )
return report
end


local ignore = function( p_name )
local ignore = function( p_name )
שורה 311: שורה 337:
if offenders > 1 then report_params( 'multiple' ) end
if offenders > 1 then report_params( 'multiple' ) end
if offenders ~= 0 then report_params( 'any' ) end -- could have tested for empty( report ), but since we count them anyway...
if offenders ~= 0 then report_params( 'any' ) end -- could have tested for empty( report ), but since we count them anyway...
return wrap_report()
return wrapReport(report, template_name, options)
end
end


return {
return {
['validateparams'] = validateParams,
['validateparams'] = validateParams,
['calculateViolations'] = calculateViolations
['calculateViolations'] = calculateViolations,
['wrapReport'] = wrapReport
}
}

תפריט ניווט