fileoverview import { parse as bcp47 } from 'bcp47' ; import { get as parseColor , ColorDescriptor } from 'color-string' ; import { Severity } from '@hint/utils-types' ; import { IHint } from 'hint/dist/src/lib/types' ; import { JSONLocationFunction } from '@hint/utils-json' ; import { isSupported } from '@hint/utils-compat-data' ; import { normalizeString } from '@hint/utils-string' ; import { Manifest , ManifestEvents , ManifestInvalidJSON , ManifestInvalidSchema , ManifestParsed } from '@hint/parser-manifest' ; import { HintContext } from 'hint/dist/src/lib/hint-context' ; import meta from './meta' ; import { getMessage } from './i18n.import' ; export default class ManifestIsValidHint implements IHint { public static readonly meta = meta ; public constructor ( context ) { const isNotSupportedColorValue = ( color , normalizedColorValue ) : boolean => { const hexWithAlphaRegex = /^#([0-9a-fA-F]{4}){1,2}$/ ; return ( color . model === 'rgb' && hexWithAlphaRegex . test ( normalizedColorValue ) && ! isSupported ( { property : 'color' , value : '#00000000' } , context . targetedBrowsers ) ) || color . model === 'hwb' ; } ; const checkColors = ( resource , manifest , getLocation ) => { const colorProperties = [ 'background_color' , 'theme_color' ] ; for ( const property of colorProperties ) { const colorValue = manifest [ property ] ; const normalizedColorValue = normalizeString ( colorValue , '' ) ; if ( ! normalizedColorValue ) { continue ; } const color = parseColor ( normalizedColorValue ) ; if ( color === null ) { const location = getLocation ( property ) ; const message = getMessage ( 'invalidValue' , context . language , [ `${ colorValue }` , property ] ) ; context . report ( resource , message , { location , severity : Severity . error } ) ; continue ; } if ( isNotSupportedColorValue ( color , normalizedColorValue ) ) { const location = getLocation ( property ) ; const message = getMessage ( 'unsupportedValue' , context . language , [ `${ colorValue }` , property ] ) ; context . report ( resource , message , { location , severity : Severity . error } ) ; } } } ; const checkLang = ( resource , manifest , getLocation ) => { const lang = manifest . lang ; if ( lang && ! bcp47 ( lang ) ) { const location = getLocation ( 'lang' ) ; const message = getMessage ( 'invalidValue' , context . language , [ lang , 'lang' ] ) ; context . report ( resource , message , { location , severity : Severity . error } ) ; } } ; const handleInvalidJSON = ( manifestInvalidJSON ) => { const { resource } = manifestInvalidJSON ; context . report ( resource , getMessage ( 'validJSON' , context . language ) , { severity : Severity . error } ) ; } ; const handleInvalidSchema = ( manifestInvalidSchemaEvent ) => { for ( let i = 0 ; i < manifestInvalidSchemaEvent . groupedErrors . length ; i ++ ) { const error = manifestInvalidSchemaEvent . groupedErrors [ i ] . message ; const location = manifestInvalidSchemaEvent . groupedErrors [ i ] . location ; context . report ( manifestInvalidSchemaEvent . resource , error , { location , severity : Severity . error } ) ; } } ; const validateOtherProperties = ( manifestParsed ) => { const { getLocation , parsedContent : manifest , resource } = manifestParsed ; checkLang ( resource , manifest , getLocation ) ; checkColors ( resource , manifest , getLocation ) ; } ; context . on ( 'parse::end::manifest' , validateOtherProperties ) ; context . on ( 'parse::error::manifest::json' , handleInvalidJSON ) ; context . on ( 'parse::error::manifest::schema' , handleInvalidSchema ) ; } }