Compare commits

...

10 Commits

Author SHA1 Message Date
5cf290b033 Update changelog v2.0.6 2021-07-08 01:08:57 +00:00
aec3da25b3 Bump version (changelog ignore) 2021-07-08 02:44:54 +02:00
66d7cb563d Merge pull request from asashay/add-custom-props-to-theme-properties
Add possibility to add custom properties to theme.properties file
2021-07-08 02:43:37 +02:00
551e9c041e add possibility to add custom properties to theme.properties file 2021-07-06 15:52:14 +03:00
fffb6d5b5e Update changelog v2.0.5 2021-07-05 01:10:51 +00:00
ac0bfeb360 Bump version (changelog ignore) 2021-07-05 03:06:49 +02:00
7c30059ca3 Fix broken url for big stylesheet 2021-07-05 03:06:31 +02:00
fdb9ae6c40 Update changelog v2.0.4 2021-07-03 00:41:40 +00:00
3c82ffc0ab Bump version (changelog ignore) 2021-07-03 02:39:59 +02:00
5dd3103aba Fix: 2021-07-03 02:39:39 +02:00
9 changed files with 276 additions and 196 deletions

@ -1,3 +1,18 @@
### **2.0.6** (2021-07-08)
- Merge pull request #18 from asashay/add-custom-props-to-theme-properties
Add possibility to add custom properties to theme.properties file
- add possibility to add custom properties to theme.properties file
### **2.0.5** (2021-07-05)
- Fix broken url for big stylesheet #16
### **2.0.4** (2021-07-03)
- Fix: #7
### **2.0.3** (2021-06-30) ### **2.0.3** (2021-06-30)
- Escape double quote in ftl to js conversion #15 - Escape double quote in ftl to js conversion #15

