import apiMetadata from "ast-metadata-inferer" ; import semver from "semver" ; import { ApiMetadata } from "ast-metadata-inferer/lib/types" ; import { reverseTargetMappings } from "../helpers" ; import { STANDARD_TARGET_NAME_MAPPING } from "../constants" ; import { AstMetadataApiWithTargetsResolver , Target } from "../types" ; const apis = apiMetadata as ApiMetadata [ ] ; const mdnRecords = new Map ( apis . map ( ( e ) => [ e . protoChainId , e ] ) ) ; interface TargetIdMappings { chrome : "chrome" ; firefox : "firefox" ; opera : "opera" ; safari : "safari" ; safari_ios : "ios_saf" ; ie : "ie" ; edge_mobile : "ie_mob" ; edge : "edge" ; opera_android : "and_opera" ; chrome_android : "and_chrome" ; firefox_android : "and_firefox" ; webview_android : "and_webview" ; samsunginternet_android : "and_samsung" ; nodejs : "node" ; } /**
 * Map ids of mdn targets to their "common/friendly" name
 */ const targetIdMappings = { chrome : "chrome" , firefox : "firefox" , opera : "opera" , safari : "safari" , safari_ios : "ios_saf" , ie : "ie" , edge_mobile : "ie_mob" , edge : "edge" , opera_android : "and_opera" , chrome_android : "and_chrome" , firefox_android : "and_firefox" , webview_android : "and_webview" , samsunginternet_android : "and_samsung" , nodejs : "node" , } ; const reversedTargetMappings = reverseTargetMappings ( targetIdMappings ) ; /**
 * Take a target's id and return it's full name by using `targetNameMappings`
 * ex. {target: and_ff, version: 40} => 'Android FireFox 40'
 */ function formatTargetNames ( target ) { return `${ STANDARD_TARGET_NAME_MAPPING [ target . target ] } ${ target . version }` ; } /**
 * Convert '9' => '9.0.0'
 */ function customCoerce ( version ) { return version . length === 1 ? [ version , 0 , 0 ] . join ( "." ) : version ; } export function isSupportedByMDN ( node , { version , target : mdnTarget } ) { const target = reversedTargetMappings [ mdnTarget ] ; if ( ! mdnRecords . has ( node . protoChainId ) ) return true ; const record = mdnRecords . get ( node . protoChainId ) ; if ( ! record || ! record . compat . support ) return true ; const compatRecord = record . compat . support [ target ] ; if ( ! compatRecord ) return true ; if ( ! Array . isArray ( compatRecord ) && ! ( "version_added" in compatRecord ) ) return true ; const { version_added : versionAdded } = Array . isArray ( compatRecord ) ? compatRecord . find ( ( e ) => "version_added" in e ) : compatRecord ; if ( typeof versionAdded === "boolean" ) return versionAdded ; if ( versionAdded === null ) return true ; if ( target === "safari" ) { if ( version === "TP" ) return true ; if ( versionAdded === "TP" ) return false ; } const semverCurrent = semver . coerce ( customCoerce ( version ) ) ; const semverAdded = semver . coerce ( customCoerce ( versionAdded ) ) ; if ( ! semverCurrent ) { console . warn ( `eslint-plugin-compat: A non-semver target "${ target } ${ version }" matched for the feature ${ node . protoChainId }, skipping. You're welcome to submit this log to https://github.com/amilajack/eslint-plugin-compat/issues for analysis.` ) ; return true ; } if ( ! versionAdded ) { console . warn ( `eslint-plugin-compat: The feature ${ node . protoChainId } is supported since a non-semver target "${ target } ${ versionAdded }", skipping. You're welcome to submit this log to https://github.com/amilajack/eslint-plugin-compat/issues for analysis.` ) ; return true ; } return semver . gte ( semverCurrent , semverAdded ) ; } /**
 * Return an array of all unsupported targets
 */ export function getUnsupportedTargets ( node , targets ) { return targets . filter ( ( target ) => ! isSupportedByMDN ( node , target ) ) . map ( formatTargetNames ) ; } function getMetadataName ( metadata ) { switch ( metadata . protoChain . length ) { case 1 : { return metadata . protoChain [ 0 ] ; } default : return `${ metadata . protoChain . join ( "." ) }()` ; } } const MdnProvider = apis . map ( ( metadata ) => metadata . astNodeTypes . map ( ( astNodeType ) => ( { ... metadata , name : getMetadataName ( metadata ) , id : metadata . protoChainId , protoChainId : metadata . protoChainId , astNodeType , object : metadata . protoChain [ 0 ] , property : metadata . protoChain [ 1 ] , } ) ) ) . flat ( ) . map ( ( rule ) => ( { ... rule , getUnsupportedTargets , } ) ) ; export default MdnProvider ;