2022-08-16 14:41:06 +07:00
import { parse as urlParse } from "url" ;
2024-06-23 21:23:06 +02:00
import {
join as pathJoin ,
sep as pathSep ,
relative as pathRelative ,
resolve as pathResolve ,
dirname as pathDirname
} from "path" ;
2024-05-16 08:23:37 +02:00
import { getAbsoluteAndInOsFormatPath } from "../tools/getAbsoluteAndInOsFormatPath" ;
import { z } from "zod" ;
import * as fs from "fs" ;
2024-06-16 01:29:15 +02:00
import { assert , type Equals } from "tsafe/assert" ;
2024-05-16 08:23:37 +02:00
import * as child_process from "child_process" ;
2024-06-16 01:29:15 +02:00
import {
2024-07-13 19:33:59 +02:00
VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES ,
2024-09-08 00:06:47 +02:00
BUILD_FOR_KEYCLOAK_MAJOR_VERSION_ENV_NAME
2024-06-16 01:29:15 +02:00
} from "./constants" ;
import type { KeycloakVersionRange } from "./KeycloakVersionRange" ;
import { exclude } from "tsafe" ;
import { crawl } from "../tools/crawl" ;
2024-07-13 19:33:59 +02:00
import { THEME_TYPES } from "./constants" ;
2024-06-16 01:29:15 +02:00
import { objectEntries } from "tsafe/objectEntries" ;
import { type ThemeType } from "./constants" ;
import { id } from "tsafe/id" ;
import chalk from "chalk" ;
2024-10-05 21:22:00 +02:00
import { getProxyFetchOptions , type FetchOptionsLike } from "../tools/fetchProxyOptions" ;
2024-10-04 12:17:08 +02:00
import { is } from "tsafe/is" ;
2022-08-16 14:41:06 +07:00
2024-06-09 09:15:16 +02:00
export type BuildContext = {
2023-08-21 05:54:17 +02:00
themeVersion : string ;
2024-06-10 07:57:12 +02:00
themeNames : [ string , . . . string [ ] ] ;
2023-08-21 05:54:17 +02:00
extraThemeProperties : string [ ] | undefined ;
groupId : string ;
artifactId : string ;
2024-06-09 09:03:43 +02:00
projectDirPath : string ;
projectBuildDirPath : string ;
2023-08-21 05:54:17 +02:00
/** Directory that keycloakify outputs to. Defaults to {cwd}/build_keycloak */
keycloakifyBuildDirPath : string ;
2023-09-03 23:26:34 +02:00
publicDirPath : string ;
cacheDirPath : string ;
2023-08-21 05:54:17 +02:00
/** If your app is hosted under a subpath, it's the case in CRA if you have "homepage": "https:/ / example . com / my - app " in your package . json
* In this case the urlPathname will be "/my-app/" * /
urlPathname : string | undefined ;
2024-01-30 00:06:17 +01:00
assetsDirPath : string ;
2024-10-05 21:22:00 +02:00
fetchOptions : FetchOptionsLike ;
2024-06-06 01:31:00 +02:00
kcContextExclusionsFtlCode : string | undefined ;
2024-06-08 14:02:07 +02:00
environmentVariables : { name : string ; default : string } [ ] ;
2024-06-16 01:29:15 +02:00
themeSrcDirPath : string ;
2024-07-20 22:43:14 +02:00
implementedThemeTypes : {
login : { isImplemented : boolean } ;
email : { isImplemented : boolean } ;
account :
| { isImplemented : false }
| { isImplemented : true ; type : "Single-Page" | "Multi-Page" } ;
2024-10-26 21:23:18 +02:00
admin : { isImplemented : boolean } ;
2024-07-20 22:43:14 +02:00
} ;
2024-07-25 18:16:43 +02:00
packageJsonFilePath : string ;
bundler : "vite" | "webpack" ;
2024-07-20 22:43:14 +02:00
jarTargets : {
keycloakVersionRange : KeycloakVersionRange ;
jarFileBasename : string ;
} [ ] ;
2024-08-17 23:20:52 +02:00
startKeycloakOptions : {
dockerImage :
| {
reference : string ;
tag : string ;
}
| undefined ;
dockerExtraArgs : string [ ] ;
keycloakExtraArgs : string [ ] ;
extensionJars : ( { type : "path" ; path : string } | { type : "url" ; url : string } ) [ ] ;
realmJsonFilePath : string | undefined ;
2024-08-18 21:10:18 +02:00
port : number | undefined ;
2024-08-17 23:20:52 +02:00
} ;
2023-08-21 05:54:17 +02:00
} ;
2022-08-16 14:41:06 +07:00
2024-07-20 22:43:14 +02:00
assert < Equals < keyof BuildContext [ "implementedThemeTypes" ] , ThemeType | "email" > > ( ) ;
2024-06-09 09:15:16 +02:00
export type BuildOptions = {
2024-06-08 14:02:07 +02:00
themeName? : string | string [ ] ;
2024-06-16 14:53:18 +02:00
themeVersion? : string ;
2024-06-08 14:02:07 +02:00
environmentVariables ? : { name : string ; default : string } [ ] ;
2024-05-16 08:23:37 +02:00
extraThemeProperties? : string [ ] ;
artifactId? : string ;
groupId? : string ;
keycloakifyBuildDirPath? : string ;
2024-06-09 09:20:55 +02:00
kcContextExclusionsFtl? : string ;
2024-08-17 23:20:52 +02:00
startKeycloakOptions ? : {
dockerImage? : string ;
dockerExtraArgs? : string [ ] ;
keycloakExtraArgs? : string [ ] ;
extensionJars? : string [ ] ;
realmJsonFilePath? : string ;
2024-08-18 21:10:18 +02:00
port? : number ;
2024-08-17 23:20:52 +02:00
} ;
2024-07-20 22:43:14 +02:00
} & BuildOptions . AccountThemeImplAndKeycloakVersionTargets ;
2024-05-16 08:23:37 +02:00
2024-06-16 01:29:15 +02:00
export namespace BuildOptions {
2024-07-20 22:43:14 +02:00
export type AccountThemeImplAndKeycloakVersionTargets =
| AccountThemeImplAndKeycloakVersionTargets . MultiPageApp
| AccountThemeImplAndKeycloakVersionTargets . SinglePageAppOrNone ;
export namespace AccountThemeImplAndKeycloakVersionTargets {
export type MultiPageApp = {
accountThemeImplementation : "Multi-Page" ;
keycloakVersionTargets? : Record <
KeycloakVersionRange . WithAccountV1Theme ,
string | boolean
> ;
} ;
export type SinglePageAppOrNone = {
accountThemeImplementation : "Single-Page" | "none" ;
keycloakVersionTargets? : Record <
KeycloakVersionRange . WithoutAccountV1Theme ,
string | boolean
> ;
} ;
}
2024-06-16 01:29:15 +02:00
}
2024-05-16 08:23:37 +02:00
export type ResolvedViteConfig = {
buildDir : string ;
publicDir : string ;
assetsDir : string ;
urlPathname : string | undefined ;
2024-06-09 09:15:16 +02:00
buildOptions : BuildOptions ;
2024-05-16 08:23:37 +02:00
} ;
2024-06-09 09:15:16 +02:00
export function getBuildContext ( params : {
2024-10-05 20:30:09 +02:00
projectDirPath : string | undefined ;
2024-06-09 09:15:16 +02:00
} ) : BuildContext {
2024-06-23 16:56:24 +02:00
const projectDirPath =
2024-10-05 20:30:09 +02:00
params . projectDirPath !== undefined
2024-06-23 16:56:24 +02:00
? getAbsoluteAndInOsFormatPath ( {
2024-10-05 20:30:09 +02:00
pathIsh : params.projectDirPath ,
2024-06-23 16:56:24 +02:00
cwd : process.cwd ( )
} )
: process . cwd ( ) ;
const { themeSrcDirPath } = ( ( ) = > {
const srcDirPath = pathJoin ( projectDirPath , "src" ) ;
const themeSrcDirPath : string | undefined = crawl ( {
dirPath : srcDirPath ,
returnedPathsType : "relative to dirPath"
} )
. map ( fileRelativePath = > {
for ( const themeSrcDirBasename of [ "keycloak-theme" , "keycloak_theme" ] ) {
const split = fileRelativePath . split ( themeSrcDirBasename ) ;
if ( split . length === 2 ) {
return pathJoin ( srcDirPath , split [ 0 ] + themeSrcDirBasename ) ;
}
}
return undefined ;
} )
. filter ( exclude ( undefined ) ) [ 0 ] ;
if ( themeSrcDirPath !== undefined ) {
return { themeSrcDirPath } ;
2024-05-16 07:47:50 +02:00
}
2024-02-08 00:56:33 +01:00
2024-07-13 19:33:59 +02:00
for ( const themeType of [ . . . THEME_TYPES , "email" ] ) {
2024-06-23 16:56:24 +02:00
if ( ! fs . existsSync ( pathJoin ( srcDirPath , themeType ) ) ) {
continue ;
}
return { themeSrcDirPath : srcDirPath } ;
}
console . log (
chalk . red (
[
` Can't locate your Keycloak theme source directory in . ${ pathSep } ${ pathRelative ( process . cwd ( ) , srcDirPath ) } ` ,
` Make sure to either use the Keycloakify CLI in the root of your Keycloakify project or use the --project CLI option ` ,
` If you are collocating your Keycloak theme with your app you must have a directory named 'keycloak-theme' or 'keycloak_theme' in your 'src' directory `
] . join ( "\n" )
)
) ;
process . exit ( 1 ) ;
2024-05-16 07:47:50 +02:00
} ) ( ) ;
2024-02-08 00:56:33 +01:00
2024-05-16 08:23:37 +02:00
const { resolvedViteConfig } = ( ( ) = > {
2024-05-20 15:48:51 +02:00
if (
fs
2024-06-09 09:03:43 +02:00
. readdirSync ( projectDirPath )
2024-05-20 15:48:51 +02:00
. find ( fileBasename = > fileBasename . startsWith ( "vite.config" ) ) ===
undefined
) {
return { resolvedViteConfig : undefined } ;
2024-05-16 08:23:37 +02:00
}
const output = child_process
. execSync ( "npx vite" , {
2024-06-09 09:03:43 +02:00
cwd : projectDirPath ,
2024-05-20 15:48:51 +02:00
env : {
2024-05-16 08:23:37 +02:00
. . . process . env ,
2024-07-13 19:33:59 +02:00
[ VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES . RESOLVE_VITE_CONFIG ] : "true"
2024-05-16 08:23:37 +02:00
}
} )
. toString ( "utf8" ) ;
2024-05-20 15:48:51 +02:00
assert (
2024-07-13 19:33:59 +02:00
output . includes ( VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES . RESOLVE_VITE_CONFIG ) ,
2024-05-20 15:48:51 +02:00
"Seems like the Keycloakify's Vite plugin is not installed."
) ;
2024-05-16 08:23:37 +02:00
2024-05-20 15:48:51 +02:00
const resolvedViteConfigStr = output
2024-07-13 19:33:59 +02:00
. split ( VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES . RESOLVE_VITE_CONFIG )
2024-05-20 15:48:51 +02:00
. reverse ( ) [ 0 ] ;
2023-04-18 03:10:29 +02:00
2024-05-16 08:23:37 +02:00
const resolvedViteConfig : ResolvedViteConfig = JSON . parse ( resolvedViteConfigStr ) ;
return { resolvedViteConfig } ;
} ) ( ) ;
2024-06-23 21:23:06 +02:00
const packageJsonFilePath = ( function getPackageJSonDirPath ( upCount : number ) : string {
const dirPath = pathResolve (
pathJoin ( . . . [ projectDirPath , . . . Array ( upCount ) . fill ( ".." ) ] )
) ;
assert ( dirPath !== pathSep , "Root package.json not found" ) ;
success : {
const packageJsonFilePath = pathJoin ( dirPath , "package.json" ) ;
if ( ! fs . existsSync ( packageJsonFilePath ) ) {
break success ;
}
const parsedPackageJson = z
. object ( {
2024-06-23 22:39:29 +02:00
name : z.string ( ) . optional ( ) ,
2024-06-23 21:23:06 +02:00
dependencies : z.record ( z . string ( ) ) . optional ( ) ,
devDependencies : z.record ( z . string ( ) ) . optional ( )
} )
. parse ( JSON . parse ( fs . readFileSync ( packageJsonFilePath ) . toString ( "utf8" ) ) ) ;
if (
parsedPackageJson . dependencies ? . keycloakify === undefined &&
2024-09-28 00:17:17 +02:00
parsedPackageJson . devDependencies ? . keycloakify === undefined
2024-06-23 21:23:06 +02:00
) {
break success ;
}
return packageJsonFilePath ;
}
return getPackageJSonDirPath ( upCount + 1 ) ;
} ) ( 0 ) ;
2024-05-16 08:23:37 +02:00
const parsedPackageJson = ( ( ) = > {
2024-06-16 01:29:15 +02:00
type BuildOptions_packageJson = BuildOptions & {
2024-06-13 22:58:32 +02:00
projectBuildDirPath? : string ;
2024-06-16 14:53:18 +02:00
staticDirPathInProjectBuildDirPath? : string ;
2024-06-16 14:58:51 +02:00
publicDirPath? : string ;
2024-06-13 22:58:32 +02:00
} ;
2024-05-16 08:23:37 +02:00
type ParsedPackageJson = {
2024-06-23 21:23:06 +02:00
name? : string ;
2024-05-16 08:23:37 +02:00
version? : string ;
homepage? : string ;
2024-06-16 01:29:15 +02:00
keycloakify? : BuildOptions_packageJson ;
2024-05-16 08:23:37 +02:00
} ;
2024-07-20 22:43:14 +02:00
const zMultiPageApp = ( ( ) = > {
type TargetType =
BuildOptions . AccountThemeImplAndKeycloakVersionTargets . MultiPageApp ;
const zTargetType = z . object ( {
accountThemeImplementation : z.literal ( "Multi-Page" ) ,
keycloakVersionTargets : z
. object ( {
"21-and-below" : z . union ( [ z . boolean ( ) , z . string ( ) ] ) ,
"23" : z . union ( [ z . boolean ( ) , z . string ( ) ] ) ,
"24" : z . union ( [ z . boolean ( ) , z . string ( ) ] ) ,
2024-10-04 12:58:31 +02:00
"25" : z . union ( [ z . boolean ( ) , z . string ( ) ] ) ,
"26-and-above" : z . union ( [ z . boolean ( ) , z . string ( ) ] )
2024-07-20 22:43:14 +02:00
} )
. optional ( )
} ) ;
assert < Equals < z.infer < typeof zTargetType > , TargetType > > ( ) ;
return id < z.ZodType < TargetType > > ( zTargetType ) ;
} ) ( ) ;
2024-06-16 01:29:15 +02:00
2024-07-20 22:43:14 +02:00
const zSinglePageApp = ( ( ) = > {
type TargetType =
BuildOptions . AccountThemeImplAndKeycloakVersionTargets . SinglePageAppOrNone ;
const zTargetType = z . object ( {
accountThemeImplementation : z.union ( [
z . literal ( "Single-Page" ) ,
z . literal ( "none" )
] ) ,
keycloakVersionTargets : z
. object ( {
2024-10-04 12:17:08 +02:00
"22-to-25" : z . union ( [ z . boolean ( ) , z . string ( ) ] ) ,
"all-other-versions" : z . union ( [ z . boolean ( ) , z . string ( ) ] )
2024-07-20 22:43:14 +02:00
} )
. optional ( )
} ) ;
assert < Equals < z.infer < typeof zTargetType > , TargetType > > ( ) ;
return id < z.ZodType < TargetType > > ( zTargetType ) ;
} ) ( ) ;
2024-06-16 01:29:15 +02:00
2024-07-20 22:43:14 +02:00
const zAccountThemeImplAndKeycloakVersionTargets = ( ( ) = > {
type TargetType = BuildOptions . AccountThemeImplAndKeycloakVersionTargets ;
2024-05-16 08:23:37 +02:00
2024-07-20 22:43:14 +02:00
const zTargetType = z . union ( [ zMultiPageApp , zSinglePageApp ] ) ;
assert < Equals < z.infer < typeof zTargetType > , TargetType > > ( ) ;
return id < z.ZodType < TargetType > > ( zTargetType ) ;
} ) ( ) ;
2024-08-17 23:20:52 +02:00
const zStartKeycloakOptions = ( ( ) = > {
type TargetType = NonNullable < BuildOptions [ "startKeycloakOptions" ] > ;
const zTargetType = z . object ( {
dockerImage : z.string ( ) . optional ( ) ,
extensionJars : z.array ( z . string ( ) ) . optional ( ) ,
realmJsonFilePath : z.string ( ) . optional ( ) ,
dockerExtraArgs : z.array ( z . string ( ) ) . optional ( ) ,
2024-08-18 21:10:18 +02:00
keycloakExtraArgs : z.array ( z . string ( ) ) . optional ( ) ,
port : z.number ( ) . optional ( )
2024-08-17 23:20:52 +02:00
} ) ;
assert < Equals < z.infer < typeof zTargetType > , TargetType > > ( ) ;
return id < z.ZodType < TargetType > > ( zTargetType ) ;
} ) ( ) ;
2024-07-20 22:43:14 +02:00
const zBuildOptions = ( ( ) = > {
type TargetType = BuildOptions ;
const zTargetType = z . intersection (
z . object ( {
themeName : z.union ( [ z . string ( ) , z . array ( z . string ( ) ) ] ) . optional ( ) ,
themeVersion : z.string ( ) . optional ( ) ,
environmentVariables : z
. array (
z . object ( {
name : z.string ( ) ,
default : z . string ( )
} )
)
. optional ( ) ,
extraThemeProperties : z.array ( z . string ( ) ) . optional ( ) ,
artifactId : z.string ( ) . optional ( ) ,
groupId : z.string ( ) . optional ( ) ,
keycloakifyBuildDirPath : z.string ( ) . optional ( ) ,
2024-08-17 23:20:52 +02:00
kcContextExclusionsFtl : z.string ( ) . optional ( ) ,
startKeycloakOptions : zStartKeycloakOptions.optional ( )
2024-07-20 22:43:14 +02:00
} ) ,
zAccountThemeImplAndKeycloakVersionTargets
) ;
assert < Equals < z.infer < typeof zTargetType > , TargetType > > ( ) ;
return id < z.ZodType < TargetType > > ( zTargetType ) ;
} ) ( ) ;
const zBuildOptions_packageJson = ( ( ) = > {
type TargetType = BuildOptions_packageJson ;
const zTargetType = z . intersection (
zBuildOptions ,
z . object ( {
projectBuildDirPath : z.string ( ) . optional ( ) ,
staticDirPathInProjectBuildDirPath : z.string ( ) . optional ( ) ,
2024-07-25 18:16:43 +02:00
publicDirPath : z.string ( ) . optional ( )
2024-07-20 22:43:14 +02:00
} )
) ;
assert < Equals < z.infer < typeof zTargetType > , TargetType > > ( ) ;
return id < z.ZodType < TargetType > > ( zTargetType ) ;
} ) ( ) ;
const zParsedPackageJson = ( ( ) = > {
type TargetType = ParsedPackageJson ;
const zTargetType = z . object ( {
name : z.string ( ) . optional ( ) ,
version : z.string ( ) . optional ( ) ,
homepage : z.string ( ) . optional ( ) ,
keycloakify : zBuildOptions_packageJson.optional ( )
} ) ;
assert < Equals < z.infer < typeof zTargetType > , TargetType > > ( ) ;
return id < z.ZodType < TargetType > > ( zTargetType ) ;
} ) ( ) ;
2024-05-16 08:23:37 +02:00
2024-06-23 21:23:06 +02:00
const configurationPackageJsonFilePath = ( ( ) = > {
const rootPackageJsonFilePath = pathJoin ( projectDirPath , "package.json" ) ;
return fs . existsSync ( rootPackageJsonFilePath )
? rootPackageJsonFilePath
: packageJsonFilePath ;
} ) ( ) ;
2024-05-20 15:48:51 +02:00
return zParsedPackageJson . parse (
2024-06-23 21:23:06 +02:00
JSON . parse ( fs . readFileSync ( configurationPackageJsonFilePath ) . toString ( "utf8" ) )
2024-05-20 15:48:51 +02:00
) ;
2024-05-16 08:23:37 +02:00
} ) ( ) ;
2024-02-23 19:15:59 +01:00
2024-07-20 22:43:14 +02:00
const bundler = resolvedViteConfig !== undefined ? "vite" : "webpack" ;
if ( bundler === "vite" && parsedPackageJson . keycloakify !== undefined ) {
console . error (
chalk . red (
` In vite projects, provide your Keycloakify options in vite.config.ts, not in package.json `
)
) ;
process . exit ( - 1 ) ;
}
const buildOptions : BuildOptions = ( ( ) = > {
switch ( bundler ) {
case "vite" :
assert ( resolvedViteConfig !== undefined ) ;
return resolvedViteConfig . buildOptions ;
case "webpack" :
assert ( parsedPackageJson . keycloakify !== undefined ) ;
return parsedPackageJson . keycloakify ;
}
assert < Equals < typeof bundler , never > > ( false ) ;
} ) ( ) ;
const implementedThemeTypes : BuildContext [ "implementedThemeTypes" ] = {
login : {
isImplemented : fs.existsSync ( pathJoin ( themeSrcDirPath , "login" ) )
} ,
email : {
isImplemented : fs.existsSync ( pathJoin ( themeSrcDirPath , "email" ) )
} ,
account : ( ( ) = > {
if ( buildOptions . accountThemeImplementation === "none" ) {
return { isImplemented : false } ;
}
return {
isImplemented : true ,
type : buildOptions . accountThemeImplementation
} ;
2024-10-26 21:23:18 +02:00
} ) ( ) ,
admin : {
isImplemented : fs.existsSync ( pathJoin ( themeSrcDirPath , "admin" ) )
}
2024-02-23 19:15:59 +01:00
} ;
2022-08-16 14:41:06 +07:00
2024-07-20 22:43:14 +02:00
if (
implementedThemeTypes . account . isImplemented &&
! fs . existsSync ( pathJoin ( themeSrcDirPath , "account" ) )
) {
console . error (
chalk . red (
[
` You have set 'accountThemeImplementation' to ' ${ implementedThemeTypes . account . type } ' ` ,
` but the 'account' directory is missing in your theme source directory ` ,
"Use the `npx keycloakify initialize-account-theme` command to create it"
] . join ( " " )
)
) ;
process . exit ( - 1 ) ;
}
2024-06-16 01:29:15 +02:00
2024-06-10 07:57:12 +02:00
const themeNames = ( ( ) : [ string , . . . string [ ] ] = > {
2024-09-28 00:34:24 +02:00
const themeNames = ( ( ) : [ string , . . . string [ ] ] = > {
if ( buildOptions . themeName === undefined ) {
return parsedPackageJson . name === undefined
? [ "keycloakify" ]
: [
parsedPackageJson . name
. replace ( /^@(.*)/ , "$1" )
. split ( "/" )
. join ( "-" )
] ;
}
2022-08-16 14:41:06 +07:00
2024-09-28 00:34:24 +02:00
if ( typeof buildOptions . themeName === "string" ) {
return [ buildOptions . themeName ] ;
}
const [ mainThemeName , . . . themeVariantNames ] = buildOptions . themeName ;
2023-09-04 01:19:21 +02:00
2024-09-28 00:34:24 +02:00
assert ( mainThemeName !== undefined ) ;
2024-06-10 07:57:12 +02:00
2024-09-28 00:34:24 +02:00
return [ mainThemeName , . . . themeVariantNames ] ;
} ) ( ) ;
for ( const themeName of themeNames ) {
if ( ! /^[a-zA-Z0-9_-]+$/ . test ( themeName ) ) {
console . error (
chalk . red (
[
` Invalid theme name: ${ themeName } ` ,
` Theme names should only contain letters, numbers, and "_" or "-" `
] . join ( " " )
)
) ;
process . exit ( - 1 ) ;
}
}
2024-06-10 07:57:12 +02:00
2024-09-28 00:34:24 +02:00
return themeNames ;
2023-09-04 01:19:21 +02:00
} ) ( ) ;
2022-08-16 14:41:06 +07:00
2024-10-13 00:55:06 +02:00
const relativePathsCwd = ( ( ) = > {
switch ( bundler ) {
case "vite" :
return projectDirPath ;
case "webpack" :
return pathDirname ( packageJsonFilePath ) ;
}
} ) ( ) ;
2024-06-09 09:03:43 +02:00
const projectBuildDirPath = ( ( ) = > {
2024-01-30 06:55:26 +01:00
webpack : {
2024-07-20 22:43:14 +02:00
if ( bundler !== "webpack" ) {
2024-01-30 06:55:26 +01:00
break webpack ;
}
2024-07-20 22:43:14 +02:00
assert ( parsedPackageJson . keycloakify !== undefined ) ;
if ( parsedPackageJson . keycloakify . projectBuildDirPath !== undefined ) {
2024-01-30 06:55:26 +01:00
return getAbsoluteAndInOsFormatPath ( {
2024-07-20 22:43:14 +02:00
pathIsh : parsedPackageJson.keycloakify.projectBuildDirPath ,
2024-10-13 00:55:06 +02:00
cwd : relativePathsCwd
2024-01-30 06:55:26 +01:00
} ) ;
}
2024-06-09 09:03:43 +02:00
return pathJoin ( projectDirPath , "build" ) ;
2024-01-30 06:55:26 +01:00
}
2024-07-20 22:43:14 +02:00
assert ( bundler === "vite" ) ;
assert ( resolvedViteConfig !== undefined ) ;
2024-06-09 09:03:43 +02:00
return pathJoin ( projectDirPath , resolvedViteConfig . buildDir ) ;
2024-01-30 06:55:26 +01:00
} ) ( ) ;
2024-01-30 05:54:36 +01:00
return {
2024-07-25 18:16:43 +02:00
bundler ,
packageJsonFilePath ,
2024-06-16 14:53:18 +02:00
themeVersion : buildOptions.themeVersion ? ? parsedPackageJson . version ? ? "0.0.0" ,
2023-09-04 01:19:21 +02:00
themeNames ,
2024-06-09 09:15:16 +02:00
extraThemeProperties : buildOptions.extraThemeProperties ,
2024-05-20 15:48:51 +02:00
groupId : ( ( ) = > {
2023-09-04 01:19:21 +02:00
const fallbackGroupId = ` ${ themeNames [ 0 ] } .keycloak ` ;
2023-08-21 05:54:17 +02:00
return (
process . env . KEYCLOAKIFY_GROUP_ID ? ?
2024-06-09 09:15:16 +02:00
buildOptions . groupId ? ?
2024-01-30 05:54:36 +01:00
( parsedPackageJson . homepage === undefined
2023-08-21 05:54:17 +02:00
? fallbackGroupId
2024-01-30 05:54:36 +01:00
: urlParse ( parsedPackageJson . homepage )
2023-08-21 05:54:17 +02:00
. host ? . replace ( /:[0-9]+$/ , "" )
? . split ( "." )
. reverse ( )
. join ( "." ) ? ? fallbackGroupId ) + ".keycloak"
) ;
} ) ( ) ,
2024-05-20 15:48:51 +02:00
artifactId :
process . env . KEYCLOAKIFY_ARTIFACT_ID ? ?
2024-06-09 09:15:16 +02:00
buildOptions . artifactId ? ?
2024-05-20 15:48:51 +02:00
` ${ themeNames [ 0 ] } -keycloak-theme ` ,
2024-06-09 09:03:43 +02:00
projectDirPath ,
projectBuildDirPath ,
2024-05-20 15:48:51 +02:00
keycloakifyBuildDirPath : ( ( ) = > {
2024-06-09 09:15:16 +02:00
if ( buildOptions . keycloakifyBuildDirPath !== undefined ) {
2024-02-11 16:17:38 +01:00
return getAbsoluteAndInOsFormatPath ( {
2024-06-09 09:15:16 +02:00
pathIsh : buildOptions.keycloakifyBuildDirPath ,
2024-10-13 00:55:06 +02:00
cwd : relativePathsCwd
2024-02-11 16:17:38 +01:00
} ) ;
}
2024-02-24 05:38:42 +01:00
return pathJoin (
2024-06-09 09:03:43 +02:00
projectDirPath ,
2024-05-20 15:48:51 +02:00
resolvedViteConfig ? . buildDir === undefined
? "build_keycloak"
: ` ${ resolvedViteConfig . buildDir } _keycloak `
2024-02-24 05:38:42 +01:00
) ;
2024-02-11 16:17:38 +01:00
} ) ( ) ,
2024-05-20 15:48:51 +02:00
publicDirPath : ( ( ) = > {
2024-06-16 14:58:51 +02:00
if ( process . env . PUBLIC_DIR_PATH !== undefined ) {
return getAbsoluteAndInOsFormatPath ( {
pathIsh : process.env.PUBLIC_DIR_PATH ,
cwd : projectDirPath
} ) ;
}
2024-01-30 06:55:26 +01:00
webpack : {
2024-07-20 22:43:14 +02:00
if ( bundler !== "webpack" ) {
2024-01-30 06:55:26 +01:00
break webpack ;
}
2024-01-27 18:49:29 +01:00
2024-07-20 22:43:14 +02:00
assert ( parsedPackageJson . keycloakify !== undefined ) ;
if ( parsedPackageJson . keycloakify . publicDirPath !== undefined ) {
2024-01-30 06:55:26 +01:00
return getAbsoluteAndInOsFormatPath ( {
2024-07-20 22:43:14 +02:00
pathIsh : parsedPackageJson.keycloakify.publicDirPath ,
2024-10-13 00:55:06 +02:00
cwd : relativePathsCwd
2024-01-30 06:55:26 +01:00
} ) ;
}
2024-06-09 09:03:43 +02:00
return pathJoin ( projectDirPath , "public" ) ;
2023-08-21 05:54:17 +02:00
}
2022-08-16 14:41:06 +07:00
2024-07-20 22:43:14 +02:00
assert ( bundler === "vite" ) ;
assert ( resolvedViteConfig !== undefined ) ;
2024-06-09 09:03:43 +02:00
return pathJoin ( projectDirPath , resolvedViteConfig . publicDir ) ;
2023-08-21 05:54:17 +02:00
} ) ( ) ,
2024-07-27 00:44:32 +02:00
cacheDirPath : pathJoin (
( ( ) = > {
if ( process . env . XDG_CACHE_HOME !== undefined ) {
return getAbsoluteAndInOsFormatPath ( {
pathIsh : process.env.XDG_CACHE_HOME ,
cwd : process.cwd ( )
} ) ;
}
2024-05-16 07:47:50 +02:00
2024-07-27 00:44:32 +02:00
return pathJoin (
pathDirname ( packageJsonFilePath ) ,
"node_modules" ,
".cache"
) ;
} ) ( ) ,
"keycloakify"
) ,
2024-05-20 15:48:51 +02:00
urlPathname : ( ( ) = > {
2024-01-30 06:55:26 +01:00
webpack : {
2024-07-20 22:43:14 +02:00
if ( bundler !== "webpack" ) {
2024-01-30 06:55:26 +01:00
break webpack ;
}
const { homepage } = parsedPackageJson ;
let url : URL | undefined = undefined ;
2022-08-16 14:41:06 +07:00
2024-01-30 06:55:26 +01:00
if ( homepage !== undefined ) {
url = new URL ( homepage ) ;
}
if ( url === undefined ) {
return undefined ;
}
2022-08-16 14:41:06 +07:00
2024-01-30 06:55:26 +01:00
const out = url . pathname . replace ( /([^/])$/ , "$1/" ) ;
return out === "/" ? undefined : out ;
2023-08-21 05:54:17 +02:00
}
2022-08-16 14:41:06 +07:00
2024-07-20 22:43:14 +02:00
assert ( bundler === "vite" ) ;
assert ( resolvedViteConfig !== undefined ) ;
2024-01-30 06:55:26 +01:00
return resolvedViteConfig . urlPathname ;
} ) ( ) ,
2024-05-20 15:48:51 +02:00
assetsDirPath : ( ( ) = > {
2024-01-30 06:55:26 +01:00
webpack : {
2024-07-20 22:43:14 +02:00
if ( bundler !== "webpack" ) {
2024-01-30 06:55:26 +01:00
break webpack ;
}
2024-07-20 22:43:14 +02:00
assert ( parsedPackageJson . keycloakify !== undefined ) ;
if (
parsedPackageJson . keycloakify . staticDirPathInProjectBuildDirPath !==
undefined
) {
2024-06-16 14:05:23 +02:00
getAbsoluteAndInOsFormatPath ( {
2024-07-20 22:43:14 +02:00
pathIsh :
parsedPackageJson . keycloakify
. staticDirPathInProjectBuildDirPath ,
2024-10-13 00:55:06 +02:00
cwd : relativePathsCwd
2024-06-16 14:05:23 +02:00
} ) ;
}
2024-06-09 09:03:43 +02:00
return pathJoin ( projectBuildDirPath , "static" ) ;
2023-08-21 05:54:17 +02:00
}
2024-07-20 22:43:14 +02:00
assert ( bundler === "vite" ) ;
assert ( resolvedViteConfig !== undefined ) ;
2022-08-16 14:41:06 +07:00
2024-06-09 09:03:43 +02:00
return pathJoin ( projectBuildDirPath , resolvedViteConfig . assetsDir ) ;
2024-02-04 10:25:48 +01:00
} ) ( ) ,
2024-06-09 09:20:55 +02:00
kcContextExclusionsFtlCode : ( ( ) = > {
if ( buildOptions . kcContextExclusionsFtl === undefined ) {
return undefined ;
}
if ( buildOptions . kcContextExclusionsFtl . endsWith ( ".ftl" ) ) {
const kcContextExclusionsFtlPath = getAbsoluteAndInOsFormatPath ( {
pathIsh : buildOptions.kcContextExclusionsFtl ,
cwd : projectDirPath
} ) ;
return fs . readFileSync ( kcContextExclusionsFtlPath ) . toString ( "utf8" ) ;
}
return buildOptions . kcContextExclusionsFtl ;
} ) ( ) ,
2024-06-16 01:29:15 +02:00
environmentVariables : buildOptions.environmentVariables ? ? [ ] ,
2024-07-20 22:43:14 +02:00
implementedThemeTypes ,
2024-06-16 01:29:15 +02:00
themeSrcDirPath ,
2024-06-23 21:23:06 +02:00
fetchOptions : getProxyFetchOptions ( {
npmConfigGetCwd : ( function callee ( upCount : number ) : string {
const dirPath = pathResolve (
pathJoin ( . . . [ projectDirPath , . . . Array ( upCount ) . fill ( ".." ) ] )
) ;
assert (
dirPath !== pathSep ,
"Couldn't find a place to run 'npm config get'"
) ;
try {
child_process . execSync ( "npm config get" , {
cwd : dirPath ,
2024-07-09 14:59:59 +02:00
stdio : "pipe"
2024-06-23 21:23:06 +02:00
} ) ;
} catch ( error ) {
if ( String ( error ) . includes ( "ENOWORKSPACES" ) ) {
return callee ( upCount + 1 ) ;
}
throw error ;
}
return dirPath ;
} ) ( 0 )
} ) ,
2024-06-16 01:29:15 +02:00
jarTargets : ( ( ) = > {
2024-06-16 02:17:55 +02:00
const getDefaultJarFileBasename = ( range : string ) = >
2024-06-16 01:29:15 +02:00
` keycloak-theme-for-kc- ${ range } .jar ` ;
build_for_specific_keycloak_major_version : {
const buildForKeycloakMajorVersionNumber = ( ( ) = > {
2024-07-13 19:33:59 +02:00
const envValue =
process . env [ BUILD_FOR_KEYCLOAK_MAJOR_VERSION_ENV_NAME ] ;
2024-06-16 01:29:15 +02:00
if ( envValue === undefined ) {
return undefined ;
}
const major = parseInt ( envValue ) ;
assert ( ! isNaN ( major ) ) ;
return major ;
} ) ( ) ;
if ( buildForKeycloakMajorVersionNumber === undefined ) {
break build_for_specific_keycloak_major_version ;
}
const keycloakVersionRange : KeycloakVersionRange = ( ( ) = > {
2024-07-20 22:43:14 +02:00
if (
implementedThemeTypes . account . isImplemented &&
implementedThemeTypes . account . type === "Multi-Page"
) {
2024-06-16 01:29:15 +02:00
const keycloakVersionRange = ( ( ) = > {
if ( buildForKeycloakMajorVersionNumber <= 21 ) {
return "21-and-below" as const ;
}
assert ( buildForKeycloakMajorVersionNumber !== 22 ) ;
if ( buildForKeycloakMajorVersionNumber === 23 ) {
return "23" as const ;
}
if ( buildForKeycloakMajorVersionNumber === 24 ) {
return "24" as const ;
}
2024-10-04 12:58:31 +02:00
if ( buildForKeycloakMajorVersionNumber === 25 ) {
return "25" as const ;
}
return "26-and-above" as const ;
2024-06-16 01:29:15 +02:00
} ) ( ) ;
assert <
Equals <
typeof keycloakVersionRange ,
2024-07-07 18:45:14 +02:00
KeycloakVersionRange . WithAccountV1Theme
2024-06-16 01:29:15 +02:00
>
> ( ) ;
return keycloakVersionRange ;
} else {
const keycloakVersionRange = ( ( ) = > {
2024-10-04 12:17:08 +02:00
if (
buildForKeycloakMajorVersionNumber <= 21 ||
buildForKeycloakMajorVersionNumber >= 26
) {
return "all-other-versions" as const ;
2024-06-16 01:29:15 +02:00
}
2024-10-04 12:17:08 +02:00
return "22-to-25" as const ;
2024-06-16 01:29:15 +02:00
} ) ( ) ;
assert <
Equals <
typeof keycloakVersionRange ,
2024-07-07 18:45:14 +02:00
KeycloakVersionRange . WithoutAccountV1Theme
2024-06-16 01:29:15 +02:00
>
> ( ) ;
return keycloakVersionRange ;
}
} ) ( ) ;
2024-06-16 02:17:55 +02:00
const jarFileBasename = ( ( ) = > {
use_custom_jar_basename : {
const { keycloakVersionTargets } = buildOptions ;
2024-10-04 12:17:08 +02:00
assert (
is < Record < KeycloakVersionRange , string | boolean > > (
keycloakVersionTargets
)
) ;
2024-06-16 02:17:55 +02:00
if ( keycloakVersionTargets === undefined ) {
break use_custom_jar_basename ;
}
const entry = objectEntries ( keycloakVersionTargets ) . find (
( [ keycloakVersionRange_entry ] ) = >
keycloakVersionRange_entry === keycloakVersionRange
) ;
if ( entry === undefined ) {
break use_custom_jar_basename ;
}
const maybeJarFileBasename = entry [ 1 ] ;
if ( typeof maybeJarFileBasename !== "string" ) {
break use_custom_jar_basename ;
}
return maybeJarFileBasename ;
}
return getDefaultJarFileBasename ( keycloakVersionRange ) ;
} ) ( ) ;
2024-06-16 01:29:15 +02:00
return [
{
keycloakVersionRange ,
2024-06-16 02:17:55 +02:00
jarFileBasename
2024-06-16 01:29:15 +02:00
}
] ;
}
const jarTargets_default = ( ( ) = > {
const jarTargets : BuildContext [ "jarTargets" ] = [ ] ;
2024-07-20 22:43:14 +02:00
if (
implementedThemeTypes . account . isImplemented &&
implementedThemeTypes . account . type === "Multi-Page"
) {
2024-06-16 01:29:15 +02:00
for ( const keycloakVersionRange of [
"21-and-below" ,
"23" ,
"24" ,
2024-10-04 12:58:31 +02:00
"25" ,
"26-and-above"
2024-06-16 01:29:15 +02:00
] as const ) {
assert <
Equals <
typeof keycloakVersionRange ,
2024-07-07 18:45:14 +02:00
KeycloakVersionRange . WithAccountV1Theme
2024-06-16 01:29:15 +02:00
>
> ( true ) ;
jarTargets . push ( {
keycloakVersionRange ,
2024-06-16 02:17:55 +02:00
jarFileBasename :
getDefaultJarFileBasename ( keycloakVersionRange )
2024-06-16 01:29:15 +02:00
} ) ;
}
} else {
for ( const keycloakVersionRange of [
2024-10-04 12:17:08 +02:00
"22-to-25" ,
"all-other-versions"
2024-06-16 01:29:15 +02:00
] as const ) {
assert <
Equals <
typeof keycloakVersionRange ,
2024-07-07 18:45:14 +02:00
KeycloakVersionRange . WithoutAccountV1Theme
2024-06-16 01:29:15 +02:00
>
> ( true ) ;
jarTargets . push ( {
keycloakVersionRange ,
2024-06-16 02:17:55 +02:00
jarFileBasename :
getDefaultJarFileBasename ( keycloakVersionRange )
2024-06-16 01:29:15 +02:00
} ) ;
}
}
return jarTargets ;
} ) ( ) ;
2024-06-16 01:34:06 +02:00
if ( buildOptions . keycloakVersionTargets === undefined ) {
2024-06-16 01:29:15 +02:00
return jarTargets_default ;
}
const jarTargets : BuildContext [ "jarTargets" ] = [ ] ;
2024-07-20 22:43:14 +02:00
for ( const [ keycloakVersionRange , jarNameOrBoolean ] of objectEntries (
2024-10-04 12:17:08 +02:00
( ( ) = > {
const { keycloakVersionTargets } = buildOptions ;
assert (
is < Record < KeycloakVersionRange , string | boolean > > (
keycloakVersionTargets
)
) ;
return keycloakVersionTargets ;
} ) ( )
2024-07-20 22:43:14 +02:00
) ) {
2024-06-16 01:29:15 +02:00
if ( jarNameOrBoolean === false ) {
continue ;
}
if ( jarNameOrBoolean === true ) {
jarTargets . push ( {
keycloakVersionRange : keycloakVersionRange ,
2024-06-16 02:17:55 +02:00
jarFileBasename : getDefaultJarFileBasename ( keycloakVersionRange )
2024-06-16 01:29:15 +02:00
} ) ;
continue ;
}
const jarFileBasename = jarNameOrBoolean ;
if ( ! jarFileBasename . endsWith ( ".jar" ) ) {
console . log (
chalk . red ( ` Bad ${ jarFileBasename } should end with '.jar' \ n ` )
) ;
process . exit ( 1 ) ;
}
if ( jarFileBasename . includes ( "/" ) || jarFileBasename . includes ( "\\" ) ) {
console . log (
chalk . red (
[
` Invalid ${ jarFileBasename } . It's not supposed to be a path, ` ,
` Only the basename of the jar file is expected. ` ,
` Example: keycloak-theme.jar `
] . join ( " " )
)
) ;
process . exit ( 1 ) ;
}
jarTargets . push ( {
keycloakVersionRange : keycloakVersionRange ,
jarFileBasename : jarNameOrBoolean
} ) ;
}
if ( jarTargets . length === 0 ) {
console . log (
chalk . red (
"All jar targets are disabled. Please enable at least one jar target."
)
) ;
process . exit ( 1 ) ;
}
return jarTargets ;
2024-08-17 23:20:52 +02:00
} ) ( ) ,
startKeycloakOptions : {
dockerImage : ( ( ) = > {
if ( buildOptions . startKeycloakOptions ? . dockerImage === undefined ) {
return undefined ;
}
const [ reference , tag , . . . rest ] =
buildOptions . startKeycloakOptions . dockerImage . split ( ":" ) ;
assert (
reference !== undefined && tag !== undefined && rest . length === 0 ,
` Invalid docker image: ${ buildOptions . startKeycloakOptions . dockerImage } `
) ;
return { reference , tag } ;
} ) ( ) ,
dockerExtraArgs : buildOptions.startKeycloakOptions?.dockerExtraArgs ? ? [ ] ,
keycloakExtraArgs : buildOptions.startKeycloakOptions?.keycloakExtraArgs ? ? [ ] ,
extensionJars : ( buildOptions . startKeycloakOptions ? . extensionJars ? ? [ ] ) . map (
urlOrPath = > {
if ( /^https?:\/\// . test ( urlOrPath ) ) {
return { type : "url" , url : urlOrPath } ;
}
return {
type : "path" ,
path : getAbsoluteAndInOsFormatPath ( {
pathIsh : urlOrPath ,
2024-10-13 00:55:06 +02:00
cwd : relativePathsCwd
2024-08-17 23:20:52 +02:00
} )
} ;
}
) ,
realmJsonFilePath :
buildOptions . startKeycloakOptions ? . realmJsonFilePath === undefined
? undefined
: getAbsoluteAndInOsFormatPath ( {
pathIsh : buildOptions.startKeycloakOptions.realmJsonFilePath ,
2024-10-13 00:55:06 +02:00
cwd : relativePathsCwd
2024-08-18 21:10:18 +02:00
} ) ,
port : buildOptions.startKeycloakOptions?.port
2024-08-17 23:20:52 +02:00
}
2023-08-21 05:54:17 +02:00
} ;
2022-08-16 14:41:06 +07:00
}