@ -1,6 +1,6 @@
{ {
"name": "keycloakify", "name": "keycloakify",
"version": "2.0.3", "version": "2.0.6",
"description": "Keycloak theme generator for Reacts app", "description": "Keycloak theme generator for Reacts app",
"repository": { "repository": {
"type": "git", "type": "git",

@ -19,6 +19,7 @@ export function main() {
console.log("🔏 Building the keycloak theme...⌚"); console.log("🔏 Building the keycloak theme...⌚");
const extraPagesId: string[] = (parsedPackageJson as any)["keycloakify"]?.["extraPages"] ?? []; const extraPagesId: string[] = (parsedPackageJson as any)["keycloakify"]?.["extraPages"] ?? [];
const extraThemeProperties: string[] = (parsedPackageJson as any)["keycloakify"]?.["extraThemeProperties"] ?? [];
generateKeycloakThemeResources({ generateKeycloakThemeResources({
keycloakThemeBuildingDirPath, keycloakThemeBuildingDirPath,
@ -55,7 +56,8 @@ export function main() {
}; };
})(), })(),
extraPagesId extraPagesId,
extraThemeProperties
}); });
const { jarFilePath } = generateJavaStackFiles({ const { jarFilePath } = generateJavaStackFiles({

@ -23,12 +23,13 @@ export function generateKeycloakThemeResources(
//If urlOrigin is not undefined then it means --externals-assets //If urlOrigin is not undefined then it means --externals-assets
urlOrigin: undefined | string; urlOrigin: undefined | string;
extraPagesId: string[]; extraPagesId: string[];
extraThemeProperties: string[];
} }
) { ) {
const { const {
themeName, reactAppBuildDirPath, keycloakThemeBuildingDirPath, themeName, reactAppBuildDirPath, keycloakThemeBuildingDirPath,
urlPathname, urlOrigin, extraPagesId urlPathname, urlOrigin, extraPagesId, extraThemeProperties
} = params; } = params;
const themeDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", themeName, "login"); const themeDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", themeName, "login");
@ -166,7 +167,10 @@ export function generateKeycloakThemeResources(
fs.writeFileSync( fs.writeFileSync(
pathJoin(themeDirPath, "theme.properties"), pathJoin(themeDirPath, "theme.properties"),
Buffer.from("parent=keycloak", "utf8") Buffer.from(
"parent=keycloak".concat("\n\n", extraThemeProperties.join("\n\n")),
"utf8"
)
); );
} }

@ -5,18 +5,39 @@ import { ftlValuesGlobalName } from "./ftlValuesGlobalName";
export function replaceImportsFromStaticInJsCode( export function replaceImportsFromStaticInJsCode(
params: { params: {
jsCode: string; jsCode: string;
urlOrigin: undefined | string; urlOrigin: undefined | string;
} }
): { fixedJsCode: string; } { ): { fixedJsCode: string; } {
/*
NOTE:
When we have urlOrigin defined it means that
we are building with --external-assets
so we have to make sur that the fixed js code will run
inside and outside keycloak.
When urlOrigin isn't defined we can assume the fixedJsCode
will always run in keycloak context.
*/
const { jsCode, urlOrigin } = params; const { jsCode, urlOrigin } = params;
const fixedJsCode = jsCode.replace( const fixedJsCode =
jsCode
.replace(
/([a-z]+\.[a-z]+)\+"static\//g, /([a-z]+\.[a-z]+)\+"static\//g,
(...[, group]) => (...[, group]) =>
urlOrigin === undefined ? urlOrigin === undefined ?
`window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/` : `window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/` :
`("${ftlValuesGlobalName}" in window ? "${urlOrigin}" : "") + ${group} + "static/` `("${ftlValuesGlobalName}" in window ? "${urlOrigin}" : "") + ${group} + "static/`
)
.replace(
/".chunk.css",([a-z])+=([a-z]+\.[a-z]+)\+([a-z]+),/,
(...[, group1, group2, group3]) =>
urlOrigin === undefined ?
`".chunk.css",${group1} = window.${ftlValuesGlobalName}.url.resourcesPath + "/build/" + ${group3},` :
`".chunk.css",${group1} = ("${ftlValuesGlobalName}" in window ? "${urlOrigin}" : "") + ${group2} + ${group3},`
); );
return { fixedJsCode }; return { fixedJsCode };

@ -8,9 +8,9 @@ import { deepAssign } from "../tools/deepAssign";
export type ExtendsKcContextBase< export type ExtendsKcContextBase<
KcContextExtended extends ({ pageId: string; } | undefined) KcContextExtended extends { pageId: string; }
> = > =
KcContextExtended extends undefined ? [KcContextExtended] extends [never] ?
KcContextBase : KcContextBase :
AndByDiscriminatingKey< AndByDiscriminatingKey<
"pageId", "pageId",
@ -18,7 +18,7 @@ export type ExtendsKcContextBase<
KcContextBase KcContextBase
>; >;
export function getKcContext<KcContextExtended extends ({ pageId: string; } | undefined) = undefined>( export function getKcContext<KcContextExtended extends { pageId: string; } = never>(
params?: { params?: {
mockPageId?: ExtendsKcContextBase<KcContextExtended>["pageId"]; mockPageId?: ExtendsKcContextBase<KcContextExtended>["pageId"];
mockData?: readonly DeepPartial<ExtendsKcContextBase<KcContextExtended>>[]; mockData?: readonly DeepPartial<ExtendsKcContextBase<KcContextExtended>>[];
@ -51,22 +51,15 @@ export function getKcContext<KcContextExtended extends ({ pageId: string; } | un
} }
const kcContext: any = { "pageId": mockPageId }; const kcContext: any = {};
deepAssign({ deepAssign({
"target": kcContext, "target": kcContext,
"source": kcContextCommonMock "source": kcContextDefaultMock !== undefined ?
kcContextDefaultMock :
{ "pageId": mockPageId, ...kcContextCommonMock, }
}); });
if (kcContextDefaultMock !== undefined) {
deepAssign({
"target": kcContext,
"source": kcContextDefaultMock
});
}
if (partialKcContextCustomMock !== undefined) { if (partialKcContextCustomMock !== undefined) {
deepAssign({ deepAssign({

@ -2,6 +2,7 @@
import { assert } from "tsafe/assert"; import { assert } from "tsafe/assert";
import { is } from "tsafe/is"; import { is } from "tsafe/is";
//Warning: Be mindful that because of array this is not idempotent.
export function deepAssign( export function deepAssign(
params: { params: {
target: Record<string, unknown>; target: Record<string, unknown>;

@ -14,6 +14,7 @@ generateKeycloakThemeResources({
"keycloakThemeBuildingDirPath": pathJoin(sampleReactProjectDirPath, "build_keycloak_theme"), "keycloakThemeBuildingDirPath": pathJoin(sampleReactProjectDirPath, "build_keycloak_theme"),
"urlPathname": "/keycloakify-demo-app/", "urlPathname": "/keycloakify-demo-app/",
"urlOrigin": undefined, "urlOrigin": undefined,
"extraPagesId": ["my-custom-page.ftl"] "extraPagesId": ["my-custom-page.ftl"],
"extraThemeProperties": ["env=test"]
}); });

@ -6,37 +6,42 @@ import { same } from "evt/tools/inDepth";
import { doExtends } from "tsafe/doExtends"; import { doExtends } from "tsafe/doExtends";
import { assert } from "tsafe/assert"; import { assert } from "tsafe/assert";
import { kcContextMocks, kcContextCommonMock } from "../../lib/getKcContext/kcContextMocks"; import { kcContextMocks, kcContextCommonMock } from "../../lib/getKcContext/kcContextMocks";
import { deepClone } from "../../lib/tools/deepClone"; import { deepClone } from "../../lib/tools/deepClone";
import type { Any } from "ts-toolbelt"; import type { Any } from "ts-toolbelt";
{
const authorizedMailDomains = [ const authorizedMailDomains = [
"example.com", "example.com",
"another-example.com", "another-example.com",
"*.yet-another-example.com", "*.yet-another-example.com",
"*.example.com", "*.example.com",
"hello-world.com" "hello-world.com"
]; ];
const displayName = "this is an overwritten common value"; const displayName = "this is an overwritten common value";
const aNonStandardValue = "a non standard value"; const aNonStandardValue1 = "a non standard value 1";
const aNonStandardValue2 = "a non standard value 2";
type KcContextExtended = { type KcContextExtended = {
pageId: "register.ftl"; pageId: "register.ftl";
authorizedMailDomains: string[]; authorizedMailDomains: string[];
} | { } | {
pageId: "info.ftl";
aNonStandardValue1: string;
} | {
pageId: "my-extra-page-1.ftl"; pageId: "my-extra-page-1.ftl";
} | { } | {
pageId: "my-extra-page-2.ftl"; pageId: "my-extra-page-2.ftl";
aNonStandardValue: string; aNonStandardValue2: string;
}; };
function getKcContextProxy( const getKcContextProxy = (
params: { params: {
mockPageId: ExtendsKcContextBase<KcContextExtended>["pageId"]; mockPageId: ExtendsKcContextBase<KcContextExtended>["pageId"];
} }
) { ) => {
const { mockPageId } = params; const { mockPageId } = params;
@ -47,33 +52,34 @@ function getKcContextProxy(
"pageId": "login.ftl", "pageId": "login.ftl",
"realm": { displayName } "realm": { displayName }
}, },
{
"pageId": "info.ftl",
aNonStandardValue1
},
{ {
"pageId": "register.ftl", "pageId": "register.ftl",
authorizedMailDomains authorizedMailDomains
}, },
{ {
"pageId": "my-extra-page-2.ftl", "pageId": "my-extra-page-2.ftl",
aNonStandardValue aNonStandardValue2
} }
] ]
}); });
return { kcContext }; return { kcContext };
} };
{ {
const pageId= "login.ftl"; const pageId = "login.ftl";
const { kcContext } = getKcContextProxy({ "mockPageId": pageId }); const { kcContext } = getKcContextProxy({ "mockPageId": pageId });
//@ts-expect-error
doExtends<Any.Equals<typeof kcContext, any>, 1>();
assert(kcContext?.pageId === pageId); assert(kcContext?.pageId === pageId);
doExtends<typeof kcContext, KcContextBase.Login>(); doExtends<Any.Equals<typeof kcContext, KcContextBase.Login>, 1>();
assert(same( assert(same(
//NOTE: deepClone for printIfExists or other functions... //NOTE: deepClone for printIfExists or other functions...
@ -91,19 +97,44 @@ function getKcContextProxy(
console.log(`PASS ${pageId}`); console.log(`PASS ${pageId}`);
} }
{ {
const pageId = "info.ftl";
const { kcContext } = getKcContextProxy({ "mockPageId": pageId });
assert(kcContext?.pageId === pageId);
//NOTE: I don't understand the need to add: pageId: typeof pageId; ...
doExtends<Any.Equals<typeof kcContext, KcContextBase.Info & { pageId: typeof pageId; aNonStandardValue1: string; }>, 1>();
assert(same(
deepClone(kcContext),
(() => {
const mock = deepClone(kcContextMocks.find(({ pageId: pageId_i }) => pageId_i === pageId)!);
Object.assign(mock, { aNonStandardValue1 });
return mock;
})()
));
console.log(`PASS ${pageId}`);
}
{
const pageId = "register.ftl"; const pageId = "register.ftl";
const { kcContext } = getKcContextProxy({ "mockPageId": pageId }); const { kcContext } = getKcContextProxy({ "mockPageId": pageId });
//@ts-expect-error
doExtends<Any.Equals<typeof kcContext, any>, 1>();
assert(kcContext?.pageId === pageId); assert(kcContext?.pageId === pageId);
doExtends<typeof kcContext, KcContextBase.Register>(); //NOTE: I don't understand the need to add: pageId: typeof pageId; ...
doExtends<Any.Equals<typeof kcContext, KcContextBase.Register & { pageId: typeof pageId; authorizedMailDomains: string[]; }>, 1>();
assert(same( assert(same(
deepClone(kcContext), deepClone(kcContext),
@ -120,23 +151,19 @@ function getKcContextProxy(
console.log(`PASS ${pageId}`); console.log(`PASS ${pageId}`);
} }
{ {
const pageId = "my-extra-page-2.ftl"; const pageId = "my-extra-page-2.ftl";
const { kcContext } = getKcContextProxy({ "mockPageId": pageId }); const { kcContext } = getKcContextProxy({ "mockPageId": pageId });
//@ts-expect-error
doExtends<Any.Equals<typeof kcContext, any>, 1>();
assert(kcContext?.pageId === pageId); assert(kcContext?.pageId === pageId);
//@ts-expect-error doExtends<Any.Equals<typeof kcContext, KcContextBase.Common & { pageId: typeof pageId; aNonStandardValue2: string; }>, 1>();
doExtends<typeof kcContext, KcContextBase>();
doExtends<typeof kcContext, KcContextBase.Common>(); kcContext.aNonStandardValue2;
assert(same( assert(same(
deepClone(kcContext), deepClone(kcContext),
@ -144,7 +171,7 @@ function getKcContextProxy(
const mock = deepClone(kcContextCommonMock); const mock = deepClone(kcContextCommonMock);
Object.assign(mock, { pageId, aNonStandardValue }); Object.assign(mock, { pageId, aNonStandardValue2 });
return mock; return mock;
@ -153,9 +180,9 @@ function getKcContextProxy(
console.log(`PASS ${pageId}`); console.log(`PASS ${pageId}`);
} }
{ {
const pageId = "my-extra-page-1.ftl"; const pageId = "my-extra-page-1.ftl";
@ -163,15 +190,10 @@ function getKcContextProxy(
const { kcContext } = getKcContextProxy({ "mockPageId": pageId }); const { kcContext } = getKcContextProxy({ "mockPageId": pageId });
//@ts-expect-error
doExtends<Any.Equals<typeof kcContext, any>, 1>();
assert(kcContext?.pageId === pageId); assert(kcContext?.pageId === pageId);
//@ts-expect-error doExtends<Any.Equals<typeof kcContext, KcContextBase.Common & { pageId: typeof pageId; }>, 1>();
doExtends<typeof kcContext, KcContextBase>();
doExtends<typeof kcContext, KcContextBase.Common>();
assert(same( assert(same(
deepClone(kcContext), deepClone(kcContext),
@ -188,20 +210,41 @@ function getKcContextProxy(
console.log(`PASS ${pageId}`); console.log(`PASS ${pageId}`);
}
} }
{ {
const pageId = "login.ftl";
const { kcContext } = getKcContext({
"mockPageId": pageId
});
doExtends<Any.Equals<typeof kcContext, KcContextBase | undefined>, 1>();
assert(same(
deepClone(kcContext),
deepClone(kcContextMocks.find(({ pageId: pageId_i }) => pageId_i === pageId)!)
));
console.log("PASS no extension");
}
{
const { kcContext } = getKcContext(); const { kcContext } = getKcContext();
//@ts-expect-error doExtends<Any.Equals<typeof kcContext, KcContextBase | undefined>, 1>();
doExtends<Any.Equals<typeof kcContext, any>, 1>();
doExtends<typeof kcContext, KcContextBase | undefined>(); assert(kcContext === undefined);
console.log("PASS no extension, no mock");
} }