import * as Metadata from "userscript-metadata" ; import Manifest from "webextension-manifest" ; import { Mode , isMode } from "./mode" ; import { ParseResult , Parser , booleanParser , enumParser , urlParser , } from "./parsing" ; const ENV_VAR_PREFIX = "USERSCRIPTER_" ; export const HOSTED_AT_EXAMPLE = "https://example.com/userscripts" ; export type BuildConfig = Readonly < { allowJs : boolean ; appendDateToVersion : { development : boolean ; nightly : boolean ; production : boolean ; } ; id : string ; hostedAt : string | null ; mainFile : string ; mode : Mode ; nightly : boolean ; now : Date ; outDir : string ; rootDir : string ; sassVariableGetter : string ; sassVariables : Record < string , unknown > ; sourceDir : string ; verbose : boolean ; } > ; export type WebpackConfigParameters = Readonly < { buildConfig : BuildConfig ; manifest ? : ( buildConfig : BuildConfig ) => Manifest ; metadata : ( buildConfig : BuildConfig ) => Metadata . Metadata ; metadataSchema : Metadata . ValidateOptions ; env : NodeJS . ProcessEnv ; } > ; type FromEnv < T > = ParseResult < T > | Readonly < { kind : "undefined" ; } > ; type EnvVarNameWithoutPrefix = keyof typeof ENVIRONMENT_VARIABLES ; type EnvVarSpec < K extends keyof BuildConfig , N extends EnvVarNameWithoutPrefix , V > = Readonly < { nameWithoutPrefix : N ; parser : Parser < V > ; overrides : K ; mustBe : string | readonly string [ ] ; } > ; export type EnvVarError = Readonly < { fullName : string ; expected : string | readonly string [ ] ; found : string ; } > ; export function envVarName ( nameWithoutPrefix ) { return ENV_VAR_PREFIX + nameWithoutPrefix ; } export const ENVIRONMENT_VARIABLES = { MODE : { nameWithoutPrefix : "MODE" , parser : enumParser ( isMode ) , overrides : "mode" , mustBe : Object . values ( Mode ) , } , NIGHTLY : { nameWithoutPrefix : "NIGHTLY" , parser : booleanParser , overrides : "nightly" , mustBe : [ "true" , "false" ] , } , HOSTED_AT : { nameWithoutPrefix : "HOSTED_AT" , parser : urlParser , overrides : "hostedAt" , mustBe : `a valid URL (e.g. "${ HOSTED_AT_EXAMPLE }")` , } , VERBOSE : { nameWithoutPrefix : "VERBOSE" , parser : booleanParser , overrides : "verbose" , mustBe : [ "true" , "false" ] , } , } as const ; { const typecheckedEnvVars = ENVIRONMENT_VARIABLES ; void typecheckedEnvVars ; } export type BuildConfigAndListOf < E > = Readonly < { buildConfig : BuildConfig ; errors : readonly E [ ] ; } > ; type DistFileType = "user" | "meta" ; export function distFileName ( id , type ) { return [ id , type , "js" ] . join ( "." ) ; } export function metadataUrl ( hostedAt , id , type ) { return hostedAt . replace ( /\/?$/ , "/" ) + distFileName ( id , type ) ; } export function envVars ( env ) { return Object . values ( ENVIRONMENT_VARIABLES ) . map ( e => { const name = envVarName ( e . nameWithoutPrefix ) ; return [ name , env [ name ] ] as const ; } ) ; } export function overrideBuildConfig ( buildConfig , env ) { return Object . values ( ENVIRONMENT_VARIABLES ) . reduce ( ( acc , envVar ) => { const envVarNameWithPrefix = envVarName ( envVar . nameWithoutPrefix ) ; const parsed = fromEnv ( envVar , env [ envVarNameWithPrefix ] ) ; switch ( parsed . kind ) { case "undefined" : return acc ; case "valid" : return { ... acc , buildConfig : { ... acc . buildConfig , [ envVar . overrides ] : parsed . value , } , } ; case "invalid" : return { ... acc , errors : acc . errors . concat ( { fullName : envVarNameWithPrefix , expected : envVar . mustBe , found : parsed . input , } ) , } ; } } , { buildConfig , errors : [ ] } ) ; } function fromEnv < R extends keyof BuildConfig , N extends EnvVarNameWithoutPrefix , V > ( envVarSpec , v ) { return ( v === undefined ? { kind : "undefined" } : ( envVarSpec . parser ( v ) ) ) ; }