Module: Phlex::Validator::HTML

Extended by:
Literal::Types
Defined in:
lib/phlex/validator/html.rb,
lib/phlex/validator/html/mixin.rb,
lib/phlex/validator/html/attributes/a.rb,
lib/phlex/validator/html/attributes/q.rb,
lib/phlex/validator/html/attributes/br.rb,
lib/phlex/validator/html/attributes/hr.rb,
lib/phlex/validator/html/attributes/li.rb,
lib/phlex/validator/html/attributes/ol.rb,
lib/phlex/validator/html/attributes/td.rb,
lib/phlex/validator/html/attributes/th.rb,
lib/phlex/validator/html/attributes/tr.rb,
lib/phlex/validator/html/attributes/ul.rb,
lib/phlex/validator/html/attributes/bdo.rb,
lib/phlex/validator/html/attributes/col.rb,
lib/phlex/validator/html/attributes/del.rb,
lib/phlex/validator/html/attributes/dfn.rb,
lib/phlex/validator/html/attributes/div.rb,
lib/phlex/validator/html/attributes/img.rb,
lib/phlex/validator/html/attributes/ins.rb,
lib/phlex/validator/html/attributes/map.rb,
lib/phlex/validator/html/attributes/pre.rb,
lib/phlex/validator/html/attributes/area.rb,
lib/phlex/validator/html/attributes/base.rb,
lib/phlex/validator/html/attributes/body.rb,
lib/phlex/validator/html/attributes/data.rb,
lib/phlex/validator/html/attributes/form.rb,
lib/phlex/validator/html/attributes/head.rb,
lib/phlex/validator/html/attributes/html.rb,
lib/phlex/validator/html/attributes/link.rb,
lib/phlex/validator/html/attributes/meta.rb,
lib/phlex/validator/html/attributes/slot.rb,
lib/phlex/validator/html/attributes/time.rb,
lib/phlex/validator/html/attributes/audio.rb,
lib/phlex/validator/html/attributes/embed.rb,
lib/phlex/validator/html/attributes/input.rb,
lib/phlex/validator/html/attributes/label.rb,
lib/phlex/validator/html/attributes/meter.rb,
lib/phlex/validator/html/attributes/style.rb,
lib/phlex/validator/html/attributes/table.rb,
lib/phlex/validator/html/attributes/tbody.rb,
lib/phlex/validator/html/attributes/tfoot.rb,
lib/phlex/validator/html/attributes/thead.rb,
lib/phlex/validator/html/attributes/track.rb,
lib/phlex/validator/html/attributes/video.rb,
lib/phlex/validator/html/attributes/button.rb,
lib/phlex/validator/html/attributes/canvas.rb,
lib/phlex/validator/html/attributes/dialog.rb,
lib/phlex/validator/html/attributes/global.rb,
lib/phlex/validator/html/attributes/iframe.rb,
lib/phlex/validator/html/attributes/object.rb,
lib/phlex/validator/html/attributes/option.rb,
lib/phlex/validator/html/attributes/output.rb,
lib/phlex/validator/html/attributes/script.rb,
lib/phlex/validator/html/attributes/select.rb,
lib/phlex/validator/html/attributes/source.rb,
lib/phlex/validator/html/attributes/caption.rb,
lib/phlex/validator/html/attributes/details.rb,
lib/phlex/validator/html/attributes/fieldset.rb,
lib/phlex/validator/html/attributes/progress.rb,
lib/phlex/validator/html/attributes/template.rb,
lib/phlex/validator/html/attributes/textarea.rb,
lib/phlex/validator/html/attributes/blockquote.rb,
lib/phlex/validator/html/attributes/fencedframe.rb

Overview

