11// @flow
22
33import browserslist from "browserslist" ;
4- import findSuggestion from "levenary" ;
5- import invariant from "invariant" ;
4+ import { findSuggestion } from "@babel/helper-validator-option" ;
65import browserModulesData from "@babel/compat-data/native-modules" ;
76
87import {
@@ -11,9 +10,11 @@ import {
1110 isUnreleasedVersion ,
1211 getLowestUnreleased ,
1312} from "./utils" ;
13+ import { OptionValidator } from "@babel/helper-validator-option" ;
1414import { browserNameMap } from "./targets" ;
1515import { TargetNames } from "./options" ;
16- import type { Target , Targets , InputTargets , Browsers } from "./types" ;
16+ import { name as packageName } from "../package.json" ;
17+ import type { Targets , InputTargets , Browsers , TargetsTuple } from "./types" ;
1718
1819export type { Targets , InputTargets } ;
1920
@@ -22,6 +23,7 @@ export { getInclusionReasons } from "./debug";
2223export { default as filterItems , isRequired } from "./filter-items" ;
2324export { unreleasedLabels } from "./targets" ;
2425
26+ const v = new OptionValidator ( packageName ) ;
2527const browserslistDefaults = browserslist . defaults ;
2628
2729const validBrowserslistTargets = [
@@ -39,29 +41,28 @@ function objectToBrowserslist(object: Targets): Array<string> {
3941 } , [ ] ) ;
4042}
4143
42- function validateTargetNames ( targets : InputTargets ) : Targets {
44+ function validateTargetNames ( targets : Targets ) : TargetsTuple {
4345 const validTargets = Object . keys ( TargetNames ) ;
44- for ( const target in targets ) {
45- if ( ! TargetNames [ target ] ) {
46+ for ( const target of Object . keys ( targets ) ) {
47+ if ( ! ( target in TargetNames ) ) {
4648 throw new Error (
47- `Invalid Option: '${ target } ' is not a valid target
48- Maybe you meant to use '${ findSuggestion ( target , validTargets ) } '?`,
49+ v . formatMessage ( ` '${ target } ' is not a valid target
50+ - Did you mean '${ findSuggestion ( target , validTargets ) } '?`) ,
4951 ) ;
5052 }
5153 }
5254
53- // $FlowIgnore
54- return targets ;
55+ return ( targets : any ) ;
5556}
5657
5758export function isBrowsersQueryValid ( browsers : Browsers | Targets ) : boolean {
5859 return typeof browsers = = = "string" || Array . isArray ( browsers ) ;
5960}
6061
6162function validateBrowsers ( browsers : Browsers | void ) {
62- invariant (
63- typeof browsers === " undefined" || isBrowsersQueryValid ( browsers ) ,
64- `Invalid Option: '${ String ( browsers ) } ' is not a valid browserslist query` ,
63+ v . invariant (
64+ browsers === undefined || isBrowsersQueryValid ( browsers ) ,
65+ `'${ String ( browsers ) } ' is not a valid browserslist query` ,
6566 ) ;
6667
6768 return browsers ;
@@ -110,8 +111,10 @@ function getLowestVersions(browsers: Array<string>): Targets {
110111 } , { } ) ;
111112}
112113
113- function outputDecimalWarning ( decimalTargets : Array < Object > ) : void {
114- if ( ! decimalTargets ?. length ) {
114+ function outputDecimalWarning (
115+ decimalTargets : Array < { | target : string , value : string | } > ,
116+ ) : void {
117+ if ( ! decimalTargets . length ) {
115118 return ;
116119 }
117120
@@ -133,7 +136,9 @@ function semverifyTarget(target, value) {
133136 return semverify ( value ) ;
134137 } catch ( error ) {
135138 throw new Error (
136- `Invalid Option: '${ value } ' is not a valid value for 'targets.${ target } '.` ,
139+ v . formatMessage (
140+ `'${ value } ' is not a valid value for 'targets.${ target } '.` ,
141+ ) ,
137142 ) ;
138143 }
139144}
@@ -156,16 +161,17 @@ const targetParserMap = {
156161 } ,
157162} ;
158163
159- type ParsedResult = {
160- targets : Targets ,
161- decimalWarnings : Array < Object > ,
162- } ;
164+ function generateTargets ( inputTargets : InputTargets ) : Targets {
165+ const input = { ...inputTargets } ;
166+ delete input . esmodules ;
167+ delete input . browsers ;
168+ return ( ( input : any ) : Targets ) ;
169+ }
163170
164171export default function getTargets (
165172 inputTargets : InputTargets = { } ,
166173 options : Object = { } ,
167174) : Targets {
168- const targetOpts : Targets = { } ;
169175 let { browsers } = inputTargets ;
170176
171177 // `esmodules` as a target indicates the specific set of browsers supporting ES Modules.
@@ -180,12 +186,8 @@ export default function getTargets(
180186 // Parse browsers target via browserslist
181187 const browsersquery = validateBrowsers ( browsers ) ;
182188
183- // Remove esmodules after being consumed to fix `hasTargets` below
184- const input = { ...inputTargets } ;
185- delete input . esmodules ;
186- delete input . browsers ;
187-
188- let targets : Targets = validateTargetNames ( input ) ;
189+ const input = generateTargets ( inputTargets ) ;
190+ let targets : TargetsTuple = validateTargetNames ( input ) ;
189191
190192 const shouldParseBrowsers = ! ! browsersquery ;
191193 const hasTargets = shouldParseBrowsers || Object . keys ( targets ) . length > 0 ;
@@ -218,34 +220,28 @@ export default function getTargets(
218220 }
219221
220222 // Parse remaining targets
221- const parsed = ( Object . keys ( targets ) : Array < Target > ) . sort ( ) . reduce (
222- ( results : ParsedResult , target : $Keys < Targets > ) : ParsedResult => {
223- const value = targets [ target ] ;
224-
225- // Warn when specifying minor/patch as a decimal
226- if ( typeof value === "number" && value % 1 !== 0 ) {
227- results . decimalWarnings . push ( { target, value } ) ;
228- }
229-
230- // Check if we have a target parser?
231- // $FlowIgnore - Flow doesn't like that some targetParserMap[target] might be missing
232- const parser = targetParserMap [ target ] ?? targetParserMap . __default ;
233- const [ parsedTarget , parsedValue ] = parser ( target , value ) ;
223+ const result : Targets = { } ;
224+ const decimalWarnings = [ ] ;
225+ for ( const target of Object . keys ( targets ) . sort ( ) ) {
226+ const value = targets [ target ] ;
227+
228+ // Warn when specifying minor/patch as a decimal
229+ if ( typeof value === "number" && value % 1 !== 0 ) {
230+ decimalWarnings . push ( { target, value } ) ;
231+ }
234232
235- if ( parsedValue ) {
236- // Merge (lowest wins)
237- results . targets [ parsedTarget ] = parsedValue ;
238- }
233+ // Check if we have a target parser?
234+ // $FlowIgnore - Flow doesn't like that some targetParserMap[target] might be missing
235+ const parser = targetParserMap [ target ] ?? targetParserMap . __default ;
236+ const [ parsedTarget , parsedValue ] = parser ( target , value ) ;
239237
240- return results ;
241- } ,
242- {
243- targets : targetOpts ,
244- decimalWarnings : [ ] ,
245- } ,
246- ) ;
238+ if ( parsedValue ) {
239+ // Merge (lowest wins)
240+ result [ parsedTarget ] = parsedValue ;
241+ }
242+ }
247243
248- outputDecimalWarning ( parsed . decimalWarnings ) ;
244+ outputDecimalWarning ( decimalWarnings ) ;
249245
250- return parsed . targets ;
246+ return result ;
251247}
0 commit comments