keycloakify 11.6.1 → 11.7.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/bin/{653.index.js → 288.index.js} +221 -201
- package/bin/313.index.js +377 -0
- package/bin/{174.index.js → 33.index.js} +37 -2
- package/bin/{615.index.js → 355.index.js} +353 -102
- package/bin/363.index.js +1537 -0
- package/bin/453.index.js +6 -42
- package/bin/{503.index.js → 678.index.js} +577 -53
- package/bin/{921.index.js → 780.index.js} +54 -45
- package/bin/880.index.js +206 -21
- package/bin/9.index.js +850 -0
- package/bin/{525.index.js → 911.index.js} +1302 -2
- package/bin/930.index.js +164 -0
- package/bin/946.index.js +20 -0
- package/bin/{153.index.js → 947.index.js} +22 -797
- package/bin/main.js +61 -19
- package/bin/{eject-file.d.ts → own.d.ts} +2 -1
- package/bin/shared/{addPostinstallScriptIfNotPresent.d.ts → initializeSpa/addSyncExtensionsToPostinstallScript.d.ts} +1 -1
- package/bin/shared/initializeSpa/index.d.ts +1 -0
- package/bin/shared/initializeSpa/initializeSpa.d.ts +9 -0
- package/bin/{postinstall/uiModuleMeta.d.ts → sync-extensions/extensionModuleMeta.d.ts} +5 -5
- package/bin/sync-extensions/getExtensionModuleFileSourceCodeReadyToBeCopied.d.ts +12 -0
- package/bin/sync-extensions/index.d.ts +1 -0
- package/bin/{postinstall/installUiModulesPeerDependencies.d.ts → sync-extensions/installExtensionModulesPeerDependencies.d.ts} +3 -3
- package/bin/{postinstall → sync-extensions}/managedGitignoreFile.d.ts +4 -4
- package/bin/tools/getInstalledModuleDirPath.d.ts +0 -1
- package/bin/tools/isKnownByGit.d.ts +3 -0
- package/bin/tools/isRootPath.d.ts +1 -0
- package/bin/tools/listInstalledModules.d.ts +0 -1
- package/package.json +41 -63
- package/src/bin/eject-page.ts +8 -84
- package/src/bin/initialize-account-theme/initialize-account-theme.ts +15 -14
- package/src/bin/initialize-admin-theme.ts +17 -124
- package/src/bin/initialize-email-theme.ts +10 -34
- package/src/bin/keycloakify/generateResources/generateResources.ts +49 -21
- package/src/bin/main.ts +61 -16
- package/src/bin/own.ts +208 -0
- package/src/bin/shared/{addPostinstallScriptIfNotPresent.ts → initializeSpa/addSyncExtensionsToPostinstallScript.ts} +4 -4
- package/src/bin/shared/initializeSpa/index.ts +1 -0
- package/src/bin/shared/initializeSpa/initializeSpa.ts +149 -0
- package/src/bin/{postinstall/uiModuleMeta.ts → sync-extensions/extensionModuleMeta.ts} +48 -43
- package/src/bin/{postinstall/getUiModuleFileSourceCodeReadyToBeCopied.ts → sync-extensions/getExtensionModuleFileSourceCodeReadyToBeCopied.ts} +32 -21
- package/src/bin/sync-extensions/index.ts +1 -0
- package/src/bin/{postinstall/installUiModulesPeerDependencies.ts → sync-extensions/installExtensionModulesPeerDependencies.ts} +15 -13
- package/src/bin/{postinstall → sync-extensions}/managedGitignoreFile.ts +18 -18
- package/src/bin/{postinstall/postinstall.ts → sync-extensions/sync-extension.ts} +14 -26
- package/src/bin/tools/getInstalledModuleDirPath.ts +24 -22
- package/src/bin/tools/isKnownByGit.ts +45 -0
- package/src/bin/tools/isRootPath.ts +22 -0
- package/src/bin/tools/listInstalledModules.ts +4 -6
- package/src/bin/tools/npmInstall.ts +1 -1
- package/src/bin/tools/untrackFromGit.ts +19 -3
- package/src/bin/tsconfig.json +1 -1
- package/bin/300.index.js +0 -770
- package/bin/375.index.js +0 -4089
- package/bin/490.index.js +0 -1108
- package/bin/568.index.js +0 -1867
- package/bin/735.index.js +0 -907
- package/bin/743.index.js +0 -69
- package/bin/854.index.js +0 -68
- package/bin/initialize-account-theme/copyBoilerplate.d.ts +0 -4
- package/bin/initialize-account-theme/initializeAccountTheme_multiPage.d.ts +0 -3
- package/bin/initialize-account-theme/initializeAccountTheme_singlePage.d.ts +0 -11
- package/bin/postinstall/getUiModuleFileSourceCodeReadyToBeCopied.d.ts +0 -12
- package/bin/postinstall/index.d.ts +0 -1
- package/bin/shared/getLatestsSemVersionedTag.d.ts +0 -15
- package/bin/shared/promptKeycloakVersion.d.ts +0 -10
- package/bin/tools/OptionalIfCanBeUndefined.d.ts +0 -14
- package/bin/tools/crc32.d.ts +0 -9
- package/bin/tools/deflate.d.ts +0 -24
- package/bin/tools/isTrackedByGit.d.ts +0 -3
- package/bin/tools/octokit-addons/getLatestsSemVersionedTag.d.ts +0 -15
- package/bin/tools/octokit-addons/listTags.d.ts +0 -13
- package/bin/tools/tee.d.ts +0 -3
- package/bin/tools/trimIndent.d.ts +0 -5
- package/src/bin/eject-file.ts +0 -68
- package/src/bin/initialize-account-theme/copyBoilerplate.ts +0 -32
- package/src/bin/initialize-account-theme/initializeAccountTheme_multiPage.ts +0 -21
- package/src/bin/initialize-account-theme/initializeAccountTheme_singlePage.ts +0 -142
- package/src/bin/initialize-account-theme/src/single-page/KcContext.ts +0 -7
- package/src/bin/initialize-account-theme/src/single-page/KcPage.tsx +0 -11
- package/src/bin/postinstall/index.ts +0 -1
- package/src/bin/shared/getLatestsSemVersionedTag.ts +0 -201
- package/src/bin/shared/promptKeycloakVersion.ts +0 -72
- package/src/bin/tools/OptionalIfCanBeUndefined.ts +0 -12
- package/src/bin/tools/crc32.ts +0 -73
- package/src/bin/tools/deflate.ts +0 -61
- package/src/bin/tools/isTrackedByGit.ts +0 -29
- package/src/bin/tools/octokit-addons/getLatestsSemVersionedTag.ts +0 -47
- package/src/bin/tools/octokit-addons/listTags.ts +0 -60
- package/src/bin/tools/tee.ts +0 -39
- package/src/bin/tools/trimIndent.ts +0 -49
- /package/bin/{postinstall/postinstall.d.ts → sync-extensions/sync-extension.d.ts} +0 -0
- /package/src/bin/initialize-account-theme/{src/multi-page → multi-page-boilerplate}/KcContext.ts +0 -0
- /package/src/bin/initialize-account-theme/{src/multi-page → multi-page-boilerplate}/KcPage.tsx +0 -0
- /package/src/bin/initialize-account-theme/{src/multi-page → multi-page-boilerplate}/KcPageStory.tsx +0 -0
- /package/src/bin/initialize-account-theme/{src/multi-page → multi-page-boilerplate}/i18n.ts +0 -0
package/src/bin/own.ts
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
import type { BuildContext } from "./shared/buildContext";
|
2
|
+
import { getExtensionModuleFileSourceCodeReadyToBeCopied } from "./sync-extensions/getExtensionModuleFileSourceCodeReadyToBeCopied";
|
3
|
+
import type { ExtensionModuleMeta } from "./sync-extensions/extensionModuleMeta";
|
4
|
+
import { command as command_syncExtensions } from "./sync-extensions/sync-extension";
|
5
|
+
import {
|
6
|
+
readManagedGitignoreFile,
|
7
|
+
writeManagedGitignoreFile
|
8
|
+
} from "./sync-extensions/managedGitignoreFile";
|
9
|
+
import { getExtensionModuleMetas } from "./sync-extensions/extensionModuleMeta";
|
10
|
+
import { getAbsoluteAndInOsFormatPath } from "./tools/getAbsoluteAndInOsFormatPath";
|
11
|
+
import { relative as pathRelative, dirname as pathDirname, join as pathJoin } from "path";
|
12
|
+
import { getInstalledModuleDirPath } from "./tools/getInstalledModuleDirPath";
|
13
|
+
import * as fsPr from "fs/promises";
|
14
|
+
import { isInside } from "./tools/isInside";
|
15
|
+
import chalk from "chalk";
|
16
|
+
|
17
|
+
export async function command(params: {
|
18
|
+
buildContext: BuildContext;
|
19
|
+
cliCommandOptions: {
|
20
|
+
path: string;
|
21
|
+
isRevert: boolean;
|
22
|
+
};
|
23
|
+
}) {
|
24
|
+
const { buildContext, cliCommandOptions } = params;
|
25
|
+
|
26
|
+
const extensionModuleMetas = await getExtensionModuleMetas({ buildContext });
|
27
|
+
|
28
|
+
const { targetFileRelativePathsByExtensionModuleMeta } = await (async () => {
|
29
|
+
const fileOrDirectoryRelativePath = pathRelative(
|
30
|
+
buildContext.themeSrcDirPath,
|
31
|
+
getAbsoluteAndInOsFormatPath({
|
32
|
+
cwd: buildContext.themeSrcDirPath,
|
33
|
+
pathIsh: cliCommandOptions.path
|
34
|
+
})
|
35
|
+
);
|
36
|
+
|
37
|
+
const arr = extensionModuleMetas
|
38
|
+
.map(extensionModuleMeta => ({
|
39
|
+
extensionModuleMeta,
|
40
|
+
fileRelativePaths: extensionModuleMeta.files
|
41
|
+
.map(({ fileRelativePath }) => fileRelativePath)
|
42
|
+
.filter(
|
43
|
+
fileRelativePath =>
|
44
|
+
fileRelativePath === fileOrDirectoryRelativePath ||
|
45
|
+
isInside({
|
46
|
+
dirPath: fileOrDirectoryRelativePath,
|
47
|
+
filePath: fileRelativePath
|
48
|
+
})
|
49
|
+
)
|
50
|
+
}))
|
51
|
+
.filter(({ fileRelativePaths }) => fileRelativePaths.length !== 0);
|
52
|
+
|
53
|
+
const targetFileRelativePathsByExtensionModuleMeta = new Map<
|
54
|
+
ExtensionModuleMeta,
|
55
|
+
string[]
|
56
|
+
>();
|
57
|
+
|
58
|
+
for (const { extensionModuleMeta, fileRelativePaths } of arr) {
|
59
|
+
targetFileRelativePathsByExtensionModuleMeta.set(
|
60
|
+
extensionModuleMeta,
|
61
|
+
fileRelativePaths
|
62
|
+
);
|
63
|
+
}
|
64
|
+
|
65
|
+
return { targetFileRelativePathsByExtensionModuleMeta };
|
66
|
+
})();
|
67
|
+
|
68
|
+
if (targetFileRelativePathsByExtensionModuleMeta.size === 0) {
|
69
|
+
console.log(
|
70
|
+
chalk.yellow(
|
71
|
+
"There is no Keycloakify extension modules files matching the provided path."
|
72
|
+
)
|
73
|
+
);
|
74
|
+
process.exit(1);
|
75
|
+
}
|
76
|
+
|
77
|
+
const { ownedFilesRelativePaths: ownedFilesRelativePaths_current } =
|
78
|
+
await readManagedGitignoreFile({
|
79
|
+
buildContext
|
80
|
+
});
|
81
|
+
|
82
|
+
await (cliCommandOptions.isRevert ? command_revert : command_own)({
|
83
|
+
extensionModuleMetas,
|
84
|
+
targetFileRelativePathsByExtensionModuleMeta,
|
85
|
+
ownedFilesRelativePaths_current,
|
86
|
+
buildContext
|
87
|
+
});
|
88
|
+
}
|
89
|
+
|
90
|
+
type Params_subcommands = {
|
91
|
+
extensionModuleMetas: ExtensionModuleMeta[];
|
92
|
+
targetFileRelativePathsByExtensionModuleMeta: Map<ExtensionModuleMeta, string[]>;
|
93
|
+
ownedFilesRelativePaths_current: string[];
|
94
|
+
buildContext: BuildContext;
|
95
|
+
};
|
96
|
+
|
97
|
+
async function command_own(params: Params_subcommands) {
|
98
|
+
const {
|
99
|
+
extensionModuleMetas,
|
100
|
+
targetFileRelativePathsByExtensionModuleMeta,
|
101
|
+
ownedFilesRelativePaths_current,
|
102
|
+
buildContext
|
103
|
+
} = params;
|
104
|
+
|
105
|
+
await writeManagedGitignoreFile({
|
106
|
+
buildContext,
|
107
|
+
extensionModuleMetas,
|
108
|
+
ownedFilesRelativePaths: [
|
109
|
+
...ownedFilesRelativePaths_current,
|
110
|
+
...Array.from(targetFileRelativePathsByExtensionModuleMeta.values())
|
111
|
+
.flat()
|
112
|
+
.filter(
|
113
|
+
fileRelativePath =>
|
114
|
+
!ownedFilesRelativePaths_current.includes(fileRelativePath)
|
115
|
+
)
|
116
|
+
]
|
117
|
+
});
|
118
|
+
|
119
|
+
const writeActions: (() => Promise<void>)[] = [];
|
120
|
+
|
121
|
+
for (const [
|
122
|
+
extensionModuleMeta,
|
123
|
+
fileRelativePaths
|
124
|
+
] of targetFileRelativePathsByExtensionModuleMeta.entries()) {
|
125
|
+
const extensionModuleDirPath = await getInstalledModuleDirPath({
|
126
|
+
moduleName: extensionModuleMeta.moduleName,
|
127
|
+
packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath)
|
128
|
+
});
|
129
|
+
|
130
|
+
for (const fileRelativePath of fileRelativePaths) {
|
131
|
+
if (ownedFilesRelativePaths_current.includes(fileRelativePath)) {
|
132
|
+
console.log(
|
133
|
+
chalk.grey(`You already have ownership over '${fileRelativePath}'.`)
|
134
|
+
);
|
135
|
+
continue;
|
136
|
+
}
|
137
|
+
|
138
|
+
writeActions.push(async () => {
|
139
|
+
const sourceCode = await getExtensionModuleFileSourceCodeReadyToBeCopied({
|
140
|
+
buildContext,
|
141
|
+
fileRelativePath,
|
142
|
+
isOwnershipAction: true,
|
143
|
+
extensionModuleName: extensionModuleMeta.moduleName,
|
144
|
+
extensionModuleDirPath,
|
145
|
+
extensionModuleVersion: extensionModuleMeta.version
|
146
|
+
});
|
147
|
+
|
148
|
+
await fsPr.writeFile(
|
149
|
+
pathJoin(buildContext.themeSrcDirPath, fileRelativePath),
|
150
|
+
sourceCode
|
151
|
+
);
|
152
|
+
|
153
|
+
console.log(chalk.green(`Ownership over '${fileRelativePath}' claimed.`));
|
154
|
+
});
|
155
|
+
}
|
156
|
+
}
|
157
|
+
|
158
|
+
if (writeActions.length === 0) {
|
159
|
+
console.log(chalk.yellow("No new file claimed."));
|
160
|
+
return;
|
161
|
+
}
|
162
|
+
|
163
|
+
await Promise.all(writeActions.map(action => action()));
|
164
|
+
}
|
165
|
+
|
166
|
+
async function command_revert(params: Params_subcommands) {
|
167
|
+
const {
|
168
|
+
extensionModuleMetas,
|
169
|
+
targetFileRelativePathsByExtensionModuleMeta,
|
170
|
+
ownedFilesRelativePaths_current,
|
171
|
+
buildContext
|
172
|
+
} = params;
|
173
|
+
|
174
|
+
const ownedFilesRelativePaths_toRemove = Array.from(
|
175
|
+
targetFileRelativePathsByExtensionModuleMeta.values()
|
176
|
+
)
|
177
|
+
.flat()
|
178
|
+
.filter(fileRelativePath => {
|
179
|
+
if (!ownedFilesRelativePaths_current.includes(fileRelativePath)) {
|
180
|
+
console.log(
|
181
|
+
chalk.grey(`Ownership over '${fileRelativePath}' wasn't claimed.`)
|
182
|
+
);
|
183
|
+
return false;
|
184
|
+
}
|
185
|
+
|
186
|
+
console.log(
|
187
|
+
chalk.green(`Ownership over '${fileRelativePath}' relinquished.`)
|
188
|
+
);
|
189
|
+
|
190
|
+
return true;
|
191
|
+
});
|
192
|
+
|
193
|
+
if (ownedFilesRelativePaths_toRemove.length === 0) {
|
194
|
+
console.log(chalk.yellow("No file relinquished."));
|
195
|
+
return;
|
196
|
+
}
|
197
|
+
|
198
|
+
await writeManagedGitignoreFile({
|
199
|
+
buildContext,
|
200
|
+
extensionModuleMetas,
|
201
|
+
ownedFilesRelativePaths: ownedFilesRelativePaths_current.filter(
|
202
|
+
fileRelativePath =>
|
203
|
+
!ownedFilesRelativePaths_toRemove.includes(fileRelativePath)
|
204
|
+
)
|
205
|
+
});
|
206
|
+
|
207
|
+
await command_syncExtensions({ buildContext });
|
208
|
+
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { dirname as pathDirname, relative as pathRelative, sep as pathSep } from "path";
|
2
2
|
import { assert } from "tsafe/assert";
|
3
|
-
import type { BuildContext } from "
|
3
|
+
import type { BuildContext } from "../buildContext";
|
4
4
|
|
5
5
|
export type BuildContextLike = {
|
6
6
|
projectDirPath: string;
|
@@ -9,13 +9,13 @@ export type BuildContextLike = {
|
|
9
9
|
|
10
10
|
assert<BuildContext extends BuildContextLike ? true : false>();
|
11
11
|
|
12
|
-
export function
|
12
|
+
export function addSyncExtensionsToPostinstallScript(params: {
|
13
13
|
parsedPackageJson: { scripts?: Record<string, string | undefined> };
|
14
14
|
buildContext: BuildContextLike;
|
15
15
|
}) {
|
16
16
|
const { parsedPackageJson, buildContext } = params;
|
17
17
|
|
18
|
-
const cmd_base = "keycloakify
|
18
|
+
const cmd_base = "keycloakify sync-extensions";
|
19
19
|
|
20
20
|
const projectCliOptionValue = (() => {
|
21
21
|
const packageJsonDirPath = pathDirname(buildContext.packageJsonFilePath);
|
@@ -56,7 +56,7 @@ export function addPostinstallScriptIfNotPresent(params: {
|
|
56
56
|
continue;
|
57
57
|
}
|
58
58
|
|
59
|
-
if (cmd_preexisting.includes(cmd_base)) {
|
59
|
+
if (!cmd_preexisting.includes(cmd_base)) {
|
60
60
|
scripts[scriptName] = generateCmd({ cmd_preexisting });
|
61
61
|
return;
|
62
62
|
}
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from "./initializeSpa";
|
@@ -0,0 +1,149 @@
|
|
1
|
+
import { dirname as pathDirname, join as pathJoin, relative as pathRelative } from "path";
|
2
|
+
import type { BuildContext } from "../buildContext";
|
3
|
+
import * as fs from "fs";
|
4
|
+
import { assert, is, type Equals } from "tsafe/assert";
|
5
|
+
import { id } from "tsafe/id";
|
6
|
+
import {
|
7
|
+
addSyncExtensionsToPostinstallScript,
|
8
|
+
type BuildContextLike as BuildContextLike_addSyncExtensionsToPostinstallScript
|
9
|
+
} from "./addSyncExtensionsToPostinstallScript";
|
10
|
+
import { getIsPrettierAvailable, runPrettier } from "../../tools/runPrettier";
|
11
|
+
import { npmInstall } from "../../tools/npmInstall";
|
12
|
+
import * as child_process from "child_process";
|
13
|
+
import { z } from "zod";
|
14
|
+
import chalk from "chalk";
|
15
|
+
|
16
|
+
export type BuildContextLike = BuildContextLike_addSyncExtensionsToPostinstallScript & {
|
17
|
+
themeSrcDirPath: string;
|
18
|
+
packageJsonFilePath: string;
|
19
|
+
};
|
20
|
+
|
21
|
+
assert<BuildContext extends BuildContextLike ? true : false>();
|
22
|
+
|
23
|
+
export async function initializeSpa(params: {
|
24
|
+
themeType: "account" | "admin";
|
25
|
+
buildContext: BuildContextLike;
|
26
|
+
}) {
|
27
|
+
const { themeType, buildContext } = params;
|
28
|
+
|
29
|
+
{
|
30
|
+
const themeTypeSrcDirPath = pathJoin(buildContext.themeSrcDirPath, themeType);
|
31
|
+
|
32
|
+
if (
|
33
|
+
fs.existsSync(themeTypeSrcDirPath) &&
|
34
|
+
fs.readdirSync(themeTypeSrcDirPath).length > 0
|
35
|
+
) {
|
36
|
+
console.warn(
|
37
|
+
chalk.red(
|
38
|
+
`There is already a ${pathRelative(
|
39
|
+
process.cwd(),
|
40
|
+
themeTypeSrcDirPath
|
41
|
+
)} directory in your project. Aborting.`
|
42
|
+
)
|
43
|
+
);
|
44
|
+
|
45
|
+
process.exit(-1);
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
const parsedPackageJson = (() => {
|
50
|
+
type ParsedPackageJson = {
|
51
|
+
scripts?: Record<string, string | undefined>;
|
52
|
+
dependencies?: Record<string, string | undefined>;
|
53
|
+
devDependencies?: Record<string, string | undefined>;
|
54
|
+
};
|
55
|
+
|
56
|
+
const zParsedPackageJson = (() => {
|
57
|
+
type TargetType = ParsedPackageJson;
|
58
|
+
|
59
|
+
const zTargetType = z.object({
|
60
|
+
scripts: z.record(z.union([z.string(), z.undefined()])).optional(),
|
61
|
+
dependencies: z.record(z.union([z.string(), z.undefined()])).optional(),
|
62
|
+
devDependencies: z.record(z.union([z.string(), z.undefined()])).optional()
|
63
|
+
});
|
64
|
+
|
65
|
+
assert<Equals<z.infer<typeof zTargetType>, TargetType>>;
|
66
|
+
|
67
|
+
return id<z.ZodType<TargetType>>(zTargetType);
|
68
|
+
})();
|
69
|
+
const parsedPackageJson = JSON.parse(
|
70
|
+
fs.readFileSync(buildContext.packageJsonFilePath).toString("utf8")
|
71
|
+
);
|
72
|
+
|
73
|
+
zParsedPackageJson.parse(parsedPackageJson);
|
74
|
+
|
75
|
+
assert(is<ParsedPackageJson>(parsedPackageJson));
|
76
|
+
|
77
|
+
return parsedPackageJson;
|
78
|
+
})();
|
79
|
+
|
80
|
+
addSyncExtensionsToPostinstallScript({
|
81
|
+
parsedPackageJson,
|
82
|
+
buildContext
|
83
|
+
});
|
84
|
+
|
85
|
+
const uiSharedMajor = (() => {
|
86
|
+
const dependencies = {
|
87
|
+
...parsedPackageJson.devDependencies,
|
88
|
+
...parsedPackageJson.dependencies
|
89
|
+
};
|
90
|
+
|
91
|
+
const version = dependencies["@keycloakify/keycloak-ui-shared"];
|
92
|
+
|
93
|
+
if (version === undefined) {
|
94
|
+
return undefined;
|
95
|
+
}
|
96
|
+
|
97
|
+
const match = version.match(/^[^~]?(\d+)\./);
|
98
|
+
|
99
|
+
if (match === null) {
|
100
|
+
return undefined;
|
101
|
+
}
|
102
|
+
|
103
|
+
return match[1];
|
104
|
+
})();
|
105
|
+
|
106
|
+
const moduleName = `@keycloakify/keycloak-${themeType}-ui`;
|
107
|
+
|
108
|
+
const version = (
|
109
|
+
JSON.parse(
|
110
|
+
child_process
|
111
|
+
.execSync(`npm show ${moduleName} versions --json`)
|
112
|
+
.toString("utf8")
|
113
|
+
.trim()
|
114
|
+
) as string[]
|
115
|
+
)
|
116
|
+
.reverse()
|
117
|
+
.filter(version => !version.includes("-"))
|
118
|
+
.find(version =>
|
119
|
+
uiSharedMajor === undefined ? true : version.startsWith(`${uiSharedMajor}.`)
|
120
|
+
);
|
121
|
+
|
122
|
+
assert(version !== undefined);
|
123
|
+
|
124
|
+
(parsedPackageJson.dependencies ??= {})[moduleName] = `~${version}`;
|
125
|
+
|
126
|
+
if (parsedPackageJson.devDependencies !== undefined) {
|
127
|
+
delete parsedPackageJson.devDependencies[moduleName];
|
128
|
+
}
|
129
|
+
|
130
|
+
{
|
131
|
+
let sourceCode = JSON.stringify(parsedPackageJson, undefined, 2);
|
132
|
+
|
133
|
+
if (await getIsPrettierAvailable()) {
|
134
|
+
sourceCode = await runPrettier({
|
135
|
+
sourceCode,
|
136
|
+
filePath: buildContext.packageJsonFilePath
|
137
|
+
});
|
138
|
+
}
|
139
|
+
|
140
|
+
fs.writeFileSync(
|
141
|
+
buildContext.packageJsonFilePath,
|
142
|
+
Buffer.from(sourceCode, "utf8")
|
143
|
+
);
|
144
|
+
}
|
145
|
+
|
146
|
+
await npmInstall({
|
147
|
+
packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath)
|
148
|
+
});
|
149
|
+
}
|
@@ -10,15 +10,15 @@ import { crawlAsync } from "../tools/crawlAsync";
|
|
10
10
|
import { getIsPrettierAvailable, getPrettier } from "../tools/runPrettier";
|
11
11
|
import { readThisNpmPackageVersion } from "../tools/readThisNpmPackageVersion";
|
12
12
|
import {
|
13
|
-
|
14
|
-
type BuildContextLike as
|
15
|
-
} from "./
|
13
|
+
getExtensionModuleFileSourceCodeReadyToBeCopied,
|
14
|
+
type BuildContextLike as BuildContextLike_getExtensionModuleFileSourceCodeReadyToBeCopied
|
15
|
+
} from "./getExtensionModuleFileSourceCodeReadyToBeCopied";
|
16
16
|
import * as crypto from "crypto";
|
17
17
|
import { KEYCLOAK_THEME } from "../shared/constants";
|
18
18
|
import { exclude } from "tsafe/exclude";
|
19
19
|
import { isAmong } from "tsafe/isAmong";
|
20
20
|
|
21
|
-
export type
|
21
|
+
export type ExtensionModuleMeta = {
|
22
22
|
moduleName: string;
|
23
23
|
version: string;
|
24
24
|
files: {
|
@@ -29,8 +29,8 @@ export type UiModuleMeta = {
|
|
29
29
|
peerDependencies: Record<string, string>;
|
30
30
|
};
|
31
31
|
|
32
|
-
const
|
33
|
-
type ExpectedType =
|
32
|
+
const zExtensionModuleMeta = (() => {
|
33
|
+
type ExpectedType = ExtensionModuleMeta;
|
34
34
|
|
35
35
|
const zTargetType = z.object({
|
36
36
|
moduleName: z.string(),
|
@@ -56,7 +56,7 @@ type ParsedCacheFile = {
|
|
56
56
|
keycloakifyVersion: string;
|
57
57
|
prettierConfigHash: string | null;
|
58
58
|
thisFilePath: string;
|
59
|
-
|
59
|
+
extensionModuleMetas: ExtensionModuleMeta[];
|
60
60
|
};
|
61
61
|
|
62
62
|
const zParsedCacheFile = (() => {
|
@@ -66,7 +66,7 @@ const zParsedCacheFile = (() => {
|
|
66
66
|
keycloakifyVersion: z.string(),
|
67
67
|
prettierConfigHash: z.union([z.string(), z.null()]),
|
68
68
|
thisFilePath: z.string(),
|
69
|
-
|
69
|
+
extensionModuleMetas: z.array(zExtensionModuleMeta)
|
70
70
|
});
|
71
71
|
|
72
72
|
type InferredType = z.infer<typeof zTargetType>;
|
@@ -76,10 +76,10 @@ const zParsedCacheFile = (() => {
|
|
76
76
|
return id<z.ZodType<ExpectedType>>(zTargetType);
|
77
77
|
})();
|
78
78
|
|
79
|
-
const CACHE_FILE_RELATIVE_PATH = pathJoin("
|
79
|
+
const CACHE_FILE_RELATIVE_PATH = pathJoin("extension-modules", "cache.json");
|
80
80
|
|
81
81
|
export type BuildContextLike =
|
82
|
-
|
82
|
+
BuildContextLike_getExtensionModuleFileSourceCodeReadyToBeCopied & {
|
83
83
|
cacheDirPath: string;
|
84
84
|
packageJsonFilePath: string;
|
85
85
|
projectDirPath: string;
|
@@ -87,9 +87,9 @@ export type BuildContextLike =
|
|
87
87
|
|
88
88
|
assert<BuildContext extends BuildContextLike ? true : false>();
|
89
89
|
|
90
|
-
export async function
|
90
|
+
export async function getExtensionModuleMetas(params: {
|
91
91
|
buildContext: BuildContextLike;
|
92
|
-
}): Promise<
|
92
|
+
}): Promise<ExtensionModuleMeta[]> {
|
93
93
|
const { buildContext } = params;
|
94
94
|
|
95
95
|
const cacheFilePath = pathJoin(buildContext.cacheDirPath, CACHE_FILE_RELATIVE_PATH);
|
@@ -106,10 +106,9 @@ export async function getUiModuleMetas(params: {
|
|
106
106
|
return configHash;
|
107
107
|
})();
|
108
108
|
|
109
|
-
const
|
109
|
+
const installedExtensionModules = await (async () => {
|
110
110
|
const installedModulesWithKeycloakifyInTheName = await listInstalledModules({
|
111
111
|
packageJsonFilePath: buildContext.packageJsonFilePath,
|
112
|
-
projectDirPath: buildContext.packageJsonFilePath,
|
113
112
|
filter: ({ moduleName }) =>
|
114
113
|
moduleName.includes("keycloakify") && moduleName !== "keycloakify"
|
115
114
|
});
|
@@ -134,7 +133,7 @@ export async function getUiModuleMetas(params: {
|
|
134
133
|
return await fsPr.readFile(cacheFilePath);
|
135
134
|
})();
|
136
135
|
|
137
|
-
const
|
136
|
+
const extensionModuleMetas_cacheUpToDate: ExtensionModuleMeta[] = await (async () => {
|
138
137
|
const parsedCacheFile: ParsedCacheFile | undefined = await (async () => {
|
139
138
|
if (cacheContent === undefined) {
|
140
139
|
return undefined;
|
@@ -177,45 +176,51 @@ export async function getUiModuleMetas(params: {
|
|
177
176
|
return [];
|
178
177
|
}
|
179
178
|
|
180
|
-
const
|
181
|
-
|
182
|
-
const
|
183
|
-
|
184
|
-
|
185
|
-
|
179
|
+
const extensionModuleMetas_cacheUpToDate =
|
180
|
+
parsedCacheFile.extensionModuleMetas.filter(extensionModuleMeta => {
|
181
|
+
const correspondingInstalledExtensionModule =
|
182
|
+
installedExtensionModules.find(
|
183
|
+
installedExtensionModule =>
|
184
|
+
installedExtensionModule.moduleName ===
|
185
|
+
extensionModuleMeta.moduleName
|
186
|
+
);
|
186
187
|
|
187
|
-
if (
|
188
|
+
if (correspondingInstalledExtensionModule === undefined) {
|
188
189
|
return false;
|
189
190
|
}
|
190
191
|
|
191
|
-
return
|
192
|
-
|
193
|
-
|
192
|
+
return (
|
193
|
+
correspondingInstalledExtensionModule.version ===
|
194
|
+
extensionModuleMeta.version
|
195
|
+
);
|
196
|
+
});
|
194
197
|
|
195
|
-
return
|
198
|
+
return extensionModuleMetas_cacheUpToDate;
|
196
199
|
})();
|
197
200
|
|
198
|
-
const
|
199
|
-
|
201
|
+
const extensionModuleMetas = await Promise.all(
|
202
|
+
installedExtensionModules.map(
|
200
203
|
async ({
|
201
204
|
moduleName,
|
202
205
|
version,
|
203
206
|
peerDependencies,
|
204
207
|
dirPath
|
205
|
-
}): Promise<
|
208
|
+
}): Promise<ExtensionModuleMeta> => {
|
206
209
|
use_cache: {
|
207
|
-
const
|
208
|
-
|
209
|
-
|
210
|
+
const extensionModuleMeta_cache =
|
211
|
+
extensionModuleMetas_cacheUpToDate.find(
|
212
|
+
extensionModuleMeta =>
|
213
|
+
extensionModuleMeta.moduleName === moduleName
|
214
|
+
);
|
210
215
|
|
211
|
-
if (
|
216
|
+
if (extensionModuleMeta_cache === undefined) {
|
212
217
|
break use_cache;
|
213
218
|
}
|
214
219
|
|
215
|
-
return
|
220
|
+
return extensionModuleMeta_cache;
|
216
221
|
}
|
217
222
|
|
218
|
-
const files:
|
223
|
+
const files: ExtensionModuleMeta["files"] = [];
|
219
224
|
|
220
225
|
{
|
221
226
|
const srcDirPath = pathJoin(dirPath, KEYCLOAK_THEME);
|
@@ -225,13 +230,13 @@ export async function getUiModuleMetas(params: {
|
|
225
230
|
returnedPathsType: "relative to dirPath",
|
226
231
|
onFileFound: async fileRelativePath => {
|
227
232
|
const sourceCode =
|
228
|
-
await
|
233
|
+
await getExtensionModuleFileSourceCodeReadyToBeCopied({
|
229
234
|
buildContext,
|
230
235
|
fileRelativePath,
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
236
|
+
isOwnershipAction: false,
|
237
|
+
extensionModuleDirPath: dirPath,
|
238
|
+
extensionModuleName: moduleName,
|
239
|
+
extensionModuleVersion: version
|
235
240
|
});
|
236
241
|
|
237
242
|
const hash = computeHash(sourceCode);
|
@@ -261,7 +266,7 @@ export async function getUiModuleMetas(params: {
|
|
261
266
|
});
|
262
267
|
}
|
263
268
|
|
264
|
-
return id<
|
269
|
+
return id<ExtensionModuleMeta>({
|
265
270
|
moduleName,
|
266
271
|
version,
|
267
272
|
files,
|
@@ -281,7 +286,7 @@ export async function getUiModuleMetas(params: {
|
|
281
286
|
keycloakifyVersion,
|
282
287
|
prettierConfigHash,
|
283
288
|
thisFilePath: cacheFilePath,
|
284
|
-
|
289
|
+
extensionModuleMetas
|
285
290
|
});
|
286
291
|
|
287
292
|
const cacheContent_new = Buffer.from(
|
@@ -306,7 +311,7 @@ export async function getUiModuleMetas(params: {
|
|
306
311
|
await fsPr.writeFile(cacheFilePath, cacheContent_new);
|
307
312
|
}
|
308
313
|
|
309
|
-
return
|
314
|
+
return extensionModuleMetas;
|
310
315
|
}
|
311
316
|
|
312
317
|
export function computeHash(data: Buffer) {
|
@@ -11,40 +11,51 @@ export type BuildContextLike = {
|
|
11
11
|
|
12
12
|
assert<BuildContext extends BuildContextLike ? true : false>();
|
13
13
|
|
14
|
-
export async function
|
14
|
+
export async function getExtensionModuleFileSourceCodeReadyToBeCopied(params: {
|
15
15
|
buildContext: BuildContextLike;
|
16
16
|
fileRelativePath: string;
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
isOwnershipAction: boolean;
|
18
|
+
extensionModuleDirPath: string;
|
19
|
+
extensionModuleName: string;
|
20
|
+
extensionModuleVersion: string;
|
21
21
|
}): Promise<Buffer> {
|
22
22
|
const {
|
23
23
|
buildContext,
|
24
|
-
|
24
|
+
extensionModuleDirPath,
|
25
25
|
fileRelativePath,
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
isOwnershipAction,
|
27
|
+
extensionModuleName,
|
28
|
+
extensionModuleVersion
|
29
29
|
} = params;
|
30
30
|
|
31
31
|
let sourceCode = (
|
32
|
-
await fsPr.readFile(
|
32
|
+
await fsPr.readFile(
|
33
|
+
pathJoin(extensionModuleDirPath, KEYCLOAK_THEME, fileRelativePath)
|
34
|
+
)
|
33
35
|
).toString("utf8");
|
34
36
|
|
35
37
|
sourceCode = addCommentToSourceCode({
|
36
38
|
sourceCode,
|
37
39
|
fileRelativePath,
|
38
|
-
commentLines:
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
40
|
+
commentLines: (() => {
|
41
|
+
const path = fileRelativePath.split(pathSep).join("/");
|
42
|
+
|
43
|
+
return isOwnershipAction
|
44
|
+
? [
|
45
|
+
`This file has been claimed for ownership from ${extensionModuleName} version ${extensionModuleVersion}.`,
|
46
|
+
`To relinquish ownership and restore this file to its original content, run the following command:`,
|
47
|
+
``,
|
48
|
+
`$ npx keycloakify own --path '${path}' --revert`
|
49
|
+
]
|
50
|
+
: [
|
51
|
+
`WARNING: Before modifying this file, run the following command:`,
|
52
|
+
``,
|
53
|
+
`$ npx keycloakify own --path '${path}'`,
|
54
|
+
``,
|
55
|
+
`This file is provided by ${extensionModuleName} version ${extensionModuleVersion}.`,
|
56
|
+
`It was copied into your repository by the postinstall script: \`keycloakify sync-extensions\`.`
|
57
|
+
];
|
58
|
+
})()
|
48
59
|
});
|
49
60
|
|
50
61
|
const destFilePath = pathJoin(buildContext.themeSrcDirPath, fileRelativePath);
|
@@ -93,7 +104,7 @@ function addCommentToSourceCode(params: {
|
|
93
104
|
`<!--`,
|
94
105
|
...commentLines.map(
|
95
106
|
line =>
|
96
|
-
` ${line.replace("--
|
107
|
+
` ${line.replace("--path", "-p").replace("Before modifying", "Before modifying or replacing")}`
|
97
108
|
),
|
98
109
|
`-->`
|
99
110
|
].join("\n");
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from "./sync-extension";
|