TODO: Only one element in the document can have the ‘autofocus` attribute.

Defined Under Namespace

Modules: Mixin

Constant Summary collapse

BCP47Language =
_Union(
	"ar-SA",
	"bn-BD",
	"bn-IN",
	"cs-CZ",
	"da-DK",
	"de-AT",
	"de-CH",
	"de-DE",
	"el-GR",
	"en-AU",
	"en-CA",
	"en-GB",
	"en-IE",
	"en-IN",
	"en-NZ",
	"en-US",
	"en-ZA",
	"es-AR",
	"es-CL",
	"es-CO",
	"es-ES",
	"es-MX",
	"es-US",
	"fi-FI",
	"fr-BE",
	"fr-CA",
	"fr-CH",
	"fr-FR",
	"he-IL",
	"hi-IN",
	"hu-HU",
	"id-ID",
	"it-CH",
	"it-IT",
	"ja-JP",
	"ko-KR",
	"nl-BE",
	"nl-NL",
	"no-NO",
	"pl-PL",
	"pt-BR",
	"pt-PT",
	"ro-RO",
	"ru-RU",
	"sk-SK",
	"sv-SE",
	"ta-IN",
	"ta-LK",
	"th-TH",
	"tr-TR",
	"zh-CN",
	"zh-HK",
	"zh-T",
)
Attribute =

Any attribute allowed by Phlex

_Union(
	nil,
	true,
	false,
	String,
	Symbol,
	Integer,
	Float,
	_Array(
		_Deferred { Attribute }
	),
	_Hash(
		_Union(String, Symbol),
		_Deferred { Attribute }
	)
)
Value =

Like Attribute, but excluding Hashes, which in most cases define other attributes

_Union(
	nil,
	true,
	false,
	String,
	Symbol,
	Integer,
	Float,
	Array(
		_Deferred { Value }
	)
)
SPECIFIC_YEAR =

YYYY

/(?<yyyy>\d{4,})/
ABSTRACT_MONTH =

MM

/(?<mm>(?:0[1-9]|1[0-2]))/
ABSTRACT_WEEK =

WW

/(?<ww>(?:0[1-9]|[1-4]\d|5[0-3]))/
ABSTRACT_DAY =

DD

/(?<dd>(?:0[1-9]|[1-2]\d|3[0-1]))/
SPECIFIC_MONTH =

YYYY-MM

/#{SPECIFIC_YEAR}-#{ABSTRACT_MONTH}/
SPECIFIC_WEEK =

YYYY-WWW

/#{SPECIFIC_YEAR}-W#{ABSTRACT_WEEK}/
SPECIFIC_DATE =

YYYY-MM-DD

/#{SPECIFIC_YEAR}-#{ABSTRACT_MONTH}-#{ABSTRACT_DAY}/
ABSTRACT_DAY_OF_MONTH =

MM-DD

/#{ABSTRACT_MONTH}-#{ABSTRACT_DAY}/
ABSTRACT_HOUR =

HH

/(?<h>([0-1]\d|2[0-3]))/
ABSTRACT_MINUTE =

MM

/(?<m>([0-5]\d))/
ABSTRACT_SECOND =

SS

/(?<s>([0-5]\d))/
ABSTRACT_MILLISECOND =

mmm

/(?<ms>(?:\d{3}))/
ABSTRACT_TIME =

HH:MM(:SS(.mmm))

/#{ABSTRACT_HOUR}:#{ABSTRACT_MINUTE}(?::#{ABSTRACT_SECOND}(?:\.#{ABSTRACT_MILLISECOND})?)?/
TIME_ZONE_OFFSET =

HHMM | -HHMM | HH:MM | -HH:MM

/(?:Z|(?:\+|-)(?:[0-1][0-9]|2[0-3]):?(?:[0-5][0-9]))/
SPECIFIC_LOCAL_DATE_TIME =

YYYY-MM-DDTHH:MM(:SS(.mmm)) | YYYY-MM-DD HH:MM(:SS(.mmm))

/#{SPECIFIC_DATE}(?:T| )#{ABSTRACT_TIME}/
SPECIFIC_DATE_TIME =

YYYY-MM-DDTHH:MM(:SS(.mmm))Z | YYYY-MM-DD HH:MM(:SS(.mmm))Z

/#{SPECIFIC_DATE}(?:T| )#{ABSTRACT_TIME}#{TIME_ZONE_OFFSET}/
INFORMAL_DURATION =

DDd HHh MMm SSs

/\A(?:(\d+d)(?: (\d+h))?(?: (\d+m))?(?: (\d+s))?|(\d+h)(?: (\d+m))?(?: (\d+s))?|(\d+m)(?: (\d+s))?|(\d+s))?\z/
PERIOD =

PdDThHmMsS

/P(?<d>\d+D)?T(?<h>\d+H)?(?<m>\d+M)?(?<s>\d+(?:\.\d{1,3})?S)/
AbstractTime =
_String(/\A#{ABSTRACT_TIME}\z/)
YearString =
_String(
	Pattern(/\A#{SPECIFIC_YEAR}\z/) { |yyyy:|
		yyyy.to_i > 0
	}
)
WeekString =
_String(
	Pattern(SPECIFIC_WEEK) { |yyyy:, ww:|
		year, week = yyyy.to_i, ww.to_i

		next false unless year > 0

		if week <= 52
			true
		else
			first_day_of_year = (1 + (5 * ((year - 1) % 4)) + (4 * ((year - 1) % 100)) + (6 * ((year - 1) % 400))) % 7

			first_day_of_year == 4 || (first_day_of_year == 3 && leap_year?(year))
		end
	}
)
MonthString =
_String(
	Pattern(/\A#{SPECIFIC_MONTH}\z/) { |yyyy:, mm:|
		year, month = yyyy.to_i, mm.to_i

		year > 0
	}
)
MONTH_LENGTHS =
[nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31].freeze
AbstractDayOfMonth =
Pattern(/\A#{ABSTRACT_DAY_OF_MONTH}\z/) do |mm:, dd:|
	month, day = mm.to_i, dd.to_i
	day <= MONTH_LENGTHS[month] || (month == 2 && day == 29)
end
DateString =
_String(
	Pattern(/\A#{SPECIFIC_DATE}\z/) { |yyyy:, mm:, dd:|
		valid_date?(yyyy.to_i, mm.to_i, dd.to_i)
	}
)
LocalDateTimeString =
_String(
	Pattern(/\A#{SPECIFIC_LOCAL_DATE_TIME}\z/) { |yyyy:, mm:, dd:, **|
		valid_date?(yyyy.to_i, mm.to_i, dd.to_i)
	}
)
DateTimeString =
_String(
	Pattern(/\A#{SPECIFIC_DATE_TIME}\z/) { |yyyy:, mm:, dd:, **|
		valid_date?(yyyy.to_i, mm.to_i, dd.to_i)
	}
)
DurationString =
_String(/\A#{INFORMAL_DURATION}\z/)
PeriodString =
_String(/\A#{PERIOD}\z/)
TimeString =
_String(/\A([01][0-9]|2[0-3]):([0-5][0-9])(:[0-5][0-9](\.\d{1,3})?)?\z/)
TimeZoneOffset =
_String(/\A#{TIME_ZONE_OFFSET}\z/)
Deprecated =
_Never
JavaScript =
Phlex::HTML::SafeObject
EmailAddressString =
_String(URI::MailTo::EMAIL_REGEXP)
NumericString =
_String(/\A-?(\d+(\.\d*)?|\.\d+)\z/)
NumericValue =
_Union(Integer, Float, NumericString)
PositiveNumeric =

An integer or float that’s greater than zero

_Constraint(Integer, Float, 0.., _Not(0), _Not(0.0))
PositiveInteger =
_Integer(1..)
RowSpan =
_Integer(0..65534)
ColSpan =
_Integer(0..1000)
Step =
_Union(Token(:any), PositiveNumeric)
Token =
_Union(String, Symbol)
Tokens =
_Union(Token, _Array(Token))
UInt =
_Integer(0..)
AutocompleteNamedGroup =
_String(/\Asection-/)
Hatch =
Enum(:open, :closed)
Toggle =
Enum(:on, :off)
Affirmation =
Enum(:yes, :no)
EnumeratedBoolean =
Enum(:true, :false)
AttributionSource =
_Union(_Boolean, String)
Blocking =
Enum(:render)
FormEncoding =
_Union(
	"application/x-www-form-urlencoded",
	"multipart/form-data",
	"text/plain",
)
PopoverTargetAction =
Enum(
	:hide,
	:show,
	:toggle
)
CrossOrigin =
Enum(
	:anonymous,
	:user_credentials
)
FetchPriority =
Enum(
	:high,
	:low,
	:auto,
)
Sizes =
_Union(
	Token(:any),
	SpaceSeparatedList(
		_String(/\A\d+[xX]\d+\z/)
	),
)
Href =

TODO — these times can have much stricter implementations

String
Language =
String
ReferrerPolicy =
Tokens
ControlsList =
Tokens
ARel =
Token
Target =
Token
MimeType =
Token
DOMID =

TODO: We can actually verify that these IDs exist on the page

Token
FormRel =
Enum(
	:external,
	:nofollow,
	:opener,
	:noopener,
	:noreferrer,
	:help,
	:prev,
	:next,
	:search,
	:license,
)
LinkRel =
Enum(
	:alternate,
	:author,
	:canonical,
	:dns_prefetch,
	:expect,
	:help,
	:license,
	:manifest,
	:me,
	:modulepreload,
	:next,
	:pingback,
	:preconnect,
	:prefetch,
	:preload,
	:prerender,
	:prev,
	:privacy_policy,
	:search,
	:stylesheet,
	:terms_of_service
)
TextDirection =
Enum(:ltr, :rtl)
InputMode =
Enum(
	:none,
	:text,
	:decimal,
	:numeric,
	:tel,
	:search,
	:email,
	:url
)
FormMethod =
Enum(
	:post,
	:get,
	:dialog
)
AutocompleteGroupingIdentifier =
Enum(
	:shipping,
	:billing,
)
AutocompleteRecipientType =
Enum(
	:home,
	:work,
	:mobile,
	:fax,
	:page,
)
AutocompleteDigitalContact =
Enum(
	:tel,
	:tel_country_code,
	:tel_national,
	:tel_area_code,
	:tel_local,
	:tel_extension,
	:email,
	:impp,
)
AutocompleteOther =
Enum(
	:name,
	:honorific_prefix,
	:given_name,
	:additional_name,
	:family_name,
	:honorific_suffix,
	:nickname,
	:username,
	:new_password,
	:current_password,
	:one_time_code,
	:organization_title,
	:organization,
	:street_address,
	:address_line1,
	:address_line2,
	:address_line3,
	:address_level4,
	:address_level3,
	:address_level2,
	:address_level1,
	:country,
	:country_name,
	:postal_code,
	:cc_name,
	:cc_given_name,
	:cc_additional_name,
	:cc_family_name,
	:cc_number,
	:cc_exp,
	:cc_exp_month,
	:cc_exp_year,
	:cc_csc,
	:cc_type,
	:transaction_currency,
	:transaction_amount,
	:language,
	:bday,
	:bday_day,
	:bday_month,
	:bday_year,
	:sex,
	:url,
	:photo,
	:webauthn,
)
Autocomplete =
_Union(
	Toggle,
	SpaceSeparatedList(
		_Union(
			AutocompleteNamedGroup,
			AutocompleteGroupingIdentifier,
			AutocompleteRecipientType,
			AutocompleteDigitalContact,
			AutocompleteOther,
		)
	)
)

Class Method Summary collapse

Class Method Details

.CommaSeparatedList(type) ⇒ Object



24
25
26
27
28
29
30
# File 'lib/phlex/validator/html.rb', line 24

def self.CommaSeparatedList(type)
	_Union(
		type,
		# _Array(type), # TODO: we can re-introduce this once Phlex supports it
		_String(-> (it) { it.split(/\s*,\s*/).all?(type) })
	)
end

.Enum(*tokens) ⇒ Object



12
13
14
# File 'lib/phlex/validator/html.rb', line 12

def self.Enum(*tokens)
	_Union(*tokens, *tokens.map { |it| it.name.tr("_", "-") })
end

.leap_year?(year) ⇒ Boolean

Returns:

  • (Boolean)


225
# File 'lib/phlex/validator/html.rb', line 225

def self.leap_year?(year) = year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)

.Pattern(regex, &block) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
# File 'lib/phlex/validator/html.rb', line 32

def self.Pattern(regex, &block)
	raise ArgumentError "Block required for Pattern" unless block

	-> (value) {
		if (data = regex.match(value))
			!!block.call(*data.captures, **data.named_captures&.transform_keys(&:to_sym))
		else
			false
		end
	}
end

.SpaceSeparatedList(type) ⇒ Object



16
17
18
19
20
21
22
# File 'lib/phlex/validator/html.rb', line 16

def self.SpaceSeparatedList(type)
	_Union(
		type,
		_Array(type),
		_String(-> (it) { it.split(/\s+/).all?(type) })
	)
end

.Token(symbol) ⇒ Object



8
9
10
# File 'lib/phlex/validator/html.rb', line 8

def self.Token(symbol)
	_Union(symbol, symbol.name.tr("_", "-"))
end

.valid_date?(year, month, day) ⇒ Boolean

Returns:

  • (Boolean)


227
228
229
230
231
# File 'lib/phlex/validator/html.rb', line 227

def self.valid_date?(year, month, day)
	day <= MONTH_LENGTHS[month] || (
		month == 2 && day == 29 && leap_year?(year)
	)
end