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