keycloakify 7.16.0-rc.0 → 8.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/account/Template.js +5 -3
- package/account/Template.js.map +1 -1
- package/account/kcContext/kcContextMocks.js +0 -4
- package/account/kcContext/kcContextMocks.js.map +1 -1
- package/bin/copy-keycloak-resources-to-public.js +3 -2
- package/bin/copy-keycloak-resources-to-public.js.map +1 -1
- package/bin/download-builtin-keycloak-theme.d.ts +1 -1
- package/bin/download-builtin-keycloak-theme.js +84 -11
- package/bin/download-builtin-keycloak-theme.js.map +1 -1
- package/bin/initialize-email-theme.js +6 -5
- package/bin/initialize-email-theme.js.map +1 -1
- package/bin/keycloakify/BuildOptions.d.ts +18 -36
- package/bin/keycloakify/BuildOptions.js +71 -145
- package/bin/keycloakify/BuildOptions.js.map +1 -1
- package/bin/keycloakify/generateFtl/generateFtl.d.ts +5 -25
- package/bin/keycloakify/generateFtl/generateFtl.js +7 -11
- package/bin/keycloakify/generateFtl/generateFtl.js.map +1 -1
- package/bin/keycloakify/{generateJavaStackFiles/generateJavaStackFiles.d.ts → generateJavaStackFiles.d.ts} +3 -4
- package/bin/keycloakify/generateJavaStackFiles.js +103 -0
- package/bin/keycloakify/generateJavaStackFiles.js.map +1 -0
- package/bin/keycloakify/generateStartKeycloakTestingContainer.js +1 -5
- package/bin/keycloakify/generateStartKeycloakTestingContainer.js.map +1 -1
- package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.d.ts +5 -1
- package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.js +24 -6
- package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.js.map +1 -1
- package/bin/keycloakify/generateTheme/generateTheme.d.ts +8 -28
- package/bin/keycloakify/generateTheme/generateTheme.js +22 -33
- package/bin/keycloakify/generateTheme/generateTheme.js.map +1 -1
- package/bin/keycloakify/generateTheme/readFieldNameUsage.js +1 -2
- package/bin/keycloakify/generateTheme/readFieldNameUsage.js.map +1 -1
- package/bin/keycloakify/generateTheme/readStaticResourcesUsage.d.ts +17 -0
- package/bin/keycloakify/generateTheme/readStaticResourcesUsage.js +172 -0
- package/bin/keycloakify/generateTheme/readStaticResourcesUsage.js.map +1 -0
- package/bin/keycloakify/keycloakify.js +17 -17
- package/bin/keycloakify/keycloakify.js.map +1 -1
- package/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode.d.ts +0 -11
- package/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode.js +6 -27
- package/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode.js.map +1 -1
- package/bin/keycloakify/replacers/replaceImportsInCssCode.js +1 -7
- package/bin/keycloakify/replacers/replaceImportsInCssCode.js.map +1 -1
- package/bin/keycloakify/replacers/replaceImportsInInlineCssCode.d.ts +3 -13
- package/bin/keycloakify/replacers/replaceImportsInInlineCssCode.js +5 -12
- package/bin/keycloakify/replacers/replaceImportsInInlineCssCode.js.map +1 -1
- package/bin/tools/downloadAndUnzip.d.ts +13 -2
- package/bin/tools/downloadAndUnzip.js +81 -15
- package/bin/tools/downloadAndUnzip.js.map +1 -1
- package/bin/tools/transformCodebase.d.ts +1 -0
- package/bin/tools/transformCodebase.js +6 -5
- package/bin/tools/transformCodebase.js.map +1 -1
- package/bin/tools/unzip.d.ts +2 -1
- package/bin/tools/unzip.js +129 -11
- package/bin/tools/unzip.js.map +1 -1
- package/lib/usePrepareTemplate.d.ts +0 -5
- package/lib/usePrepareTemplate.js +4 -10
- package/lib/usePrepareTemplate.js.map +1 -1
- package/login/Template.js +5 -6
- package/login/Template.js.map +1 -1
- package/login/kcContext/KcContext.d.ts +1 -1
- package/login/kcContext/kcContextMocks.js +1 -5
- package/login/kcContext/kcContextMocks.js.map +1 -1
- package/login/pages/Login.js +16 -20
- package/login/pages/Login.js.map +1 -1
- package/login/pages/LoginOtp.js +1 -2
- package/login/pages/LoginOtp.js.map +1 -1
- package/package.json +11 -77
- package/src/account/Template.tsx +5 -3
- package/src/account/kcContext/kcContextMocks.ts +0 -4
- package/src/bin/copy-keycloak-resources-to-public.ts +3 -2
- package/src/bin/download-builtin-keycloak-theme.ts +71 -14
- package/src/bin/initialize-email-theme.ts +6 -4
- package/src/bin/keycloakify/BuildOptions.ts +99 -192
- package/src/bin/keycloakify/generateFtl/generateFtl.ts +16 -45
- package/src/bin/keycloakify/generateJavaStackFiles.ts +84 -0
- package/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts +1 -6
- package/src/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.ts +30 -6
- package/src/bin/keycloakify/generateTheme/generateTheme.ts +34 -69
- package/src/bin/keycloakify/generateTheme/readFieldNameUsage.ts +1 -4
- package/src/bin/keycloakify/generateTheme/readStaticResourcesUsage.ts +83 -0
- package/src/bin/keycloakify/keycloakify.ts +2 -1
- package/src/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode.ts +9 -51
- package/src/bin/keycloakify/replacers/replaceImportsInCssCode.ts +1 -9
- package/src/bin/keycloakify/replacers/replaceImportsInInlineCssCode.ts +5 -29
- package/src/bin/tools/downloadAndUnzip.ts +99 -15
- package/src/bin/tools/transformCodebase.ts +7 -6
- package/src/bin/tools/unzip.ts +57 -8
- package/src/lib/usePrepareTemplate.ts +13 -24
- package/src/login/Template.tsx +5 -6
- package/src/login/kcContext/KcContext.ts +1 -1
- package/src/login/kcContext/kcContextMocks.ts +1 -5
- package/src/login/pages/Login.tsx +31 -34
- package/src/login/pages/LoginOtp.tsx +1 -2
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountPages.java +0 -33
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProvider.java +0 -76
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProviderFactory.java +0 -25
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountSpi.java +0 -50
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProvider.java +0 -424
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProviderFactory.java +0 -51
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/Templates.java +0 -51
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountBean.java +0 -91
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountFederatedIdentityBean.java +0 -157
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ApplicationsBean.java +0 -258
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AuthorizationBean.java +0 -515
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/FeaturesBean.java +0 -56
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/LogBean.java +0 -95
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/PasswordBean.java +0 -34
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/RealmBean.java +0 -75
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ReferrerBean.java +0 -38
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/SessionsBean.java +0 -93
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/TotpBean.java +0 -125
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/UrlBean.java +0 -121
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/AccountUrls.java +0 -115
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormService.java +0 -1320
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormServiceFactory.java +0 -64
- package/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.js +0 -298
- package/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.js.map +0 -1
- package/bin/keycloakify/generateJavaStackFiles/index.d.ts +0 -1
- package/bin/keycloakify/generateJavaStackFiles/index.js +0 -18
- package/bin/keycloakify/generateJavaStackFiles/index.js.map +0 -1
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountPages.java +0 -33
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProvider.java +0 -76
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProviderFactory.java +0 -25
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountSpi.java +0 -50
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProvider.java +0 -424
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProviderFactory.java +0 -51
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/Templates.java +0 -51
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountBean.java +0 -91
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountFederatedIdentityBean.java +0 -157
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ApplicationsBean.java +0 -258
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AuthorizationBean.java +0 -515
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/FeaturesBean.java +0 -56
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/LogBean.java +0 -95
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/PasswordBean.java +0 -34
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/RealmBean.java +0 -75
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ReferrerBean.java +0 -38
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/SessionsBean.java +0 -93
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/TotpBean.java +0 -125
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/UrlBean.java +0 -121
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/AccountUrls.java +0 -115
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormService.java +0 -1320
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormServiceFactory.java +0 -64
- package/src/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.ts +0 -249
- package/src/bin/keycloakify/generateJavaStackFiles/index.ts +0 -1
@@ -12,46 +12,20 @@ import { downloadKeycloakStaticResources } from "./downloadKeycloakStaticResourc
|
|
12
12
|
import { readFieldNameUsage } from "./readFieldNameUsage";
|
13
13
|
import { readExtraPagesNames } from "./readExtraPageNames";
|
14
14
|
import { generateMessageProperties } from "./generateMessageProperties";
|
15
|
-
import {
|
16
|
-
|
17
|
-
export type BuildOptionsLike =
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
themeVersion: string;
|
25
|
-
keycloakVersionDefaultAssets: string;
|
26
|
-
};
|
27
|
-
|
28
|
-
export type Standalone = Common & {
|
29
|
-
isStandalone: true;
|
30
|
-
urlPathname: string | undefined;
|
31
|
-
};
|
32
|
-
|
33
|
-
export type ExternalAssets = ExternalAssets.SameDomain | ExternalAssets.DifferentDomains;
|
34
|
-
|
35
|
-
export namespace ExternalAssets {
|
36
|
-
export type CommonExternalAssets = Common & {
|
37
|
-
isStandalone: false;
|
38
|
-
};
|
39
|
-
|
40
|
-
export type SameDomain = CommonExternalAssets & {
|
41
|
-
areAppAndKeycloakServerSharingSameDomain: true;
|
42
|
-
};
|
43
|
-
|
44
|
-
export type DifferentDomains = CommonExternalAssets & {
|
45
|
-
areAppAndKeycloakServerSharingSameDomain: false;
|
46
|
-
urlOrigin: string;
|
47
|
-
urlPathname: string | undefined;
|
48
|
-
};
|
49
|
-
}
|
50
|
-
}
|
15
|
+
import { readStaticResourcesUsage } from "./readStaticResourcesUsage";
|
16
|
+
|
17
|
+
export type BuildOptionsLike = {
|
18
|
+
themeName: string;
|
19
|
+
extraThemeProperties: string[] | undefined;
|
20
|
+
themeVersion: string;
|
21
|
+
keycloakVersionDefaultAssets: string;
|
22
|
+
urlPathname: string | undefined;
|
23
|
+
};
|
51
24
|
|
52
25
|
assert<BuildOptions extends BuildOptionsLike ? true : false>();
|
53
26
|
|
54
27
|
export async function generateTheme(params: {
|
28
|
+
projectDirPath: string;
|
55
29
|
reactAppBuildDirPath: string;
|
56
30
|
keycloakThemeBuildingDirPath: string;
|
57
31
|
themeSrcDirPath: string;
|
@@ -59,7 +33,15 @@ export async function generateTheme(params: {
|
|
59
33
|
buildOptions: BuildOptionsLike;
|
60
34
|
keycloakifyVersion: string;
|
61
35
|
}): Promise<void> {
|
62
|
-
const {
|
36
|
+
const {
|
37
|
+
projectDirPath,
|
38
|
+
reactAppBuildDirPath,
|
39
|
+
keycloakThemeBuildingDirPath,
|
40
|
+
themeSrcDirPath,
|
41
|
+
keycloakifySrcDirPath,
|
42
|
+
buildOptions,
|
43
|
+
keycloakifyVersion
|
44
|
+
} = params;
|
63
45
|
|
64
46
|
const getThemeDirPath = (themeType: ThemeType | "email") =>
|
65
47
|
pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", buildOptions.themeName, themeType);
|
@@ -78,17 +60,16 @@ export async function generateTheme(params: {
|
|
78
60
|
copy_app_resources_to_theme_path: {
|
79
61
|
const isFirstPass = themeType.indexOf(themeType) === 0;
|
80
62
|
|
81
|
-
if (!isFirstPass
|
63
|
+
if (!isFirstPass) {
|
82
64
|
break copy_app_resources_to_theme_path;
|
83
65
|
}
|
84
66
|
|
85
67
|
transformCodebase({
|
86
|
-
"destDirPath":
|
68
|
+
"destDirPath": pathJoin(themeDirPath, "resources", "build"),
|
87
69
|
"srcDirPath": reactAppBuildDirPath,
|
88
70
|
"transformSourceCode": ({ filePath, sourceCode }) => {
|
89
71
|
//NOTE: Prevent cycles, excludes the folder we generated for debug in public/
|
90
72
|
if (
|
91
|
-
buildOptions.isStandalone &&
|
92
73
|
isInside({
|
93
74
|
"dirPath": pathJoin(reactAppBuildDirPath, basenameOfKeycloakDirInPublicDir),
|
94
75
|
filePath
|
@@ -98,10 +79,6 @@ export async function generateTheme(params: {
|
|
98
79
|
}
|
99
80
|
|
100
81
|
if (/\.css?$/i.test(filePath)) {
|
101
|
-
if (!buildOptions.isStandalone) {
|
102
|
-
return undefined;
|
103
|
-
}
|
104
|
-
|
105
82
|
const { cssGlobalsToDefine, fixedCssCode } = replaceImportsInCssCode({
|
106
83
|
"cssCode": sourceCode.toString("utf8")
|
107
84
|
});
|
@@ -121,19 +98,14 @@ export async function generateTheme(params: {
|
|
121
98
|
}
|
122
99
|
|
123
100
|
if (/\.js?$/i.test(filePath)) {
|
124
|
-
if (!buildOptions.isStandalone && buildOptions.areAppAndKeycloakServerSharingSameDomain) {
|
125
|
-
return undefined;
|
126
|
-
}
|
127
|
-
|
128
101
|
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
|
129
|
-
"jsCode": sourceCode.toString("utf8")
|
130
|
-
buildOptions
|
102
|
+
"jsCode": sourceCode.toString("utf8")
|
131
103
|
});
|
132
104
|
|
133
105
|
return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") };
|
134
106
|
}
|
135
107
|
|
136
|
-
return
|
108
|
+
return { "modifiedSourceCode": sourceCode };
|
137
109
|
}
|
138
110
|
});
|
139
111
|
}
|
@@ -198,10 +170,11 @@ export async function generateTheme(params: {
|
|
198
170
|
}
|
199
171
|
|
200
172
|
await downloadKeycloakStaticResources({
|
201
|
-
|
173
|
+
projectDirPath,
|
202
174
|
"keycloakVersion": buildOptions.keycloakVersionDefaultAssets,
|
203
175
|
"themeDirPath": keycloakDirInPublicDir,
|
204
|
-
themeType
|
176
|
+
themeType,
|
177
|
+
"usedResources": undefined
|
205
178
|
});
|
206
179
|
|
207
180
|
if (themeType !== themeTypes[0]) {
|
@@ -223,28 +196,20 @@ export async function generateTheme(params: {
|
|
223
196
|
}
|
224
197
|
|
225
198
|
await downloadKeycloakStaticResources({
|
226
|
-
|
199
|
+
projectDirPath,
|
227
200
|
"keycloakVersion": buildOptions.keycloakVersionDefaultAssets,
|
228
201
|
themeDirPath,
|
229
|
-
themeType
|
202
|
+
themeType,
|
203
|
+
"usedResources": readStaticResourcesUsage({
|
204
|
+
keycloakifySrcDirPath,
|
205
|
+
themeSrcDirPath,
|
206
|
+
themeType
|
207
|
+
})
|
230
208
|
});
|
231
209
|
|
232
210
|
fs.writeFileSync(
|
233
211
|
pathJoin(themeDirPath, "theme.properties"),
|
234
|
-
Buffer.from(
|
235
|
-
[
|
236
|
-
`parent=${(() => {
|
237
|
-
switch (themeType) {
|
238
|
-
case "login":
|
239
|
-
return "keycloak";
|
240
|
-
case "account":
|
241
|
-
return accountV1Keycloak;
|
242
|
-
}
|
243
|
-
})()}`,
|
244
|
-
...(buildOptions.extraThemeProperties ?? [])
|
245
|
-
].join("\n\n"),
|
246
|
-
"utf8"
|
247
|
-
)
|
212
|
+
Buffer.from([`parent=keycloak`, ...(buildOptions.extraThemeProperties ?? [])].join("\n\n"), "utf8")
|
248
213
|
);
|
249
214
|
}
|
250
215
|
|
@@ -3,7 +3,6 @@ import { removeDuplicates } from "evt/tools/reducers/removeDuplicates";
|
|
3
3
|
import { join as pathJoin } from "path";
|
4
4
|
import * as fs from "fs";
|
5
5
|
import type { ThemeType } from "../generateFtl";
|
6
|
-
import { exclude } from "tsafe/exclude";
|
7
6
|
|
8
7
|
/** Assumes the theme type exists */
|
9
8
|
export function readFieldNameUsage(params: { keycloakifySrcDirPath: string; themeSrcDirPath: string; themeType: ThemeType }): string[] {
|
@@ -11,9 +10,7 @@ export function readFieldNameUsage(params: { keycloakifySrcDirPath: string; them
|
|
11
10
|
|
12
11
|
const fieldNames: string[] = [];
|
13
12
|
|
14
|
-
for (const srcDirPath of
|
15
|
-
exclude(undefined)
|
16
|
-
)) {
|
13
|
+
for (const srcDirPath of [pathJoin(keycloakifySrcDirPath, themeType), pathJoin(themeSrcDirPath, themeType)]) {
|
17
14
|
const filePaths = crawl({ "dirPath": srcDirPath, "returnedPathsType": "absolute" }).filter(filePath => /\.(ts|tsx|js|jsx)$/.test(filePath));
|
18
15
|
|
19
16
|
for (const filePath of filePaths) {
|
@@ -0,0 +1,83 @@
|
|
1
|
+
import { crawl } from "../../tools/crawl";
|
2
|
+
import { join as pathJoin } from "path";
|
3
|
+
import * as fs from "fs";
|
4
|
+
import type { ThemeType } from "../generateFtl";
|
5
|
+
|
6
|
+
/** Assumes the theme type exists */
|
7
|
+
export function readStaticResourcesUsage(params: { keycloakifySrcDirPath: string; themeSrcDirPath: string; themeType: ThemeType }): {
|
8
|
+
resourcesCommonFilePaths: string[];
|
9
|
+
resourcesFilePaths: string[];
|
10
|
+
} {
|
11
|
+
const { keycloakifySrcDirPath, themeSrcDirPath, themeType } = params;
|
12
|
+
|
13
|
+
const resourcesCommonFilePaths = new Set<string>();
|
14
|
+
const resourcesFilePaths = new Set<string>();
|
15
|
+
|
16
|
+
for (const srcDirPath of [pathJoin(keycloakifySrcDirPath, themeType), pathJoin(themeSrcDirPath, themeType)]) {
|
17
|
+
const filePaths = crawl({ "dirPath": srcDirPath, "returnedPathsType": "absolute" }).filter(filePath => /\.(ts|tsx|js|jsx)$/.test(filePath));
|
18
|
+
|
19
|
+
for (const filePath of filePaths) {
|
20
|
+
const rawSourceFile = fs.readFileSync(filePath).toString("utf8");
|
21
|
+
|
22
|
+
if (!rawSourceFile.includes("resourcesCommonPath") && !rawSourceFile.includes("resourcesPath")) {
|
23
|
+
continue;
|
24
|
+
}
|
25
|
+
|
26
|
+
const wrap = readPaths({ rawSourceFile });
|
27
|
+
|
28
|
+
wrap.resourcesCommonFilePaths.forEach(filePath => resourcesCommonFilePaths.add(filePath));
|
29
|
+
wrap.resourcesFilePaths.forEach(filePath => resourcesFilePaths.add(filePath));
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
return {
|
34
|
+
"resourcesCommonFilePaths": Array.from(resourcesCommonFilePaths),
|
35
|
+
"resourcesFilePaths": Array.from(resourcesFilePaths)
|
36
|
+
};
|
37
|
+
}
|
38
|
+
|
39
|
+
/** Exported for testing purpose */
|
40
|
+
export function readPaths(params: { rawSourceFile: string }): {
|
41
|
+
resourcesCommonFilePaths: string[];
|
42
|
+
resourcesFilePaths: string[];
|
43
|
+
} {
|
44
|
+
const { rawSourceFile } = params;
|
45
|
+
|
46
|
+
const resourcesCommonFilePaths = new Set<string>();
|
47
|
+
const resourcesFilePaths = new Set<string>();
|
48
|
+
|
49
|
+
for (const isCommon of [true, false]) {
|
50
|
+
const set = isCommon ? resourcesCommonFilePaths : resourcesFilePaths;
|
51
|
+
|
52
|
+
{
|
53
|
+
const regexp = new RegExp(`resources${isCommon ? "Common" : ""}Path\\s*}([^\`]+)\``, "g");
|
54
|
+
|
55
|
+
const matches = [...rawSourceFile.matchAll(regexp)];
|
56
|
+
|
57
|
+
for (const match of matches) {
|
58
|
+
const filePath = match[1];
|
59
|
+
|
60
|
+
set.add(filePath);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
{
|
65
|
+
const regexp = new RegExp(`resources${isCommon ? "Common" : ""}Path\\s*[+,]\\s*["']([^"'\`]+)["'\`]`, "g");
|
66
|
+
|
67
|
+
const matches = [...rawSourceFile.matchAll(regexp)];
|
68
|
+
|
69
|
+
for (const match of matches) {
|
70
|
+
const filePath = match[1];
|
71
|
+
|
72
|
+
set.add(filePath);
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
const removePrefixSlash = (filePath: string) => (filePath.startsWith("/") ? filePath.slice(1) : filePath);
|
78
|
+
|
79
|
+
return {
|
80
|
+
"resourcesCommonFilePaths": Array.from(resourcesCommonFilePaths).map(removePrefixSlash),
|
81
|
+
"resourcesFilePaths": Array.from(resourcesFilePaths).map(removePrefixSlash)
|
82
|
+
};
|
83
|
+
}
|
@@ -30,6 +30,7 @@ export async function main() {
|
|
30
30
|
|
31
31
|
for (const themeName of [buildOptions.themeName, ...buildOptions.extraThemeNames]) {
|
32
32
|
await generateTheme({
|
33
|
+
projectDirPath,
|
33
34
|
"keycloakThemeBuildingDirPath": buildOptions.keycloakifyBuildDirPath,
|
34
35
|
themeSrcDirPath,
|
35
36
|
"keycloakifySrcDirPath": pathJoin(keycloakifyDirPath, "src"),
|
@@ -48,7 +49,7 @@ export async function main() {
|
|
48
49
|
});
|
49
50
|
}
|
50
51
|
|
51
|
-
const { jarFilePath } =
|
52
|
+
const { jarFilePath } = generateJavaStackFiles({
|
52
53
|
"keycloakThemeBuildingDirPath": buildOptions.keycloakifyBuildDirPath,
|
53
54
|
"implementedThemeTypes": (() => {
|
54
55
|
const implementedThemeTypes = {
|
@@ -1,31 +1,6 @@
|
|
1
1
|
import { ftlValuesGlobalName } from "../ftlValuesGlobalName";
|
2
|
-
import type { BuildOptions } from "../BuildOptions";
|
3
|
-
import { assert } from "tsafe/assert";
|
4
|
-
import { is } from "tsafe/is";
|
5
|
-
import { Reflect } from "tsafe/Reflect";
|
6
2
|
|
7
|
-
export
|
8
|
-
|
9
|
-
export namespace BuildOptionsLike {
|
10
|
-
export type Standalone = {
|
11
|
-
isStandalone: true;
|
12
|
-
};
|
13
|
-
|
14
|
-
export type ExternalAssets = {
|
15
|
-
isStandalone: false;
|
16
|
-
urlOrigin: string;
|
17
|
-
};
|
18
|
-
}
|
19
|
-
|
20
|
-
{
|
21
|
-
const buildOptions = Reflect<BuildOptions>();
|
22
|
-
|
23
|
-
assert(!is<BuildOptions.ExternalAssets.CommonExternalAssets>(buildOptions));
|
24
|
-
|
25
|
-
assert<typeof buildOptions extends BuildOptionsLike ? true : false>();
|
26
|
-
}
|
27
|
-
|
28
|
-
export function replaceImportsFromStaticInJsCode(params: { jsCode: string; buildOptions: BuildOptionsLike }): { fixedJsCode: string } {
|
3
|
+
export function replaceImportsFromStaticInJsCode(params: { jsCode: string }): { fixedJsCode: string } {
|
29
4
|
/*
|
30
5
|
NOTE:
|
31
6
|
|
@@ -38,7 +13,7 @@ export function replaceImportsFromStaticInJsCode(params: { jsCode: string; build
|
|
38
13
|
will always run in keycloak context.
|
39
14
|
*/
|
40
15
|
|
41
|
-
const { jsCode
|
16
|
+
const { jsCode } = params;
|
42
17
|
|
43
18
|
const getReplaceArgs = (language: "js" | "css"): Parameters<typeof String.prototype.replace> => [
|
44
19
|
new RegExp(`([a-zA-Z_]+)\\.([a-zA-Z]+)=function\\(([a-zA-Z]+)\\){return"static\\/${language}\\/"`, "g"),
|
@@ -46,40 +21,23 @@ export function replaceImportsFromStaticInJsCode(params: { jsCode: string; build
|
|
46
21
|
${n}[(function(){
|
47
22
|
var pd= Object.getOwnPropertyDescriptor(${n}, "p");
|
48
23
|
if( pd === undefined || pd.configurable ){
|
49
|
-
${
|
50
|
-
buildOptions.isStandalone
|
51
|
-
? `
|
52
|
-
Object.defineProperty(${n}, "p", {
|
53
|
-
get: function() { return window.${ftlValuesGlobalName}.url.resourcesPath; },
|
54
|
-
set: function (){}
|
55
|
-
});
|
56
|
-
`
|
57
|
-
: `
|
58
|
-
var p= "";
|
59
24
|
Object.defineProperty(${n}, "p", {
|
60
|
-
get: function() { return
|
61
|
-
set: function (
|
25
|
+
get: function() { return window.${ftlValuesGlobalName}.url.resourcesPath; },
|
26
|
+
set: function (){}
|
62
27
|
});
|
63
|
-
`
|
64
|
-
}
|
65
28
|
}
|
66
29
|
return "${u}";
|
67
|
-
})()] = function(${e}) { return "${
|
30
|
+
})()] = function(${e}) { return "${true ? "/build/" : ""}static/${language}/"`
|
68
31
|
];
|
69
32
|
|
70
33
|
const fixedJsCode = jsCode
|
71
34
|
.replace(...getReplaceArgs("js"))
|
72
35
|
.replace(...getReplaceArgs("css"))
|
73
|
-
.replace(/
|
74
|
-
buildOptions.isStandalone
|
75
|
-
? `window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/`
|
76
|
-
: `("${ftlValuesGlobalName}" in window ? "${buildOptions.urlOrigin}/" : ${group}) + "static/`
|
77
|
-
)
|
36
|
+
.replace(/[a-zA-Z]+\.[a-zA-Z]+\+"static\//g, `window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/`)
|
78
37
|
//TODO: Write a test case for this
|
79
|
-
.replace(
|
80
|
-
|
81
|
-
|
82
|
-
: `".chunk.css",${group1} = ("${ftlValuesGlobalName}" in window ? "${buildOptions.urlOrigin}/" : ${group2}) + ${group3},`
|
38
|
+
.replace(
|
39
|
+
/".chunk.css",([a-zA-Z])+=[a-zA-Z]+\.[a-zA-Z]+\+([a-zA-Z]+),/,
|
40
|
+
(...[, group1, group2]) => `".chunk.css",${group1} = window.${ftlValuesGlobalName}.url.resourcesPath + "/build/" + ${group2},`
|
83
41
|
);
|
84
42
|
|
85
43
|
return { fixedJsCode };
|
@@ -1,20 +1,12 @@
|
|
1
1
|
import * as crypto from "crypto";
|
2
2
|
import type { BuildOptions } from "../BuildOptions";
|
3
3
|
import { assert } from "tsafe/assert";
|
4
|
-
import { is } from "tsafe/is";
|
5
|
-
import { Reflect } from "tsafe/Reflect";
|
6
4
|
|
7
5
|
export type BuildOptionsLike = {
|
8
6
|
urlPathname: string | undefined;
|
9
7
|
};
|
10
8
|
|
11
|
-
|
12
|
-
const buildOptions = Reflect<BuildOptions>();
|
13
|
-
|
14
|
-
assert(!is<BuildOptions.ExternalAssets.CommonExternalAssets>(buildOptions));
|
15
|
-
|
16
|
-
assert<typeof buildOptions extends BuildOptionsLike ? true : false>();
|
17
|
-
}
|
9
|
+
assert<BuildOptions extends BuildOptionsLike ? true : false>();
|
18
10
|
|
19
11
|
export function replaceImportsInCssCode(params: { cssCode: string }): {
|
20
12
|
fixedCssCode: string;
|
@@ -1,32 +1,11 @@
|
|
1
1
|
import type { BuildOptions } from "../BuildOptions";
|
2
2
|
import { assert } from "tsafe/assert";
|
3
|
-
import { is } from "tsafe/is";
|
4
|
-
import { Reflect } from "tsafe/Reflect";
|
5
3
|
|
6
|
-
export type BuildOptionsLike =
|
4
|
+
export type BuildOptionsLike = {
|
5
|
+
urlPathname: string | undefined;
|
6
|
+
};
|
7
7
|
|
8
|
-
|
9
|
-
export type Common = {
|
10
|
-
urlPathname: string | undefined;
|
11
|
-
};
|
12
|
-
|
13
|
-
export type Standalone = Common & {
|
14
|
-
isStandalone: true;
|
15
|
-
};
|
16
|
-
|
17
|
-
export type ExternalAssets = Common & {
|
18
|
-
isStandalone: false;
|
19
|
-
urlOrigin: string;
|
20
|
-
};
|
21
|
-
}
|
22
|
-
|
23
|
-
{
|
24
|
-
const buildOptions = Reflect<BuildOptions>();
|
25
|
-
|
26
|
-
assert(!is<BuildOptions.ExternalAssets.CommonExternalAssets>(buildOptions));
|
27
|
-
|
28
|
-
assert<typeof buildOptions extends BuildOptionsLike ? true : false>();
|
29
|
-
}
|
8
|
+
assert<BuildOptions extends BuildOptionsLike ? true : false>();
|
30
9
|
|
31
10
|
export function replaceImportsInInlineCssCode(params: { cssCode: string; buildOptions: BuildOptionsLike }): {
|
32
11
|
fixedCssCode: string;
|
@@ -37,10 +16,7 @@ export function replaceImportsInInlineCssCode(params: { cssCode: string; buildOp
|
|
37
16
|
buildOptions.urlPathname === undefined
|
38
17
|
? /url\(["']?\/([^/][^)"']+)["']?\)/g
|
39
18
|
: new RegExp(`url\\(["']?${buildOptions.urlPathname}([^)"']+)["']?\\)`, "g"),
|
40
|
-
(...[, group]) =>
|
41
|
-
`url(${
|
42
|
-
buildOptions.isStandalone ? "${url.resourcesPath}/build/" + group : buildOptions.urlOrigin + (buildOptions.urlPathname ?? "/") + group
|
43
|
-
})`
|
19
|
+
(...[, group]) => `url(\${url.resourcesPath}/build/${group})`
|
44
20
|
);
|
45
21
|
|
46
22
|
return { fixedCssCode };
|
@@ -1,18 +1,55 @@
|
|
1
1
|
import { exec as execCallback } from "child_process";
|
2
2
|
import { createHash } from "crypto";
|
3
|
-
import { mkdir, readFile, stat, writeFile } from "fs/promises";
|
3
|
+
import { mkdir, readFile, stat, writeFile, unlink, rm } from "fs/promises";
|
4
4
|
import fetch, { type FetchOptions } from "make-fetch-happen";
|
5
5
|
import { dirname as pathDirname, join as pathJoin, resolve as pathResolve, sep as pathSep } from "path";
|
6
6
|
import { assert } from "tsafe/assert";
|
7
7
|
import { promisify } from "util";
|
8
|
-
import { getProjectRoot } from "./getProjectRoot";
|
9
8
|
import { transformCodebase } from "./transformCodebase";
|
10
|
-
import { unzip } from "./unzip";
|
9
|
+
import { unzip, zip } from "./unzip";
|
11
10
|
|
12
11
|
const exec = promisify(execCallback);
|
13
12
|
|
14
|
-
function
|
15
|
-
|
13
|
+
function generateFileNameFromURL(params: {
|
14
|
+
url: string;
|
15
|
+
preCacheTransform:
|
16
|
+
| {
|
17
|
+
actionCacheId: string;
|
18
|
+
actionFootprint: string;
|
19
|
+
}
|
20
|
+
| undefined;
|
21
|
+
}): string {
|
22
|
+
const { preCacheTransform } = params;
|
23
|
+
|
24
|
+
// Parse the URL
|
25
|
+
const url = new URL(params.url);
|
26
|
+
|
27
|
+
// Extract pathname and remove leading slashes
|
28
|
+
let fileName = url.pathname.replace(/^\//, "").replace(/\//g, "_");
|
29
|
+
|
30
|
+
// Optionally, add query parameters replacing special characters
|
31
|
+
if (url.search) {
|
32
|
+
fileName += url.search.replace(/[&=?]/g, "-");
|
33
|
+
}
|
34
|
+
|
35
|
+
// Replace any characters that are not valid in filenames
|
36
|
+
fileName = fileName.replace(/[^a-zA-Z0-9-_]/g, "");
|
37
|
+
|
38
|
+
// Trim or pad the fileName to a specific length
|
39
|
+
fileName = fileName.substring(0, 50);
|
40
|
+
|
41
|
+
add_pre_cache_transform: {
|
42
|
+
if (preCacheTransform === undefined) {
|
43
|
+
break add_pre_cache_transform;
|
44
|
+
}
|
45
|
+
|
46
|
+
// Sanitize actionCacheId the same way as other components
|
47
|
+
const sanitizedActionCacheId = preCacheTransform.actionCacheId.replace(/[^a-zA-Z0-9-_]/g, "_");
|
48
|
+
|
49
|
+
fileName += `_${sanitizedActionCacheId}_${createHash("sha256").update(preCacheTransform.actionFootprint).digest("hex").substring(0, 5)}`;
|
50
|
+
}
|
51
|
+
|
52
|
+
return fileName;
|
16
53
|
}
|
17
54
|
|
18
55
|
async function exists(path: string) {
|
@@ -57,8 +94,6 @@ function readNpmConfig(): Promise<string> {
|
|
57
94
|
try {
|
58
95
|
stdout = await exec("npm config get", { "encoding": "utf8", cwd }).then(({ stdout }) => stdout);
|
59
96
|
} catch (error) {
|
60
|
-
console.log(String(error), error);
|
61
|
-
|
62
97
|
if (String(error).includes("ENOWORKSPACES")) {
|
63
98
|
assert(cwd !== pathSep);
|
64
99
|
|
@@ -115,14 +150,43 @@ async function getFetchOptions(): Promise<Pick<FetchOptions, "proxy" | "noProxy"
|
|
115
150
|
return { proxy, noProxy, strictSSL, cert, ca: ca.length === 0 ? undefined : ca };
|
116
151
|
}
|
117
152
|
|
118
|
-
export async function downloadAndUnzip(
|
119
|
-
|
153
|
+
export async function downloadAndUnzip(
|
154
|
+
params: {
|
155
|
+
url: string;
|
156
|
+
destDirPath: string;
|
157
|
+
specificDirsToExtract?: string[];
|
158
|
+
preCacheTransform?: {
|
159
|
+
actionCacheId: string;
|
160
|
+
action: (params: { destDirPath: string }) => Promise<void>;
|
161
|
+
};
|
162
|
+
} & (
|
163
|
+
| {
|
164
|
+
doUseCache: true;
|
165
|
+
projectDirPath: string;
|
166
|
+
}
|
167
|
+
| {
|
168
|
+
doUseCache: false;
|
169
|
+
}
|
170
|
+
)
|
171
|
+
) {
|
172
|
+
const { url, destDirPath, specificDirsToExtract, preCacheTransform, ...rest } = params;
|
173
|
+
|
174
|
+
const zipFileBasename = generateFileNameFromURL({
|
175
|
+
url,
|
176
|
+
"preCacheTransform":
|
177
|
+
preCacheTransform === undefined
|
178
|
+
? undefined
|
179
|
+
: {
|
180
|
+
"actionCacheId": preCacheTransform.actionCacheId,
|
181
|
+
"actionFootprint": preCacheTransform.action.toString()
|
182
|
+
}
|
183
|
+
});
|
120
184
|
|
121
|
-
const
|
122
|
-
|
123
|
-
|
124
|
-
const zipFilePath = pathJoin(cacheRoot,
|
125
|
-
const extractDirPath = pathJoin(cacheRoot,
|
185
|
+
const cacheRoot = !rest.doUseCache
|
186
|
+
? `tmp_${Math.random().toString().slice(2, 12)}`
|
187
|
+
: pathJoin(process.env.XDG_CACHE_HOME ?? pathJoin(rest.projectDirPath, "node_modules", ".cache"), "keycloakify");
|
188
|
+
const zipFilePath = pathJoin(cacheRoot, `${zipFileBasename}.zip`);
|
189
|
+
const extractDirPath = pathJoin(cacheRoot, `tmp_unzip_${zipFileBasename}`);
|
126
190
|
|
127
191
|
if (!(await exists(zipFilePath))) {
|
128
192
|
const opts = await getFetchOptions();
|
@@ -138,12 +202,32 @@ export async function downloadAndUnzip(params: { url: string; destDirPath: strin
|
|
138
202
|
response.body?.setMaxListeners(Number.MAX_VALUE);
|
139
203
|
assert(typeof response.body !== "undefined" && response.body != null);
|
140
204
|
await writeFile(zipFilePath, response.body);
|
205
|
+
|
206
|
+
if (specificDirsToExtract !== undefined || preCacheTransform !== undefined) {
|
207
|
+
await unzip(zipFilePath, extractDirPath, specificDirsToExtract);
|
208
|
+
|
209
|
+
await preCacheTransform?.action({
|
210
|
+
"destDirPath": extractDirPath
|
211
|
+
});
|
212
|
+
|
213
|
+
await unlink(zipFilePath);
|
214
|
+
|
215
|
+
await zip(extractDirPath, zipFilePath);
|
216
|
+
|
217
|
+
await rm(extractDirPath, { "recursive": true });
|
218
|
+
}
|
141
219
|
}
|
142
220
|
|
143
|
-
await unzip(zipFilePath, extractDirPath
|
221
|
+
await unzip(zipFilePath, extractDirPath);
|
144
222
|
|
145
223
|
transformCodebase({
|
146
224
|
"srcDirPath": extractDirPath,
|
147
225
|
"destDirPath": destDirPath
|
148
226
|
});
|
227
|
+
|
228
|
+
if (!rest.doUseCache) {
|
229
|
+
await rm(cacheRoot, { "recursive": true });
|
230
|
+
} else {
|
231
|
+
await rm(extractDirPath, { "recursive": true });
|
232
|
+
}
|
149
233
|
}
|
@@ -3,7 +3,7 @@ import * as path from "path";
|
|
3
3
|
import { crawl } from "./crawl";
|
4
4
|
import { id } from "tsafe/id";
|
5
5
|
|
6
|
-
type TransformSourceCode = (params: { sourceCode: Buffer; filePath: string }) =>
|
6
|
+
type TransformSourceCode = (params: { sourceCode: Buffer; filePath: string; fileRelativePath: string }) =>
|
7
7
|
| {
|
8
8
|
modifiedSourceCode: Buffer;
|
9
9
|
newFileName?: string;
|
@@ -20,26 +20,27 @@ export function transformCodebase(params: { srcDirPath: string; destDirPath: str
|
|
20
20
|
}))
|
21
21
|
} = params;
|
22
22
|
|
23
|
-
for (const
|
24
|
-
const filePath = path.join(srcDirPath,
|
23
|
+
for (const fileRelativePath of crawl({ "dirPath": srcDirPath, "returnedPathsType": "relative to dirPath" })) {
|
24
|
+
const filePath = path.join(srcDirPath, fileRelativePath);
|
25
25
|
|
26
26
|
const transformSourceCodeResult = transformSourceCode({
|
27
27
|
"sourceCode": fs.readFileSync(filePath),
|
28
|
-
filePath
|
28
|
+
filePath,
|
29
|
+
fileRelativePath
|
29
30
|
});
|
30
31
|
|
31
32
|
if (transformSourceCodeResult === undefined) {
|
32
33
|
continue;
|
33
34
|
}
|
34
35
|
|
35
|
-
fs.mkdirSync(path.dirname(path.join(destDirPath,
|
36
|
+
fs.mkdirSync(path.dirname(path.join(destDirPath, fileRelativePath)), {
|
36
37
|
"recursive": true
|
37
38
|
});
|
38
39
|
|
39
40
|
const { newFileName, modifiedSourceCode } = transformSourceCodeResult;
|
40
41
|
|
41
42
|
fs.writeFileSync(
|
42
|
-
path.join(path.dirname(path.join(destDirPath,
|
43
|
+
path.join(path.dirname(path.join(destDirPath, fileRelativePath)), newFileName ?? path.basename(fileRelativePath)),
|
43
44
|
modifiedSourceCode
|
44
45
|
);
|
45
46
|
}
|